🔀 Merge branch 'release/v82'
[Sone.git] / src / test / kotlin / net / pterodactylus / sone / web / pages / OptionsPageTest.kt
1 package net.pterodactylus.sone.web.pages
2
3 import net.pterodactylus.sone.data.SoneOptions.*
4 import net.pterodactylus.sone.data.SoneOptions.LoadExternalContent.*
5 import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.*
6 import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.ALWAYS
7 import net.pterodactylus.sone.test.*
8 import net.pterodactylus.sone.web.*
9 import net.pterodactylus.sone.web.page.*
10 import net.pterodactylus.util.web.Method.*
11 import org.hamcrest.MatcherAssert.*
12 import org.hamcrest.Matchers.*
13 import org.junit.*
14
15 /**
16  * Unit test for [OptionsPage].
17  */
18 class OptionsPageTest : WebPageTest(::OptionsPage) {
19
20         @Before
21         fun setupPreferences() {
22                 core.preferences.newInsertionDelay = 1
23                 core.preferences.newCharactersPerPost = 50
24                 core.preferences.newFcpFullAccessRequired = WRITING
25                 core.preferences.newImagesPerPage = 4
26                 core.preferences.newFcpInterfaceActive = true
27                 core.preferences.newRequireFullAccess = true
28                 core.preferences.newPostCutOffLength = 51
29                 core.preferences.newPostsPerPage = 10
30                 core.preferences.newStrictFiltering = true
31         }
32
33         @Before
34         fun setupSoneOptions() {
35                 whenever(currentSone.options).thenReturn(DefaultSoneOptions().apply {
36                         isAutoFollow = true
37                         isShowNewPostNotifications = true
38                         isShowNewReplyNotifications = true
39                         isShowNewSoneNotifications = true
40                         isSoneInsertNotificationEnabled = true
41                         loadLinkedImages = FOLLOWED
42                         showCustomAvatars = FOLLOWED
43                 })
44         }
45
46         @Test
47         fun `page returns correct path`() {
48                 assertThat(page.path, equalTo("options.html"))
49         }
50
51         @Test
52         fun `page does not require login`() {
53                 assertThat(page.requiresLogin(), equalTo(false))
54         }
55
56         @Test
57         fun `page returns correct title`() {
58                 addTranslation("Page.Options.Title", "options page title")
59                 assertThat(page.getPageTitle(soneRequest), equalTo("options page title"))
60         }
61
62         @Test
63         fun `get request stores all preferences in the template context`() {
64                 verifyNoRedirect {
65                         assertThat(templateContext["auto-follow"], equalTo<Any>(true))
66                         assertThat(templateContext["show-notification-new-sones"], equalTo<Any>(true))
67                         assertThat(templateContext["show-notification-new-posts"], equalTo<Any>(true))
68                         assertThat(templateContext["show-notification-new-replies"], equalTo<Any>(true))
69                         assertThat(templateContext["enable-sone-insert-notifications"], equalTo<Any>(true))
70                         assertThat(templateContext["load-linked-images"], equalTo<Any>("FOLLOWED"))
71                         assertThat(templateContext["show-custom-avatars"], equalTo<Any>("FOLLOWED"))
72                         assertThat(templateContext["insertion-delay"], equalTo<Any>(1))
73                         assertThat(templateContext["characters-per-post"], equalTo<Any>(50))
74                         assertThat(templateContext["fcp-full-access-required"], equalTo<Any>(1))
75                         assertThat(templateContext["images-per-page"], equalTo<Any>(4))
76                         assertThat(templateContext["fcp-interface-active"], equalTo<Any>(true))
77                         assertThat(templateContext["require-full-access"], equalTo<Any>(true))
78                         assertThat(templateContext["post-cut-off-length"], equalTo<Any>(51))
79                         assertThat(templateContext["posts-per-page"], equalTo<Any>(10))
80                         assertThat(templateContext["strict-filtering"], equalTo<Any>(true))
81                 }
82         }
83
84         @Test
85         fun `get request without sone does not store sone-specific preferences in the template context`() {
86                 unsetCurrentSone()
87                 verifyNoRedirect {
88                         assertThat(templateContext["auto-follow"], nullValue())
89                         assertThat(templateContext["show-notification-new-sones"], nullValue())
90                         assertThat(templateContext["show-notification-new-posts"], nullValue())
91                         assertThat(templateContext["show-notification-new-replies"], nullValue())
92                         assertThat(templateContext["enable-sone-insert-notifications"], nullValue())
93                         assertThat(templateContext["load-linked-images"], nullValue())
94                         assertThat(templateContext["show-custom-avatars"], nullValue())
95                 }
96         }
97
98         private fun <T> verifyThatOptionCanBeSet(option: String, setValue: Any?, expectedValue: T, getter: () -> T) {
99                 setMethod(POST)
100                 addHttpRequestPart("show-custom-avatars", "ALWAYS")
101                 addHttpRequestPart("load-linked-images", "ALWAYS")
102                 setValue?.also { addHttpRequestPart(option, it.toString()) }
103                 verifyRedirect("options.html") {
104                         assertThat(getter(), equalTo(expectedValue))
105                 }
106         }
107
108         @Test
109         fun `auto-follow option can be set`() {
110                 verifyThatOptionCanBeSet("auto-follow", "checked", true) { currentSone.options.isAutoFollow }
111         }
112
113         @Test
114         fun `auto-follow option can be unset`() {
115                 verifyThatOptionCanBeSet("auto-follow", null, false) { currentSone.options.isAutoFollow }
116         }
117
118         @Test
119         fun `show new sone notification option can be set`() {
120                 verifyThatOptionCanBeSet("show-notification-new-sones", "checked", true) { currentSone.options.isShowNewSoneNotifications }
121         }
122
123         @Test
124         fun `show new sone notification option can be unset`() {
125                 verifyThatOptionCanBeSet("" +
126                                 "", null, false) { currentSone.options.isShowNewSoneNotifications }
127         }
128
129         @Test
130         fun `show new post notification option can be set`() {
131                 verifyThatOptionCanBeSet("show-notification-new-posts", "checked", true) { currentSone.options.isShowNewPostNotifications }
132         }
133
134         @Test
135         fun `show new post notification option can be unset`() {
136                 verifyThatOptionCanBeSet("show-notification-new-posts", null, false) { currentSone.options.isShowNewPostNotifications }
137         }
138
139         @Test
140         fun `show new reply notification option can be set`() {
141                 verifyThatOptionCanBeSet("show-notification-new-replies", "checked", true) { currentSone.options.isShowNewReplyNotifications }
142         }
143
144         @Test
145         fun `show new reply notification option can be unset`() {
146                 verifyThatOptionCanBeSet("show-notification-new-replies", null, false) { currentSone.options.isShowNewReplyNotifications }
147         }
148
149         @Test
150         fun `enable sone insert notifications option can be set`() {
151                 verifyThatOptionCanBeSet("enable-sone-insert-notifications", "checked", true) { currentSone.options.isSoneInsertNotificationEnabled }
152         }
153
154         @Test
155         fun `enable sone insert notifications option can be unset`() {
156                 verifyThatOptionCanBeSet("enable-sone-insert-notifications", null, false) { currentSone.options.isSoneInsertNotificationEnabled }
157         }
158
159         @Test
160         fun `load linked images option can be set`() {
161                 verifyThatOptionCanBeSet("load-linked-images", "TRUSTED", TRUSTED) { currentSone.options.loadLinkedImages }
162         }
163
164         @Test
165         fun `show custom avatar option can be set`() {
166                 verifyThatOptionCanBeSet("show-custom-avatars", "TRUSTED", TRUSTED) { currentSone.options.showCustomAvatars }
167         }
168
169         private fun verifyThatWrongValueForPreferenceIsDetected(name: String, value: String) {
170                 unsetCurrentSone()
171                 setMethod(POST)
172                 addHttpRequestPart(name, value)
173                 verifyNoRedirect {
174                         assertThat(templateContext["fieldErrors"] as Iterable<*>, hasItem(name))
175                 }
176         }
177
178         private fun <T> verifyThatPreferencesCanBeSet(name: String, setValue: String?, expectedValue: T, getter: () -> T) {
179                 unsetCurrentSone()
180                 setMethod(POST)
181                 setValue?.also { addHttpRequestPart(name, it) }
182                 verifyRedirect("options.html") {
183                         assertThat(getter(), equalTo(expectedValue))
184                 }
185         }
186
187         @Test
188         fun `insertion delay can not be set to less than 0 seconds`() {
189                 verifyThatWrongValueForPreferenceIsDetected("insertion-delay", "-1")
190         }
191
192         @Test
193         fun `insertion delay can be set to 0 seconds`() {
194                 verifyThatPreferencesCanBeSet("insertion-delay", "0", 0) { core.preferences.insertionDelay }
195         }
196
197         @Test
198         fun `setting insertion to an invalid value will reset it`() {
199                 verifyThatPreferencesCanBeSet("insertion-delay", "foo", 60) { core.preferences.insertionDelay }
200         }
201
202         @Test
203         fun `characters per post can not be set to less than -1`() {
204                 verifyThatWrongValueForPreferenceIsDetected("characters-per-post", "-2")
205         }
206
207         @Test
208         fun `characters per post can be set to -1`() {
209                 verifyThatPreferencesCanBeSet("characters-per-post", "-1", -1) { core.preferences.charactersPerPost }
210         }
211
212         @Test
213         fun `characters per post can not be set to 0`() {
214                 verifyThatWrongValueForPreferenceIsDetected("characters-per-post", "0")
215         }
216
217         @Test
218         fun `characters per post can not be set to 49`() {
219                 verifyThatWrongValueForPreferenceIsDetected("characters-per-post", "49")
220         }
221
222         @Test
223         fun `characters per post can be set to 50`() {
224                 verifyThatPreferencesCanBeSet("characters-per-post", "50", 50) { core.preferences.charactersPerPost }
225         }
226
227         @Test
228         fun `fcp full acess required option can be set to always`() {
229                 verifyThatPreferencesCanBeSet("fcp-full-access-required", "2", ALWAYS) { core.preferences.fcpFullAccessRequired }
230         }
231
232         @Test
233         fun `fcp full acess required option can be set to writing`() {
234                 verifyThatPreferencesCanBeSet("fcp-full-access-required", "1", WRITING) { core.preferences.fcpFullAccessRequired }
235         }
236
237         @Test
238         fun `fcp full acess required option can be set to no`() {
239                 verifyThatPreferencesCanBeSet("fcp-full-access-required", "0", NO) { core.preferences.fcpFullAccessRequired }
240         }
241
242         @Test
243         fun `fcp full acess required option is not changed if invalid value is set`() {
244                 verifyThatPreferencesCanBeSet("fcp-full-access-required", "foo", WRITING) { core.preferences.fcpFullAccessRequired }
245         }
246
247         @Test
248         fun `images per page can not be set to 0`() {
249                 verifyThatWrongValueForPreferenceIsDetected("images-per-page", "0")
250         }
251
252         @Test
253         fun `images per page can be set to 1`() {
254                 verifyThatPreferencesCanBeSet("images-per-page", "1", 1) { core.preferences.imagesPerPage }
255         }
256
257         @Test
258         fun `images per page is set to 9 if invalid value is requested`() {
259                 verifyThatPreferencesCanBeSet("images-per-page", "foo", 9) { core.preferences.imagesPerPage }
260         }
261
262         @Test
263         fun `fcp interface can be set to true`() {
264                 verifyThatPreferencesCanBeSet("fcp-interface-active", "checked", true) { core.preferences.fcpInterfaceActive }
265         }
266
267         @Test
268         fun `fcp interface can be set to false`() {
269                 verifyThatPreferencesCanBeSet("fcp-interface-active", null, false) { core.preferences.fcpInterfaceActive }
270         }
271
272         @Test
273         fun `require full access can be set to true`() {
274                 verifyThatPreferencesCanBeSet("require-full-access", "checked", true) { core.preferences.requireFullAccess }
275         }
276
277         @Test
278         fun `require full access can be set to false`() {
279                 verifyThatPreferencesCanBeSet("require-full-access", null, false) { core.preferences.requireFullAccess }
280         }
281
282         @Test
283         fun `post cut off length can not be set to -49`() {
284                 verifyThatWrongValueForPreferenceIsDetected("post-cut-off-length", "-49")
285         }
286
287         @Test
288         fun `post cut off length can be set to 50`() {
289                 verifyThatPreferencesCanBeSet("post-cut-off-length", "50", 50) { core.preferences.postCutOffLength }
290         }
291
292         @Test
293         fun `post cut off length is set to default on invalid value`() {
294                 verifyThatPreferencesCanBeSet("post-cut-off-length", "invalid", 200) { core.preferences.postCutOffLength }
295         }
296
297         @Test
298         fun `posts per page can not be set to 0`() {
299                 verifyThatWrongValueForPreferenceIsDetected("posts-per-page", "-49")
300         }
301
302         @Test
303         fun `posts per page can be set to 1`() {
304                 verifyThatPreferencesCanBeSet("posts-per-page", "1", 1) { core.preferences.postsPerPage }
305         }
306
307         @Test
308         fun `posts per page is set to default on invalid value`() {
309                 verifyThatPreferencesCanBeSet("posts-per-page", "invalid", 10) { core.preferences.postsPerPage }
310         }
311
312         @Test
313         fun `strict filtering can be set to true`() {
314                 verifyThatPreferencesCanBeSet("strict-filtering", "checked", true) { core.preferences.strictFiltering }
315         }
316
317         @Test
318         fun `strict filtering can be set to false`() {
319                 verifyThatPreferencesCanBeSet("strict-filtering", null, false) { core.preferences.strictFiltering }
320         }
321
322         @Test
323         fun `page can be created by dependency injection`() {
324                 assertThat(baseInjector.getInstance<OptionsPage>(), notNullValue())
325         }
326
327         @Test
328         fun `page is annotated with correct menuname`() {
329                 assertThat(page.menuName, equalTo("Options"))
330         }
331
332         @Test
333         fun `page is annotated with correct template path`() {
334                 assertThat(page.templatePath, equalTo("/templates/options.html"))
335         }
336
337 }