87b29397491e8c852152191c23d21ef227eef92c
[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 posts = mutableMapOf<String, Post>()
54         private val newPosts = mutableMapOf<String, Post>()
55         private val newReplies = mutableMapOf<String, PostReply>()
56         private val linkedElements = mutableMapOf<String, LinkedElement>()
57         private val notifications = mutableListOf<Notification>()
58
59         @Before
60         fun setupWebInterface() {
61                 whenever(webInterface.getCurrentSone(eq(toadletContext), anyBoolean())).thenReturn(currentSone)
62                 whenever(webInterface.getCurrentSoneCreatingSession(toadletContext)).thenReturn(currentSone)
63                 whenever(webInterface.getCurrentSoneWithoutCreatingSession(toadletContext)).thenReturn(currentSone)
64                 whenever(webInterface.core).thenReturn(core)
65                 whenever(webInterface.getNotifications(currentSone)).thenAnswer { notifications }
66                 whenever(webInterface.getNewPosts(currentSone)).thenAnswer { newPosts.values }
67                 whenever(webInterface.getNewReplies(currentSone)).thenAnswer { newReplies.values }
68         }
69
70         @Before
71         fun setupCore() {
72                 whenever(core.getSone(anyString())).thenAnswer { (localSones + remoteSones)[it.getArgument(0)].asOptional() }
73                 whenever(core.getLocalSone(anyString())).thenAnswer { localSones[it[0]] }
74                 whenever(core.getPost(anyString())).thenAnswer { (posts + newPosts)[it[0]].asOptional() }
75         }
76
77         @Before
78         fun setupElementLoader() {
79                 whenever(elementLoader.loadElement(anyString())).thenAnswer {
80                         linkedElements[it.getArgument(0)] ?: LinkedElement(it.getArgument(0), loading = true)
81                 }
82         }
83
84         @Before
85         fun setupCurrentSone() {
86                 currentSone.mock("soneId", "Sone_Id", true, 1000, idle)
87         }
88
89         @Before
90         fun setupFreenetRequest() {
91                 whenever(freenetRequest.toadletContext).thenReturn(toadletContext)
92                 whenever(freenetRequest.method).thenReturn(GET)
93                 whenever(freenetRequest.httpRequest).thenReturn(httpRequest)
94         }
95
96         @Before
97         fun setupHttpRequest() {
98                 whenever(httpRequest.method).thenReturn("GET")
99                 whenever(httpRequest.getHeader(anyString())).thenAnswer { requestHeaders[it.get<String>(0).toLowerCase()] }
100                 whenever(httpRequest.getParam(anyString())).thenAnswer { requestParameters[it.getArgument(0)] ?: "" }
101                 whenever(httpRequest.getParam(anyString(), anyString())).thenAnswer { requestParameters[it.getArgument(0)] ?: it.getArgument(1) }
102                 whenever(httpRequest.getParam(anyString(), isNull())).thenAnswer { requestParameters[it.getArgument(0)] }
103                 whenever(httpRequest.getPart(anyString())).thenAnswer { requestParts[it.getArgument(0)]?.let { SimpleReadOnlyArrayBucket(it.toByteArray()) } }
104                 whenever(httpRequest.getPartAsBytesFailsafe(anyString(), anyInt())).thenAnswer { requestParts[it.getArgument(0)]?.toByteArray()?.copyOf(it.getArgument(1)) ?: ByteArray(0) }
105                 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() }
106                 whenever(httpRequest.getPartAsStringFailsafe(anyString(), anyInt())).thenAnswer { requestParts[it.getArgument(0)]?.substring(0, it.getArgument(1)) ?: "" }
107                 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() }
108                 whenever(httpRequest.getIntPart(anyString(), anyInt())).thenAnswer { invocation -> requestParts[invocation.getArgument(0)]?.toIntOrNull() ?: invocation.getArgument(1) }
109                 whenever(httpRequest.isPartSet(anyString())).thenAnswer { it.getArgument(0) in requestParts }
110         }
111
112         protected val JsonReturnObject.error get() = if (this is JsonErrorReturnObject) this.error else null
113
114         protected fun Sone.mock(id: String, name: String, local: Boolean = false, time: Long, status: SoneStatus = idle) = apply {
115                 whenever(this.id).thenReturn(id)
116                 whenever(this.name).thenReturn(name)
117                 whenever(isLocal).thenReturn(local)
118                 whenever(this.time).thenReturn(time)
119                 whenever(this.status).thenReturn(status)
120         }
121
122         protected fun unsetCurrentSone() {
123                 whenever(webInterface.getCurrentSone(eq(toadletContext), anyBoolean())).thenReturn(null)
124                 whenever(webInterface.getCurrentSoneWithoutCreatingSession(toadletContext)).thenReturn(null)
125                 whenever(webInterface.getCurrentSoneCreatingSession(toadletContext)).thenReturn(null)
126         }
127
128         protected fun addRequestHeader(key: String, value: String) {
129                 requestHeaders += key.toLowerCase() to value
130         }
131
132         protected fun addRequestParameter(key: String, value: String) {
133                 requestParameters += key to value
134         }
135
136         protected fun addRequestPart(key: String, value: String) {
137                 requestParts += key to value
138         }
139
140         protected fun addNotification(vararg notifications: Notification) {
141                 this.notifications += notifications
142         }
143
144         protected fun addSone(sone: Sone) {
145                 remoteSones += sone.id to sone
146         }
147
148         protected fun addLocalSone(id: String, sone: Sone) {
149                 localSones += id to sone
150         }
151
152         protected fun addPost(id: String, post: Post) {
153                 posts[id] = post
154         }
155
156         protected fun addNewPost(id: String, soneId: String, time: Long, recipientId: String? = null) =
157                         mock<Post>().apply {
158                                 whenever(this.id).thenReturn(id)
159                                 val sone = mock<Sone>().apply { whenever(this.id).thenReturn(soneId) }
160                                 whenever(this.sone).thenReturn(sone)
161                                 whenever(this.time).thenReturn(time)
162                                 whenever(this.recipientId).thenReturn(recipientId.asOptional())
163                         }.also { newPosts[id] = it }
164
165         protected fun addNewReply(id: String, soneId: String, postId: String, postSoneId: String) {
166                 newReplies[id] = mock<PostReply>().apply {
167                         whenever(this.id).thenReturn(id)
168                         val sone = mock<Sone>().apply { whenever(this.id).thenReturn(soneId) }
169                         whenever(this.sone).thenReturn(sone)
170                         val postSone = mock<Sone>().apply { whenever(this.id).thenReturn(postSoneId) }
171                         val post = mock<Post>().apply {
172                                 whenever(this.sone).thenReturn(postSone)
173                         }
174                         whenever(this.post).thenReturn(post.asOptional())
175                         whenever(this.postId).thenReturn(postId)
176                 }
177         }
178
179         protected fun addLinkedElement(link: String, loading: Boolean, failed: Boolean) {
180                 linkedElements[link] = LinkedElement(link, failed, loading)
181         }
182
183 }