1 package net.pterodactylus.sone.web.ajax
3 import freenet.clients.http.ToadletContext
4 import freenet.support.SimpleReadOnlyArrayBucket
5 import freenet.support.api.HTTPRequest
6 import net.pterodactylus.sone.core.Core
7 import net.pterodactylus.sone.core.ElementLoader
8 import net.pterodactylus.sone.core.LinkedElement
9 import net.pterodactylus.sone.data.Post
10 import net.pterodactylus.sone.data.PostReply
11 import net.pterodactylus.sone.data.Sone
12 import net.pterodactylus.sone.data.Sone.SoneStatus
13 import net.pterodactylus.sone.data.Sone.SoneStatus.idle
14 import net.pterodactylus.sone.test.deepMock
15 import net.pterodactylus.sone.test.get
16 import net.pterodactylus.sone.test.mock
17 import net.pterodactylus.sone.test.whenever
18 import net.pterodactylus.sone.utils.asOptional
19 import net.pterodactylus.sone.web.WebInterface
20 import net.pterodactylus.sone.web.page.FreenetRequest
21 import net.pterodactylus.util.notify.Notification
22 import net.pterodactylus.util.web.Method.GET
23 import org.hamcrest.MatcherAssert.assertThat
24 import org.hamcrest.Matchers.equalTo
25 import org.junit.Before
27 import org.mockito.ArgumentMatchers.anyBoolean
28 import org.mockito.ArgumentMatchers.anyInt
29 import org.mockito.ArgumentMatchers.anyString
30 import org.mockito.ArgumentMatchers.eq
31 import org.mockito.ArgumentMatchers.isNull
32 import java.util.NoSuchElementException
33 import javax.naming.SizeLimitExceededException
36 * Base class for tests for any [JsonPage] implementations.
38 abstract class JsonPageTest(
39 private val expectedPath: String,
40 private val requiresLogin: Boolean = true,
41 private val needsFormPassword: Boolean = true,
42 pageSupplier: (WebInterface) -> JsonPage = { _ -> mock<JsonPage>() }) {
44 protected val webInterface = mock<WebInterface>()
45 protected val core = mock<Core>()
46 protected val elementLoader = mock<ElementLoader>()
47 protected open val page: JsonPage by lazy { pageSupplier(webInterface) }
48 protected val json by lazy { page.createJsonObject(freenetRequest)!! }
50 protected val toadletContext = mock<ToadletContext>()
51 protected val freenetRequest = mock<FreenetRequest>()
52 protected val httpRequest = mock<HTTPRequest>()
53 protected val currentSone = deepMock<Sone>()
55 private val requestHeaders = mutableMapOf<String, String>()
56 private val requestParameters = mutableMapOf<String, String>()
57 private val requestParts = mutableMapOf<String, String>()
58 private val localSones = mutableMapOf<String, Sone>()
59 private val remoteSones = mutableMapOf<String, Sone>()
60 private val posts = mutableMapOf<String, Post>()
61 private val newPosts = mutableMapOf<String, Post>()
62 private val newReplies = mutableMapOf<String, PostReply>()
63 private val linkedElements = mutableMapOf<String, LinkedElement>()
64 private val notifications = mutableListOf<Notification>()
67 fun setupWebInterface() {
68 whenever(webInterface.getCurrentSone(eq(toadletContext), anyBoolean())).thenReturn(currentSone)
69 whenever(webInterface.getCurrentSoneCreatingSession(toadletContext)).thenReturn(currentSone)
70 whenever(webInterface.getCurrentSoneWithoutCreatingSession(toadletContext)).thenReturn(currentSone)
71 whenever(webInterface.core).thenReturn(core)
72 whenever(webInterface.getNotifications(currentSone)).thenAnswer { notifications }
73 whenever(webInterface.getNewPosts(currentSone)).thenAnswer { newPosts.values }
74 whenever(webInterface.getNewReplies(currentSone)).thenAnswer { newReplies.values }
79 whenever(core.getSone(anyString())).thenAnswer { (localSones + remoteSones)[it.getArgument(0)].asOptional() }
80 whenever(core.getLocalSone(anyString())).thenAnswer { localSones[it[0]] }
81 whenever(core.getPost(anyString())).thenAnswer { (posts + newPosts)[it[0]].asOptional() }
85 fun setupElementLoader() {
86 whenever(elementLoader.loadElement(anyString())).thenAnswer {
87 linkedElements[it.getArgument(0)] ?: LinkedElement(it.getArgument(0), loading = true)
92 fun setupCurrentSone() {
93 currentSone.mock("soneId", "Sone_Id", true, 1000, idle)
97 fun setupFreenetRequest() {
98 whenever(freenetRequest.toadletContext).thenReturn(toadletContext)
99 whenever(freenetRequest.method).thenReturn(GET)
100 whenever(freenetRequest.httpRequest).thenReturn(httpRequest)
104 fun setupHttpRequest() {
105 whenever(httpRequest.method).thenReturn("GET")
106 whenever(httpRequest.getHeader(anyString())).thenAnswer { requestHeaders[it.get<String>(0).toLowerCase()] }
107 whenever(httpRequest.getParam(anyString())).thenAnswer { requestParameters[it.getArgument(0)] ?: "" }
108 whenever(httpRequest.getParam(anyString(), anyString())).thenAnswer { requestParameters[it.getArgument(0)] ?: it.getArgument(1) }
109 whenever(httpRequest.getParam(anyString(), isNull())).thenAnswer { requestParameters[it.getArgument(0)] }
110 whenever(httpRequest.getPart(anyString())).thenAnswer { requestParts[it.getArgument(0)]?.let { SimpleReadOnlyArrayBucket(it.toByteArray()) } }
111 whenever(httpRequest.getPartAsBytesFailsafe(anyString(), anyInt())).thenAnswer { requestParts[it.getArgument(0)]?.toByteArray()?.copyOf(it.getArgument(1)) ?: ByteArray(0) }
112 whenever(httpRequest.getPartAsBytesThrowing(anyString(), anyInt())).thenAnswer { invocation -> requestParts[invocation.getArgument(0)]?.let { it.toByteArray().let { if (it.size > invocation.getArgument<Int>(1)) throw SizeLimitExceededException() else it } } ?: throw NoSuchElementException() }
113 whenever(httpRequest.getPartAsStringFailsafe(anyString(), anyInt())).thenAnswer { requestParts[it.getArgument(0)]?.substring(0, it.getArgument(1)) ?: "" }
114 whenever(httpRequest.getPartAsStringThrowing(anyString(), anyInt())).thenAnswer { invocation -> requestParts[invocation.getArgument(0)]?.let { if (it.length > invocation.getArgument<Int>(1)) throw SizeLimitExceededException() else it } ?: throw NoSuchElementException() }
115 whenever(httpRequest.getIntPart(anyString(), anyInt())).thenAnswer { invocation -> requestParts[invocation.getArgument(0)]?.toIntOrNull() ?: invocation.getArgument(1) }
116 whenever(httpRequest.isPartSet(anyString())).thenAnswer { it.getArgument(0) in requestParts }
119 protected val JsonReturnObject.error get() = if (this is JsonErrorReturnObject) this.error else null
121 protected fun Sone.mock(id: String, name: String, local: Boolean = false, time: Long, status: SoneStatus = idle) = apply {
122 whenever(this.id).thenReturn(id)
123 whenever(this.name).thenReturn(name)
124 whenever(isLocal).thenReturn(local)
125 whenever(this.time).thenReturn(time)
126 whenever(this.status).thenReturn(status)
129 protected fun unsetCurrentSone() {
130 whenever(webInterface.getCurrentSone(eq(toadletContext), anyBoolean())).thenReturn(null)
131 whenever(webInterface.getCurrentSoneWithoutCreatingSession(toadletContext)).thenReturn(null)
132 whenever(webInterface.getCurrentSoneCreatingSession(toadletContext)).thenReturn(null)
135 protected fun addRequestHeader(key: String, value: String) {
136 requestHeaders += key.toLowerCase() to value
139 protected fun addRequestParameter(key: String, value: String) {
140 requestParameters += key to value
143 protected fun addRequestPart(key: String, value: String) {
144 requestParts += key to value
147 protected fun addNotification(vararg notifications: Notification) {
148 this.notifications += notifications
151 protected fun addSone(sone: Sone) {
152 remoteSones += sone.id to sone
155 protected fun addLocalSone(id: String, sone: Sone) {
156 localSones += id to sone
159 protected fun addPost(id: String, post: Post) {
163 protected fun addNewPost(id: String, soneId: String, time: Long, recipientId: String? = null) =
165 whenever(this.id).thenReturn(id)
166 val sone = mock<Sone>().apply { whenever(this.id).thenReturn(soneId) }
167 whenever(this.sone).thenReturn(sone)
168 whenever(this.time).thenReturn(time)
169 whenever(this.recipientId).thenReturn(recipientId.asOptional())
170 }.also { newPosts[id] = it }
172 protected fun addNewReply(id: String, soneId: String, postId: String, postSoneId: String) {
173 newReplies[id] = mock<PostReply>().apply {
174 whenever(this.id).thenReturn(id)
175 val sone = mock<Sone>().apply { whenever(this.id).thenReturn(soneId) }
176 whenever(this.sone).thenReturn(sone)
177 val postSone = mock<Sone>().apply { whenever(this.id).thenReturn(postSoneId) }
178 val post = mock<Post>().apply {
179 whenever(this.sone).thenReturn(postSone)
181 whenever(this.post).thenReturn(post.asOptional())
182 whenever(this.postId).thenReturn(postId)
186 protected fun addLinkedElement(link: String, loading: Boolean, failed: Boolean) {
187 linkedElements[link] = LinkedElement(link, failed, loading)
191 fun `page returns correct path`() {
192 assertThat(page.path, equalTo(expectedPath))
196 fun `page needs form password`() {
197 assertThat(page.needsFormPassword(), equalTo(needsFormPassword))
201 fun `page requires login`() {
202 assertThat(page.requiresLogin(), equalTo(requiresLogin))