fbafdaf143ac12fe007a874e2deea8415e45a61e
[Sone.git] / src / test / kotlin / net / pterodactylus / sone / template / RenderFilterTest.kt
1 package net.pterodactylus.sone.template
2
3 import com.google.common.base.Optional
4 import net.pterodactylus.sone.core.Core
5 import net.pterodactylus.sone.data.Post
6 import net.pterodactylus.sone.data.Profile
7 import net.pterodactylus.sone.data.Sone
8 import net.pterodactylus.sone.test.mock
9 import net.pterodactylus.sone.text.FreemailPart
10 import net.pterodactylus.sone.text.FreenetLinkPart
11 import net.pterodactylus.sone.text.LinkPart
12 import net.pterodactylus.sone.text.Part
13 import net.pterodactylus.sone.text.PlainTextPart
14 import net.pterodactylus.sone.text.PostPart
15 import net.pterodactylus.sone.text.SonePart
16 import net.pterodactylus.util.template.HtmlFilter
17 import net.pterodactylus.util.template.TemplateContext
18 import net.pterodactylus.util.template.TemplateContextFactory
19 import org.hamcrest.MatcherAssert.assertThat
20 import org.hamcrest.Matchers.`is`
21 import org.hamcrest.Matchers.containsInAnyOrder
22 import org.jsoup.Jsoup
23 import org.jsoup.nodes.Attribute
24 import org.jsoup.nodes.Element
25 import org.jsoup.nodes.TextNode
26 import org.junit.Test
27 import org.mockito.Mockito.`when`
28 import java.net.URLEncoder
29
30 /**
31  * Unit test for [RenderFilter].
32  */
33 class RenderFilterTest {
34
35         companion object {
36                 private const val FREEMAIL_ID = "t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra"
37                 private const val SONE_FREEMAIL = "sone@$FREEMAIL_ID.freemail"
38                 private const val SONE_IDENTITY = "nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI"
39                 private const val POST_ID = "37a06250-6775-4b94-86ff-257ba690953c"
40         }
41
42         private val core = mock<Core>()
43         private val templateContextFactory = TemplateContextFactory()
44         private val templateContext: TemplateContext
45         private val sone = setupSone(SONE_IDENTITY, "Sone", "First")
46         private val parameters = mutableMapOf<String, Any?>()
47
48         init {
49                 templateContextFactory.addFilter("html", HtmlFilter())
50                 templateContext = templateContextFactory.createTemplateContext()
51         }
52
53         private val filter = RenderFilter(core, templateContextFactory)
54
55         @Test
56         fun `plain text part is rendered correctly`() {
57                 assertThat(renderParts(PlainTextPart("plain text")), `is`("plain text"))
58         }
59
60         private fun renderParts(vararg part: Part) = filter.format(templateContext, listOf(*part), parameters) as String
61
62         @Test
63         fun `plain text part is shortened if length exceeds maxl ength`() {
64                 setLengthAndCutOffLength(15, 10)
65                 assertThat(renderParts(PlainTextPart("This is a long text.")), `is`("This is a &hellip;"))
66         }
67
68         @Test
69         fun `plain text part is not shortened if length does not exceed max length`() {
70                 setLengthAndCutOffLength(20, 10)
71                 assertThat(renderParts(PlainTextPart("This is a long text.")), `is`("This is a &hellip;"))
72         }
73
74         @Test
75         fun `short parts are not shortened`() {
76                 setLengthAndCutOffLength(15, 10)
77                 assertThat(renderParts(PlainTextPart("This.")), `is`("This."))
78         }
79
80         @Test
81         fun `multiple plain text parts are shortened`() {
82                 setLengthAndCutOffLength(15, 10)
83                 assertThat(renderParts(PlainTextPart("This "), PlainTextPart("is a long text.")), `is`("This is a &hellip;"))
84         }
85
86         @Test
87         fun `parts after length has been reached are ignored`() {
88                 setLengthAndCutOffLength(15, 10)
89                 assertThat(renderParts(PlainTextPart("This is a long text."), PlainTextPart(" And even more.")), `is`("This is a &hellip;"))
90         }
91
92         @Test
93         fun `link parts are not shortened`() {
94                 setLengthAndCutOffLength(15, 10)
95                 val linkNode = Jsoup.parseBodyFragment(renderParts(FreenetLinkPart("KSK@gpl.txt", "This is a long text.", false))).body().child(0)
96                 verifyLink(linkNode, "/KSK@gpl.txt", "freenet", "KSK@gpl.txt", "This is a long text.")
97         }
98
99         @Test
100         fun `additional link parts are ignored`() {
101                 setLengthAndCutOffLength(15, 10)
102                 assertThat(renderParts(PlainTextPart("This is a long text."), FreenetLinkPart("KSK@gpl.txt", "This is a long text.", false)), `is`("This is a &hellip;"))
103         }
104
105         private fun setLengthAndCutOffLength(length: Int, cutOffLength: Int) {
106                 parameters.put("length", length)
107                 parameters.put("cut-off-length", cutOffLength)
108         }
109
110         @Test
111         fun `sone parts are added but their length is ignored`() {
112                 setLengthAndCutOffLength(15, 10)
113                 val body = Jsoup.parseBodyFragment(renderParts(SonePart(sone), PlainTextPart("This is a long text."))).body()
114                 val linkNode = body.childNode(0) as Element
115                 println(linkNode)
116                 verifyLink(linkNode, "viewSone.html?sone=$SONE_IDENTITY", "in-sone", "First", "First")
117                 assertThat((body.childNode(1) as TextNode).text(), `is`("This is a …"))
118         }
119
120         @Test
121         fun `additional sone parts are ignored`() {
122                 setLengthAndCutOffLength(15, 10)
123                 assertThat(renderParts(PlainTextPart("This is a long text."), SonePart(sone)), `is`("This is a &hellip;"))
124         }
125
126         @Test
127         fun `freenet link is rendered correctly`() {
128                 val linkNode = renderParts(FreenetLinkPart("KSK@gpl.txt", "gpl.txt", false)).toLinkNode()
129                 verifyLink(linkNode, "/KSK@gpl.txt", "freenet", "KSK@gpl.txt", "gpl.txt")
130         }
131
132         private fun verifyLink(linkNode: Element, url: String, cssClass: String, tooltip: String, text: String) {
133                 assertThat(linkNode.nodeName(), `is`("a"))
134                 assertThat<List<Attribute>>(linkNode.attributes().asList(), containsInAnyOrder(
135                                 Attribute("href", url),
136                                 Attribute("class", cssClass),
137                                 Attribute("title", tooltip)
138                 ))
139                 assertThat(linkNode.text(), `is`(text))
140         }
141
142         @Test
143         fun `trusted freenet link is rendered with correct css class`() {
144                 val linkNode = renderParts(FreenetLinkPart("KSK@gpl.txt", "gpl.txt", true)).toLinkNode()
145                 verifyLink(linkNode, "/KSK@gpl.txt", "freenet-trusted", "KSK@gpl.txt", "gpl.txt")
146         }
147
148         private fun String.toLinkNode() = Jsoup.parseBodyFragment(this).body().child(0)
149
150         @Test
151         fun `internet link is rendered correctly`() {
152                 val linkNode = renderParts(LinkPart("http://test.com/test.html", "test.com/test.html")).toLinkNode()
153                 verifyLink(linkNode, "/external-link/?_CHECKED_HTTP_=${URLEncoder.encode("http://test.com/test.html", "UTF-8")}", "internet",
154                                 "http://test.com/test.html", "test.com/test.html")
155         }
156
157         @Test
158         fun `sone parts are rendered correctly`() {
159                 val linkNode = renderParts(SonePart(sone)).toLinkNode()
160                 verifyLink(linkNode, "viewSone.html?sone=" + SONE_IDENTITY, "in-sone", "First", "First")
161         }
162
163         private fun setupSone(identity: String, name: String?, firstName: String): Sone {
164                 val sone = mock<Sone>()
165                 `when`(sone.id).thenReturn(identity)
166                 `when`(sone.profile).thenReturn(Profile(sone))
167                 `when`(sone.name).thenReturn(name)
168                 sone.profile.firstName = firstName
169                 `when`(core.getSone(identity)).thenReturn(Optional.of<Sone>(sone))
170                 return sone
171         }
172
173         @Test
174         fun `sone part with unknown sone is rendered as link to web of trust`() {
175                 val sone = setupSone(SONE_IDENTITY, null, "First")
176                 val linkNode = renderParts(SonePart(sone)).toLinkNode()
177                 verifyLink(linkNode, "/WebOfTrust/ShowIdentity?id=$SONE_IDENTITY", "in-sone", SONE_IDENTITY, SONE_IDENTITY)
178         }
179
180         @Test
181         fun `post part is cut off correctly when there are spaces`() {
182                 val post = setupPost(sone, "1234 678901 345 789012 45678 01.")
183                 val linkNode = renderParts(PostPart(post)).toLinkNode()
184                 verifyLink(linkNode, "viewPost.html?post=$POST_ID", "in-sone", "First", "1234 678901 345…")
185         }
186
187         private fun setupPost(sone: Sone, value: String): Post {
188                 val post = mock<Post>()
189                 `when`(post.id).thenReturn(POST_ID)
190                 `when`(post.sone).thenReturn(sone)
191                 `when`(post.text).thenReturn(value)
192                 return post
193         }
194
195         @Test
196         fun `post part is cut off correctly when there are no spaces`() {
197                 val post = setupPost(sone, "1234567890123456789012345678901.")
198                 val linkNode = renderParts(PostPart(post)).toLinkNode()
199                 verifyLink(linkNode, "viewPost.html?post=$POST_ID", "in-sone", "First", "12345678901234567890…")
200         }
201
202         @Test
203         fun `post part shorter than 21 chars is not cut off`() {
204                 val post = setupPost(sone, "12345678901234567890")
205                 val linkNode = renderParts(PostPart(post)).toLinkNode()
206                 verifyLink(linkNode, "viewPost.html?post=$POST_ID", "in-sone", "First", "12345678901234567890")
207         }
208
209         @Test
210         fun `multiple parts are rendered correctly`() {
211                 val parts = arrayOf(PlainTextPart("te"), PlainTextPart("xt"))
212                 assertThat(renderParts(*parts), `is`("text"))
213         }
214
215         @Test
216         fun `freemail address is displayed correctly`() {
217                 val linkNode = renderParts(FreemailPart("sone", FREEMAIL_ID, SONE_IDENTITY)).toLinkNode()
218                 verifyLink(linkNode, "/Freemail/NewMessage?to=$SONE_IDENTITY", "in-sone", "First\n$SONE_FREEMAIL", "sone@First.freemail")
219         }
220
221 }