✨ Use @TemplatePath annotations on most pages
[Sone.git] / src / test / kotlin / net / pterodactylus / sone / web / pages / ViewSonePageTest.kt
1 package net.pterodactylus.sone.web.pages
2
3 import net.pterodactylus.sone.data.Post
4 import net.pterodactylus.sone.data.PostReply
5 import net.pterodactylus.sone.data.Profile
6 import net.pterodactylus.sone.data.Sone
7 import net.pterodactylus.sone.test.getInstance
8 import net.pterodactylus.sone.test.isOnPage
9 import net.pterodactylus.sone.test.mock
10 import net.pterodactylus.sone.test.whenever
11 import net.pterodactylus.sone.utils.Pagination
12 import net.pterodactylus.sone.utils.asOptional
13 import net.pterodactylus.sone.web.baseInjector
14 import net.pterodactylus.sone.web.page.*
15 import org.hamcrest.MatcherAssert.assertThat
16 import org.hamcrest.Matchers.contains
17 import org.hamcrest.Matchers.equalTo
18 import org.hamcrest.Matchers.notNullValue
19 import org.hamcrest.Matchers.nullValue
20 import org.junit.Before
21 import org.junit.Test
22 import java.net.*
23
24 /**
25  * Unit test for [ViewSonePage].
26  */
27 class ViewSonePageTest: WebPageTest(::ViewSonePage) {
28
29         init {
30                 whenever(currentSone.id).thenReturn("sone-id")
31         }
32
33         private val post1 = createPost("post1", "First Post.", 1000, currentSone)
34         private val post2 = createPost("post2", "Second Post.", 2000, currentSone)
35         private val foreignPost1 = createPost("foreign-post1", "First Foreign Post.", 1000, mock())
36         private val foreignPost2 = createPost("foreign-post2", "Second Foreign Post.", 2000, mock())
37         private val foreignPost3 = createPost("foreign-post3", "Third Foreign Post.", 3000, mock())
38         private val directed1 = createPost("post3", "First directed.", 1500, mock(), recipient = currentSone)
39         private val directed2 = createPost("post4", "Second directed.", 2500, mock(), recipient = currentSone)
40
41         @Before
42         fun setup() {
43                 whenever(currentSone.posts).thenReturn(mutableListOf(post2, post1))
44                 whenever(core.getDirectedPosts("sone-id")).thenReturn(setOf(directed1, directed2))
45                 core.preferences.newPostsPerPage = 2
46         }
47
48         @Test
49         fun `page returns correct path`() {
50                 assertThat(page.path, equalTo("viewSone.html"))
51         }
52
53         @Test
54         fun `page does not require login`() {
55                 assertThat(page.requiresLogin(), equalTo(false))
56         }
57
58         @Test
59         fun `get request without sone parameter stores null in template context`() {
60                 verifyNoRedirect {
61                         assertThat(templateContext["sone"], nullValue())
62                         assertThat(templateContext["soneId"], equalTo<Any>(""))
63                 }
64         }
65
66         @Test
67         fun `get request with invalid sone parameter stores null in template context`() {
68                 addHttpRequestParameter("sone", "invalid-sone-id")
69                 verifyNoRedirect {
70                         assertThat(templateContext["sone"], nullValue())
71                         assertThat(templateContext["soneId"], equalTo<Any>("invalid-sone-id"))
72                 }
73         }
74
75         @Test
76         fun `get request with valid sone parameter stores sone in template context`() {
77                 whenever(currentSone.posts).thenReturn(mutableListOf())
78                 whenever(core.getDirectedPosts("sone-id")).thenReturn(emptyList())
79                 addHttpRequestParameter("sone", "sone-id")
80                 addSone("sone-id", currentSone)
81                 verifyNoRedirect {
82                         assertThat(templateContext["sone"], equalTo<Any>(currentSone))
83                         assertThat(templateContext["soneId"], equalTo<Any>("sone-id"))
84                 }
85         }
86
87         private fun createPost(id: String, text: String, time: Long, sender: Sone? = null, recipient: Sone? = null) = mock<Post>().apply {
88                 whenever(this.id).thenReturn(id)
89                 sender?.run { whenever(this@apply.sone).thenReturn(this) }
90                 val recipientId = recipient?.id
91                 whenever(this.recipientId).thenReturn(recipientId.asOptional())
92                 whenever(this.recipient).thenReturn(recipient.asOptional())
93                 whenever(this.time).thenReturn(time)
94                 whenever(this.text).thenReturn(text)
95         }
96
97         @Test
98         @Suppress("UNCHECKED_CAST")
99         fun `request with valid sone stores posts and directed posts in template context`() {
100                 addSone("sone-id", currentSone)
101                 addHttpRequestParameter("sone", "sone-id")
102                 verifyNoRedirect {
103                         assertThat(templateContext["posts"] as Iterable<Post>, contains(directed2, post2))
104                         assertThat(templateContext["postPagination"] as Pagination<Post>, isOnPage(0).hasPages(2))
105                 }
106         }
107
108         @Test
109         @Suppress("UNCHECKED_CAST")
110         fun `second page of posts is shown correctly`() {
111                 addSone("sone-id", currentSone)
112                 addHttpRequestParameter("sone", "sone-id")
113                 addHttpRequestParameter("postPage", "1")
114                 verifyNoRedirect {
115                         assertThat(templateContext["posts"] as Iterable<Post>, contains(directed1, post1))
116                         assertThat(templateContext["postPagination"] as Pagination<Post>, isOnPage(1).hasPages(2))
117                 }
118         }
119
120         private fun createReply(text: String, time: Long, post: Post?) = mock<PostReply>().apply {
121                 whenever(this.text).thenReturn(text)
122                 whenever(this.time).thenReturn(time)
123                 whenever(this.post).thenReturn(post.asOptional())
124         }
125
126         @Test
127         @Suppress("UNCHECKED_CAST")
128         fun `replies are shown correctly`() {
129                 val reply1 = createReply("First Reply", 1500, foreignPost1)
130                 val reply2 = createReply("Second Reply", 2500, foreignPost2)
131                 val reply3 = createReply("Third Reply", 1750, post1)
132                 val reply4 = createReply("Fourth Reply", 2250, post2)
133                 val reply5 = createReply("Fifth Reply", 1600, post1)
134                 val reply6 = createReply("Sixth Reply", 2100, directed1)
135                 val reply7 = createReply("Seventh Reply", 2200, null)
136                 val reply8 = createReply("Eigth Reply", 2300, foreignPost1)
137                 val reply9 = createReply("Ninth Reply", 2050, foreignPost3)
138                 whenever(currentSone.replies).thenReturn(setOf(reply1, reply2, reply3, reply4, reply5, reply6, reply7, reply8, reply9))
139                 whenever(core.getReplies("post1")).thenReturn(listOf(reply3, reply5))
140                 whenever(core.getReplies("post2")).thenReturn(listOf(reply4))
141                 whenever(core.getReplies("foreign-post1")).thenReturn(listOf(reply8, reply1))
142                 whenever(core.getReplies("foreign-post2")).thenReturn(listOf(reply2))
143                 whenever(core.getReplies("post3")).thenReturn(listOf(reply6))
144                 whenever(core.getReplies("foreign-post3")).thenReturn(listOf(reply9))
145                 addSone("sone-id", currentSone)
146                 addHttpRequestParameter("sone", "sone-id")
147                 verifyNoRedirect {
148                         assertThat(templateContext["repliedPosts"] as Iterable<Post>, contains(foreignPost2, foreignPost1))
149                         assertThat(templateContext["repliedPostPagination"] as Pagination<Post>, isOnPage(0).hasPages(2))
150                 }
151         }
152
153         @Test
154         @Suppress("UNCHECKED_CAST")
155         fun `second page of replies is shown correctly`() {
156                 val reply1 = createReply("First Reply", 1500, foreignPost1)
157                 val reply2 = createReply("Second Reply", 2500, foreignPost2)
158                 val reply3 = createReply("Third Reply", 1750, post1)
159                 val reply4 = createReply("Fourth Reply", 2250, post2)
160                 val reply5 = createReply("Fifth Reply", 1600, post1)
161                 val reply6 = createReply("Sixth Reply", 2100, directed1)
162                 val reply7 = createReply("Seventh Reply", 2200, null)
163                 val reply8 = createReply("Eigth Reply", 2300, foreignPost1)
164                 val reply9 = createReply("Ninth Reply", 2050, foreignPost3)
165                 whenever(currentSone.replies).thenReturn(setOf(reply1, reply2, reply3, reply4, reply5, reply6, reply7, reply8, reply9))
166                 whenever(core.getReplies("post1")).thenReturn(listOf(reply3, reply5))
167                 whenever(core.getReplies("post2")).thenReturn(listOf(reply4))
168                 whenever(core.getReplies("foreign-post1")).thenReturn(listOf(reply8, reply1))
169                 whenever(core.getReplies("foreign-post2")).thenReturn(listOf(reply2))
170                 whenever(core.getReplies("post3")).thenReturn(listOf(reply6))
171                 whenever(core.getReplies("foreign-post3")).thenReturn(listOf(reply9))
172                 addSone("sone-id", currentSone)
173                 addHttpRequestParameter("sone", "sone-id")
174                 addHttpRequestParameter("repliedPostPage", "1")
175                 verifyNoRedirect {
176                         assertThat(templateContext["repliedPosts"] as Iterable<Post>, contains(foreignPost3))
177                         assertThat(templateContext["repliedPostPagination"] as Pagination<Post>, isOnPage(1).hasPages(2))
178                 }
179         }
180
181         @Test
182         fun `page title is default for request without parameters`() {
183                 addTranslation("Page.ViewSone.Page.TitleWithoutSone", "view sone page without sone")
184                 assertThat(page.getPageTitle(soneRequest), equalTo("view sone page without sone"))
185         }
186
187         @Test
188         fun `page title is default for request with invalid sone parameters`() {
189                 addHttpRequestParameter("sone", "invalid-sone-id")
190                 addTranslation("Page.ViewSone.Page.TitleWithoutSone", "view sone page without sone")
191                 assertThat(page.getPageTitle(soneRequest), equalTo("view sone page without sone"))
192         }
193
194         @Test
195         fun `page title contains sone name for request with sone parameters`() {
196                 addHttpRequestParameter("sone", "sone-id")
197                 addSone("sone-id", currentSone)
198                 whenever(currentSone.profile).thenReturn(Profile(currentSone).apply {
199                         firstName = "First"
200                         middleName = "M."
201                         lastName = "Last"
202                 })
203                 addTranslation("Page.ViewSone.Title", "view sone page")
204                 assertThat(page.getPageTitle(soneRequest), equalTo("First M. Last - view sone page"))
205         }
206
207         @Test
208         fun `page is link-excepted`() {
209                 assertThat(page.isLinkExcepted(URI("")), equalTo(true))
210         }
211
212         @Test
213         fun `page can be created by dependency injection`() {
214             assertThat(baseInjector.getInstance<ViewSonePage>(), notNullValue())
215         }
216
217         @Test
218         fun `page is annotated with correct template path`() {
219             assertThat(page.templatePath, equalTo("/templates/viewSone.html"))
220         }
221
222 }