Move recurring tests for ajax pages to test base class
[Sone.git] / src / test / kotlin / net / pterodactylus / sone / web / ajax / JsonPageTest.kt
1 package net.pterodactylus.sone.web.ajax
2
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
26 import org.junit.Test
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
34
35 /**
36  * Base class for tests for any [JsonPage] implementations.
37  */
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>() }) {
43
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)!! }
49
50         protected val toadletContext = mock<ToadletContext>()
51         protected val freenetRequest = mock<FreenetRequest>()
52         protected val httpRequest = mock<HTTPRequest>()
53         protected val currentSone = deepMock<Sone>()
54
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>()
65
66         @Before
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 }
75         }
76
77         @Before
78         fun setupCore() {
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() }
82         }
83
84         @Before
85         fun setupElementLoader() {
86                 whenever(elementLoader.loadElement(anyString())).thenAnswer {
87                         linkedElements[it.getArgument(0)] ?: LinkedElement(it.getArgument(0), loading = true)
88                 }
89         }
90
91         @Before
92         fun setupCurrentSone() {
93                 currentSone.mock("soneId", "Sone_Id", true, 1000, idle)
94         }
95
96         @Before
97         fun setupFreenetRequest() {
98                 whenever(freenetRequest.toadletContext).thenReturn(toadletContext)
99                 whenever(freenetRequest.method).thenReturn(GET)
100                 whenever(freenetRequest.httpRequest).thenReturn(httpRequest)
101         }
102
103         @Before
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 }
117         }
118
119         protected val JsonReturnObject.error get() = if (this is JsonErrorReturnObject) this.error else null
120
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)
127         }
128
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)
133         }
134
135         protected fun addRequestHeader(key: String, value: String) {
136                 requestHeaders += key.toLowerCase() to value
137         }
138
139         protected fun addRequestParameter(key: String, value: String) {
140                 requestParameters += key to value
141         }
142
143         protected fun addRequestPart(key: String, value: String) {
144                 requestParts += key to value
145         }
146
147         protected fun addNotification(vararg notifications: Notification) {
148                 this.notifications += notifications
149         }
150
151         protected fun addSone(sone: Sone) {
152                 remoteSones += sone.id to sone
153         }
154
155         protected fun addLocalSone(id: String, sone: Sone) {
156                 localSones += id to sone
157         }
158
159         protected fun addPost(id: String, post: Post) {
160                 posts[id] = post
161         }
162
163         protected fun addNewPost(id: String, soneId: String, time: Long, recipientId: String? = null) =
164                         mock<Post>().apply {
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 }
171
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)
180                         }
181                         whenever(this.post).thenReturn(post.asOptional())
182                         whenever(this.postId).thenReturn(postId)
183                 }
184         }
185
186         protected fun addLinkedElement(link: String, loading: Boolean, failed: Boolean) {
187                 linkedElements[link] = LinkedElement(link, failed, loading)
188         }
189
190         @Test
191         fun `page returns correct path`() {
192                 assertThat(page.path, equalTo(expectedPath))
193         }
194
195         @Test
196         fun `page needs form password`() {
197                 assertThat(page.needsFormPassword(), equalTo(needsFormPassword))
198         }
199
200         @Test
201         fun `page requires login`() {
202                 assertThat(page.requiresLogin(), equalTo(requiresLogin))
203         }
204
205 }