2 * Sone - SoneTextParserTest.kt - Copyright © 2011–2020 David Roden
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 package net.pterodactylus.sone.text
20 import com.google.inject.Guice.*
21 import freenet.keys.FreenetURI
22 import net.pterodactylus.sone.data.*
23 import net.pterodactylus.sone.data.impl.*
24 import net.pterodactylus.sone.database.*
25 import net.pterodactylus.sone.test.*
26 import org.hamcrest.MatcherAssert.*
27 import org.hamcrest.Matchers.*
31 * JUnit test case for [SoneTextParser].
33 class SoneTextParserTest {
35 private val soneTextParser = SoneTextParser(null, null)
38 fun `basic operation`() {
39 val parts = soneTextParser.parse("Test.", null)
40 assertThat("Part Text", convertText(parts, PlainTextPart::class.java), equalTo("Test."))
44 fun `empty lines at start and end are stripped`() {
45 val parts = soneTextParser.parse("\nTest.\n\n", null)
46 assertThat("Part Text", convertText(parts, PlainTextPart::class.java), equalTo("Test."))
50 fun `duplicate empty lines in the text are stripped`() {
51 val parts = soneTextParser.parse("\nTest.\n\n\nTest.", null)
52 assertThat("Part Text", convertText(parts, PlainTextPart::class.java), equalTo("Test.\n\nTest."))
56 fun `consecutive lines are separated by linefeed`() {
57 val parts = soneTextParser.parse("Text.\nText", null)
58 assertThat("Part Text", convertText(parts), equalTo("Text.\nText"))
62 fun `freenet links have the freenet prefix removed`() {
63 val parts = soneTextParser.parse("freenet:KSK@gpl.txt", null)
64 assertThat("Part Text", convertText(parts), equalTo("[KSK@gpl.txt|KSK@gpl.txt|gpl.txt]"))
68 fun `only the first item in a line is prefixed with a line break`() {
69 val parts = soneTextParser.parse("Text.\nKSK@gpl.txt and KSK@gpl.txt", null)
70 assertThat("Part Text", convertText(parts), equalTo("Text.\n[KSK@gpl.txt|KSK@gpl.txt|gpl.txt] and [KSK@gpl.txt|KSK@gpl.txt|gpl.txt]"))
74 fun `sone link with too short sone ID is rendered as plain text`() {
75 val parts = soneTextParser.parse("sone://too-short", null)
76 assertThat("Part Text", convertText(parts), equalTo("sone://too-short"))
80 fun `sone link is rendered correctly if sone is not present`() {
81 val parser = SoneTextParser(AbsentSoneProvider(), null)
82 val parts = parser.parse("sone://DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU", null)
83 assertThat("Part Text", convertText(parts), equalTo("[Sone|DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU]"))
87 fun `sone and post can be parsed from the same text`() {
88 val parser = SoneTextParser(TestSoneProvider(), TestPostProvider())
89 val parts = parser.parse("Text sone://DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU more text post://f3757817-b45a-497a-803f-9c5aafc10dc6 even more text", null)
90 assertThat("Part Text", convertText(parts), equalTo("Text [Sone|DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU] more text [Post|f3757817-b45a-497a-803f-9c5aafc10dc6|text] even more text"))
94 fun `post link is rendered as plain text if post ID is too short`() {
95 val parts = soneTextParser.parse("post://too-short", null)
96 assertThat("Part Text", convertText(parts), equalTo("post://too-short"))
100 fun `post link is rendered correctly if post is present`() {
101 val parser = SoneTextParser(null, TestPostProvider())
102 val parts = parser.parse("post://f3757817-b45a-497a-803f-9c5aafc10dc6", null)
103 assertThat("Part Text", convertText(parts), equalTo("[Post|f3757817-b45a-497a-803f-9c5aafc10dc6|text]"))
107 fun `post link is rendered as plain text if post is absent`() {
108 val parser = SoneTextParser(null, AbsentPostProvider())
109 val parts = parser.parse("post://f3757817-b45a-497a-803f-9c5aafc10dc6", null)
110 assertThat("Part Text", convertText(parts), equalTo("post://f3757817-b45a-497a-803f-9c5aafc10dc6"))
114 fun `name of freenet link does not contain url parameters`() {
115 val parts = soneTextParser.parse("KSK@gpl.txt?max-size=12345", null)
116 assertThat("Part Text", convertText(parts), equalTo("[KSK@gpl.txt?max-size=12345|KSK@gpl.txt|gpl.txt]"))
120 fun `trailing slash in freenet link is removed for name`() {
121 val parts = soneTextParser.parse("KSK@gpl.txt/", null)
122 assertThat("Part Text", convertText(parts), equalTo("[KSK@gpl.txt/|KSK@gpl.txt/|gpl.txt]"))
126 fun `last meta string of freenet link is used as name`() {
127 val parts = soneTextParser.parse("CHK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/COPYING", null)
128 assertThat("Part Text", convertText(parts), equalTo("[CHK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/COPYING|CHK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/COPYING|COPYING]"))
132 fun `freenet link without meta strings and doc name gets first nine characters of key as name`() {
133 val parts = soneTextParser.parse("CHK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8", null)
134 assertThat("Part Text", convertText(parts), equalTo("[CHK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8|CHK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8|CHK@qM1nm]"))
138 fun `malformed key is rendered as plain text`() {
139 val parts = soneTextParser.parse("CHK@qM1nmgU", null)
140 assertThat("Part Text", convertText(parts), equalTo("CHK@qM1nmgU"))
144 fun `https link has its paths shortened`() {
145 val parts = soneTextParser.parse("https://test.test/some-long-path/file.txt", null)
146 assertThat("Part Text", convertText(parts), equalTo("[https://test.test/some-long-path/file.txt|https://test.test/some-long-path/file.txt|test.test/…/file.txt]"))
150 fun `http links have their last slash removed`() {
151 val parts = soneTextParser.parse("http://test.test/test/", null)
152 assertThat("Part Text", convertText(parts), equalTo("[http://test.test/test/|http://test.test/test/|test.test/…]"))
156 fun `www prefix is removed for hostname with two dots and no path`() {
157 val parts = soneTextParser.parse("http://www.test.test", null)
158 assertThat("Part Text", convertText(parts), equalTo("[http://www.test.test|http://www.test.test|test.test]"))
162 fun `www prefix is removed for hostname with two dots and a path`() {
163 val parts = soneTextParser.parse("http://www.test.test/test.html", null)
164 assertThat("Part Text", convertText(parts), equalTo("[http://www.test.test/test.html|http://www.test.test/test.html|test.test/test.html]"))
168 fun `hostname is kept intact if not beginning with www`() {
169 val parts = soneTextParser.parse("http://test.test.test/test.html", null)
170 assertThat("Part Text", convertText(parts), equalTo("[http://test.test.test/test.html|http://test.test.test/test.html|test.test.test/test.html]"))
174 fun `hostname with one dot but no slash is kept intact`() {
175 val parts = soneTextParser.parse("http://test.test", null)
176 assertThat("Part Text", convertText(parts), equalTo("[http://test.test|http://test.test|test.test]"))
180 fun `url parameters are removed for http links`() {
181 val parts = soneTextParser.parse("http://test.test?foo=bar", null)
182 assertThat("Part Text", convertText(parts), equalTo("[http://test.test?foo=bar|http://test.test?foo=bar|test.test]"))
186 fun `empty string is parsed correctly`() {
187 val parts = soneTextParser.parse("", null)
188 assertThat("Part Text", convertText(parts), equalTo(""))
192 fun `links are parsed in correct order`() {
193 val parts = soneTextParser.parse("KSK@ CHK@", null)
194 assertThat("Part Text", convertText(parts), equalTo("KSK@ CHK@"))
198 fun `invalid ssk and usk link is parsed as text`() {
199 val parts = soneTextParser.parse("SSK@a USK@a", null)
200 assertThat("Part Text", convertText(parts), equalTo("SSK@a USK@a"))
204 fun `ssk without document name is parsed correctly`() {
205 val parts = soneTextParser.parse(
206 "SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8", null)
207 assertThat("Part Text", convertText(parts),
208 equalTo("[SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8|"
209 + "SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8|"
210 + "SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU]"))
214 fun `ssk link without context is not trusted`() {
215 val parts = soneTextParser.parse("SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test", null)
216 assertThat("Part Text", convertText(parts), equalTo("[SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|test]"))
220 fun `ssk link with context without sone is not trusted`() {
221 val context = SoneTextParserContext(null)
222 val parts = soneTextParser.parse("SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test", context)
223 assertThat("Part Text", convertText(parts), equalTo("[SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|test]"))
227 fun `ssk link with context with different sone is not trusted`() {
228 val context = SoneTextParserContext(IdOnlySone("DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU"))
229 val parts = soneTextParser.parse("SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test", context)
230 assertThat("Part Text", convertText(parts), equalTo("[SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|test]"))
234 fun `ssk link with context with correct sone is trusted`() {
235 val context = SoneTextParserContext(IdOnlySone("qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU"))
236 val parts = soneTextParser.parse("SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test", context)
237 assertThat("Part Text", convertText(parts), equalTo("[SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|trusted|SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|test]"))
241 fun `usk link with context with correct sone is trusted`() {
242 val context = SoneTextParserContext(IdOnlySone("qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU"))
243 val parts = soneTextParser.parse("USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0", context)
244 assertThat("Part Text", convertText(parts), equalTo("[USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0|trusted|USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0|test]"))
248 fun `usk links with backlinks is parsed correctly`() {
249 val context = SoneTextParserContext(IdOnlySone("qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU"))
250 val parts = soneTextParser.parse("USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0/../../../USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/78/", context)
251 assertThat("Part Text", convertText(parts), equalTo("[USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0|trusted|USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0|test]"))
255 fun `broken usk links is parsed as plain text`() {
256 val context = SoneTextParserContext(IdOnlySone("qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU"))
257 val parts = soneTextParser.parse("USK@/someCrazyName.R1/0", context)
258 FreenetURI("USK@/someCrazyName.R1/0")
259 assertThat("Part Text", convertText(parts), equalTo("USK@/someCrazyName.R1/0"))
263 fun `test basic ksk links`() {
264 val parts: Iterable<Part> = soneTextParser.parse("KSK@gpl.txt", null)
265 assertThat("Part Text", convertText(parts, FreenetLinkPart::class.java), equalTo("[KSK@gpl.txt|KSK@gpl.txt|gpl.txt]"))
269 fun `embedded ksk links are parsed correctly`() {
270 val parts = soneTextParser.parse("Link is KSK@gpl.txt\u200b.", null)
271 assertThat("Part Text", convertText(parts, PlainTextPart::class.java, FreenetLinkPart::class.java), equalTo("Link is [KSK@gpl.txt|KSK@gpl.txt|gpl.txt]\u200b."))
275 fun `embedded ksk links and line breaks are parsed correctly`() {
276 val parts = soneTextParser.parse("Link is KSK@gpl.txt\nKSK@test.dat\n", null)
277 assertThat("Part Text", convertText(parts, PlainTextPart::class.java, FreenetLinkPart::class.java), equalTo("Link is [KSK@gpl.txt|KSK@gpl.txt|gpl.txt]\n[KSK@test.dat|KSK@test.dat|test.dat]"))
281 fun `ksk links with backlinks are parsed correctly`() {
282 val parts = soneTextParser.parse("KSK@gallery/../Sone/imageBrowser.html?album=30c930ee-97cd-11e9-bd44-f3e595768b77", null)
283 assertThat("Part Text", convertText(parts, FreenetLinkPart::class.java), equalTo("[KSK@gallery|KSK@gallery|gallery]"))
287 fun `test empty lines and sone links`() {
288 val soneTextParser = SoneTextParser(TestSoneProvider(), null)
290 /* check basic links. */
291 val parts = soneTextParser.parse("Some text.\n\nLink to sone://DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU and stuff.", null)
292 assertThat("Part Text", convertText(parts, PlainTextPart::class.java, SonePart::class.java), equalTo("Some text.\n\nLink to [Sone|DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU] and stuff."))
296 fun `test empy http links`() {
297 val soneTextParser = SoneTextParser(TestSoneProvider(), null)
299 /* check empty http links. */
300 val parts = soneTextParser.parse("Some text. Empty link: http:// – nice!", null)
301 assertThat("Part Text", convertText(parts, PlainTextPart::class.java), equalTo("Some text. Empty link: http:// – nice!"))
305 fun `http link without parens ends at next closing paren`() {
306 val parts = soneTextParser.parse("Some text (and a link: http://example.sone/abc) – nice!", null)
307 assertThat("Part Text", convertText(parts, PlainTextPart::class.java, LinkPart::class.java), equalTo("Some text (and a link: [http://example.sone/abc|http://example.sone/abc|example.sone/abc]) – nice!"))
311 fun `usk link ends at first non numeric non slash character after version number`() {
312 val parts = soneTextParser.parse("Some link (USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0). Nice", null)
313 assertThat("Part Text", convertText(parts), equalTo("Some link ([USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0|USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0|test]). Nice"))
317 fun `usk link with filename shows the filename`() {
318 val parts = soneTextParser.parse("Some link (USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0/images/image.jpg). Nice", null)
319 assertThat("Part Text", convertText(parts), equalTo("Some link ([USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0/images/image.jpg|USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0/images/image.jpg|image.jpg]). Nice"))
323 fun `usk link without filename but ending in slash shows the path`() {
324 val parts = soneTextParser.parse("Some link (USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0/). Nice", null)
325 assertThat("Part Text", convertText(parts), equalTo("Some link ([USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0|USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0|test]). Nice"))
329 fun `http link with opened and closed parens ends at next closing paren`() {
330 val parts = soneTextParser.parse("Some text (and a link: http://example.sone/abc_(def)) – nice!", null)
331 assertThat("Part Text", convertText(parts, PlainTextPart::class.java, LinkPart::class.java), equalTo("Some text (and a link: [http://example.sone/abc_(def)|http://example.sone/abc_(def)|example.sone/abc_(def)]) – nice!"))
335 fun `punctuation is ignored at end of link before whitespace`() {
336 val parts = soneTextParser.parse("Some text and a link: http://example.sone/abc. Nice!", null)
337 assertThat("Part Text", convertText(parts, PlainTextPart::class.java, LinkPart::class.java), equalTo("Some text and a link: [http://example.sone/abc|http://example.sone/abc|example.sone/abc]. Nice!"))
341 fun `multiple punctuation characters are ignored at end of link before whitespace`() {
342 val parts = soneTextParser.parse("Some text and a link: http://example.sone/abc... Nice!", null)
343 assertThat("Part Text", convertText(parts, PlainTextPart::class.java, LinkPart::class.java), equalTo("Some text and a link: [http://example.sone/abc|http://example.sone/abc|example.sone/abc]... Nice!"))
347 fun `commas are ignored at end of link before whitespace`() {
348 val parts = soneTextParser.parse("Some text and a link: http://example.sone/abc, nice!", null)
349 assertThat("Part Text", convertText(parts, PlainTextPart::class.java, LinkPart::class.java), equalTo("Some text and a link: [http://example.sone/abc|http://example.sone/abc|example.sone/abc], nice!"))
353 fun `exclamation marks are ignored at end of link before whitespace`() {
354 val parts = soneTextParser.parse("A link: http://example.sone/abc!", null)
355 assertThat("Part Text", convertText(parts, PlainTextPart::class.java, LinkPart::class.java), equalTo("A link: [http://example.sone/abc|http://example.sone/abc|example.sone/abc]!"))
359 fun `question marks are ignored at end of link before whitespace`() {
360 val parts = soneTextParser.parse("A link: http://example.sone/abc?", null)
361 assertThat("Part Text", convertText(parts, PlainTextPart::class.java, LinkPart::class.java), equalTo("A link: [http://example.sone/abc|http://example.sone/abc|example.sone/abc]?"))
365 fun `correct freemail address is linked to correctly`() {
366 val parts = soneTextParser.parse("Mail me at sone@t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra.freemail!", null)
367 assertThat("Part Text", convertText(parts), equalTo("Mail me at [Freemail|sone|t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra|nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI]!"))
371 fun `freemail address with invalid freemail id is parsed as text`() {
372 val parts = soneTextParser.parse("Mail me at sone@t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqr8.freemail!", null)
373 assertThat("Part Text", convertText(parts), equalTo("Mail me at sone@t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqr8.freemail!"))
377 fun `freemail address with invalid sized freemail id is parsed as text`() {
378 val parts = soneTextParser.parse("Mail me at sone@4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra.freemail!", null)
379 assertThat("Part Text", convertText(parts), equalTo("Mail me at sone@4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra.freemail!"))
383 fun `freemail address without local part is parsed as text`() {
384 val parts = soneTextParser.parse(" @t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra.freemail!", null)
385 assertThat("Part Text", convertText(parts), equalTo(" @t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra.freemail!"))
389 fun `local part of freemail address can contain letters digits minus dot underscore`() {
390 val parts = soneTextParser.parse("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._@t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra.freemail", null)
391 assertThat("Part Text", convertText(parts), equalTo("[Freemail|ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._|t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra|nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI]"))
394 private fun convertText(parts: Iterable<Part>, vararg validClasses: Class<*>): String {
395 if (validClasses.isNotEmpty()) {
396 assertThat(parts.map { it.javaClass }.distinct() - validClasses.distinct(), empty())
398 return parts.joinToString("") { part ->
400 is PlainTextPart -> part.text
401 is FreenetLinkPart -> "[${part.link}|${if (part.trusted) "trusted|" else ""}${part.title}|${part.text}]"
402 is FreemailPart -> "[Freemail|${part.emailLocalPart}|${part.freemailId}|${part.identityId}]"
403 is LinkPart -> "[${part.link}|${part.title}|${part.text}]"
404 is SonePart -> "[Sone|${part.sone.id}]"
405 is PostPart -> "[Post|${part.post.id}|${part.post.text}]"
406 else -> throw NoSuchElementException()
412 fun `parser can be created by guice`() {
413 val injector = createInjector(
414 SoneProvider::class.isProvidedByMock(),
415 PostProvider::class.isProvidedByMock()
417 assertThat(injector.getInstance<SoneTextParser>(), notNullValue())
421 * Mock Sone provider.
423 private open class TestSoneProvider : SoneProvider {
425 override val soneLoader = this::getSone
426 override val sones: Collection<Sone> = emptySet()
427 override val localSones: Collection<Sone> = emptySet()
428 override val remoteSones: Collection<Sone> = emptySet()
430 override fun getSone(soneId: String): Sone? = IdOnlySone(soneId)
434 private class AbsentSoneProvider : TestSoneProvider() {
436 override fun getSone(soneId: String): Sone? = null
440 private open class TestPostProvider : PostProvider {
442 override fun getPost(postId: String): Post? {
443 return object : Post {
444 override val id = postId
445 override fun isLoaded() = false
446 override fun getSone() = null
447 override fun getRecipientId() = null
448 override fun getRecipient() = null
449 override fun getTime() = 0L
450 override fun getText() = "text"
451 override fun isKnown() = false
452 override fun setKnown(known: Boolean) = null
456 override fun getPosts(soneId: String) = emptySet<Post>()
457 override fun getDirectedPosts(recipientId: String) = emptySet<Post>()
461 private class AbsentPostProvider : TestPostProvider() {
463 override fun getPost(postId: String): Post? = null