Add test for delete profile field ajax page
[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 newReplies = mutableMapOf<String, PostReply>()
65         private val linkedElements = mutableMapOf<String, LinkedElement>()
66         private val notifications = mutableListOf<Notification>()
67
68         @Before
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 }
77         }
78
79         @Before
80         fun setupCore() {
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() }
84         }
85
86         @Before
87         fun setupElementLoader() {
88                 whenever(elementLoader.loadElement(anyString())).thenAnswer {
89                         linkedElements[it.getArgument(0)] ?: LinkedElement(it.getArgument(0), loading = true)
90                 }
91         }
92
93         @Before
94         fun setupCurrentSone() {
95                 currentSone.mock("soneId", "Sone_Id", true, 1000, idle)
96         }
97
98         @Before
99         fun setupFreenetRequest() {
100                 whenever(freenetRequest.toadletContext).thenReturn(toadletContext)
101                 whenever(freenetRequest.method).thenReturn(GET)
102                 whenever(freenetRequest.httpRequest).thenReturn(httpRequest)
103         }
104
105         @Before
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 }
119         }
120
121         @Before
122         fun setupProfile() {
123                 whenever(currentSone.profile).thenReturn(profile)
124         }
125
126         protected val JsonReturnObject.error get() = if (this is JsonErrorReturnObject) this.error else null
127
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)
134         }
135
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)
140         }
141
142         protected fun addRequestHeader(key: String, value: String) {
143                 requestHeaders += key.toLowerCase() to value
144         }
145
146         protected fun addRequestParameter(key: String, value: String) {
147                 requestParameters += key to value
148         }
149
150         protected fun addRequestPart(key: String, value: String) {
151                 requestParts += key to value
152         }
153
154         protected fun addNotification(vararg notifications: Notification) {
155                 this.notifications += notifications
156         }
157
158         protected fun addSone(sone: Sone) {
159                 remoteSones += sone.id to sone
160         }
161
162         protected fun addLocalSone(id: String, sone: Sone) {
163                 localSones += id to sone
164         }
165
166         protected fun addPost(id: String, post: Post) {
167                 posts[id] = post
168         }
169
170         protected fun addNewPost(id: String, soneId: String, time: Long, recipientId: String? = null) =
171                         mock<Post>().apply {
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 }
178
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)
187                         }
188                         whenever(this.post).thenReturn(post.asOptional())
189                         whenever(this.postId).thenReturn(postId)
190                 }
191         }
192
193         protected fun addLinkedElement(link: String, loading: Boolean, failed: Boolean) {
194                 linkedElements[link] = LinkedElement(link, failed, loading)
195         }
196
197         @Test
198         fun `page returns correct path`() {
199                 assertThat(page.path, equalTo(expectedPath))
200         }
201
202         @Test
203         fun `page needs form password`() {
204                 assertThat(page.needsFormPassword(), equalTo(needsFormPassword))
205         }
206
207         @Test
208         fun `page requires login`() {
209                 assertThat(page.requiresLogin(), equalTo(requiresLogin))
210         }
211
212 }