Add unit test for sone template page and fix parameter encoding
[Sone.git] / src / test / kotlin / net / pterodactylus / sone / web / SoneTemplatePageTest.kt
1 package net.pterodactylus.sone.web
2
3 import net.pterodactylus.sone.data.Sone
4 import net.pterodactylus.sone.main.SonePlugin
5 import net.pterodactylus.sone.test.mock
6 import net.pterodactylus.sone.test.whenever
7 import net.pterodactylus.sone.web.page.FreenetRequest
8 import net.pterodactylus.util.notify.Notification
9 import net.pterodactylus.util.template.TemplateContext
10 import net.pterodactylus.util.version.Version
11 import net.pterodactylus.util.web.Method.GET
12 import org.hamcrest.Matcher
13 import org.hamcrest.MatcherAssert.assertThat
14 import org.hamcrest.Matchers.anyOf
15 import org.hamcrest.Matchers.contains
16 import org.hamcrest.Matchers.containsInAnyOrder
17 import org.hamcrest.Matchers.equalTo
18 import org.hamcrest.Matchers.nullValue
19 import org.junit.Test
20 import org.mockito.Mockito.verify
21
22 /**
23  * Unit test for [SoneTemplatePage].
24  */
25 class SoneTemplatePageTest : WebPageTest() {
26
27         //      @get:JvmName("getPage1")
28         private val page = object : SoneTemplatePage("path.html", template, webInterface, true) {}
29
30         @Test
31         fun `current sone is retrieved from web interface`() {
32                 assertThat(page.getCurrentSone(toadletContext), equalTo(currentSone))
33         }
34
35         @Test
36         fun `retrieving current sone with creation is forwarded to web interface`() {
37                 mock<Sone>().let {
38                         whenever(webInterface.getCurrentSone(toadletContext, true)).thenReturn(it)
39                         assertThat(page.getCurrentSone(toadletContext, true), equalTo(it))
40                 }
41         }
42
43         @Test
44         fun `retrieving current sone without creation is forwarded to web interface`() {
45                 mock<Sone>().let {
46                         whenever(webInterface.getCurrentSone(toadletContext, false)).thenReturn(it)
47                         assertThat(page.getCurrentSone(toadletContext, false), equalTo(it))
48                 }
49         }
50
51         @Test
52         fun `setting the current sone is forwarded to web interface`() {
53                 mock<Sone>().let {
54                         page.setCurrentSone(toadletContext, it)
55                         verify(webInterface).setCurrentSone(toadletContext, it)
56                 }
57         }
58
59         @Test
60         fun `page title is empty string if no page title key was given`() {
61                 SoneTemplatePage("path.html", template, null, webInterface).let { page ->
62                         assertThat(page.getPageTitle(freenetRequest), equalTo(""))
63                 }
64         }
65
66         @Test
67         fun `page title is retrieved from l10n if page title key is given`() {
68                 SoneTemplatePage("path.html", template, "page.title", webInterface).let { page ->
69                         whenever(l10n.getString("page.title")).thenReturn("Page Title")
70                         assertThat(page.getPageTitle(freenetRequest), equalTo("Page Title"))
71                 }
72         }
73
74         @Test
75         fun `additional link nodes contain open search link`() {
76                 addHttpRequestHeader("Host", "www.example.com")
77                 assertThat(page.getAdditionalLinkNodes(freenetRequest), contains(mapOf(
78                                 "rel" to "search",
79                                 "type" to "application/opensearchdescription+xml",
80                                 "title" to "Sone",
81                                 "href" to "http://www.example.com/Sone/OpenSearch.xml"
82                 )))
83         }
84
85         @Test
86         fun `style sheets contains sone CSS file`() {
87                 assertThat(page.styleSheets, contains("css/sone.css"))
88         }
89
90         @Test
91         fun `shortcut icon is the sone icon`() {
92                 assertThat(page.shortcutIcon, equalTo("images/icon.png"))
93         }
94
95         @Test
96         fun `page requires login if require login was specified in the constructor`() {
97                 SoneTemplatePage("path.html", template, webInterface, true).let { page ->
98                         assertThat(page.requiresLogin(), equalTo(true))
99                 }
100         }
101
102         @Test
103         fun `page does not require login if require login was not specified in the constructor`() {
104                 SoneTemplatePage("path.html", template, webInterface, false).let { page ->
105                         assertThat(page.requiresLogin(), equalTo(false))
106                 }
107         }
108
109         private fun verifyVariableIsSet(name: String, value: Any) = verifyVariableMatches(name, equalTo<Any>(value))
110
111         private fun <T> verifyVariableMatches(name: String, matcher: Matcher<T>) {
112                 page.processTemplate(freenetRequest, templateContext)
113                 @Suppress("UNCHECKED_CAST")
114                 assertThat(templateContext[name] as T, matcher)
115         }
116
117         @Test
118         fun `core is set in template context`() {
119                 verifyVariableIsSet("core", core)
120         }
121
122         @Test
123         fun `current sone is set in template context`() {
124                 verifyVariableIsSet("currentSone", currentSone)
125         }
126
127         @Test
128         fun `local sones are set in template context`() {
129                 val localSones = listOf(mock<Sone>(), mock<Sone>())
130                 whenever(core.localSones).thenReturn(localSones)
131                 verifyVariableMatches("localSones", containsInAnyOrder(*localSones.toTypedArray()))
132         }
133
134         @Test
135         fun `freenet request is set in template context`() {
136                 verifyVariableIsSet("request", freenetRequest)
137         }
138
139         @Test
140         fun `current version is set in template context`() {
141                 verifyVariableIsSet("currentVersion", SonePlugin.getPluginVersion())
142         }
143
144         @Test
145         fun `has latest version is set correctly in template context if true`() {
146                 whenever(core.updateChecker.hasLatestVersion()).thenReturn(true)
147                 verifyVariableIsSet("hasLatestVersion", true)
148         }
149
150         @Test
151         fun `has latest version is set correctly in template context if false`() {
152                 whenever(core.updateChecker.hasLatestVersion()).thenReturn(false)
153                 verifyVariableIsSet("hasLatestVersion", false)
154         }
155
156         @Test
157         fun `latest edition is set in template context`() {
158                 whenever(core.updateChecker.latestEdition).thenReturn(1234L)
159                 verifyVariableIsSet("latestEdition", 1234L)
160         }
161
162         @Test
163         fun `latest version is set in template context`() {
164                 whenever(core.updateChecker.latestVersion).thenReturn(Version(1, 2, 3))
165                 verifyVariableIsSet("latestVersion", Version(1, 2, 3))
166         }
167
168         @Test
169         fun `latest version time is set in template context`() {
170                 whenever(core.updateChecker.latestVersionDate).thenReturn(12345L)
171                 verifyVariableIsSet("latestVersionTime", 12345L)
172         }
173
174         private fun createNotification(time: Long) = mock<Notification>().apply {
175                 whenever(createdTime).thenReturn(time)
176         }
177
178         @Test
179         fun `notifications are set in template context`() {
180                 val notifications = listOf(createNotification(3000), createNotification(1000), createNotification(2000))
181                 whenever(webInterface.getNotifications(currentSone)).thenReturn(notifications)
182                 verifyVariableMatches("notifications", contains(notifications[1], notifications[2], notifications[0]))
183         }
184
185         @Test
186         fun `notification hash is set in template context`() {
187                 val notifications = listOf(createNotification(3000), createNotification(1000), createNotification(2000))
188                 whenever(webInterface.getNotifications(currentSone)).thenReturn(notifications)
189                 verifyVariableIsSet("notificationHash", listOf(notifications[1], notifications[2], notifications[0]).hashCode())
190         }
191
192         @Test
193         fun `handleRequest method is called`() {
194                 var called = false
195                 val page = object : SoneTemplatePage("path.html", template, webInterface, true) {
196                         override fun handleRequest(request: FreenetRequest, templateContext: TemplateContext) {
197                                 called = true
198                         }
199                 }
200                 page.processTemplate(freenetRequest, templateContext)
201                 assertThat(called, equalTo(true))
202         }
203
204         @Test
205         fun `redirect does not happen if login is not required`() {
206                 val page = SoneTemplatePage("page.html", template, webInterface, false)
207                 assertThat(page.getRedirectTarget(freenetRequest), nullValue())
208         }
209
210         @Test
211         fun `redirect does not happen if sone is logged in`() {
212                 assertThat(page.getRedirectTarget(freenetRequest), nullValue())
213         }
214
215         @Test
216         fun `redirect does happen if sone is not logged in`() {
217                 unsetCurrentSone()
218                 request("index.html", GET)
219                 assertThat(page.getRedirectTarget(freenetRequest), equalTo("login.html?target=index.html"))
220         }
221
222         @Test
223         fun `redirect does happen with parameters encoded correctly if sone is not logged in`() {
224                 unsetCurrentSone()
225                 request("index.html", GET)
226                 addHttpRequestParameter("foo", "b=r")
227                 addHttpRequestParameter("baz", "q&o")
228                 assertThat(page.getRedirectTarget(freenetRequest), anyOf(
229                                 equalTo("login.html?target=index.html%3Ffoo%3Db%253Dr%26baz%3Dq%2526o"),
230                                 equalTo("login.html?target=index.html%3Fbaz%3Dq%2526o%26foo%3Db%253Dr")
231                 ))
232         }
233
234         @Test
235         fun `full access requirement is correctly forwarded from the preferences if false`() {
236                 assertThat(page.isFullAccessOnly, equalTo(false))
237         }
238
239         @Test
240         fun `full access requirement is correctly forwarded from the preferences if true`() {
241                 core.preferences.isRequireFullAccess = true
242                 assertThat(page.isFullAccessOnly, equalTo(true))
243         }
244
245         @Test
246         fun `page is disabled if full access is required but request does not have full access`() {
247                 core.preferences.isRequireFullAccess = true
248                 assertThat(page.isEnabled(toadletContext), equalTo(false))
249         }
250
251         @Test
252         fun `page is disabled if login is required but there is no current sone`() {
253                 unsetCurrentSone()
254                 assertThat(page.isEnabled(toadletContext), equalTo(false))
255         }
256
257         @Test
258         fun `page is enabled if login is required and there is a current sone`() {
259                 assertThat(page.isEnabled(toadletContext), equalTo(true))
260         }
261
262         @Test
263         fun `page is enabled if full access is required and request has full access and login is required and there is a current sone`() {
264                 core.preferences.isRequireFullAccess = true
265                 whenever(toadletContext.isAllowedFullAccess).thenReturn(true)
266                 assertThat(page.isEnabled(toadletContext), equalTo(true))
267         }
268
269         @Test
270         fun `page is enabled if no full access is required and login is not required`() {
271                 SoneTemplatePage("path.html", template, webInterface, false).let { page ->
272                         assertThat(page.isEnabled(toadletContext), equalTo(true))
273                 }
274         }
275
276 }