From: David ‘Bombe’ Roden Date: Fri, 11 Nov 2016 14:02:24 +0000 (+0100) Subject: Add filter that shortens a number of parts X-Git-Tag: 0.9.7^2~446 X-Git-Url: https://git.pterodactylus.net/?p=Sone.git;a=commitdiff_plain;h=b86b2cbef3b08619f99fb7aa68aaf55fab7bfcd2 Add filter that shortens a number of parts --- diff --git a/src/main/kotlin/net/pterodactylus/sone/template/ShortenFilter.kt b/src/main/kotlin/net/pterodactylus/sone/template/ShortenFilter.kt new file mode 100644 index 0000000..de7a930 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/template/ShortenFilter.kt @@ -0,0 +1,54 @@ +package net.pterodactylus.sone.template + +import net.pterodactylus.sone.text.LinkPart +import net.pterodactylus.sone.text.Part +import net.pterodactylus.sone.text.PlainTextPart +import net.pterodactylus.util.template.Filter +import net.pterodactylus.util.template.TemplateContext +import java.util.* + +/** + * [Filter] that shortens a number of [Part]s in order to restrict the maximum visible text length. + */ +class ShortenFilter : Filter { + + override fun format(templateContext: TemplateContext?, data: Any?, parameters: Map?): Any? { + @Suppress("UNCHECKED_CAST") + val parts = data as? Iterable ?: return null + val length = parameters?.parseInt("length") ?: -1 + val cutOffLength = parameters?.parseInt("cut-off-length") ?: length + if (length > -1) { + var allPartsLength = 0 + val shortenedParts = ArrayList() + for (part in parts) { + if (part is PlainTextPart) { + val longText = part.text + if (allPartsLength < cutOffLength) { + if (allPartsLength + longText.length > cutOffLength) { + shortenedParts.add(PlainTextPart(longText.substring(0, cutOffLength - allPartsLength) + "…")) + } else { + shortenedParts.add(part) + } + } + allPartsLength += longText.length + } else if (part is LinkPart) { + if (allPartsLength < cutOffLength) { + shortenedParts.add(part) + } + allPartsLength += part.text.length + } else { + if (allPartsLength < cutOffLength) { + shortenedParts.add(part) + } + } + } + if (allPartsLength > length) { + return shortenedParts + } + } + return parts + } + + private fun Map.parseInt(key: String) = this[key]?.toString()?.toInt() + +} diff --git a/src/test/kotlin/net/pterodactylus/sone/template/ShortenFilterTest.kt b/src/test/kotlin/net/pterodactylus/sone/template/ShortenFilterTest.kt new file mode 100644 index 0000000..c6990a7 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/template/ShortenFilterTest.kt @@ -0,0 +1,96 @@ +package net.pterodactylus.sone.template + +import net.pterodactylus.sone.data.Profile +import net.pterodactylus.sone.data.Sone +import net.pterodactylus.sone.test.mock +import net.pterodactylus.sone.text.FreenetLinkPart +import net.pterodactylus.sone.text.Part +import net.pterodactylus.sone.text.PlainTextPart +import net.pterodactylus.sone.text.SonePart +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.contains +import org.junit.Test +import org.mockito.Mockito.`when` + +/** + * Unit test for [ShortenFilter]. + */ +class ShortenFilterTest { + + private val filter = ShortenFilter() + + @Suppress("UNCHECKED_CAST") + private fun shortenParts(length: Int, cutOffLength: Int, vararg parts: Part) = + filter.format(null, listOf(*parts), mapOf("cut-off-length" to cutOffLength, "length" to length)) as Iterable + + @Test + fun `plain text part is shortened if length exceeds maxl ength`() { + assertThat(shortenParts(15, 10, PlainTextPart("This is a long text.")), contains( + PlainTextPart("This is a …") + )) + } + + @Test + fun `plain text part is not shortened if length does not exceed max length`() { + assertThat(shortenParts(20, 10, PlainTextPart("This is a long text.")), contains( + PlainTextPart("This is a long text.") + )) + } + + @Test + fun `short parts are not shortened`() { + assertThat(shortenParts(15, 10, PlainTextPart("This.")), contains( + PlainTextPart("This.") + )) + } + + @Test + fun `multiple plain text parts are shortened`() { + assertThat(shortenParts(15, 10, PlainTextPart("This "), PlainTextPart("is a long text.")), contains( + PlainTextPart("This "), + PlainTextPart("is a …") + )) + } + + @Test + fun `parts after length has been reached are ignored`() { + assertThat(shortenParts(15, 10, PlainTextPart("This is a long text."), PlainTextPart(" And even more.")), contains( + PlainTextPart("This is a …") + )) + } + + @Test + fun `link parts are not shortened`() { + assertThat(shortenParts(15, 10, FreenetLinkPart("KSK@gpl.txt", "This is a long text.", false)), contains( + FreenetLinkPart("KSK@gpl.txt", "This is a long text.", false) + )) + } + + @Test + fun `additional link parts are ignored`() { + assertThat(shortenParts(15, 10, PlainTextPart("This is a long text."), FreenetLinkPart("KSK@gpl.txt", "This is a long text.", false)), contains( + PlainTextPart("This is a …") + )) + } + + @Test + fun `sone parts are added but their length is ignored`() { + val sone = mock() + `when`(sone.profile).thenReturn(Profile(sone)) + assertThat(shortenParts(15, 10, SonePart(sone), PlainTextPart("This is a long text.")), contains( + SonePart(sone), + PlainTextPart("This is a …") + )) + } + + @Test + fun `additional sone parts are ignored`() { + val sone = mock() + `when`(sone.profile).thenReturn(Profile(sone)) + assertThat(shortenParts(15, 10, PlainTextPart("This is a long text."), SonePart(sone)), contains( + PlainTextPart("This is a …") + )) + } + +} +