2 * Sone - PageToadletTest.kt - Copyright © 2020 David 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.web.page
20 import freenet.client.HighLevelSimpleClient
21 import freenet.clients.http.Cookie
22 import freenet.clients.http.FProxyFetchInProgress.REFILTER_POLICY
23 import freenet.clients.http.LinkEnabledCallback
24 import freenet.clients.http.PageMaker
25 import freenet.clients.http.ReceivedCookie
26 import freenet.clients.http.Toadlet
27 import freenet.clients.http.ToadletContainer
28 import freenet.clients.http.ToadletContext
29 import freenet.clients.http.bookmark.BookmarkManager
30 import freenet.node.useralerts.UserAlertManager
31 import freenet.support.HTMLNode
32 import freenet.support.MultiValueTable
33 import freenet.support.api.Bucket
34 import freenet.support.api.BucketFactory
35 import freenet.support.api.HTTPRequest
36 import freenet.support.io.ArrayBucket
37 import net.pterodactylus.sone.test.deepMock
38 import net.pterodactylus.sone.test.mock
39 import net.pterodactylus.sone.test.whenever
40 import net.pterodactylus.util.web.Method
41 import net.pterodactylus.util.web.Page
42 import net.pterodactylus.util.web.Response
43 import org.hamcrest.MatcherAssert.assertThat
44 import org.hamcrest.Matchers.arrayContaining
45 import org.hamcrest.Matchers.equalTo
46 import org.hamcrest.Matchers.sameInstance
48 import org.mockito.ArgumentMatchers.anyLong
51 import kotlin.text.Charsets.UTF_8
54 * Unit test for PageToadletTest.
56 class PageToadletTest {
58 private val highLevelSimpleClient = mock<HighLevelSimpleClient>()
59 private val httpRequest = mock<HTTPRequest>()
60 private val toadletContext = deepMock<ToadletContext>()
63 whenever(toadletContext.bucketFactory.makeBucket(anyLong())).then { ArrayBucket() }
67 fun `get request is forwarded to page correctly`() {
68 var capturedRequest: FreenetRequest? = null
69 val page = object : TestPage() {
70 override fun handleRequest(request: FreenetRequest, response: Response) =
71 super.handleRequest(request, response)
72 .also { capturedRequest = request }
74 val pageToadlet = PageToadlet(highLevelSimpleClient, "MenuName", page, "/path/")
75 pageToadlet.handleMethodGET(URI("/test"), httpRequest, toadletContext)
76 assertThat(capturedRequest!!.uri, equalTo(URI("/test")))
77 assertThat(capturedRequest!!.method, equalTo(Method.GET))
81 fun `post request is forwarded to page correctly`() {
82 var capturedRequest: FreenetRequest? = null
83 val page = object : TestPage() {
84 override fun handleRequest(request: FreenetRequest, response: Response) =
85 super.handleRequest(request, response)
86 .also { capturedRequest = request }
88 val pageToadlet = PageToadlet(highLevelSimpleClient, "MenuName", page, "/path/")
89 pageToadlet.handleMethodPOST(URI("/test"), httpRequest, toadletContext)
90 assertThat(capturedRequest!!.uri, equalTo(URI("/test")))
91 assertThat(capturedRequest!!.method, equalTo(Method.POST))
95 fun `content written to response is written to context`() {
96 val page = object : TestPage() {
97 override fun handleRequest(request: FreenetRequest, response: Response) =
101 contentType = "data/test"
102 addHeader("Test", "Value")
103 addHeader("More", "true")
104 addHeader("Test", "Another")
108 val pageToadlet = PageToadlet(highLevelSimpleClient, "MenuName", page, "/path/")
109 var writtenData: ByteArray? = null
110 var capturedReply: CapturedReply? = null
111 val toadletContext = object : DelegatingToadletContext(this.toadletContext) {
112 override fun sendReplyHeaders(code: Int, desc: String?, mvt: MultiValueTable<String, String>?, mimeType: String?, length: Long) =
113 sendReplyHeaders(code, desc, mvt, mimeType, length, false)
115 override fun sendReplyHeaders(code: Int, desc: String?, mvt: MultiValueTable<String, String>?, mimeType: String?, length: Long, forceDisableJavascript: Boolean) {
116 capturedReply = CapturedReply(code, desc, mvt, mimeType, length)
119 override fun writeData(data: ByteArray?, offset: Int, length: Int) {
120 writtenData = data!!.copyOfRange(offset, offset + length)
123 override fun writeData(data: ByteArray?) = writeData(data, 0, data!!.size)
124 override fun writeData(data: Bucket?) = writeData(data!!.inputStream.readBytes())
126 pageToadlet.handleMethodGET(URI("/test"), httpRequest, toadletContext)
127 assertThat(capturedReply!!.code, equalTo(123))
128 assertThat(capturedReply!!.status, equalTo("Works"))
129 assertThat(capturedReply!!.mimeType, equalTo("data/test"))
130 assertThat(capturedReply!!.length, equalTo(7L))
131 assertThat(capturedReply!!.headers!!.getArray("Test"), arrayContaining<Any>("Value", "Another"))
132 assertThat(capturedReply!!.headers!!.getArray("More"), arrayContaining<Any>("true"))
133 assertThat(writtenData!!.toString(UTF_8), equalTo("Content"))
137 fun `link-enabled is true for non-callback pages`() {
138 val page = TestPage()
139 val pageToadlet = PageToadlet(highLevelSimpleClient, "MenuName", page, "/path/")
140 assertThat(pageToadlet.isEnabled(toadletContext), equalTo(true))
144 fun `link-enabled is passed through for callback pages`() {
145 var capturedToadletContext: ToadletContext? = null
146 val page = object : TestPage(), LinkEnabledCallback {
147 override fun isEnabled(ctx: ToadletContext?) = false.also { capturedToadletContext = toadletContext }
149 val pageToadlet = PageToadlet(highLevelSimpleClient, "MenuName", page, "/path/")
150 assertThat(pageToadlet.isEnabled(toadletContext), equalTo(false))
151 assertThat(capturedToadletContext, sameInstance(toadletContext))
155 fun `link excemption is false for non-freenet pages`() {
156 val page = TestPage()
157 val pageToadlet = PageToadlet(highLevelSimpleClient, "MenuName", page, "/path/")
158 assertThat(pageToadlet.isLinkExcepted(URI("/test")), equalTo(false))
162 fun `link excemption is passed through for freenet pages`() {
163 var capturedUri: URI? = null
164 val page = object : TestPage(), FreenetPage {
165 override fun isLinkExcepted(link: URI) = true.also { capturedUri = link }
167 val pageToadlet = PageToadlet(highLevelSimpleClient, "MenuName", page, "/path/")
168 assertThat(pageToadlet.isLinkExcepted(URI("/test")), equalTo(true))
169 assertThat(capturedUri, equalTo(URI("/test")))
173 fun `path is created correctly from prefix and page path`() {
174 val page = object : TestPage() {
175 override fun getPath() = "test-path"
177 val pageToadlet = PageToadlet(highLevelSimpleClient, "MenuName", page, "/path/")
178 assertThat(pageToadlet.path(), equalTo("/path/test-path"))
182 fun `menu name is returned correctly`() {
183 val pageToadlet = PageToadlet(highLevelSimpleClient, "MenuName", TestPage(), "/path/")
184 assertThat(pageToadlet.menuName, equalTo("MenuName"))
189 private data class CapturedReply(val code: Int, val status: String?, val headers: MultiValueTable<String, String>?, val mimeType: String?, val length: Long?)
191 private open class TestPage : Page<FreenetRequest> {
192 override fun getPath() = ""
193 override fun isPrefixPage() = false
194 override fun handleRequest(request: FreenetRequest, response: Response) = response
197 private open class DelegatingToadletContext(private val toadletContext: ToadletContext) : ToadletContext {
198 override fun activeToadlet(): Toadlet = toadletContext.activeToadlet()
199 override fun forceDisconnect() = toadletContext.forceDisconnect()
200 override fun sendReplyHeaders(code: Int, desc: String?, mvt: MultiValueTable<String, String>?, mimeType: String?, length: Long) = toadletContext.sendReplyHeaders(code, desc, mvt, mimeType, length)
201 override fun sendReplyHeaders(code: Int, desc: String?, mvt: MultiValueTable<String, String>?, mimeType: String?, length: Long, forceDisableJavascript: Boolean) = toadletContext.sendReplyHeaders(code, desc, mvt, mimeType, length, forceDisableJavascript)
202 @Suppress("DEPRECATION")
203 override fun sendReplyHeaders(code: Int, desc: String?, mvt: MultiValueTable<String, String>?, mimeType: String?, length: Long, mTime: Date?) = toadletContext.sendReplyHeaders(code, desc, mvt, mimeType, length, mTime)
204 override fun getUri(): URI = toadletContext.uri
205 override fun getPageMaker(): PageMaker = toadletContext.pageMaker
206 override fun getBucketFactory(): BucketFactory = toadletContext.bucketFactory
207 override fun getHeaders(): MultiValueTable<String, String> = toadletContext.headers
208 override fun checkFullAccess(toadlet: Toadlet?): Boolean = toadletContext.checkFullAccess(toadlet)
209 override fun doRobots(): Boolean = toadletContext.doRobots()
210 override fun getReFilterPolicy(): REFILTER_POLICY = toadletContext.reFilterPolicy
211 override fun getAlertManager(): UserAlertManager = toadletContext.alertManager
212 override fun checkFormPassword(request: HTTPRequest?, redirectTo: String?): Boolean = toadletContext.checkFormPassword(request, redirectTo)
213 override fun checkFormPassword(request: HTTPRequest?): Boolean = toadletContext.checkFormPassword(request)
214 override fun addFormChild(parentNode: HTMLNode?, target: String?, id: String?): HTMLNode = toadletContext.addFormChild(parentNode, target, id)
215 override fun sendReplyHeadersFProxy(code: Int, desc: String?, mvt: MultiValueTable<String, String>?, mimeType: String?, length: Long) = toadletContext.sendReplyHeadersFProxy(code, desc, mvt, mimeType, length)
216 override fun setCookie(newCookie: Cookie?) = toadletContext.setCookie(newCookie)
217 override fun isAdvancedModeEnabled(): Boolean = toadletContext.isAdvancedModeEnabled
218 override fun disableProgressPage(): Boolean = toadletContext.disableProgressPage()
219 override fun writeData(data: ByteArray?, offset: Int, length: Int) = toadletContext.writeData(data, offset, length)
220 override fun writeData(data: ByteArray?) = toadletContext.writeData(data)
221 override fun writeData(data: Bucket?) = toadletContext.writeData(data)
222 override fun getCookie(domain: URI?, path: URI?, name: String?): ReceivedCookie? = toadletContext.getCookie(domain, path, name)
223 override fun getUniqueId(): String = toadletContext.uniqueId
224 override fun sendReplyHeadersStatic(code: Int, desc: String?, mvt: MultiValueTable<String, String>?, mimeType: String?, length: Long, mTime: Date?) = toadletContext.sendReplyHeadersStatic(code, desc, mvt, mimeType, length, mTime)
225 override fun getBookmarkManager(): BookmarkManager = toadletContext.bookmarkManager
226 override fun isAllowedFullAccess(): Boolean = toadletContext.isAllowedFullAccess
227 override fun hasFormPassword(request: HTTPRequest?): Boolean = toadletContext.hasFormPassword(request)
228 override fun getFormPassword(): String = toadletContext.formPassword
229 override fun getContainer(): ToadletContainer = toadletContext.container