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.Profile
12 import net.pterodactylus.sone.data.Sone
13 import net.pterodactylus.sone.data.Sone.SoneStatus
14 import net.pterodactylus.sone.data.Sone.SoneStatus.idle
15 import net.pterodactylus.sone.test.deepMock
16 import net.pterodactylus.sone.test.get
17 import net.pterodactylus.sone.test.mock
18 import net.pterodactylus.sone.test.whenever
19 import net.pterodactylus.sone.utils.asOptional
20 import net.pterodactylus.sone.web.WebInterface
21 import net.pterodactylus.sone.web.page.FreenetRequest
22 import net.pterodactylus.util.notify.Notification
23 import net.pterodactylus.util.web.Method.GET
24 import org.hamcrest.MatcherAssert.assertThat
25 import org.hamcrest.Matchers.equalTo
26 import org.junit.Before
28 import org.mockito.ArgumentMatchers.anyBoolean
29 import org.mockito.ArgumentMatchers.anyInt
30 import org.mockito.ArgumentMatchers.anyString
31 import org.mockito.ArgumentMatchers.eq
32 import org.mockito.ArgumentMatchers.isNull
33 import java.util.NoSuchElementException
34 import javax.naming.SizeLimitExceededException
37 * Base class for tests for any [JsonPage] implementations.
39 abstract class JsonPageTest(
40 private val expectedPath: String,
41 private val requiresLogin: Boolean = true,
42 private val needsFormPassword: Boolean = true,
43 pageSupplier: (WebInterface) -> JsonPage = { _ -> mock<JsonPage>() }) {
45 protected val webInterface = mock<WebInterface>()
46 protected val core = mock<Core>()
47 protected val elementLoader = mock<ElementLoader>()
48 protected open val page: JsonPage by lazy { pageSupplier(webInterface) }
49 protected val json by lazy { page.createJsonObject(freenetRequest)!! }
51 protected val toadletContext = mock<ToadletContext>()
52 protected val freenetRequest = mock<FreenetRequest>()
53 protected val httpRequest = mock<HTTPRequest>()
54 protected val currentSone = deepMock<Sone>()
55 protected val profile = Profile(currentSone)
57 private val requestHeaders = mutableMapOf<String, String>()
58 private val requestParameters = mutableMapOf<String, String>()
59 private val requestParts = mutableMapOf<String, String>()
60 private val localSones = mutableMapOf<String, Sone>()
61 private val remoteSones = mutableMapOf<String, Sone>()
62 private val posts = mutableMapOf<String, Post>()
63 private val newPosts = mutableMapOf<String, Post>()
64 private val newReplies = mutableMapOf<String, PostReply>()
65 private val linkedElements = mutableMapOf<String, LinkedElement>()
66 private val notifications = mutableListOf<Notification>()
69 fun setupWebInterface() {
70 whenever(webInterface.getCurrentSone(eq(toadletContext), anyBoolean())).thenReturn(currentSone)
71 whenever(webInterface.getCurrentSoneCreatingSession(toadletContext)).thenReturn(currentSone)
72 whenever(webInterface.getCurrentSoneWithoutCreatingSession(toadletContext)).thenReturn(currentSone)
73 whenever(webInterface.core).thenReturn(core)
74 whenever(webInterface.getNotifications(currentSone)).thenAnswer { notifications }
75 whenever(webInterface.getNewPosts(currentSone)).thenAnswer { newPosts.values }
76 whenever(webInterface.getNewReplies(currentSone)).thenAnswer { newReplies.values }
81 whenever(core.getSone(anyString())).thenAnswer { (localSones + remoteSones)[it.getArgument(0)].asOptional() }
82 whenever(core.getLocalSone(anyString())).thenAnswer { localSones[it[0]] }
83 whenever(core.getPost(anyString())).thenAnswer { (posts + newPosts)[it[0]].asOptional() }
87 fun setupElementLoader() {
88 whenever(elementLoader.loadElement(anyString())).thenAnswer {
89 linkedElements[it.getArgument(0)] ?: LinkedElement(it.getArgument(0), loading = true)
94 fun setupCurrentSone() {
95 currentSone.mock("soneId", "Sone_Id", true, 1000, idle)
99 fun setupFreenetRequest() {
100 whenever(freenetRequest.toadletContext).thenReturn(toadletContext)
101 whenever(freenetRequest.method).thenReturn(GET)
102 whenever(freenetRequest.httpRequest).thenReturn(httpRequest)
106 fun setupHttpRequest() {
107 whenever(httpRequest.method).thenReturn("GET")
108 whenever(httpRequest.getHeader(anyString())).thenAnswer { requestHeaders[it.get<String>(0).toLowerCase()] }
109 whenever(httpRequest.getParam(anyString())).thenAnswer { requestParameters[it.getArgument(0)] ?: "" }
110 whenever(httpRequest.getParam(anyString(), anyString())).thenAnswer { requestParameters[it.getArgument(0)] ?: it.getArgument(1) }
111 whenever(httpRequest.getParam(anyString(), isNull())).thenAnswer { requestParameters[it.getArgument(0)] }
112 whenever(httpRequest.getPart(anyString())).thenAnswer { requestParts[it.getArgument(0)]?.let { SimpleReadOnlyArrayBucket(it.toByteArray()) } }
113 whenever(httpRequest.getPartAsBytesFailsafe(anyString(), anyInt())).thenAnswer { requestParts[it.getArgument(0)]?.toByteArray()?.copyOf(it.getArgument(1)) ?: ByteArray(0) }
114 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() }
115 whenever(httpRequest.getPartAsStringFailsafe(anyString(), anyInt())).thenAnswer { requestParts[it.getArgument(0)]?.substring(0, it.getArgument(1)) ?: "" }
116 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() }
117 whenever(httpRequest.getIntPart(anyString(), anyInt())).thenAnswer { invocation -> requestParts[invocation.getArgument(0)]?.toIntOrNull() ?: invocation.getArgument(1) }
118 whenever(httpRequest.isPartSet(anyString())).thenAnswer { it.getArgument(0) in requestParts }
123 whenever(currentSone.profile).thenReturn(profile)
126 protected val JsonReturnObject.error get() = if (this is JsonErrorReturnObject) this.error else null
128 protected fun Sone.mock(id: String, name: String, local: Boolean = false, time: Long, status: SoneStatus = idle) = apply {
129 whenever(this.id).thenReturn(id)
130 whenever(this.name).thenReturn(name)
131 whenever(isLocal).thenReturn(local)
132 whenever(this.time).thenReturn(time)
133 whenever(this.status).thenReturn(status)
136 protected fun unsetCurrentSone() {
137 whenever(webInterface.getCurrentSone(eq(toadletContext), anyBoolean())).thenReturn(null)
138 whenever(webInterface.getCurrentSoneWithoutCreatingSession(toadletContext)).thenReturn(null)
139 whenever(webInterface.getCurrentSoneCreatingSession(toadletContext)).thenReturn(null)
142 protected fun addRequestHeader(key: String, value: String) {
143 requestHeaders += key.toLowerCase() to value
146 protected fun addRequestParameter(key: String, value: String) {
147 requestParameters += key to value
150 protected fun addRequestPart(key: String, value: String) {
151 requestParts += key to value
154 protected fun addNotification(vararg notifications: Notification) {
155 this.notifications += notifications
158 protected fun addSone(sone: Sone) {
159 remoteSones += sone.id to sone
162 protected fun addLocalSone(id: String, sone: Sone) {
163 localSones += id to sone
166 protected fun addPost(id: String, post: Post) {
170 protected fun addNewPost(id: String, soneId: String, time: Long, recipientId: String? = null) =
172 whenever(this.id).thenReturn(id)
173 val sone = mock<Sone>().apply { whenever(this.id).thenReturn(soneId) }
174 whenever(this.sone).thenReturn(sone)
175 whenever(this.time).thenReturn(time)
176 whenever(this.recipientId).thenReturn(recipientId.asOptional())
177 }.also { newPosts[id] = it }
179 protected fun addNewReply(id: String, soneId: String, postId: String, postSoneId: String) {
180 newReplies[id] = mock<PostReply>().apply {
181 whenever(this.id).thenReturn(id)
182 val sone = mock<Sone>().apply { whenever(this.id).thenReturn(soneId) }
183 whenever(this.sone).thenReturn(sone)
184 val postSone = mock<Sone>().apply { whenever(this.id).thenReturn(postSoneId) }
185 val post = mock<Post>().apply {
186 whenever(this.sone).thenReturn(postSone)
188 whenever(this.post).thenReturn(post.asOptional())
189 whenever(this.postId).thenReturn(postId)
193 protected fun addLinkedElement(link: String, loading: Boolean, failed: Boolean) {
194 linkedElements[link] = LinkedElement(link, failed, loading)
198 fun `page returns correct path`() {
199 assertThat(page.path, equalTo(expectedPath))
203 fun `page needs form password`() {
204 assertThat(page.needsFormPassword(), equalTo(needsFormPassword))
208 fun `page requires login`() {
209 assertThat(page.requiresLogin(), equalTo(requiresLogin))