Add new render filter
[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.text.FreemailPart
9 import net.pterodactylus.sone.text.FreenetLinkPart
10 import net.pterodactylus.sone.text.LinkPart
11 import net.pterodactylus.sone.text.Part
12 import net.pterodactylus.sone.text.PartContainer
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 org.mockito.Mockito.mock
29 import java.net.URLEncoder
30
31 /**
32  * Unit test for [RenderFilter].
33  */
34 class RenderFilterTest {
35
36         companion object {
37                 private const val FREEMAIL_ID = "t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra"
38                 private const val SONE_FREEMAIL = "sone@$FREEMAIL_ID.freemail"
39                 private const val SONE_IDENTITY = "nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI"
40                 private const val POST_ID = "37a06250-6775-4b94-86ff-257ba690953c"
41         }
42
43         private val core = mock(Core::class.java)
44         private val templateContextFactory = TemplateContextFactory()
45         private val templateContext: TemplateContext
46         private val sone = setupSone(SONE_IDENTITY, "Sone", "First")
47         private val parameters = mutableMapOf<String, Any?>()
48
49         init {
50                 templateContextFactory.addFilter("html", HtmlFilter())
51                 templateContext = templateContextFactory.createTemplateContext()
52         }
53
54         private val filter = RenderFilter(core, templateContextFactory)
55
56         @Test
57         fun plainTextIsRenderedCorrectly() {
58                 assertThat(renderParts(PlainTextPart("plain text")), `is`("plain text"))
59         }
60
61         private fun renderParts(vararg part: Part) = filter.format(templateContext, listOf(*part), parameters) as String
62
63         @Test
64         fun plainTextPartIsShortenedIfLengthExceedsMaxLength() {
65                 setLengthAndCutOffLength(15, 10)
66                 assertThat(renderParts(PlainTextPart("This is a long text.")), `is`("This is a &hellip;"))
67         }
68
69         @Test
70         fun plainTextPartIsNotShortenedIfLengthDoesNotExceedMaxLength() {
71                 setLengthAndCutOffLength(20, 10)
72                 assertThat(renderParts(PlainTextPart("This is a long text.")), `is`("This is a &hellip;"))
73         }
74
75         @Test
76         fun shortPartsAreNotShortened() {
77                 setLengthAndCutOffLength(15, 10)
78                 assertThat(renderParts(PlainTextPart("This.")), `is`("This."))
79         }
80
81         @Test
82         fun multiplePlainTextPartsAreShortened() {
83                 setLengthAndCutOffLength(15, 10)
84                 assertThat(renderParts(PlainTextPart("This "), PlainTextPart("is a long text.")), `is`("This is a &hellip;"))
85         }
86
87         @Test
88         fun partsAfterLengthHasBeenReachedAreIgnored() {
89                 setLengthAndCutOffLength(15, 10)
90                 assertThat(renderParts(PlainTextPart("This is a long text."), PlainTextPart(" And even more.")), `is`("This is a &hellip;"))
91         }
92
93         @Test
94         fun linkPartsAreNotShortened() {
95                 setLengthAndCutOffLength(15, 10)
96                 val linkNode = Jsoup.parseBodyFragment(renderParts(FreenetLinkPart("KSK@gpl.txt", "This is a long text.", false))).body().child(0)
97                 verifyLink(linkNode, "/KSK@gpl.txt", "freenet", "KSK@gpl.txt", "This is a long text.")
98         }
99
100         @Test
101         fun additionalLinkPartsAreIgnored() {
102                 setLengthAndCutOffLength(15, 10)
103                 assertThat(renderParts(PlainTextPart("This is a long text."), FreenetLinkPart("KSK@gpl.txt", "This is a long text.", false)), `is`("This is a &hellip;"))
104         }
105
106         private fun setLengthAndCutOffLength(length: Int, cutOffLength: Int) {
107                 parameters.put("length", length)
108                 parameters.put("cut-off-length", cutOffLength)
109         }
110
111         @Test
112         fun sonePartsAreAddedButTheirLengthIsIgnored() {
113                 setLengthAndCutOffLength(15, 10)
114                 val body = Jsoup.parseBodyFragment(renderParts(SonePart(sone), PlainTextPart("This is a long text."))).body()
115                 val linkNode = body.childNode(0) as Element
116                 println(linkNode)
117                 verifyLink(linkNode, "viewSone.html?sone=$SONE_IDENTITY", "in-sone", "First", "First")
118                 assertThat((body.childNode(1) as TextNode).text(), `is`("This is a …"))
119         }
120
121         @Test
122         fun additionalSonePartsAreIgnored() {
123                 setLengthAndCutOffLength(15, 10)
124                 assertThat(renderParts(PlainTextPart("This is a long text."), SonePart(sone)), `is`("This is a &hellip;"))
125         }
126
127         @Test
128         fun freenetLinkIsRenderedCorrectly() {
129                 val linkNode = renderParts(FreenetLinkPart("KSK@gpl.txt", "gpl.txt", false)).toLinkNode()
130                 verifyLink(linkNode, "/KSK@gpl.txt", "freenet", "KSK@gpl.txt", "gpl.txt")
131         }
132
133         private fun verifyLink(linkNode: Element, url: String, cssClass: String, tooltip: String, text: String) {
134                 assertThat(linkNode.nodeName(), `is`("a"))
135                 assertThat<List<Attribute>>(linkNode.attributes().asList(), containsInAnyOrder(
136                                 Attribute("href", url),
137                                 Attribute("class", cssClass),
138                                 Attribute("title", tooltip)
139                 ))
140                 assertThat(linkNode.text(), `is`(text))
141         }
142
143         @Test
144         fun trustedFreenetLinkIsRenderedWithCorrectCssClass() {
145                 val linkNode = renderParts(FreenetLinkPart("KSK@gpl.txt", "gpl.txt", true)).toLinkNode()
146                 verifyLink(linkNode, "/KSK@gpl.txt", "freenet-trusted", "KSK@gpl.txt", "gpl.txt")
147         }
148
149         private fun String.toLinkNode() = Jsoup.parseBodyFragment(this).body().child(0)
150
151         @Test
152         fun internetLinkIsRenderedCorrectly() {
153                 val linkNode = renderParts(LinkPart("http://test.com/test.html", "test.com/test.html")).toLinkNode()
154                 verifyLink(linkNode, "/external-link/?_CHECKED_HTTP_=${URLEncoder.encode("http://test.com/test.html", "UTF-8")}", "internet",
155                                 "http://test.com/test.html", "test.com/test.html")
156         }
157
158         @Test
159         fun sonePartsAreRenderedCorrectly() {
160                 val linkNode = renderParts(SonePart(sone)).toLinkNode()
161                 verifyLink(linkNode, "viewSone.html?sone=" + SONE_IDENTITY, "in-sone", "First", "First")
162         }
163
164         private fun setupSone(identity: String, name: String?, firstName: String): Sone {
165                 val sone = mock<Sone>(Sone::class.java)
166                 `when`(sone.id).thenReturn(identity)
167                 `when`(sone.profile).thenReturn(Profile(sone))
168                 `when`(sone.name).thenReturn(name)
169                 sone.profile.firstName = firstName
170                 `when`(core.getSone(identity)).thenReturn(Optional.of<Sone>(sone))
171                 return sone
172         }
173
174         @Test
175         fun sonePartsWithUnknownSoneIsRenderedAsLinkToWebOfTrust() {
176                 val sone = setupSone(SONE_IDENTITY, null, "First")
177                 val linkNode = renderParts(SonePart(sone)).toLinkNode()
178                 verifyLink(linkNode, "/WebOfTrust/ShowIdentity?id=$SONE_IDENTITY", "in-sone", SONE_IDENTITY, SONE_IDENTITY)
179         }
180
181         @Test
182         fun postPartIsCutOffCorrectlyWhenThereAreSpaces() {
183                 val post = setupPost(sone, "1234 678901 345 789012 45678 01.")
184                 val linkNode = renderParts(PostPart(post)).toLinkNode()
185                 verifyLink(linkNode, "viewPost.html?post=$POST_ID", "in-sone", "First", "1234 678901 345…")
186         }
187
188         private fun setupPost(sone: Sone, value: String): Post {
189                 val post = mock<Post>(Post::class.java)
190                 `when`(post.id).thenReturn(POST_ID)
191                 `when`(post.sone).thenReturn(sone)
192                 `when`(post.text).thenReturn(value)
193                 return post
194         }
195
196         @Test
197         fun postPartIsCutOffCorrectlyWhenThereAreNoSpaces() {
198                 val post = setupPost(sone, "1234567890123456789012345678901.")
199                 val linkNode = renderParts(PostPart(post)).toLinkNode()
200                 verifyLink(linkNode, "viewPost.html?post=$POST_ID", "in-sone", "First", "12345678901234567890…")
201         }
202
203         @Test
204         fun postPartShorterThan21CharsIsNotCutOff() {
205                 val post = setupPost(sone, "12345678901234567890")
206                 val linkNode = renderParts(PostPart(post)).toLinkNode()
207                 verifyLink(linkNode, "viewPost.html?post=$POST_ID", "in-sone", "First", "12345678901234567890")
208         }
209
210         @Test
211         fun multiplePartsAreRenderedCorrectly() {
212                 val parts = PartContainer()
213                 parts.add(PlainTextPart("te"))
214                 parts.add(PlainTextPart("xt"))
215                 assertThat(renderParts(parts), `is`("text"))
216         }
217
218         @Test
219         fun freemailAddressIsDisplayedCorrectly() {
220                 val linkNode = renderParts(FreemailPart("sone", FREEMAIL_ID, SONE_IDENTITY)).toLinkNode()
221                 verifyLink(linkNode, "/Freemail/NewMessage?to=$SONE_IDENTITY", "in-sone", "First\n$SONE_FREEMAIL", "sone@First.freemail")
222         }
223
224 }