X-Git-Url: https://git.pterodactylus.net/?p=Sone.git;a=blobdiff_plain;f=src%2Ftest%2Fkotlin%2Fnet%2Fpterodactylus%2Fsone%2Fweb%2Fpages%2FSearchPageTest.kt;h=440fe1db8acd1fb63c0d33e99d20a47a24112734;hp=65b65a99c1660f23a0c9ef6b9f7effa9cb630f67;hb=6a3f1fede0cda5cd6ed56204aa1dd37a19813cb9;hpb=de7568a82eb4150bf6d2b0553841b7b69f84c968 diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/SearchPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/SearchPageTest.kt index 65b65a9..440fe1d 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/SearchPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/SearchPageTest.kt @@ -1,28 +1,51 @@ package net.pterodactylus.sone.web.pages import com.google.common.base.Optional.absent +import com.google.common.base.Ticker import net.pterodactylus.sone.data.Album import net.pterodactylus.sone.data.Image import net.pterodactylus.sone.data.Post import net.pterodactylus.sone.data.PostReply import net.pterodactylus.sone.data.Profile import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.asOptional +import net.pterodactylus.sone.test.getInstance +import net.pterodactylus.sone.test.isOnPage import net.pterodactylus.sone.test.mock import net.pterodactylus.sone.test.whenever -import net.pterodactylus.sone.web.pages.SearchPage +import net.pterodactylus.sone.utils.asOptional +import net.pterodactylus.sone.web.baseInjector import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.contains +import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.notNullValue import org.junit.Test +import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicInteger /** * Unit test for [SearchPage]. */ -class SearchPageTest : WebPageTest() { +class SearchPageTest: WebPageTest({ template, webInterface, loaders -> SearchPage(template, webInterface, loaders, ticker) }) { - private val page = SearchPage(template, webInterface) + companion object { + val ticker = mock() + } - override fun getPage() = page + @Test + fun `page returns correct path`() { + assertThat(page.path, equalTo("search.html")) + } + + @Test + fun `page does not require login`() { + assertThat(page.requiresLogin(), equalTo(false)) + } + + @Test + fun `page returns correct title`() { + addTranslation("Page.Search.Title", "search page title") + assertThat(page.getPageTitle(soneRequest), equalTo("search page title")) + } @Test fun `empty query redirects to index page`() { @@ -43,28 +66,28 @@ class SearchPageTest : WebPageTest() { @Test fun `searching for sone link redirects to view sone page`() { - addSone("sone-id", mock()) - addHttpRequestParameter("query", "sone://sone-id") - verifyRedirect("viewSone.html?sone=sone-id") + addSone("Sone-ID", mock()) + addHttpRequestParameter("query", "sone://Sone-ID") + verifyRedirect("viewSone.html?sone=Sone-ID") } @Test fun `searching for sone link without prefix redirects to view sone page`() { - addSone("sone-id", mock()) + addSone("sone-id", mock()) addHttpRequestParameter("query", "sone-id") verifyRedirect("viewSone.html?sone=sone-id") } @Test fun `searching for a post link redirects to post page`() { - addPost("post-id", mock()) - addHttpRequestParameter("query", "post://post-id") - verifyRedirect("viewPost.html?post=post-id") + addPost("Post-id", mock()) + addHttpRequestParameter("query", "post://Post-id") + verifyRedirect("viewPost.html?post=Post-id") } @Test fun `searching for a post ID without prefix redirects to post page`() { - addPost("post-id", mock()) + addPost("post-id", mock()) addHttpRequestParameter("query", "post-id") verifyRedirect("viewPost.html?post=post-id") } @@ -72,8 +95,8 @@ class SearchPageTest : WebPageTest() { @Test fun `searching for a reply link redirects to the post page`() { val postReply = mock().apply { whenever(postId).thenReturn("post-id") } - addPostReply("reply-id", postReply) - addHttpRequestParameter("query", "reply://reply-id") + addPostReply("Reply-id", postReply) + addHttpRequestParameter("query", "reply://Reply-id") verifyRedirect("viewPost.html?post=post-id") } @@ -87,28 +110,28 @@ class SearchPageTest : WebPageTest() { @Test fun `searching for an album link redirects to the image browser`() { - addAlbum("album-id", mock()) + addAlbum("album-id", mock()) addHttpRequestParameter("query", "album://album-id") verifyRedirect("imageBrowser.html?album=album-id") } @Test fun `searching for an album ID redirects to the image browser`() { - addAlbum("album-id", mock()) + addAlbum("album-id", mock()) addHttpRequestParameter("query", "album-id") verifyRedirect("imageBrowser.html?album=album-id") } @Test fun `searching for an image link redirects to the image browser`() { - addImage("image-id", mock()) + addImage("image-id", mock()) addHttpRequestParameter("query", "image://image-id") verifyRedirect("imageBrowser.html?image=image-id") } @Test fun `searching for an image ID redirects to the image browser`() { - addImage("image-id", mock()) + addImage("image-id", mock()) addHttpRequestParameter("query", "image-id") verifyRedirect("imageBrowser.html?image=image-id") } @@ -141,8 +164,9 @@ class SearchPageTest : WebPageTest() { addSone("sone-with-match", soneWithMatch) addSone("sone-without-match", soneWithoutMatch) addHttpRequestParameter("query", "word") - page.handleRequest(freenetRequest, templateContext) - assertThat(this["postHits"], contains(postWithMatch)) + verifyNoRedirect { + assertThat(this["postHits"], contains(postWithMatch)) + } } @Test @@ -158,8 +182,9 @@ class SearchPageTest : WebPageTest() { addSone("sone-with-match", soneWithMatch) addSone("sone-without-match", soneWithoutMatch) addHttpRequestParameter("query", "word") - page.handleRequest(freenetRequest, templateContext) - assertThat(this["postHits"], contains(postWithMatch)) + verifyNoRedirect { + assertThat(this["postHits"], contains(postWithMatch)) + } } private fun createSoneWithPost(idPostfix: String, text: String, recipient: Sone? = null, sender: Sone? = null) = @@ -172,8 +197,9 @@ class SearchPageTest : WebPageTest() { val postWithEarlyMatch = createSoneWithPost("with-early-match", "optional match") val postWithLaterMatch = createSoneWithPost("with-later-match", "match that is optional") addHttpRequestParameter("query", "optional ") - page.handleRequest(freenetRequest, templateContext) - assertThat(this["postHits"], contains(postWithEarlyMatch, postWithLaterMatch)) + verifyNoRedirect { + assertThat(this["postHits"], contains(postWithEarlyMatch, postWithLaterMatch)) + } } @Test @@ -181,8 +207,9 @@ class SearchPageTest : WebPageTest() { val postWithRequiredMatch = createSoneWithPost("with-required-match", "required match") createPost("without-required-match", "not a match") addHttpRequestParameter("query", "+required ") - page.handleRequest(freenetRequest, templateContext) - assertThat(this["postHits"], contains(postWithRequiredMatch)) + verifyNoRedirect { + assertThat(this["postHits"], contains(postWithRequiredMatch)) + } } @Test @@ -190,8 +217,9 @@ class SearchPageTest : WebPageTest() { createSoneWithPost("with-forbidden-match", "forbidden match") val postWithoutForbiddenMatch = createSoneWithPost("without-forbidden-match", "not a match") addHttpRequestParameter("query", "match -forbidden") - page.handleRequest(freenetRequest, templateContext) - assertThat(this["postHits"], contains(postWithoutForbiddenMatch)) + verifyNoRedirect { + assertThat(this["postHits"], contains(postWithoutForbiddenMatch)) + } } @Test @@ -199,8 +227,9 @@ class SearchPageTest : WebPageTest() { val postWithMatch = createSoneWithPost("with-match", "with + match") createSoneWithPost("without-match", "without match") addHttpRequestParameter("query", "+") - page.handleRequest(freenetRequest, templateContext) - assertThat(this["postHits"], contains(postWithMatch)) + verifyNoRedirect { + assertThat(this["postHits"], contains(postWithMatch)) + } } @Test @@ -208,8 +237,9 @@ class SearchPageTest : WebPageTest() { val postWithMatch = createSoneWithPost("with-match", "with - match") createSoneWithPost("without-match", "without match") addHttpRequestParameter("query", "-") - page.handleRequest(freenetRequest, templateContext) - assertThat(this["postHits"], contains(postWithMatch)) + verifyNoRedirect { + assertThat(this["postHits"], contains(postWithMatch)) + } } private fun createPost(id: String, text: String, recipient: Sone?) = mock().apply { @@ -220,7 +250,7 @@ class SearchPageTest : WebPageTest() { whenever(this.text).thenReturn(text) } - private fun createSone(id: String, firstName: String, middleName: String, lastName: String) = mock().apply { + private fun createSone(id: String, firstName: String? = null, middleName: String? = null, lastName: String? = null) = mock().apply { whenever(this.id).thenReturn(id) whenever(this.name).thenReturn(id) whenever(this.profile).thenReturn(Profile(this).apply { @@ -236,8 +266,9 @@ class SearchPageTest : WebPageTest() { val postWithMatch = createSoneWithPost("with-match", "test", recipient) createSoneWithPost("without-match", "no match") addHttpRequestParameter("query", "recipient") - page.handleRequest(freenetRequest, templateContext) - assertThat(this["postHits"], contains(postWithMatch)) + verifyNoRedirect { + assertThat(this["postHits"], contains(postWithMatch)) + } } @Test @@ -247,11 +278,98 @@ class SearchPageTest : WebPageTest() { createSoneWithPost("with-match", "test", sender = soneWithProfileField) createSoneWithPost("without-match", "no match") addHttpRequestParameter("query", "value") - page.handleRequest(freenetRequest, templateContext) - assertThat(this["soneHits"], contains(soneWithProfileField)) + verifyNoRedirect { + assertThat(this["soneHits"], contains(soneWithProfileField)) + } + } + + @Test + fun `sone hits are paginated correctly`() { + core.preferences.newPostsPerPage = 2 + val sones = listOf(createSone("1Sone"), createSone("Other1"), createSone("22Sone"), createSone("333Sone"), createSone("Other2")) + .onEach { addSone(it.id, it) } + addHttpRequestParameter("query", "sone") + verifyNoRedirect { + assertThat(this["sonePagination"], isOnPage(0).hasPages(2)) + assertThat(this["soneHits"], contains(sones[0], sones[2])) + } + } + + @Test + fun `sone hits page 2 is shown correctly`() { + core.preferences.newPostsPerPage = 2 + val sones = listOf(createSone("1Sone"), createSone("Other1"), createSone("22Sone"), createSone("333Sone"), createSone("Other2")) + .onEach { addSone(it.id, it) } + addHttpRequestParameter("query", "sone") + addHttpRequestParameter("sonePage", "1") + verifyNoRedirect { + assertThat(this["sonePagination"], isOnPage(1).hasPages(2)) + assertThat(this["soneHits"], contains(sones[3])) + } + } + + @Test + fun `post hits are paginated correctly`() { + core.preferences.newPostsPerPage = 2 + val sones = listOf(createSoneWithPost("match1", "1Sone"), createSoneWithPost("no-match1", "Other1"), createSoneWithPost("match2", "22Sone"), createSoneWithPost("match3", "333Sone"), createSoneWithPost("no-match2", "Other2")) + addHttpRequestParameter("query", "sone") + verifyNoRedirect { + assertThat(this["postPagination"], isOnPage(0).hasPages(2)) + assertThat(this["postHits"], contains(sones[0], sones[2])) + } + } + + @Test + fun `post hits page 2 is shown correctly`() { + core.preferences.newPostsPerPage = 2 + val sones = listOf(createSoneWithPost("match1", "1Sone"), createSoneWithPost("no-match1", "Other1"), createSoneWithPost("match2", "22Sone"), createSoneWithPost("match3", "333Sone"), createSoneWithPost("no-match2", "Other2")) + addHttpRequestParameter("query", "sone") + addHttpRequestParameter("postPage", "1") + verifyNoRedirect { + assertThat(this["postPagination"], isOnPage(1).hasPages(2)) + assertThat(this["postHits"], contains(sones[3])) + } + } + + @Test + fun `post search results are cached`() { + val post = createPost("with-match", "text") + val callCounter = AtomicInteger() + whenever(post.text).thenAnswer { callCounter.incrementAndGet(); "text" } + val sone = createSoneWithPost(post) + addSone("sone", sone) + addHttpRequestParameter("query", "text") + verifyNoRedirect { + assertThat(this["postHits"], contains(post)) + } + verifyNoRedirect { + assertThat(callCounter.get(), equalTo(1)) + } + } + + @Test + fun `post search results are cached for five minutes`() { + val post = createPost("with-match", "text") + val callCounter = AtomicInteger() + whenever(post.text).thenAnswer { callCounter.incrementAndGet(); "text" } + val sone = createSoneWithPost(post) + addSone("sone", sone) + addHttpRequestParameter("query", "text") + verifyNoRedirect { + assertThat(this["postHits"], contains(post)) + } + whenever(ticker.read()).thenReturn(TimeUnit.MINUTES.toNanos(5) + 1) + verifyNoRedirect { + assertThat(callCounter.get(), equalTo(2)) + } } @Suppress("UNCHECKED_CAST") private operator fun get(key: String): T? = templateContext[key] as? T + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + }