b0a67d477368732b6c3d95f0adfef9b4aeae9cac
[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.junit.Before
24 import org.mockito.ArgumentMatchers.anyBoolean
25 import org.mockito.ArgumentMatchers.anyInt
26 import org.mockito.ArgumentMatchers.anyString
27 import org.mockito.ArgumentMatchers.eq
28 import org.mockito.ArgumentMatchers.isNull
29 import java.util.NoSuchElementException
30 import javax.naming.SizeLimitExceededException
31
32 /**
33  * Base class for tests for any [JsonPage] implementations.
34  */
35 open class JsonPageTest(pageSupplier: (WebInterface) -> JsonPage = { _ -> mock<JsonPage>() }) {
36
37         protected val webInterface = mock<WebInterface>()
38         protected val core = mock<Core>()
39         protected val elementLoader = mock<ElementLoader>()
40         protected open val page: JsonPage by lazy { pageSupplier(webInterface) }
41         protected val json by lazy { page.createJsonObject(freenetRequest)!! }
42
43         protected val toadletContext = mock<ToadletContext>()
44         protected val freenetRequest = mock<FreenetRequest>()
45         protected val httpRequest = mock<HTTPRequest>()
46         protected val currentSone = deepMock<Sone>()
47
48         private val requestHeaders = mutableMapOf<String, String>()
49         private val requestParameters = mutableMapOf<String, String>()
50         private val requestParts = mutableMapOf<String, String>()
51         private val localSones = mutableMapOf<String, Sone>()
52         private val remoteSones = mutableMapOf<String, Sone>()
53         private val newPosts = mutableMapOf<String, Post>()
54         private val newReplies = mutableMapOf<String, PostReply>()
55         private val linkedElements = mutableMapOf<String, LinkedElement>()
56         private val notifications = mutableListOf<Notification>()
57
58         @Before
59         fun setupWebInterface() {
60                 whenever(webInterface.getCurrentSone(eq(toadletContext), anyBoolean())).thenReturn(currentSone)
61                 whenever(webInterface.getCurrentSoneCreatingSession(toadletContext)).thenReturn(currentSone)
62                 whenever(webInterface.getCurrentSoneWithoutCreatingSession(toadletContext)).thenReturn(currentSone)
63                 whenever(webInterface.core).thenReturn(core)
64                 whenever(webInterface.getNotifications(currentSone)).thenAnswer { notifications }
65                 whenever(webInterface.getNewPosts(currentSone)).thenAnswer { newPosts.values }
66                 whenever(webInterface.getNewReplies(currentSone)).thenAnswer { newReplies.values }
67         }
68
69         @Before
70         fun setupCore() {
71                 whenever(core.getSone(anyString())).thenAnswer { (localSones + remoteSones)[it.getArgument(0)].asOptional() }
72                 whenever(core.getPost(anyString())).thenAnswer { newPosts[it[0]].asOptional() }
73         }
74
75         @Before
76         fun setupElementLoader() {
77                 whenever(elementLoader.loadElement(anyString())).thenAnswer {
78                         linkedElements[it.getArgument(0)] ?: LinkedElement(it.getArgument(0), loading = true)
79                 }
80         }
81
82         @Before
83         fun setupCurrentSone() {
84                 currentSone.mock("soneId", "Sone_Id", true, 1000, idle)
85         }
86
87         @Before
88         fun setupFreenetRequest() {
89                 whenever(freenetRequest.toadletContext).thenReturn(toadletContext)
90                 whenever(freenetRequest.method).thenReturn(GET)
91                 whenever(freenetRequest.httpRequest).thenReturn(httpRequest)
92         }
93
94         @Before
95         fun setupHttpRequest() {
96                 whenever(httpRequest.method).thenReturn("GET")
97                 whenever(httpRequest.getHeader(anyString())).thenAnswer { requestHeaders[it.get<String>(0).toLowerCase()] }
98                 whenever(httpRequest.getParam(anyString())).thenAnswer { requestParameters[it.getArgument(0)] ?: "" }
99                 whenever(httpRequest.getParam(anyString(), anyString())).thenAnswer { requestParameters[it.getArgument(0)] ?: it.getArgument(1) }
100                 whenever(httpRequest.getParam(anyString(), isNull())).thenAnswer { requestParameters[it.getArgument(0)] }
101                 whenever(httpRequest.getPart(anyString())).thenAnswer { requestParts[it.getArgument(0)]?.let { SimpleReadOnlyArrayBucket(it.toByteArray()) } }
102                 whenever(httpRequest.getPartAsBytesFailsafe(anyString(), anyInt())).thenAnswer { requestParts[it.getArgument(0)]?.toByteArray()?.copyOf(it.getArgument(1)) ?: ByteArray(0) }
103                 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() }
104                 whenever(httpRequest.getPartAsStringFailsafe(anyString(), anyInt())).thenAnswer { requestParts[it.getArgument(0)]?.substring(0, it.getArgument(1)) ?: "" }
105                 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() }
106                 whenever(httpRequest.getIntPart(anyString(), anyInt())).thenAnswer { invocation -> requestParts[invocation.getArgument(0)]?.toIntOrNull() ?: invocation.getArgument(1) }
107                 whenever(httpRequest.isPartSet(anyString())).thenAnswer { it.getArgument(0) in requestParts }
108         }
109
110         protected val JsonReturnObject.error get() = if (this is JsonErrorReturnObject) this.error else null
111
112         protected fun Sone.mock(id: String, name: String, local: Boolean = false, time: Long, status: SoneStatus = idle) = apply {
113                 whenever(this.id).thenReturn(id)
114                 whenever(this.name).thenReturn(name)
115                 whenever(isLocal).thenReturn(local)
116                 whenever(this.time).thenReturn(time)
117                 whenever(this.status).thenReturn(status)
118         }
119
120         protected fun unsetCurrentSone() {
121                 whenever(webInterface.getCurrentSone(eq(toadletContext), anyBoolean())).thenReturn(null)
122                 whenever(webInterface.getCurrentSoneWithoutCreatingSession(toadletContext)).thenReturn(null)
123                 whenever(webInterface.getCurrentSoneCreatingSession(toadletContext)).thenReturn(null)
124         }
125
126         protected fun addRequestHeader(key: String, value: String) {
127                 requestHeaders += key.toLowerCase() to value
128         }
129
130         protected fun addRequestParameter(key: String, value: String) {
131                 requestParameters += key to value
132         }
133
134         protected fun addRequestPart(key: String, value: String) {
135                 requestParts += key to value
136         }
137
138         protected fun addNotification(vararg notifications: Notification) {
139                 this.notifications += notifications
140         }
141
142         protected fun addSone(sone: Sone) {
143                 remoteSones += sone.id to sone
144         }
145
146         protected fun addNewPost(id: String, soneId: String, time: Long, recipientId: String? = null) =
147                         mock<Post>().apply {
148                                 whenever(this.id).thenReturn(id)
149                                 val sone = mock<Sone>().apply { whenever(this.id).thenReturn(soneId) }
150                                 whenever(this.sone).thenReturn(sone)
151                                 whenever(this.time).thenReturn(time)
152                                 whenever(this.recipientId).thenReturn(recipientId.asOptional())
153                         }.also { newPosts[id] = it }
154
155         protected fun addNewReply(id: String, soneId: String, postId: String, postSoneId: String) {
156                 newReplies[id] = mock<PostReply>().apply {
157                         whenever(this.id).thenReturn(id)
158                         val sone = mock<Sone>().apply { whenever(this.id).thenReturn(soneId) }
159                         whenever(this.sone).thenReturn(sone)
160                         val postSone = mock<Sone>().apply { whenever(this.id).thenReturn(postSoneId) }
161                         val post = mock<Post>().apply {
162                                 whenever(this.sone).thenReturn(postSone)
163                         }
164                         whenever(this.post).thenReturn(post.asOptional())
165                         whenever(this.postId).thenReturn(postId)
166                 }
167         }
168
169         protected fun addLinkedElement(link: String, loading: Boolean, failed: Boolean) {
170                 linkedElements[link] = LinkedElement(link, failed, loading)
171         }
172
173 }