✨ Annotate KnownSonesPage with MenuName
[Sone.git] / src / test / kotlin / net / pterodactylus / sone / web / pages / WebPageTest.kt
1 package net.pterodactylus.sone.web.pages
2
3 import com.google.common.eventbus.EventBus
4 import freenet.clients.http.*
5 import freenet.support.SimpleReadOnlyArrayBucket
6 import freenet.support.api.HTTPRequest
7 import freenet.support.api.HTTPUploadedFile
8 import net.pterodactylus.sone.core.Preferences
9 import net.pterodactylus.sone.data.Album
10 import net.pterodactylus.sone.data.Image
11 import net.pterodactylus.sone.data.Post
12 import net.pterodactylus.sone.data.PostReply
13 import net.pterodactylus.sone.data.Sone
14 import net.pterodactylus.sone.data.TemporaryImage
15 import net.pterodactylus.sone.freenet.wot.OwnIdentity
16 import net.pterodactylus.sone.test.deepMock
17 import net.pterodactylus.sone.test.get
18 import net.pterodactylus.sone.test.mock
19 import net.pterodactylus.sone.test.whenever
20 import net.pterodactylus.sone.utils.asList
21 import net.pterodactylus.sone.utils.asOptional
22 import net.pterodactylus.sone.web.WebInterface
23 import net.pterodactylus.sone.web.page.*
24 import net.pterodactylus.sone.web.page.FreenetTemplatePage.RedirectException
25 import net.pterodactylus.util.notify.Notification
26 import net.pterodactylus.util.template.Template
27 import net.pterodactylus.util.template.TemplateContext
28 import net.pterodactylus.util.web.Method
29 import net.pterodactylus.util.web.Method.GET
30 import net.pterodactylus.util.web.Response
31 import org.junit.Assert.fail
32 import org.mockito.ArgumentMatchers.anyBoolean
33 import org.mockito.ArgumentMatchers.anyInt
34 import org.mockito.ArgumentMatchers.anyLong
35 import org.mockito.ArgumentMatchers.anyString
36 import org.mockito.ArgumentMatchers.eq
37 import java.io.ByteArrayOutputStream
38 import java.net.URI
39 import java.nio.charset.Charset
40 import kotlin.text.Charsets.UTF_8
41
42 /**
43  * Base class for web page tests.
44  */
45 open class WebPageTest(pageSupplier: (Template, WebInterface) -> SoneTemplatePage = { _, _ -> mock() }) {
46
47         val currentSone = mock<Sone>()
48         val template = mock<Template>()
49         val webInterface = deepMock<WebInterface>()
50         val core = webInterface.core
51         val eventBus = mock<EventBus>()
52         val preferences = Preferences(eventBus)
53         val l10n = webInterface.l10n!!
54         val sessionManager = mock<SessionManager>()
55
56         val page by lazy { pageSupplier(template, webInterface) }
57
58         val httpRequest = mock<HTTPRequest>()
59         val freenetRequest = mock<FreenetRequest>()
60         init {
61                 whenever(freenetRequest.l10n).thenReturn(l10n)
62                 whenever(freenetRequest.sessionManager).thenReturn(sessionManager)
63                 whenever(freenetRequest.uri).thenReturn(mock())
64         }
65         val soneRequest by lazy { freenetRequest.toSoneRequest(core, webInterface) }
66         val templateContext = TemplateContext()
67         val toadletContext = deepMock<ToadletContext>()
68         val responseContent = ByteArrayOutputStream()
69         val response = Response(responseContent)
70
71         private val requestHeaders = mutableMapOf<String, String>()
72         private val getRequestParameters = mutableMapOf<String, MutableList<String>>()
73         private val postRequestParameters = mutableMapOf<String, ByteArray>()
74         private val uploadedFileNames = mutableMapOf<String, String>()
75         private val uploadedFileContentTypes = mutableMapOf<String, String>()
76         private val uploadedFileResources = mutableMapOf<String, String>()
77         private val ownIdentities = mutableSetOf<OwnIdentity>()
78         private val allSones = mutableMapOf<String, Sone>()
79         private val localSones = mutableMapOf<String, Sone>()
80         private val allPosts = mutableMapOf<String, Post>()
81         private val allPostReplies = mutableMapOf<String, PostReply>()
82         private val perPostReplies = mutableMapOf<String, PostReply>()
83         private val allAlbums = mutableMapOf<String, Album>()
84         private val allImages = mutableMapOf<String, Image>()
85         private val notifications = mutableMapOf<String, Notification>()
86         private val translations = mutableMapOf<String, String>()
87
88         init {
89                 setupCore()
90                 setupWebInterface()
91                 setupHttpRequest()
92                 setupFreenetRequest()
93                 setupTranslations()
94         }
95
96         private fun setupCore() {
97                 whenever(core.preferences).thenReturn(preferences)
98                 whenever(core.identityManager.allOwnIdentities).then { ownIdentities }
99                 whenever(core.sones).then { allSones.values }
100                 whenever(core.getSone(anyString())).then { allSones[it[0]] }
101                 whenever(core.localSones).then { localSones.values }
102                 whenever(core.getLocalSone(anyString())).then { localSones[it[0]] }
103                 whenever(core.getPost(anyString())).then { allPosts[it[0]] }
104                 whenever(core.getPostReply(anyString())).then { allPostReplies[it[0]] }
105                 whenever(core.getReplies(anyString())).then { perPostReplies[it[0]].asList() }
106                 whenever(core.getAlbum(anyString())).then { allAlbums[it[0]] }
107                 whenever(core.getImage(anyString())).then { allImages[it[0]]}
108                 whenever(core.getImage(anyString(), anyBoolean())).then { allImages[it[0]]}
109                 whenever(core.getTemporaryImage(anyString())).thenReturn(null)
110         }
111
112         private fun setupWebInterface() {
113                 whenever(webInterface.sessionManager).thenReturn(sessionManager)
114                 whenever(webInterface.getCurrentSoneCreatingSession(eq(toadletContext))).thenReturn(currentSone)
115                 whenever(webInterface.getCurrentSone(eq(toadletContext), anyBoolean())).thenReturn(currentSone)
116                 whenever(webInterface.getCurrentSoneWithoutCreatingSession(eq(toadletContext))).thenReturn(currentSone)
117                 whenever(webInterface.getNotifications(currentSone)).then { notifications.values }
118                 whenever(webInterface.getNotification(anyString())).then { notifications[it[0]].asOptional() }
119         }
120
121         private fun setupHttpRequest() {
122                 whenever(httpRequest.method).thenReturn("GET")
123                 whenever(httpRequest.getHeader(anyString())).then { requestHeaders[it.get<String>(0).toLowerCase()] }
124                 whenever(httpRequest.hasParameters()).then { getRequestParameters.isNotEmpty() }
125                 whenever(httpRequest.parameterNames).then { getRequestParameters.keys }
126                 whenever(httpRequest.isParameterSet(anyString())).then { it[0] in getRequestParameters }
127                 whenever(httpRequest.getParam(anyString())).then { getRequestParameters[it[0]]?.firstOrNull() ?: "" }
128                 whenever(httpRequest.getParam(anyString(), anyString())).then { getRequestParameters[it[0]]?.firstOrNull() ?: it[1] }
129                 whenever(httpRequest.getIntParam(anyString())).then { getRequestParameters[it[0]]?.first()?.toIntOrNull() ?: 0 }
130                 whenever(httpRequest.getIntParam(anyString(), anyInt())).then { getRequestParameters[it[0]]?.first()?.toIntOrNull() ?: it[1] }
131                 whenever(httpRequest.getLongParam(anyString(), anyLong())).then { getRequestParameters[it[0]]?.first()?.toLongOrNull() ?: it[1] }
132                 whenever(httpRequest.getMultipleParam(anyString())).then { getRequestParameters[it[0]]?.toTypedArray() ?: emptyArray<String>() }
133                 whenever(httpRequest.getMultipleIntParam(anyString())).then { getRequestParameters[it[0]]?.map { it.toIntOrNull() ?: 0 } ?: emptyArray<Int>() }
134                 whenever(httpRequest.isPartSet(anyString())).then { it[0] in postRequestParameters }
135                 whenever(httpRequest.getPartAsStringFailsafe(anyString(), anyInt())).then { postRequestParameters[it[0]]?.decode()?.take(it[1]) ?: "" }
136                 whenever(httpRequest.getUploadedFile(anyString())).then {
137                         it.get<String>(0).takeIf { it in uploadedFileNames }
138                                         ?.let { name -> UploadedFile(uploadedFileNames[name]!!, uploadedFileContentTypes[name]!!, uploadedFileResources[name]!!)
139                         }
140                 }
141         }
142
143         private class UploadedFile(private val filename: String, private val contentType: String, private val resourceName: String): HTTPUploadedFile {
144                 override fun getFilename() = filename
145                 override fun getContentType() = contentType
146                 override fun getData() = javaClass.getResourceAsStream(resourceName).readBytes().let(::SimpleReadOnlyArrayBucket)
147         }
148
149         private fun ByteArray.decode(charset: Charset = UTF_8) = String(this, charset)
150
151         private fun setupFreenetRequest() {
152                 whenever(freenetRequest.method).thenReturn(GET)
153                 whenever(freenetRequest.httpRequest).thenReturn(httpRequest)
154                 whenever(freenetRequest.toadletContext).thenReturn(toadletContext)
155         }
156
157         private fun setupTranslations() {
158                 whenever(l10n.getString(anyString())).then { translations[it[0]] ?: it[0] }
159         }
160
161         fun setMethod(method: Method) {
162                 whenever(httpRequest.method).thenReturn(method.name)
163                 whenever(freenetRequest.method).thenReturn(method)
164         }
165
166         fun request(uri: String) {
167                 whenever(httpRequest.path).thenReturn(uri)
168                 whenever(freenetRequest.uri).thenReturn(URI(uri))
169         }
170
171         fun addHttpRequestHeader(name: String, value: String) {
172                 requestHeaders[name.toLowerCase()] = value
173         }
174
175         fun addHttpRequestParameter(name: String, value: String) {
176                 getRequestParameters[name] = getRequestParameters.getOrElse(name) { mutableListOf() }.apply { add(value) }
177         }
178
179         fun addHttpRequestPart(name: String, value: String) {
180                 postRequestParameters[name] = value.toByteArray(UTF_8)
181         }
182
183         fun unsetCurrentSone() {
184                 whenever(webInterface.getCurrentSoneCreatingSession(eq(toadletContext))).thenReturn(null)
185                 whenever(webInterface.getCurrentSone(eq(toadletContext), anyBoolean())).thenReturn(null)
186                 whenever(webInterface.getCurrentSoneWithoutCreatingSession(eq(toadletContext))).thenReturn(null)
187         }
188
189         fun addOwnIdentity(ownIdentity: OwnIdentity) {
190                 ownIdentities += ownIdentity
191         }
192
193         fun addSone(id: String, sone: Sone) {
194                 allSones[id] = sone
195         }
196
197         fun addLocalSone(id: String, localSone: Sone) {
198                 localSones[id] = localSone
199         }
200
201         fun addPost(id: String, post: Post) {
202                 allPosts[id] = post
203         }
204
205         fun addPostReply(id: String, postReply: PostReply) {
206                 allPostReplies[id] = postReply
207                 postReply.postId?.also { perPostReplies[it] = postReply }
208         }
209
210         fun addAlbum(id: String, album: Album) {
211                 allAlbums[id] = album
212         }
213
214         fun addImage(id: String, image: Image) {
215                 allImages[id] = image
216         }
217
218         fun addTranslation(key: String, value: String) {
219                 translations[key] = value
220         }
221
222         fun addNotification(id: String, notification: Notification) {
223                 notifications[id] = notification
224         }
225
226         fun addTemporaryImage(id: String, temporaryImage: TemporaryImage) {
227                 whenever(core.getTemporaryImage(id)).thenReturn(temporaryImage)
228         }
229
230         fun addUploadedFile(name: String, filename: String, contentType: String, resource: String) {
231                 uploadedFileNames[name] = filename
232                 uploadedFileContentTypes[name] = contentType
233                 uploadedFileResources[name] = resource
234         }
235
236         fun verifyNoRedirect(assertions: () -> Unit) {
237                 var caughtException: Exception? = null
238                 try {
239                         page.handleRequest(freenetRequest, templateContext)
240                 } catch (e: Exception) {
241                         caughtException = e
242                 }
243                 caughtException?.run { throw this } ?: assertions()
244         }
245
246         fun verifyRedirect(target: String, assertions: () -> Unit = {}) {
247                 try {
248                         page.handleRequest(freenetRequest, templateContext)
249                         fail()
250                 } catch (re: RedirectException) {
251                         if (re.target != target) {
252                                 throw re
253                         }
254                         assertions()
255                 } catch (e: Exception) {
256                         throw e
257                 }
258         }
259
260 }