1 package net.pterodactylus.sone.web.ajax
3 import com.google.common.eventbus.EventBus
4 import freenet.clients.http.ToadletContext
5 import freenet.support.SimpleReadOnlyArrayBucket
6 import freenet.support.api.HTTPRequest
7 import net.pterodactylus.sone.core.Core
8 import net.pterodactylus.sone.core.ElementLoader
9 import net.pterodactylus.sone.core.LinkedElement
10 import net.pterodactylus.sone.core.Preferences
11 import net.pterodactylus.sone.data.Album
12 import net.pterodactylus.sone.data.Image
13 import net.pterodactylus.sone.data.Post
14 import net.pterodactylus.sone.data.PostReply
15 import net.pterodactylus.sone.data.Profile
16 import net.pterodactylus.sone.data.Sone
17 import net.pterodactylus.sone.data.Sone.SoneStatus
18 import net.pterodactylus.sone.data.Sone.SoneStatus.idle
19 import net.pterodactylus.sone.test.deepMock
20 import net.pterodactylus.sone.test.get
21 import net.pterodactylus.sone.test.mock
22 import net.pterodactylus.sone.test.whenever
23 import net.pterodactylus.sone.utils.asOptional
24 import net.pterodactylus.sone.web.WebInterface
25 import net.pterodactylus.sone.web.page.FreenetRequest
26 import net.pterodactylus.util.notify.Notification
27 import net.pterodactylus.util.web.Method.GET
28 import org.hamcrest.MatcherAssert.assertThat
29 import org.hamcrest.Matchers.equalTo
30 import org.junit.Before
32 import org.mockito.ArgumentMatchers.anyBoolean
33 import org.mockito.ArgumentMatchers.anyInt
34 import org.mockito.ArgumentMatchers.anyString
35 import org.mockito.ArgumentMatchers.eq
36 import org.mockito.ArgumentMatchers.isNull
37 import java.util.NoSuchElementException
38 import javax.naming.SizeLimitExceededException
41 * Base class for tests for any [JsonPage] implementations.
43 abstract class JsonPageTest(
44 private val expectedPath: String,
45 private val requiresLogin: Boolean = true,
46 private val needsFormPassword: Boolean = true,
47 pageSupplier: (WebInterface) -> JsonPage = { _ -> mock<JsonPage>() }) {
49 protected val webInterface = mock<WebInterface>()
50 protected val core = mock<Core>()
51 protected val eventBus = mock<EventBus>()
52 protected val preferences = Preferences(eventBus)
53 protected val elementLoader = mock<ElementLoader>()
54 protected open val page: JsonPage by lazy { pageSupplier(webInterface) }
55 protected val json by lazy { page.createJsonObject(freenetRequest) }
57 protected val toadletContext = mock<ToadletContext>()
58 protected val freenetRequest = mock<FreenetRequest>()
59 protected val httpRequest = mock<HTTPRequest>()
60 protected val currentSone = deepMock<Sone>()
61 protected val profile = Profile(currentSone)
63 private val requestHeaders = mutableMapOf<String, String>()
64 private val requestParameters = mutableMapOf<String, String>()
65 private val requestParts = mutableMapOf<String, String>()
66 private val localSones = mutableMapOf<String, Sone>()
67 private val remoteSones = mutableMapOf<String, Sone>()
68 private val posts = mutableMapOf<String, Post>()
69 private val newPosts = mutableMapOf<String, Post>()
70 private val replies = mutableMapOf<String, PostReply>()
71 private val newReplies = mutableMapOf<String, PostReply>()
72 private val linkedElements = mutableMapOf<String, LinkedElement>()
73 private val notifications = mutableMapOf<String, Notification>()
74 private val albums = mutableMapOf<String, Album>()
75 private val images = mutableMapOf<String, Image>()
78 fun setupWebInterface() {
79 whenever(webInterface.getCurrentSone(eq(toadletContext), anyBoolean())).thenReturn(currentSone)
80 whenever(webInterface.getCurrentSoneCreatingSession(toadletContext)).thenReturn(currentSone)
81 whenever(webInterface.getCurrentSoneWithoutCreatingSession(toadletContext)).thenReturn(currentSone)
82 whenever(webInterface.core).thenReturn(core)
83 whenever(webInterface.getNotifications(currentSone)).thenAnswer { notifications.values }
84 whenever(webInterface.getNotification(anyString())).then { notifications[it[0]].asOptional() }
85 whenever(webInterface.getNewPosts(currentSone)).thenAnswer { newPosts.values }
86 whenever(webInterface.getNewReplies(currentSone)).thenAnswer { newReplies.values }
91 whenever(core.preferences).thenReturn(preferences)
92 whenever(core.getSone(anyString())).thenAnswer { (localSones + remoteSones)[it.getArgument(0)].asOptional() }
93 whenever(core.getLocalSone(anyString())).thenAnswer { localSones[it[0]] }
94 whenever(core.getPost(anyString())).thenAnswer { (posts + newPosts)[it[0]].asOptional() }
95 whenever(core.getPostReply(anyString())).then { replies[it[0]].asOptional() }
96 whenever(core.getAlbum(anyString())).then { albums[it[0]] }
97 whenever(core.getImage(anyString())).then { images[it[0]] }
98 whenever(core.getImage(anyString(), anyBoolean())).then { images[it[0]] }
102 fun setupElementLoader() {
103 whenever(elementLoader.loadElement(anyString())).thenAnswer {
104 linkedElements[it.getArgument(0)] ?: LinkedElement(it.getArgument(0), loading = true)
109 fun setupCurrentSone() {
110 currentSone.mock("soneId", "Sone_Id", true, 1000, idle)
114 fun setupFreenetRequest() {
115 whenever(freenetRequest.toadletContext).thenReturn(toadletContext)
116 whenever(freenetRequest.method).thenReturn(GET)
117 whenever(freenetRequest.httpRequest).thenReturn(httpRequest)
121 fun setupHttpRequest() {
122 whenever(httpRequest.method).thenReturn("GET")
123 whenever(httpRequest.getHeader(anyString())).thenAnswer { requestHeaders[it.get<String>(0).toLowerCase()] }
124 whenever(httpRequest.getParam(anyString())).thenAnswer { requestParameters[it.getArgument(0)] ?: "" }
125 whenever(httpRequest.getParam(anyString(), anyString())).thenAnswer { requestParameters[it.getArgument(0)] ?: it.getArgument(1) }
126 whenever(httpRequest.getParam(anyString(), isNull())).thenAnswer { requestParameters[it.getArgument(0)] }
127 whenever(httpRequest.getPart(anyString())).thenAnswer { requestParts[it.getArgument(0)]?.let { SimpleReadOnlyArrayBucket(it.toByteArray()) } }
128 whenever(httpRequest.getPartAsBytesFailsafe(anyString(), anyInt())).thenAnswer { requestParts[it.getArgument(0)]?.toByteArray()?.copyOf(it.getArgument(1)) ?: ByteArray(0) }
129 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() }
130 whenever(httpRequest.getPartAsStringFailsafe(anyString(), anyInt())).thenAnswer { requestParts[it.getArgument(0)]?.substring(0, it.getArgument(1)) ?: "" }
131 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() }
132 whenever(httpRequest.getIntPart(anyString(), anyInt())).thenAnswer { invocation -> requestParts[invocation.getArgument(0)]?.toIntOrNull() ?: invocation.getArgument(1) }
133 whenever(httpRequest.isPartSet(anyString())).thenAnswer { it.getArgument(0) in requestParts }
138 whenever(currentSone.profile).thenReturn(profile)
141 protected val JsonReturnObject.error get() = if (this is JsonErrorReturnObject) this.error else null
143 protected fun Sone.mock(id: String, name: String, local: Boolean = false, time: Long, status: SoneStatus = idle) = apply {
144 whenever(this.id).thenReturn(id)
145 whenever(this.name).thenReturn(name)
146 whenever(isLocal).thenReturn(local)
147 whenever(this.time).thenReturn(time)
148 whenever(this.status).thenReturn(status)
151 protected fun unsetCurrentSone() {
152 whenever(webInterface.getCurrentSone(eq(toadletContext), anyBoolean())).thenReturn(null)
153 whenever(webInterface.getCurrentSoneWithoutCreatingSession(toadletContext)).thenReturn(null)
154 whenever(webInterface.getCurrentSoneCreatingSession(toadletContext)).thenReturn(null)
157 protected fun addRequestHeader(key: String, value: String) {
158 requestHeaders += key.toLowerCase() to value
161 protected fun addRequestParameter(key: String, value: String) {
162 requestParameters += key to value
165 protected fun addRequestPart(key: String, value: String) {
166 requestParts += key to value
169 protected fun addNotification(notification: Notification, notificationId: String? = null) {
170 notifications[notificationId ?: notification.id] = notification
173 protected fun addSone(sone: Sone, soneId: String? = null) {
174 remoteSones += (soneId ?: sone.id) to sone
177 protected fun addLocalSone(id: String, sone: Sone) {
178 localSones += id to sone
181 protected fun addPost(id: String, post: Post) {
185 protected fun addNewPost(id: String, soneId: String, time: Long, recipientId: String? = null) =
187 whenever(this.id).thenReturn(id)
188 val sone = mock<Sone>().apply { whenever(this.id).thenReturn(soneId) }
189 whenever(this.sone).thenReturn(sone)
190 whenever(this.time).thenReturn(time)
191 whenever(this.recipientId).thenReturn(recipientId.asOptional())
192 }.also { newPosts[id] = it }
194 protected fun addReply(id: String, reply: PostReply) {
198 protected fun addNewReply(id: String, soneId: String, postId: String, postSoneId: String) {
199 newReplies[id] = mock<PostReply>().apply {
200 whenever(this.id).thenReturn(id)
201 val sone = mock<Sone>().apply { whenever(this.id).thenReturn(soneId) }
202 whenever(this.sone).thenReturn(sone)
203 val postSone = mock<Sone>().apply { whenever(this.id).thenReturn(postSoneId) }
204 val post = mock<Post>().apply {
205 whenever(this.sone).thenReturn(postSone)
207 whenever(this.post).thenReturn(post.asOptional())
208 whenever(this.postId).thenReturn(postId)
212 protected fun addLinkedElement(link: String, loading: Boolean, failed: Boolean) {
213 linkedElements[link] = LinkedElement(link, failed, loading)
216 protected fun addAlbum(album: Album, albumId: String? = null) {
217 albums[albumId ?: album.id] = album
220 protected fun addImage(image: Image, imageId: String? = null) {
221 images[imageId ?: image.id] = image
225 fun `page returns correct path`() {
226 assertThat(page.path, equalTo(expectedPath))
230 fun `page needs form password`() {
231 assertThat(page.needsFormPassword(), equalTo(needsFormPassword))
235 fun `page requires login`() {
236 assertThat(page.requiresLogin(), equalTo(requiresLogin))