Add test for distrust ajax page
[Sone.git] / src / test / kotlin / net / pterodactylus / sone / web / ajax / JsonPageTest.kt
1 package net.pterodactylus.sone.web.ajax
2
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.Post
12 import net.pterodactylus.sone.data.PostReply
13 import net.pterodactylus.sone.data.Profile
14 import net.pterodactylus.sone.data.Sone
15 import net.pterodactylus.sone.data.Sone.SoneStatus
16 import net.pterodactylus.sone.data.Sone.SoneStatus.idle
17 import net.pterodactylus.sone.test.deepMock
18 import net.pterodactylus.sone.test.get
19 import net.pterodactylus.sone.test.mock
20 import net.pterodactylus.sone.test.whenever
21 import net.pterodactylus.sone.utils.asOptional
22 import net.pterodactylus.sone.web.WebInterface
23 import net.pterodactylus.sone.web.page.FreenetRequest
24 import net.pterodactylus.util.notify.Notification
25 import net.pterodactylus.util.web.Method.GET
26 import org.hamcrest.MatcherAssert.assertThat
27 import org.hamcrest.Matchers.equalTo
28 import org.junit.Before
29 import org.junit.Test
30 import org.mockito.ArgumentMatchers.anyBoolean
31 import org.mockito.ArgumentMatchers.anyInt
32 import org.mockito.ArgumentMatchers.anyString
33 import org.mockito.ArgumentMatchers.eq
34 import org.mockito.ArgumentMatchers.isNull
35 import java.util.NoSuchElementException
36 import javax.naming.SizeLimitExceededException
37
38 /**
39  * Base class for tests for any [JsonPage] implementations.
40  */
41 abstract class JsonPageTest(
42                 private val expectedPath: String,
43                 private val requiresLogin: Boolean = true,
44                 private val needsFormPassword: Boolean = true,
45                 pageSupplier: (WebInterface) -> JsonPage = { _ -> mock<JsonPage>() }) {
46
47         protected val webInterface = mock<WebInterface>()
48         protected val core = mock<Core>()
49         protected val eventBus = mock<EventBus>()
50         protected val preferences = Preferences(eventBus)
51         protected val elementLoader = mock<ElementLoader>()
52         protected open val page: JsonPage by lazy { pageSupplier(webInterface) }
53         protected val json by lazy { page.createJsonObject(freenetRequest)!! }
54
55         protected val toadletContext = mock<ToadletContext>()
56         protected val freenetRequest = mock<FreenetRequest>()
57         protected val httpRequest = mock<HTTPRequest>()
58         protected val currentSone = deepMock<Sone>()
59         protected val profile = Profile(currentSone)
60
61         private val requestHeaders = mutableMapOf<String, String>()
62         private val requestParameters = mutableMapOf<String, String>()
63         private val requestParts = mutableMapOf<String, String>()
64         private val localSones = mutableMapOf<String, Sone>()
65         private val remoteSones = mutableMapOf<String, Sone>()
66         private val posts = mutableMapOf<String, Post>()
67         private val newPosts = mutableMapOf<String, Post>()
68         private val replies = mutableMapOf<String, PostReply>()
69         private val newReplies = mutableMapOf<String, PostReply>()
70         private val linkedElements = mutableMapOf<String, LinkedElement>()
71         private val notifications = mutableMapOf<String, Notification>()
72
73         @Before
74         fun setupWebInterface() {
75                 whenever(webInterface.getCurrentSone(eq(toadletContext), anyBoolean())).thenReturn(currentSone)
76                 whenever(webInterface.getCurrentSoneCreatingSession(toadletContext)).thenReturn(currentSone)
77                 whenever(webInterface.getCurrentSoneWithoutCreatingSession(toadletContext)).thenReturn(currentSone)
78                 whenever(webInterface.core).thenReturn(core)
79                 whenever(webInterface.getNotifications(currentSone)).thenAnswer { notifications.values }
80                 whenever(webInterface.getNotification(anyString())).then { notifications[it[0]].asOptional() }
81                 whenever(webInterface.getNewPosts(currentSone)).thenAnswer { newPosts.values }
82                 whenever(webInterface.getNewReplies(currentSone)).thenAnswer { newReplies.values }
83         }
84
85         @Before
86         fun setupCore() {
87                 whenever(core.preferences).thenReturn(preferences)
88                 whenever(core.getSone(anyString())).thenAnswer { (localSones + remoteSones)[it.getArgument(0)].asOptional() }
89                 whenever(core.getLocalSone(anyString())).thenAnswer { localSones[it[0]] }
90                 whenever(core.getPost(anyString())).thenAnswer { (posts + newPosts)[it[0]].asOptional() }
91                 whenever(core.getPostReply(anyString())).then { replies[it[0]].asOptional() }
92         }
93
94         @Before
95         fun setupElementLoader() {
96                 whenever(elementLoader.loadElement(anyString())).thenAnswer {
97                         linkedElements[it.getArgument(0)] ?: LinkedElement(it.getArgument(0), loading = true)
98                 }
99         }
100
101         @Before
102         fun setupCurrentSone() {
103                 currentSone.mock("soneId", "Sone_Id", true, 1000, idle)
104         }
105
106         @Before
107         fun setupFreenetRequest() {
108                 whenever(freenetRequest.toadletContext).thenReturn(toadletContext)
109                 whenever(freenetRequest.method).thenReturn(GET)
110                 whenever(freenetRequest.httpRequest).thenReturn(httpRequest)
111         }
112
113         @Before
114         fun setupHttpRequest() {
115                 whenever(httpRequest.method).thenReturn("GET")
116                 whenever(httpRequest.getHeader(anyString())).thenAnswer { requestHeaders[it.get<String>(0).toLowerCase()] }
117                 whenever(httpRequest.getParam(anyString())).thenAnswer { requestParameters[it.getArgument(0)] ?: "" }
118                 whenever(httpRequest.getParam(anyString(), anyString())).thenAnswer { requestParameters[it.getArgument(0)] ?: it.getArgument(1) }
119                 whenever(httpRequest.getParam(anyString(), isNull())).thenAnswer { requestParameters[it.getArgument(0)] }
120                 whenever(httpRequest.getPart(anyString())).thenAnswer { requestParts[it.getArgument(0)]?.let { SimpleReadOnlyArrayBucket(it.toByteArray()) } }
121                 whenever(httpRequest.getPartAsBytesFailsafe(anyString(), anyInt())).thenAnswer { requestParts[it.getArgument(0)]?.toByteArray()?.copyOf(it.getArgument(1)) ?: ByteArray(0) }
122                 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() }
123                 whenever(httpRequest.getPartAsStringFailsafe(anyString(), anyInt())).thenAnswer { requestParts[it.getArgument(0)]?.substring(0, it.getArgument(1)) ?: "" }
124                 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() }
125                 whenever(httpRequest.getIntPart(anyString(), anyInt())).thenAnswer { invocation -> requestParts[invocation.getArgument(0)]?.toIntOrNull() ?: invocation.getArgument(1) }
126                 whenever(httpRequest.isPartSet(anyString())).thenAnswer { it.getArgument(0) in requestParts }
127         }
128
129         @Before
130         fun setupProfile() {
131                 whenever(currentSone.profile).thenReturn(profile)
132         }
133
134         protected val JsonReturnObject.error get() = if (this is JsonErrorReturnObject) this.error else null
135
136         protected fun Sone.mock(id: String, name: String, local: Boolean = false, time: Long, status: SoneStatus = idle) = apply {
137                 whenever(this.id).thenReturn(id)
138                 whenever(this.name).thenReturn(name)
139                 whenever(isLocal).thenReturn(local)
140                 whenever(this.time).thenReturn(time)
141                 whenever(this.status).thenReturn(status)
142         }
143
144         protected fun unsetCurrentSone() {
145                 whenever(webInterface.getCurrentSone(eq(toadletContext), anyBoolean())).thenReturn(null)
146                 whenever(webInterface.getCurrentSoneWithoutCreatingSession(toadletContext)).thenReturn(null)
147                 whenever(webInterface.getCurrentSoneCreatingSession(toadletContext)).thenReturn(null)
148         }
149
150         protected fun addRequestHeader(key: String, value: String) {
151                 requestHeaders += key.toLowerCase() to value
152         }
153
154         protected fun addRequestParameter(key: String, value: String) {
155                 requestParameters += key to value
156         }
157
158         protected fun addRequestPart(key: String, value: String) {
159                 requestParts += key to value
160         }
161
162         protected fun addNotification(notification: Notification, notificationId: String? = null) {
163                 notifications[notificationId ?: notification.id] = notification
164         }
165
166         protected fun addSone(sone: Sone, soneId: String? = null) {
167                 remoteSones += (soneId ?: sone.id) to sone
168         }
169
170         protected fun addLocalSone(id: String, sone: Sone) {
171                 localSones += id to sone
172         }
173
174         protected fun addPost(id: String, post: Post) {
175                 posts[id] = post
176         }
177
178         protected fun addNewPost(id: String, soneId: String, time: Long, recipientId: String? = null) =
179                         mock<Post>().apply {
180                                 whenever(this.id).thenReturn(id)
181                                 val sone = mock<Sone>().apply { whenever(this.id).thenReturn(soneId) }
182                                 whenever(this.sone).thenReturn(sone)
183                                 whenever(this.time).thenReturn(time)
184                                 whenever(this.recipientId).thenReturn(recipientId.asOptional())
185                         }.also { newPosts[id] = it }
186
187         protected fun addReply(id: String, reply: PostReply) {
188                 replies[id] = reply
189         }
190
191         protected fun addNewReply(id: String, soneId: String, postId: String, postSoneId: String) {
192                 newReplies[id] = mock<PostReply>().apply {
193                         whenever(this.id).thenReturn(id)
194                         val sone = mock<Sone>().apply { whenever(this.id).thenReturn(soneId) }
195                         whenever(this.sone).thenReturn(sone)
196                         val postSone = mock<Sone>().apply { whenever(this.id).thenReturn(postSoneId) }
197                         val post = mock<Post>().apply {
198                                 whenever(this.sone).thenReturn(postSone)
199                         }
200                         whenever(this.post).thenReturn(post.asOptional())
201                         whenever(this.postId).thenReturn(postId)
202                 }
203         }
204
205         protected fun addLinkedElement(link: String, loading: Boolean, failed: Boolean) {
206                 linkedElements[link] = LinkedElement(link, failed, loading)
207         }
208
209         @Test
210         fun `page returns correct path`() {
211                 assertThat(page.path, equalTo(expectedPath))
212         }
213
214         @Test
215         fun `page needs form password`() {
216                 assertThat(page.needsFormPassword(), equalTo(needsFormPassword))
217         }
218
219         @Test
220         fun `page requires login`() {
221                 assertThat(page.requiresLogin(), equalTo(requiresLogin))
222         }
223
224 }