f3558fa94fe229eedef53000be34205916bbf7f5
[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.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
27 import org.junit.Test
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
35
36 /**
37  * Base class for tests for any [JsonPage] implementations.
38  */
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>() }) {
44
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)!! }
50
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)
56
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 replies = mutableMapOf<String, PostReply>()
65         private val newReplies = mutableMapOf<String, PostReply>()
66         private val linkedElements = mutableMapOf<String, LinkedElement>()
67         private val notifications = mutableMapOf<String, Notification>()
68
69         @Before
70         fun setupWebInterface() {
71                 whenever(webInterface.getCurrentSone(eq(toadletContext), anyBoolean())).thenReturn(currentSone)
72                 whenever(webInterface.getCurrentSoneCreatingSession(toadletContext)).thenReturn(currentSone)
73                 whenever(webInterface.getCurrentSoneWithoutCreatingSession(toadletContext)).thenReturn(currentSone)
74                 whenever(webInterface.core).thenReturn(core)
75                 whenever(webInterface.getNotifications(currentSone)).thenAnswer { notifications.values }
76                 whenever(webInterface.getNotification(anyString())).then { notifications[it[0]].asOptional() }
77                 whenever(webInterface.getNewPosts(currentSone)).thenAnswer { newPosts.values }
78                 whenever(webInterface.getNewReplies(currentSone)).thenAnswer { newReplies.values }
79         }
80
81         @Before
82         fun setupCore() {
83                 whenever(core.getSone(anyString())).thenAnswer { (localSones + remoteSones)[it.getArgument(0)].asOptional() }
84                 whenever(core.getLocalSone(anyString())).thenAnswer { localSones[it[0]] }
85                 whenever(core.getPost(anyString())).thenAnswer { (posts + newPosts)[it[0]].asOptional() }
86                 whenever(core.getPostReply(anyString())).then { replies[it[0]].asOptional() }
87         }
88
89         @Before
90         fun setupElementLoader() {
91                 whenever(elementLoader.loadElement(anyString())).thenAnswer {
92                         linkedElements[it.getArgument(0)] ?: LinkedElement(it.getArgument(0), loading = true)
93                 }
94         }
95
96         @Before
97         fun setupCurrentSone() {
98                 currentSone.mock("soneId", "Sone_Id", true, 1000, idle)
99         }
100
101         @Before
102         fun setupFreenetRequest() {
103                 whenever(freenetRequest.toadletContext).thenReturn(toadletContext)
104                 whenever(freenetRequest.method).thenReturn(GET)
105                 whenever(freenetRequest.httpRequest).thenReturn(httpRequest)
106         }
107
108         @Before
109         fun setupHttpRequest() {
110                 whenever(httpRequest.method).thenReturn("GET")
111                 whenever(httpRequest.getHeader(anyString())).thenAnswer { requestHeaders[it.get<String>(0).toLowerCase()] }
112                 whenever(httpRequest.getParam(anyString())).thenAnswer { requestParameters[it.getArgument(0)] ?: "" }
113                 whenever(httpRequest.getParam(anyString(), anyString())).thenAnswer { requestParameters[it.getArgument(0)] ?: it.getArgument(1) }
114                 whenever(httpRequest.getParam(anyString(), isNull())).thenAnswer { requestParameters[it.getArgument(0)] }
115                 whenever(httpRequest.getPart(anyString())).thenAnswer { requestParts[it.getArgument(0)]?.let { SimpleReadOnlyArrayBucket(it.toByteArray()) } }
116                 whenever(httpRequest.getPartAsBytesFailsafe(anyString(), anyInt())).thenAnswer { requestParts[it.getArgument(0)]?.toByteArray()?.copyOf(it.getArgument(1)) ?: ByteArray(0) }
117                 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() }
118                 whenever(httpRequest.getPartAsStringFailsafe(anyString(), anyInt())).thenAnswer { requestParts[it.getArgument(0)]?.substring(0, it.getArgument(1)) ?: "" }
119                 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() }
120                 whenever(httpRequest.getIntPart(anyString(), anyInt())).thenAnswer { invocation -> requestParts[invocation.getArgument(0)]?.toIntOrNull() ?: invocation.getArgument(1) }
121                 whenever(httpRequest.isPartSet(anyString())).thenAnswer { it.getArgument(0) in requestParts }
122         }
123
124         @Before
125         fun setupProfile() {
126                 whenever(currentSone.profile).thenReturn(profile)
127         }
128
129         protected val JsonReturnObject.error get() = if (this is JsonErrorReturnObject) this.error else null
130
131         protected fun Sone.mock(id: String, name: String, local: Boolean = false, time: Long, status: SoneStatus = idle) = apply {
132                 whenever(this.id).thenReturn(id)
133                 whenever(this.name).thenReturn(name)
134                 whenever(isLocal).thenReturn(local)
135                 whenever(this.time).thenReturn(time)
136                 whenever(this.status).thenReturn(status)
137         }
138
139         protected fun unsetCurrentSone() {
140                 whenever(webInterface.getCurrentSone(eq(toadletContext), anyBoolean())).thenReturn(null)
141                 whenever(webInterface.getCurrentSoneWithoutCreatingSession(toadletContext)).thenReturn(null)
142                 whenever(webInterface.getCurrentSoneCreatingSession(toadletContext)).thenReturn(null)
143         }
144
145         protected fun addRequestHeader(key: String, value: String) {
146                 requestHeaders += key.toLowerCase() to value
147         }
148
149         protected fun addRequestParameter(key: String, value: String) {
150                 requestParameters += key to value
151         }
152
153         protected fun addRequestPart(key: String, value: String) {
154                 requestParts += key to value
155         }
156
157         protected fun addNotification(notification: Notification, notificationId: String? = null) {
158                 notifications[notificationId ?: notification.id] = notification
159         }
160
161         protected fun addSone(sone: Sone) {
162                 remoteSones += sone.id to sone
163         }
164
165         protected fun addLocalSone(id: String, sone: Sone) {
166                 localSones += id to sone
167         }
168
169         protected fun addPost(id: String, post: Post) {
170                 posts[id] = post
171         }
172
173         protected fun addNewPost(id: String, soneId: String, time: Long, recipientId: String? = null) =
174                         mock<Post>().apply {
175                                 whenever(this.id).thenReturn(id)
176                                 val sone = mock<Sone>().apply { whenever(this.id).thenReturn(soneId) }
177                                 whenever(this.sone).thenReturn(sone)
178                                 whenever(this.time).thenReturn(time)
179                                 whenever(this.recipientId).thenReturn(recipientId.asOptional())
180                         }.also { newPosts[id] = it }
181
182         protected fun addReply(id: String, reply: PostReply) {
183                 replies[id] = reply
184         }
185
186         protected fun addNewReply(id: String, soneId: String, postId: String, postSoneId: String) {
187                 newReplies[id] = mock<PostReply>().apply {
188                         whenever(this.id).thenReturn(id)
189                         val sone = mock<Sone>().apply { whenever(this.id).thenReturn(soneId) }
190                         whenever(this.sone).thenReturn(sone)
191                         val postSone = mock<Sone>().apply { whenever(this.id).thenReturn(postSoneId) }
192                         val post = mock<Post>().apply {
193                                 whenever(this.sone).thenReturn(postSone)
194                         }
195                         whenever(this.post).thenReturn(post.asOptional())
196                         whenever(this.postId).thenReturn(postId)
197                 }
198         }
199
200         protected fun addLinkedElement(link: String, loading: Boolean, failed: Boolean) {
201                 linkedElements[link] = LinkedElement(link, failed, loading)
202         }
203
204         @Test
205         fun `page returns correct path`() {
206                 assertThat(page.path, equalTo(expectedPath))
207         }
208
209         @Test
210         fun `page needs form password`() {
211                 assertThat(page.needsFormPassword(), equalTo(needsFormPassword))
212         }
213
214         @Test
215         fun `page requires login`() {
216                 assertThat(page.requiresLogin(), equalTo(requiresLogin))
217         }
218
219 }