From 7abc17c77a9ab34855f6088c4a71973e62a05d67 Mon Sep 17 00:00:00 2001 From: cketti Date: Sun, 28 Jan 2018 05:59:41 +0100 Subject: [PATCH] Rewrite text to HTML conversion --- .../fsck/k9/message/html/DividerReplacer.kt | 27 ++ .../fsck/k9/message/html/EmailTextToHtml.kt | 68 +++++ .../fsck/k9/message/html/HtmlConverter.java | 265 +----------------- .../fsck/k9/message/html/HtmlModification.kt | 12 + .../com/fsck/k9/message/html/TextToHtml.kt | 83 ++++++ .../com/fsck/k9/message/html/UriLinkifier.kt | 42 ++- .../com/fsck/k9/message/html/UriMatcher.kt | 3 +- .../MessageViewInfoExtractorTest.java | 6 +- .../k9/message/html/HtmlConverterTest.java | 88 +++--- .../k9/message/html/UriLinkifierTest.java | 148 ---------- .../k9/message/html/UriParserTestHelper.java | 38 --- 11 files changed, 257 insertions(+), 523 deletions(-) create mode 100644 k9mail/src/main/java/com/fsck/k9/message/html/DividerReplacer.kt create mode 100644 k9mail/src/main/java/com/fsck/k9/message/html/EmailTextToHtml.kt create mode 100644 k9mail/src/main/java/com/fsck/k9/message/html/HtmlModification.kt create mode 100644 k9mail/src/main/java/com/fsck/k9/message/html/TextToHtml.kt delete mode 100644 k9mail/src/test/java/com/fsck/k9/message/html/UriLinkifierTest.java delete mode 100644 k9mail/src/test/java/com/fsck/k9/message/html/UriParserTestHelper.java diff --git a/k9mail/src/main/java/com/fsck/k9/message/html/DividerReplacer.kt b/k9mail/src/main/java/com/fsck/k9/message/html/DividerReplacer.kt new file mode 100644 index 000000000..6eb0b925e --- /dev/null +++ b/k9mail/src/main/java/com/fsck/k9/message/html/DividerReplacer.kt @@ -0,0 +1,27 @@ +package com.fsck.k9.message.html + +internal object DividerReplacer : TextToHtml.HtmlModifier { + private const val SIMPLE_DIVIDER = "[-=_]{3,}" + private const val ASCII_SCISSORS = "(?:-{2,}\\s?(?:>[%8]|[%8]<)\\s?-{2,})+" + private val PATTERN = Regex("(?:^|\\n)" + + "(?:" + + "\\s*" + + "(?:" + SIMPLE_DIVIDER + "|" + ASCII_SCISSORS + ")" + + "\\s*" + + "(?:\\n|$)" + + ")+") + + + override fun findModifications(text: CharSequence): List { + return PATTERN.findAll(text).map { matchResult -> + Divider(matchResult.range.start, matchResult.range.endInclusive + 1) + }.toList() + } + + + class Divider(startIndex: Int, endIndex: Int) : HtmlModification.Replace(startIndex, endIndex) { + override fun replace(textToHtml: TextToHtml) { + textToHtml.appendHtml("
") + } + } +} diff --git a/k9mail/src/main/java/com/fsck/k9/message/html/EmailTextToHtml.kt b/k9mail/src/main/java/com/fsck/k9/message/html/EmailTextToHtml.kt new file mode 100644 index 000000000..bca3b7105 --- /dev/null +++ b/k9mail/src/main/java/com/fsck/k9/message/html/EmailTextToHtml.kt @@ -0,0 +1,68 @@ +package com.fsck.k9.message.html + +class EmailTextToHtml private constructor(private val text: String) { + private val html = StringBuilder(text.length + EXTRA_BUFFER_LENGTH) + private var previousQuoteDepth = 0 + + fun convert(): String { + appendHtmlPrefix() + + val sections = EmailSectionExtractor.extract(text) + sections.forEach { section -> + appendBlockQuoteElement(section.quoteDepth) + + TextToHtml.appendAsHtmlFragment(html, section) + } + + appendBlockQuoteElement(quoteDepth = 0) + + appendHtmlSuffix() + + return html.toString() + } + + private fun appendHtmlPrefix() { + html.append("
")
+    }
+
+    private fun appendHtmlSuffix() {
+        html.append("
") + } + + private fun appendBlockQuoteElement(quoteDepth: Int) { + if (previousQuoteDepth > quoteDepth) { + repeat(previousQuoteDepth - quoteDepth) { + html.append("") + } + } else if (quoteDepth > previousQuoteDepth) { + for (depth in (previousQuoteDepth + 1)..quoteDepth) { + html.append("
") + } + } + previousQuoteDepth = quoteDepth + } + + private fun quoteColor(depth: Int): String = when (depth) { + 1 -> "#729fcf" + 2 -> "#ad7fa8" + 3 -> "#8ae234" + 4 -> "#fcaf3e" + 5 -> "#e9b96e" + else -> "#ccc" + } + + + companion object { + private const val EXTRA_BUFFER_LENGTH = 2048 + const val K9MAIL_CSS_CLASS = "k9mail" + + @JvmStatic + fun convert(text: String): String { + return EmailTextToHtml(text).convert() + } + } +} diff --git a/k9mail/src/main/java/com/fsck/k9/message/html/HtmlConverter.java b/k9mail/src/main/java/com/fsck/k9/message/html/HtmlConverter.java index a9e22337e..4334fd9a4 100644 --- a/k9mail/src/main/java/com/fsck/k9/message/html/HtmlConverter.java +++ b/k9mail/src/main/java/com/fsck/k9/message/html/HtmlConverter.java @@ -5,7 +5,6 @@ import java.util.Collections; import java.util.HashSet; import java.util.Locale; import java.util.Set; -import java.util.regex.Pattern; import android.text.Annotation; import android.text.Editable; @@ -13,7 +12,6 @@ import android.text.Html; import android.text.Html.TagHandler; import android.text.Spannable; import android.text.Spanned; -import android.text.TextUtils; import com.fsck.k9.K9; import org.xml.sax.XMLReader; @@ -37,8 +35,6 @@ public class HtmlConverter { private static final char NBSP_CHARACTER = (char)0x00a0; // utf-8 non-breaking space private static final char NBSP_REPLACEMENT = (char)0x20; // space - // Number of extra bytes to allocate in a string buffer for htmlification. - private static final int TEXT_TO_HTML_EXTRA_BUFFER_LENGTH = 512; /** * Convert an HTML string to a plain text string. @@ -128,254 +124,16 @@ public class HtmlConverter { } } - private static final int MAX_SMART_HTMLIFY_MESSAGE_LENGTH = 1024 * 256 ; - - /** - * Naively convert a text string into an HTML document. - * - *

- * This method avoids using regular expressions on the entire message body to save memory. - *

- *

- * No HTML headers or footers are added to the result. Headers and footers - * are added at display time in - * {@link com.fsck.k9.view#MessageWebView.setText(String) MessageWebView.setText()} - *

- * - * @param text - * Plain text string. - * @return HTML string. - */ - private static String simpleTextToHtml(String text) { - // Encode HTML entities to make sure we don't display something evil. - text = TextUtils.htmlEncode(text); - - StringBuilder buff = new StringBuilder(text.length() + TEXT_TO_HTML_EXTRA_BUFFER_LENGTH); - - buff.append(htmlifyMessageHeader()); - - for (int index = 0; index < text.length(); index++) { - char c = text.charAt(index); - switch (c) { - case '\n': - // pine treats
as two newlines, but
as one newline. Use
so our messages aren't - // doublespaced. - buff.append("
"); - break; - case '\r': - break; - default: - buff.append(c); - }//switch - } - - buff.append(htmlifyMessageFooter()); - - return buff.toString(); - } - - private static final String HTML_BLOCKQUOTE_COLOR_TOKEN = "$$COLOR$$"; - private static final String HTML_BLOCKQUOTE_START = "
"; - private static final String HTML_BLOCKQUOTE_END = "
"; - private static final String HTML_NEWLINE = "
"; - private static final Pattern ASCII_PATTERN_FOR_HR = Pattern.compile( - "(^|\\Q" + HTML_NEWLINE + "\\E)\\s*((\\Q" + HTML_NEWLINE + "\\E)*" + - "((((\\Q" + HTML_NEWLINE + "\\E){0,2}([-=_]{3,})(\\Q" + HTML_NEWLINE + - "\\E){0,2})|(([-=_]{2,} ?)(8<|8|%<|%)" + - "( ?[-=_]{2,})))+(\\Q" + HTML_NEWLINE + "\\E|$)))"); - /** * Convert a text string into an HTML document. * *

- * Attempts to do smart replacement for large documents to prevent OOM - * errors. - *

* No HTML headers or footers are added to the result. Headers and footers - * are added at display time in - * {@link com.fsck.k9.view#MessageWebView.setText(String) MessageWebView.setText()} + * are added at display time. *

- *

- * To convert to a fragment, use {@link #textToHtmlFragment(String)} . - *

- * - * @param text - * Plain text string. - * @return HTML string. */ public static String textToHtml(String text) { - // Our HTMLification code is somewhat memory intensive - // and was causing lots of OOM errors on the market - // if the message is big and plain text, just do - // a trivial htmlification - if (text.length() > MAX_SMART_HTMLIFY_MESSAGE_LENGTH) { - return simpleTextToHtml(text); - } - StringBuilder buff = new StringBuilder(text.length() + TEXT_TO_HTML_EXTRA_BUFFER_LENGTH); - boolean isStartOfLine = true; // Are we currently at the start of a line? - int spaces = 0; - int quoteDepth = 0; // Number of DIVs deep we are. - int quotesThisLine = 0; // How deep we should be quoting for this line. - for (int index = 0; index < text.length(); index++) { - char c = text.charAt(index); - if (isStartOfLine) { - switch (c) { - case ' ': - spaces++; - break; - case '>': - quotesThisLine++; - spaces = 0; - break; - case '\n': - appendbq(buff, quotesThisLine, quoteDepth); - quoteDepth = quotesThisLine; - - appendsp(buff, spaces); - spaces = 0; - - appendchar(buff, c); - isStartOfLine = true; - quotesThisLine = 0; - break; - default: - isStartOfLine = false; - - appendbq(buff, quotesThisLine, quoteDepth); - quoteDepth = quotesThisLine; - - appendsp(buff, spaces); - spaces = 0; - - appendchar(buff, c); - isStartOfLine = false; - break; - } - } - else { - appendchar(buff, c); - if (c == '\n') { - isStartOfLine = true; - quotesThisLine = 0; - } - } - } - // Close off any quotes we may have opened. - if (quoteDepth > 0) { - for (int i = quoteDepth; i > 0; i--) { - buff.append(HTML_BLOCKQUOTE_END); - } - } - text = buff.toString(); - - // Make newlines at the end of blockquotes nicer by putting newlines beyond the first one outside of the - // blockquote. - text = text.replaceAll( - "\\Q" + HTML_NEWLINE + "\\E((\\Q" + HTML_NEWLINE + "\\E)+?)\\Q" + HTML_BLOCKQUOTE_END + "\\E", - HTML_BLOCKQUOTE_END + "$1" - ); - - text = ASCII_PATTERN_FOR_HR.matcher(text).replaceAll("
"); - - StringBuffer sb = new StringBuffer(text.length() + TEXT_TO_HTML_EXTRA_BUFFER_LENGTH); - - sb.append(htmlifyMessageHeader()); - UriLinkifier.linkifyText(text, sb); - sb.append(htmlifyMessageFooter()); - - text = sb.toString(); - - // Above we replaced > with , now make it > - text = text.replaceAll("", ">"); - - return text; - } - - private static void appendchar(StringBuilder buff, int c) { - switch (c) { - case '&': - buff.append("&"); - break; - case '<': - buff.append("<"); - break; - case '>': - // We use a token here which can't occur in htmlified text because > is valid - // within links (where > is not), and linkifying links will include it if we - // do it here. We'll make another pass and change this back to > after - // the linkification is done. - buff.append(""); - break; - case '\r': - break; - case '\n': - // pine treats
as two newlines, but
as one newline. Use
so our messages aren't - // doublespaced. - buff.append(HTML_NEWLINE); - break; - default: - buff.append((char)c); - break; - } - } - - private static void appendsp(StringBuilder buff, int spaces) { - while (spaces > 0) { - buff.append(' '); - spaces--; - } - } - - private static void appendbq(StringBuilder buff, int quotesThisLine, int quoteDepth) { - // Add/remove blockquotes by comparing this line's quotes to the previous line's quotes. - if (quotesThisLine > quoteDepth) { - for (int i = quoteDepth; i < quotesThisLine; i++) { - buff.append(HTML_BLOCKQUOTE_START.replace(HTML_BLOCKQUOTE_COLOR_TOKEN, getQuoteColor(i + 1))); - } - } else if (quotesThisLine < quoteDepth) { - for (int i = quoteDepth; i > quotesThisLine; i--) { - buff.append(HTML_BLOCKQUOTE_END); - } - } - } - - protected static final String QUOTE_COLOR_DEFAULT = "#ccc"; - protected static final String QUOTE_COLOR_LEVEL_1 = "#729fcf"; - protected static final String QUOTE_COLOR_LEVEL_2 = "#ad7fa8"; - protected static final String QUOTE_COLOR_LEVEL_3 = "#8ae234"; - protected static final String QUOTE_COLOR_LEVEL_4 = "#fcaf3e"; - protected static final String QUOTE_COLOR_LEVEL_5 = "#e9b96e"; - private static final String K9MAIL_CSS_CLASS = "k9mail"; - - /** - * Return an HTML hex color string for a given quote level. - * @param level Quote level - * @return Hex color string with prepended #. - */ - protected static String getQuoteColor(final int level) { - switch(level) { - case 1: - return QUOTE_COLOR_LEVEL_1; - case 2: - return QUOTE_COLOR_LEVEL_2; - case 3: - return QUOTE_COLOR_LEVEL_3; - case 4: - return QUOTE_COLOR_LEVEL_4; - case 5: - return QUOTE_COLOR_LEVEL_5; - default: - return QUOTE_COLOR_DEFAULT; - } - } - - private static String htmlifyMessageHeader() { - return "
";
-    }
-
-    private static String htmlifyMessageFooter() {
-        return "
"; + return EmailTextToHtml.convert(text); } public static String wrapStatusMessage(CharSequence status) { @@ -419,29 +177,16 @@ public class HtmlConverter { final String font = K9.messageViewFixedWidthFont() ? "monospace" : "sans-serif"; - return ""; } /** * Convert a plain text string into an HTML fragment. - * @param text Plain text. - * @return HTML fragment. */ - public static String textToHtmlFragment(final String text) { - // Escape the entities and add newlines. - String htmlified = TextUtils.htmlEncode(text); - - // Linkify the message. - StringBuffer linkified = new StringBuffer(htmlified.length() + TEXT_TO_HTML_EXTRA_BUFFER_LENGTH); - UriLinkifier.linkifyText(htmlified, linkified); - - // Add newlines and unescaping. - // - // For some reason, TextUtils.htmlEncode escapes ' into ', which is technically part of the XHTML 1.0 - // standard, but Gmail doesn't recognize it as an HTML entity. We unescape that here. - return linkified.toString().replaceAll("\r?\n", "
\r\n").replace("'", "'"); + public static String textToHtmlFragment(String text) { + return TextToHtml.toHtmlFragment(text); } /** diff --git a/k9mail/src/main/java/com/fsck/k9/message/html/HtmlModification.kt b/k9mail/src/main/java/com/fsck/k9/message/html/HtmlModification.kt new file mode 100644 index 000000000..4494f7181 --- /dev/null +++ b/k9mail/src/main/java/com/fsck/k9/message/html/HtmlModification.kt @@ -0,0 +1,12 @@ +package com.fsck.k9.message.html + +internal abstract class HtmlModification private constructor(val startIndex: Int, val endIndex: Int) { + abstract class Wrap(startIndex: Int, endIndex: Int) : HtmlModification(startIndex, endIndex) { + abstract fun appendPrefix(textToHtml: TextToHtml) + abstract fun appendSuffix(textToHtml: TextToHtml) + } + + abstract class Replace(startIndex: Int, endIndex: Int) : HtmlModification(startIndex, endIndex) { + abstract fun replace(textToHtml: TextToHtml) + } +} diff --git a/k9mail/src/main/java/com/fsck/k9/message/html/TextToHtml.kt b/k9mail/src/main/java/com/fsck/k9/message/html/TextToHtml.kt new file mode 100644 index 000000000..8ca04b3b5 --- /dev/null +++ b/k9mail/src/main/java/com/fsck/k9/message/html/TextToHtml.kt @@ -0,0 +1,83 @@ +package com.fsck.k9.message.html + +class TextToHtml private constructor(private val text: CharSequence, private val html: StringBuilder) { + fun appendAsHtmlFragment() { + val modifications = HTML_MODIFIERS + .flatMap { it.findModifications(text) } + .sortedBy { it.startIndex } + + var currentIndex = 0 + modifications.forEach { modification -> + appendHtmlEncoded(currentIndex, modification.startIndex) + + when (modification) { + is HtmlModification.Wrap -> { + modification.appendPrefix(this) + appendHtmlEncoded(modification.startIndex, modification.endIndex) + modification.appendSuffix(this) + } + is HtmlModification.Replace -> { + modification.replace(this) + } + } + + currentIndex = modification.endIndex + } + + appendHtmlEncoded(currentIndex, text.length) + } + + private fun appendHtmlEncoded(startIndex: Int, endIndex: Int) { + for (i in startIndex until endIndex) { + appendHtmlEncoded(text[i]) + } + } + + internal fun appendHtml(text: String) { + html.append(text) + } + + internal fun appendHtmlEncoded(ch: Char) { + when (ch) { + '&' -> html.append("&") + '<' -> html.append("<") + '>' -> html.append(">") + '\r' -> Unit + '\n' -> html.append(TextToHtml.HTML_NEWLINE) + else -> html.append(ch) + } + } + + internal fun appendHtmlAttributeEncoded(attributeValue: CharSequence) { + for (ch in attributeValue) { + when (ch) { + '&' -> html.append("&") + '<' -> html.append("<") + '"' -> html.append(""") + else -> html.append(ch) + } + } + } + + companion object { + private val HTML_MODIFIERS = listOf(DividerReplacer, UriLinkifier) + private const val HTML_NEWLINE = "
" + private const val TEXT_TO_HTML_EXTRA_BUFFER_LENGTH = 512 + + @JvmStatic + fun appendAsHtmlFragment(html: StringBuilder, text: CharSequence) { + TextToHtml(text, html).appendAsHtmlFragment() + } + + @JvmStatic + fun toHtmlFragment(text: CharSequence): String { + val html = StringBuilder(text.length + TEXT_TO_HTML_EXTRA_BUFFER_LENGTH) + TextToHtml(text, html).appendAsHtmlFragment() + return html.toString() + } + } + + internal interface HtmlModifier { + fun findModifications(text: CharSequence): List + } +} diff --git a/k9mail/src/main/java/com/fsck/k9/message/html/UriLinkifier.kt b/k9mail/src/main/java/com/fsck/k9/message/html/UriLinkifier.kt index 6a78f0b05..e97a9099b 100644 --- a/k9mail/src/main/java/com/fsck/k9/message/html/UriLinkifier.kt +++ b/k9mail/src/main/java/com/fsck/k9/message/html/UriLinkifier.kt @@ -1,31 +1,27 @@ package com.fsck.k9.message.html - -@Deprecated("Helper to be able to transition to the new text to HTML conversion in smaller steps") -object UriLinkifier { - @JvmStatic - fun linkifyText(text: String, html: StringBuffer) { - val uriMatches = UriMatcher.findUris(text) - - var currentIndex = 0 - uriMatches.forEach { uriMatch -> - append(html, text, currentIndex, uriMatch.startIndex) - - html.append("") - html.append(uriMatch.uri) - html.append("") - - currentIndex = uriMatch.endIndex +internal object UriLinkifier : TextToHtml.HtmlModifier { + override fun findModifications(text: CharSequence): List { + return UriMatcher.findUris(text).map { + LinkifyUri(it.startIndex, it.endIndex, it.uri) } - - append(html, text, currentIndex, text.length) } - private fun append(html: StringBuffer, text: String, startIndex: Int, endIndex: Int) { - for (i in startIndex until endIndex) { - html.append(text[i]) + + class LinkifyUri( + startIndex: Int, + endIndex: Int, + val uri: CharSequence + ) : HtmlModification.Wrap(startIndex, endIndex) { + + override fun appendPrefix(textToHtml: TextToHtml) { + textToHtml.appendHtml("") + } + + override fun appendSuffix(textToHtml: TextToHtml) { + textToHtml.appendHtml("") } } } diff --git a/k9mail/src/main/java/com/fsck/k9/message/html/UriMatcher.kt b/k9mail/src/main/java/com/fsck/k9/message/html/UriMatcher.kt index ba447f2af..711760622 100644 --- a/k9mail/src/main/java/com/fsck/k9/message/html/UriMatcher.kt +++ b/k9mail/src/main/java/com/fsck/k9/message/html/UriMatcher.kt @@ -13,8 +13,7 @@ object UriMatcher { ) }.invoke(HttpUriParser()) - // FIXME: Remove > once the text to HTML code has been replaced - private const val SCHEME_SEPARATORS = " (\\n<>" + private const val SCHEME_SEPARATORS = " (\\n<" private const val ALLOWED_SEPARATORS_PATTERN = "(?:^|[$SCHEME_SEPARATORS])" private val URI_SCHEME = Regex( "$ALLOWED_SEPARATORS_PATTERN(${ SUPPORTED_URIS.keys.joinToString("|") })", diff --git a/k9mail/src/test/java/com/fsck/k9/mailstore/MessageViewInfoExtractorTest.java b/k9mail/src/test/java/com/fsck/k9/mailstore/MessageViewInfoExtractorTest.java index eae6f7aca..36cc80fc1 100644 --- a/k9mail/src/test/java/com/fsck/k9/mailstore/MessageViewInfoExtractorTest.java +++ b/k9mail/src/test/java/com/fsck/k9/mailstore/MessageViewInfoExtractorTest.java @@ -151,7 +151,7 @@ public class MessageViewInfoExtractorTest { "not flowed line"; String expectedHtml = "
" +
-                        "K-9 Mail rocks :> flowed line
not flowed line" + + "K-9 Mail rocks :> flowed line
not flowed line" + "
"; assertEquals(expectedText, container.text); @@ -353,12 +353,12 @@ public class MessageViewInfoExtractorTest { String expectedHtmlText = "" + "" + "
Subject:(No subject)
" + - "
text body of first message
" + + "
text body of first message
" + "

" + "" + "" + "
Subject:subject of second message
" + - "
text part of second message
"; + "
text part of second message
"; assertEquals(4, outputViewableParts.size()); diff --git a/k9mail/src/test/java/com/fsck/k9/message/html/HtmlConverterTest.java b/k9mail/src/test/java/com/fsck/k9/message/html/HtmlConverterTest.java index 238afa27e..bddb8ce26 100644 --- a/k9mail/src/test/java/com/fsck/k9/message/html/HtmlConverterTest.java +++ b/k9mail/src/test/java/com/fsck/k9/message/html/HtmlConverterTest.java @@ -55,27 +55,27 @@ public class HtmlConverterTest { String result = HtmlConverter.textToHtml(message); writeToFile(result); assertEquals("
"
-                + "Panama!
" - + "
" - + "Bob Barker <bob@aol.com> wrote:
" + + "Panama!
" + + "
" + + "Bob Barker <bob@aol.com> wrote:
" + "
" - + " a canal
" - + "
" - + " Dorothy Jo Gideon <dorothy@aol.com> espoused:
" + + " a canal
" + + "
" + + " Dorothy Jo Gideon <dorothy@aol.com> espoused:
" + "
" - + "A man, a plan...
" + + "A man, a plan...
" + "
" - + " Too easy!
" + + "Too easy!
" + "
" - + "
" - + "Nice job :)
" + + "
" + + "Nice job :)
" + "
" + "
" - + " Guess!" + + "Guess!" + "
" + "
" + "
", result); @@ -94,14 +94,14 @@ public class HtmlConverterTest { String result = HtmlConverter.textToHtml(message); writeToFile(result); assertEquals("
"
-                + "*facepalm*
" - + "
" - + "Bob Barker <bob@aol.com> wrote:
" + + "*facepalm*
" + + "
" + + "Bob Barker <bob@aol.com> wrote:
" + "
" - + " A wise man once said...
" - + "
" - + " LOL F1RST!!!!!
" - + "
" + + " A wise man once said...
" + + "
" + + " LOL F1RST!!!!!
" + + "
" + " :)" + "
", result); @@ -109,16 +109,6 @@ public class HtmlConverterTest { @Test public void testQuoteDepthColor() { - assertEquals(HtmlConverter.getQuoteColor(1), HtmlConverter.QUOTE_COLOR_LEVEL_1); - assertEquals(HtmlConverter.getQuoteColor(2), HtmlConverter.QUOTE_COLOR_LEVEL_2); - assertEquals(HtmlConverter.getQuoteColor(3), HtmlConverter.QUOTE_COLOR_LEVEL_3); - assertEquals(HtmlConverter.getQuoteColor(4), HtmlConverter.QUOTE_COLOR_LEVEL_4); - assertEquals(HtmlConverter.getQuoteColor(5), HtmlConverter.QUOTE_COLOR_LEVEL_5); - - assertEquals(HtmlConverter.getQuoteColor(-1), HtmlConverter.QUOTE_COLOR_DEFAULT); - assertEquals(HtmlConverter.getQuoteColor(0), HtmlConverter.QUOTE_COLOR_DEFAULT); - assertEquals(HtmlConverter.getQuoteColor(6), HtmlConverter.QUOTE_COLOR_DEFAULT); - String message = "zero\r\n" + "> one\r\n" + ">> two\r\n" + @@ -129,19 +119,19 @@ public class HtmlConverterTest { String result = HtmlConverter.textToHtml(message); writeToFile(result); assertEquals("
"
-                + "zero
" + + "zero
" + "
" - + " one
" + + "one
" + "
" - + " two
" + + "two
" + "
" - + " three
" + + "three
" + "
" - + " four
" + + "four
" + "
" - + " five
" + + "five
" + "
" - + " six" + + "six" + "
" + "
" + "
" @@ -183,9 +173,9 @@ public class HtmlConverterTest { String result = HtmlConverter.textToHtml(message); writeToFile(result); assertEquals("
"
-                + "foo
" - + " bar
" - + " baz
" + + "foo
" + + " bar
" + + " baz
" + "
", result); } @@ -200,12 +190,12 @@ public class HtmlConverterTest { String result = HtmlConverter.textToHtml(message); writeToFile(result); assertEquals("
"
-                + " 
" - + " &
" - + "
" - + " <
" + + "
" + + " &
" + + "
" + + " <
" + "
" - + "
" + + "
" + "
" + "
", result); } @@ -237,7 +227,7 @@ public class HtmlConverterTest { public void dashesContainingSpacesIgnoredAsHR() { String text = "hello\n--- --- --- --- ---\nfoo bar"; String result = HtmlConverter.textToHtml(text); - assertEquals("
hello
--- --- --- --- ---
foo bar
", + assertEquals("
hello
--- --- --- --- ---
foo bar
", result); } @@ -252,28 +242,28 @@ public class HtmlConverterTest { public void dashedHorizontalRulePrefixedWithTextIgnoredAsHR() { String text = "hello----\n\n"; String result = HtmlConverter.textToHtml(text); - assertEquals("
hello----

", result); + assertEquals("
hello----

", result); } @Test public void doubleMinusIgnoredAsHR() { String text = "--\n"; String result = HtmlConverter.textToHtml(text); - assertEquals("
--
", result); + assertEquals("
--
", result); } @Test public void doubleEqualsIgnoredAsHR() { String text = "==\n"; String result = HtmlConverter.textToHtml(text); - assertEquals("
==
", result); + assertEquals("
==
", result); } @Test public void doubleUnderscoreIgnoredAsHR() { String text = "__\n"; String result = HtmlConverter.textToHtml(text); - assertEquals("
__
", result); + assertEquals("
__
", result); } @Test @@ -308,7 +298,7 @@ public class HtmlConverterTest { public void replacementOfScissorsByHR() { String text = "hello\n-- %< -------------- >8 --\nworld\n"; String result = HtmlConverter.textToHtml(text); - assertEquals("
hello
world
", result); + assertEquals("
hello
world
", result); } @Test diff --git a/k9mail/src/test/java/com/fsck/k9/message/html/UriLinkifierTest.java b/k9mail/src/test/java/com/fsck/k9/message/html/UriLinkifierTest.java deleted file mode 100644 index 81abbbb34..000000000 --- a/k9mail/src/test/java/com/fsck/k9/message/html/UriLinkifierTest.java +++ /dev/null @@ -1,148 +0,0 @@ -package com.fsck.k9.message.html; - - -import com.fsck.k9.K9RobolectricTestRunner; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -import static com.fsck.k9.message.html.UriParserTestHelper.assertLinkOnly; -import static junit.framework.Assert.assertEquals; - - -@RunWith(K9RobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class UriLinkifierTest { - private StringBuffer outputBuffer = new StringBuffer(); - - - @Test - public void emptyText() { - String text = ""; - - UriLinkifier.linkifyText(text, outputBuffer); - - assertEquals(text, outputBuffer.toString()); - } - - @Test - public void textWithoutUri_shouldBeCopiedToOutputBuffer() { - String text = "some text here"; - - UriLinkifier.linkifyText(text, outputBuffer); - - assertEquals(text, outputBuffer.toString()); - } - - @Test - public void simpleUri() { - String uri = "http://example.org"; - - UriLinkifier.linkifyText(uri, outputBuffer); - - assertLinkOnly(uri, outputBuffer); - } - - @Test - public void uriPrecededBySpace() { - String text = " http://example.org"; - - UriLinkifier.linkifyText(text, outputBuffer); - - assertEquals(" http://example.org", outputBuffer.toString()); - } - - @Test - public void uriPrecededByOpeningParenthesis() { - String text = "(http://example.org"; - - UriLinkifier.linkifyText(text, outputBuffer); - - assertEquals("(http://example.org", outputBuffer.toString()); - } - - @Test - public void uriPrecededBySomeText() { - String uri = "Check out my fantastic URI: http://example.org"; - - UriLinkifier.linkifyText(uri, outputBuffer); - - assertEquals("Check out my fantastic URI: http://example.org", - outputBuffer.toString()); - } - - @Test - public void uriWithTrailingText() { - String uri = "http://example.org/ is the best"; - - UriLinkifier.linkifyText(uri, outputBuffer); - - assertEquals("http://example.org/ is the best", outputBuffer.toString()); - } - - @Test - public void uriEmbeddedInText() { - String uri = "prefix http://example.org/ suffix"; - - UriLinkifier.linkifyText(uri, outputBuffer); - - assertEquals("prefix http://example.org/ suffix", outputBuffer.toString()); - } - - @Test - public void uriWithUppercaseScheme() { - String uri = "HTTP://example.org/"; - - UriLinkifier.linkifyText(uri, outputBuffer); - - assertEquals("HTTP://example.org/", outputBuffer.toString()); - } - - @Test - public void uriNotPrecededByValidSeparator_shouldNotBeLinkified() { - String text = "myhttp://example.org"; - - UriLinkifier.linkifyText(text, outputBuffer); - - assertEquals(text, outputBuffer.toString()); - } - - @Test - public void uriNotPrecededByValidSeparatorFollowedByValidUri() { - String text = "myhttp: http://example.org"; - - UriLinkifier.linkifyText(text, outputBuffer); - - assertEquals("myhttp: http://example.org", outputBuffer.toString()); - } - - @Test - public void schemaMatchWithInvalidUriInMiddleOfTextFollowedByValidUri() { - String text = "prefix http:42 http://example.org"; - - UriLinkifier.linkifyText(text, outputBuffer); - - assertEquals("prefix http:42 http://example.org", outputBuffer.toString()); - } - - @Test - public void multipleValidUrisInRow() { - String text = "prefix http://uri1.example.org some text http://uri2.example.org/path postfix"; - - UriLinkifier.linkifyText(text, outputBuffer); - - assertEquals( - "prefix http://uri1.example.org some text " + - "http://uri2.example.org/path postfix", - outputBuffer.toString()); - } - - @Test - public void uriSurroundedByHtmlTags() { - String text = "
http://uri.example.org
"; - - UriLinkifier.linkifyText(text, outputBuffer); - - assertEquals("
http://uri.example.org
", outputBuffer.toString()); - } -} diff --git a/k9mail/src/test/java/com/fsck/k9/message/html/UriParserTestHelper.java b/k9mail/src/test/java/com/fsck/k9/message/html/UriParserTestHelper.java deleted file mode 100644 index a57ea4b48..000000000 --- a/k9mail/src/test/java/com/fsck/k9/message/html/UriParserTestHelper.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.fsck.k9.message.html; - - -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - - -public class UriParserTestHelper { - public static void assertContainsLink(String expected, StringBuffer actual) { - String linkifiedUri = actual.toString(); - Document document = Jsoup.parseBodyFragment(linkifiedUri); - Element anchorElement = document.select("a").first(); - assertNotNull("No element found", anchorElement); - assertEquals(expected, anchorElement.text()); - assertEquals(expected, anchorElement.attr("href")); - } - - public static void assertLinkOnly(String expected, StringBuffer actual) { - String linkifiedUri = actual.toString(); - Document document = Jsoup.parseBodyFragment(linkifiedUri); - Element anchorElement = document.select("a").first(); - assertNotNull("No element found", anchorElement); - assertEquals(expected, anchorElement.text()); - assertEquals(expected, anchorElement.attr("href")); - - assertAnchorElementIsSoleContent(document, anchorElement); - } - - private static void assertAnchorElementIsSoleContent(Document document, Element anchorElement) { - assertEquals(document.body(), anchorElement.parent()); - assertTrue(" element is surrounded by text", document.body().textNodes().isEmpty()); - } -}