diff --git a/k9mail/src/main/java/com/fsck/k9/message/html/BitcoinUriParser.java b/k9mail/src/main/java/com/fsck/k9/message/html/BitcoinUriParser.java
index 0d104e32a..f266da7a4 100644
--- a/k9mail/src/main/java/com/fsck/k9/message/html/BitcoinUriParser.java
+++ b/k9mail/src/main/java/com/fsck/k9/message/html/BitcoinUriParser.java
@@ -5,9 +5,6 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
-/**
- * Parses and "linkifies" bitcoin links.
- */
class BitcoinUriParser implements UriParser {
private static final Pattern BITCOIN_URI_PATTERN =
Pattern.compile("bitcoin:[1-9a-km-zA-HJ-NP-Z]{27,34}(\\?[a-zA-Z0-9$\\-_.+!*'(),%:@&=]*)?");
@@ -16,7 +13,6 @@ class BitcoinUriParser implements UriParser {
public int linkifyUri(String text, int startPos, StringBuffer outputBuffer) {
Matcher matcher = BITCOIN_URI_PATTERN.matcher(text);
- // Skip not matching uris
if (!matcher.find(startPos) || matcher.start() != startPos) {
return startPos;
}
diff --git a/k9mail/src/main/java/com/fsck/k9/message/html/HttpUriParser.java b/k9mail/src/main/java/com/fsck/k9/message/html/HttpUriParser.java
index 78bcc2897..c4070ed0a 100644
--- a/k9mail/src/main/java/com/fsck/k9/message/html/HttpUriParser.java
+++ b/k9mail/src/main/java/com/fsck/k9/message/html/HttpUriParser.java
@@ -10,8 +10,10 @@ import java.util.regex.Pattern;
/**
* Parses and "linkifies" http links.
*
- * This class is in parts inspired by OkHttp's HttpUrl (https://github.com/square/okhttp/blob/master/okhttp/src/main/java/okhttp3/HttpUrl.java),s
- * but leaving out much of the parsing part.
+ * This class is in parts inspired by OkHttp's
+ * HttpUrl.
+ * But much of the parsing parts have been left out.
+ *
*/
class HttpUriParser implements UriParser {
// This string represent character group sub-delim as described in RFC 3986
@@ -19,11 +21,12 @@ class HttpUriParser implements UriParser {
private static final Pattern IPv4_PATTERN =
Pattern.compile("(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})(:(\\d{0,5}))?");
+
@Override
public int linkifyUri(String text, int startPos, StringBuffer outputBuffer) {
int currentPos = startPos;
- // Test scheme
+ // Scheme
String shortScheme = text.substring(currentPos, Math.min(currentPos + 7, text.length()));
String longScheme = text.substring(currentPos, Math.min(currentPos + 8, text.length()));
if (shortScheme.equalsIgnoreCase("https://")) {
@@ -33,20 +36,17 @@ class HttpUriParser implements UriParser {
} else if (longScheme.equalsIgnoreCase("rtsp://")) {
currentPos += "rtsp://".length();
} else {
- // Unsupported scheme
return startPos;
}
- // Test authority
+ // Authority
int authorityEnd = text.indexOf('/', currentPos);
if (authorityEnd == -1) {
authorityEnd = text.length();
}
- // Authority: Take a look at user info if available
currentPos = matchUserInfoIfAvailable(text, currentPos, authorityEnd);
- // Authority: Take a look at host
if (!tryMatchDomainName(text, currentPos, authorityEnd) &&
!tryMatchIpv4Address(text, currentPos, authorityEnd, true) &&
!tryMatchIpv6Address(text, currentPos, authorityEnd)) {
@@ -54,24 +54,27 @@ class HttpUriParser implements UriParser {
}
currentPos = authorityEnd;
- // Test path
+ // Path
if (currentPos < text.length() && text.charAt(currentPos) == '/') {
currentPos = matchUnreservedPCTEncodedSubDelimClassesGreedy(text, currentPos + 1, "/:@");
}
- // Test for query
+ // Query
if (currentPos < text.length() && text.charAt(currentPos) == '?') {
currentPos = matchUnreservedPCTEncodedSubDelimClassesGreedy(text, currentPos + 1, ":@/?");
}
- // Test for fragment.
+ // Fragment
if (currentPos < text.length() && text.charAt(currentPos) == '#') {
currentPos = matchUnreservedPCTEncodedSubDelimClassesGreedy(text, currentPos + 1, ":@/?");
}
- // Final link generation
- String linkifiedUri = String.format("%1$s", text.substring(startPos, currentPos));
- outputBuffer.append(linkifiedUri);
+ String httpUri = text.substring(startPos, currentPos);
+ outputBuffer.append("")
+ .append(httpUri)
+ .append("");
return currentPos;
}
@@ -89,7 +92,7 @@ class HttpUriParser implements UriParser {
}
private boolean tryMatchDomainName(String text, int startPos, int authorityEnd) {
- // Partly from OkHttp's HttpUrl (https://github.com/square/okhttp/blob/master/okhttp/src/main/java/okhttp3/HttpUrl.java)
+ // Partly from OkHttp's HttpUrl
try {
// Check for port
int portPos = text.indexOf(':', startPos);
@@ -143,7 +146,6 @@ class HttpUriParser implements UriParser {
return false;
}
- // Validate segments
for (int i = 1; i <= 4; i++) {
int segment = Integer.parseInt(matcher.group(1));
if (segment > 255) {
@@ -151,12 +153,10 @@ class HttpUriParser implements UriParser {
}
}
- // Make sure port does not exist if missing
if (!portAllowed && matcher.group(5) != null) {
return false;
}
- // Validate optional port
String portString = matcher.group(6);
if (portString != null && !portString.isEmpty()) {
int port = Integer.parseInt(portString);
@@ -169,7 +169,6 @@ class HttpUriParser implements UriParser {
}
private boolean tryMatchIpv6Address(String text, int startPos, int authorityEnd) {
- // General validation
if (text.codePointAt(startPos) != '[') {
return false;
}
diff --git a/k9mail/src/main/java/com/fsck/k9/message/html/UriLinkifier.java b/k9mail/src/main/java/com/fsck/k9/message/html/UriLinkifier.java
index 1c343d951..0fd97ac1c 100644
--- a/k9mail/src/main/java/com/fsck/k9/message/html/UriLinkifier.java
+++ b/k9mail/src/main/java/com/fsck/k9/message/html/UriLinkifier.java
@@ -2,6 +2,7 @@ package com.fsck.k9.message.html;
import java.util.HashMap;
+import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -9,13 +10,7 @@ import java.util.regex.Pattern;
import android.text.TextUtils;
-/**
- * Allows conversion of link in text to html link.
- */
public class UriLinkifier {
- /**
- * Regular expression pattern to match uri scheme and parsers for supported uris as defined in RFC 3987
- */
private static final Pattern URI_SCHEME;
private static final Map SUPPORTED_URIS;
private static final String SCHEME_SEPARATOR = " (";
@@ -32,16 +27,8 @@ public class UriLinkifier {
URI_SCHEME = Pattern.compile(allSchemes, Pattern.CASE_INSENSITIVE);
}
- /**
- * Searches for link-like text in a string and turn it into a link. Append the result to
- * outputBuffer. text is not modified.
- *
- * @param text
- * Plain text to be linkified.
- * @param outputBuffer
- * Buffer to append linked text to.
- */
- public static void linkifyText(final String text, final StringBuffer outputBuffer) {
+
+ public static void linkifyText(String text, StringBuffer outputBuffer) {
int currentPos = 0;
Matcher matcher = URI_SCHEME.matcher(text);
@@ -51,31 +38,39 @@ public class UriLinkifier {
String textBeforeMatch = text.substring(currentPos, startPos);
outputBuffer.append(textBeforeMatch);
- if (!textBeforeMatch.isEmpty() &&
- !SCHEME_SEPARATOR.contains(textBeforeMatch.substring(textBeforeMatch.length() - 1))) {
+ if (!isPrecededByValidSeparator(textBeforeMatch)) {
outputBuffer.append(text.charAt(startPos));
currentPos = startPos + 1;
continue;
}
- // Find responsible parser and let it do it's job
- String scheme = matcher.group();
- UriParser parser = SUPPORTED_URIS.get(scheme.toLowerCase());
+ String scheme = matcher.group().toLowerCase(Locale.US);
+ UriParser parser = SUPPORTED_URIS.get(scheme);
int newPos = parser.linkifyUri(text, startPos, outputBuffer);
- // Handle invalid uri, at least advance by one to prevent endless loop
- if (newPos <= startPos) {
+ boolean uriWasNotLinkified = newPos <= startPos;
+ if (uriWasNotLinkified) {
outputBuffer.append(text.charAt(startPos));
currentPos++;
} else {
currentPos = (newPos > currentPos) ? newPos : currentPos + 1;
}
+
if (currentPos >= text.length()) {
break;
}
}
- // Copy rest
- outputBuffer.append(text.substring(currentPos));
+ String textAfterLastMatch = text.substring(currentPos);
+ outputBuffer.append(textAfterLastMatch);
+ }
+
+ private static boolean isPrecededByValidSeparator(String textBeforeMatch) {
+ if (textBeforeMatch.isEmpty()) {
+ return true;
+ }
+
+ String characterBeforeMatch = textBeforeMatch.substring(textBeforeMatch.length() - 1);
+ return SCHEME_SEPARATOR.contains(characterBeforeMatch);
}
}
diff --git a/k9mail/src/main/java/com/fsck/k9/message/html/UriParser.java b/k9mail/src/main/java/com/fsck/k9/message/html/UriParser.java
index d5cbefda7..ad08c0d14 100644
--- a/k9mail/src/main/java/com/fsck/k9/message/html/UriParser.java
+++ b/k9mail/src/main/java/com/fsck/k9/message/html/UriParser.java
@@ -1,15 +1,19 @@
package com.fsck.k9.message.html;
-/**
- * General framework to handle uris when parsing. Allows different handling depending on the scheme identifier.
- */
+
public interface UriParser {
/**
- * Parse and linkify scheme specific uri beginning from given position. The result will be written to given buffer.
- * @param text String to parse uri from.
- * @param startPos Position where uri starts (first letter of scheme).
- * @param outputBuffer Buffer where linkified variant of uri is written to.
- * @return Index where parsed uri ends (first non-uri letter). Should be startPos or smaller if no valid uri was found.
+ * Parse and linkify scheme specific URI beginning from given position. The result will be written to given buffer.
+ *
+ * @param text
+ * String to parse URI from.
+ * @param startPos
+ * Position where URI starts (first letter of scheme).
+ * @param outputBuffer
+ * Buffer where linkified variant of URI is written to.
+ *
+ * @return Index where parsed URI ends (first non-URI letter). Should be {@code startPos} or smaller if no valid
+ * URI was found.
*/
int linkifyUri(String text, int startPos, StringBuffer outputBuffer);
}
diff --git a/k9mail/src/test/java/com/fsck/k9/message/html/BitcoinUriParserTest.java b/k9mail/src/test/java/com/fsck/k9/message/html/BitcoinUriParserTest.java
new file mode 100644
index 000000000..12b9f5bbf
--- /dev/null
+++ b/k9mail/src/test/java/com/fsck/k9/message/html/BitcoinUriParserTest.java
@@ -0,0 +1,84 @@
+package com.fsck.k9.message.html;
+
+
+import org.junit.Test;
+
+import static com.fsck.k9.message.html.UriParserTestHelper.assertLinkOnly;
+import static org.junit.Assert.assertEquals;
+
+
+public class BitcoinUriParserTest {
+ BitcoinUriParser parser = new BitcoinUriParser();
+ StringBuffer outputBuffer = new StringBuffer();
+
+
+ @Test
+ public void basicBitcoinUri() throws Exception {
+ assertLinkify("bitcoin:19W6QZkx8SYPG7BBCS7odmWGRxqRph5jFU");
+ }
+
+ @Test
+ public void bitcoinUriWithAmount() throws Exception {
+ assertLinkify("bitcoin:12A1MyfXbW6RhdRAZEqofac5jCQQjwEPBu?amount=1.2");
+ }
+
+ @Test
+ public void bitcoinUriWithQueryParameters() throws Exception {
+ assertLinkify("bitcoin:12A1MyfXbW6RhdRAZEqofac5jCQQjwEPBu?amount=1.2" +
+ "&message=Payment&label=Satoshi&extra=other-param");
+ }
+
+ @Test
+ public void uriInMiddleOfInput() throws Exception {
+ String prefix = "prefix ";
+ String uri = "bitcoin:12A1MyfXbW6RhdRAZEqofac5jCQQjwEPBu?amount=1.2";
+ String text = prefix + uri;
+
+ parser.linkifyUri(text, prefix.length(), outputBuffer);
+
+ assertLinkOnly(uri, outputBuffer);
+ }
+
+ @Test
+ public void invalidScheme() throws Exception {
+ assertNotLinkify("bitcion:19W6QZkx8SYPG7BBCS7odmWGRxqRph5jFU");
+ }
+
+ @Test
+ public void invalidAddress() throws Exception {
+ assertNotLinkify("bitcoin:[invalid]");
+ }
+
+ @Test
+ public void invalidBitcoinUri_shouldReturnStartingPosition() throws Exception {
+ String uri = "bitcoin:[invalid]";
+
+ int newPos = linkify(uri);
+
+ assertEquals(0, newPos);
+ }
+
+ @Test
+ public void invalidBitcoinUri_shouldNotWriteToOutputBuffer() throws Exception {
+ String uri = "bitcoin:[invalid]";
+
+ linkify(uri);
+
+ assertEquals(0, outputBuffer.length());
+ }
+
+
+ int linkify(String uri) {
+ return parser.linkifyUri(uri, 0, outputBuffer);
+ }
+
+ void assertLinkify(String uri) {
+ linkify(uri);
+ assertLinkOnly(uri, outputBuffer);
+ }
+
+ void assertNotLinkify(String text) {
+ int newPos = linkify(text);
+ assertEquals(0, newPos);
+ }
+}
diff --git a/k9mail/src/test/java/com/fsck/k9/message/html/HttpUriParserTest.java b/k9mail/src/test/java/com/fsck/k9/message/html/HttpUriParserTest.java
index d930db8e7..159e4ddb1 100644
--- a/k9mail/src/test/java/com/fsck/k9/message/html/HttpUriParserTest.java
+++ b/k9mail/src/test/java/com/fsck/k9/message/html/HttpUriParserTest.java
@@ -1,216 +1,155 @@
package com.fsck.k9.message.html;
-import com.fsck.k9.K9RobolectricTestRunner;
-import org.junit.Before;
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 HttpUriParserTest {
- private HttpUriParser parser;
- private StringBuffer outputBuffer;
+ private final HttpUriParser parser = new HttpUriParser();
+ private final StringBuffer outputBuffer = new StringBuffer();
- @Before
- public void setUp() {
- parser = new HttpUriParser();
- outputBuffer = new StringBuffer();
+
+ @Test
+ public void simpleDomain() {
+ assertLinkify("http://www.google.com");
}
@Test
- public void testSimpleDomain() {
- String text = "http://www.google.com";
- int endPos = parser.linkifyUri(text, 0, outputBuffer);
- assertEquals(String.format("%1$s", text), outputBuffer.toString());
- assertEquals(text.length(), endPos);
+ public void domainWithTrailingSlash() {
+ assertLinkify("http://www.google.com/");
}
@Test
- public void testDomainWithTrailingSlash() {
- String text = "http://www.google.com/";
- int endPos = parser.linkifyUri(text, 0, outputBuffer);
- assertEquals(String.format("%1$s", text), outputBuffer.toString());
- assertEquals(text.length(), endPos);
+ public void domainWithoutWww() {
+ assertLinkify("http://google.com/");
}
@Test
- public void testDomainWithoutWWW() {
- String text = "http://google.com/";
- int endPos = parser.linkifyUri(text, 0, outputBuffer);
- assertEquals(String.format("%1$s", text), outputBuffer.toString());
- assertEquals(text.length(), endPos);
+ public void query() {
+ assertLinkify("http://google.com/give/me/?q=mode&c=information");
}
@Test
- public void testDomainWithTrailingSpace() {
+ public void fragment() {
+ assertLinkify("http://google.com/give/me#only-the-best");
+ }
+
+ @Test
+ public void queryAndFragment() {
+ assertLinkify("http://google.com/give/me/?q=mode&c=information#only-the-best");
+ }
+
+ @Test
+ public void ipv4Address() {
+ assertLinkify("http://127.0.0.1");
+ }
+
+ @Test
+ public void ipv4AddressWithTrailingSlash() {
+ assertLinkify("http://127.0.0.1/");
+ }
+
+ @Test
+ public void ipv4AddressWithEmptyPort() {
+ assertLinkify("http://127.0.0.1:");
+ }
+
+ @Test
+ public void ipv4AddressWithPort() {
+ assertLinkify("http://127.0.0.1:524/");
+ }
+
+ @Test
+ public void ipv6Address() {
+ assertLinkify("http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]");
+ }
+
+ @Test
+ public void ipv6AddressWithPort() {
+ assertLinkify("http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80");
+ }
+
+ @Test
+ public void ipv6AddressWithTrailingSlash() {
+ assertLinkify("http://[1080:0:0:0:8:800:200C:417A]/");
+ }
+
+ @Test
+ public void ipv6AddressWithEndCompression() {
+ assertLinkify("http://[3ffe:2a00:100:7031::1]");
+ }
+
+ @Test
+ public void ipv6AddressWithBeginCompression() {
+ assertLinkify("http://[1080::8:800:200C:417A]/");
+ }
+
+ @Test
+ public void ipv6AddressWithCompressionPort() {
+ assertLinkify("http://[::FFFF:129.144.52.38]:80/");
+ }
+
+ @Test
+ public void ipv6AddressWithPrependedCompression() {
+ assertLinkify("http://[::192.9.5.5]/");
+ }
+
+ @Test
+ public void ipv6AddressWithTrailingIp4AndPort() {
+ assertLinkify("http://[::192.9.5.5]:80/");
+ }
+
+ @Test
+ public void domainWithTrailingSpace() {
String text = "http://google.com/ ";
+
int endPos = parser.linkifyUri(text, 0, outputBuffer);
- assertEquals("http://google.com/", outputBuffer.toString());
+
+ assertLinkOnly("http://google.com/", outputBuffer);
assertEquals(text.length() - 1, endPos);
}
@Test
- public void testDomainWithTrailingSpaceNewline() {
- String text = "http://google.com/ \n";
- int endPos = parser.linkifyUri(text, 0, outputBuffer);
- assertEquals("http://google.com/", outputBuffer.toString());
- assertEquals(text.length() - 2, endPos);
- }
-
- @Test
- public void testDomainWithTrailingNewline() {
+ public void domainWithTrailingNewline() {
String text = "http://google.com/\n";
+
int endPos = parser.linkifyUri(text, 0, outputBuffer);
- assertEquals("http://google.com/", outputBuffer.toString());
+
+ assertLinkOnly("http://google.com/", outputBuffer);
assertEquals(text.length() - 1, endPos);
}
@Test
- public void testDomainsWithQueryAndFragment() {
- String text = "http://google.com/give/me/?q=mode&c=information#only-the-best";
- int endPos = parser.linkifyUri(text, 0, outputBuffer);
- assertEquals(
- "http://google.com/give/me/?q=mode&c=information#only-the-best",
- outputBuffer.toString());
- assertEquals(text.length(), endPos);
- }
+ public void domainWithTrailingAngleBracket() {
+ String text = "";
- @Test
- public void testDomainsWithQuery() {
- String text = "http://google.com/give/me/?q=mode&c=information";
- int endPos = parser.linkifyUri(text, 0, outputBuffer);
- assertEquals(
- "http://google.com/give/me/?q=mode&c=information",
- outputBuffer.toString());
- assertEquals(text.length(), endPos);
- }
+ int endPos = parser.linkifyUri(text, 1, outputBuffer);
- @Test
- public void testDomainsWithFragment() {
- String text = "http://google.com/give/me#only-the-best";
- int endPos = parser.linkifyUri(text, 0, outputBuffer);
- assertEquals(
- "http://google.com/give/me#only-the-best",
- outputBuffer.toString());
- assertEquals(text.length(), endPos);
- }
-
- @Test
- public void testDomainsWithQueryAndFragmentWithoutWWWW() {
- String text = "http://google.com/give/me/?q=mode+c=information#only-the-best\n";
- int endPos = parser.linkifyUri(text, 0, outputBuffer);
- assertEquals(
- "http://google.com/give/me/?q=mode+c=information#only-the-best",
- outputBuffer.toString());
+ assertLinkOnly("http://google.com/", outputBuffer);
assertEquals(text.length() - 1, endPos);
}
@Test
- public void testIpv4Address() {
- String text = "http://127.0.0.1";
- int endPos = parser.linkifyUri(text, 0, outputBuffer);
- assertEquals(String.format("%1$s", text), outputBuffer.toString());
- assertEquals(text.length(), endPos);
+ public void uriInMiddleOfInput() throws Exception {
+ String prefix = "prefix ";
+ String uri = "http://google.com/";
+ String text = prefix + uri;
+
+ parser.linkifyUri(text, prefix.length(), outputBuffer);
+
+ assertLinkOnly(uri, outputBuffer);
}
- @Test
- public void testIpv4AddressWithTrailingSlash() {
- String text = "http://127.0.0.1/";
- int endPos = parser.linkifyUri(text, 0, outputBuffer);
- assertEquals(String.format("%1$s", text), outputBuffer.toString());
- assertEquals(text.length(), endPos);
+
+ int linkify(String uri) {
+ return parser.linkifyUri(uri, 0, outputBuffer);
}
- @Test
- public void testIpv4AddressWithEmptyPort() {
- String text = "http://127.0.0.1:";
- int endPos = parser.linkifyUri(text, 0, outputBuffer);
- assertEquals(String.format("%1$s", text), outputBuffer.toString());
- assertEquals(text.length(), endPos);
- }
-
- @Test
- public void testIpv4AddressWithPort() {
- String text = "http://127.0.0.1:524/";
- int endPos = parser.linkifyUri(text, 0, outputBuffer);
- assertEquals(String.format("%1$s", text), outputBuffer.toString());
- assertEquals(text.length(), endPos);
- }
-
- @Test
- public void testIpv6Address() {
- String text = "http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]";
- int endPos = parser.linkifyUri(text, 0, outputBuffer);
- assertEquals(String.format("%1$s", text), outputBuffer.toString());
- assertEquals(text.length(), endPos);
- }
-
- @Test
- public void testIpv6AddressWithPort() {
- String text = "http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80";
- int endPos = parser.linkifyUri(text, 0, outputBuffer);
- assertEquals(String.format("%1$s", text), outputBuffer.toString());
- assertEquals(text.length(), endPos);
- }
-
- @Test
- public void testIpv6AddressShort() {
- String text = "http://[1080:0:0:0:8:800:200C:417A]/";
- int endPos = parser.linkifyUri(text, 0, outputBuffer);
- assertEquals(String.format("%1$s", text), outputBuffer.toString());
- assertEquals(text.length(), endPos);
- }
-
- @Test
- public void testIpv6AddressWithEndCompression() {
- String text = "http://[3ffe:2a00:100:7031::1]";
- int endPos = parser.linkifyUri(text, 0, outputBuffer);
- assertEquals(String.format("%1$s", text), outputBuffer.toString());
- assertEquals(text.length(), endPos);
- }
-
- @Test
- public void testIpv6AddressWithBeginCompression() {
- String text = "http://[1080::8:800:200C:417A]/";
- int endPos = parser.linkifyUri(text, 0, outputBuffer);
- assertEquals(String.format("%1$s", text), outputBuffer.toString());
- assertEquals(text.length(), endPos);
- }
-
- @Test
- public void testIpv6AddressWithPrependedCompression() {
- String text = "http://[::192.9.5.5]/";
- int endPos = parser.linkifyUri(text, 0, outputBuffer);
- assertEquals(String.format("%1$s", text), outputBuffer.toString());
- assertEquals(text.length(), endPos);
- }
-
- @Test
- public void testIpv6AddressWithCompressionPort() {
- String text = "http://[::FFFF:129.144.52.38]:80/";
- int endPos = parser.linkifyUri(text, 0, outputBuffer);
- assertEquals(String.format("%1$s", text), outputBuffer.toString());
- assertEquals(text.length(), endPos);
- }
-
- @Test
- public void testIpv6AddressWithTrailingIp4() {
- String text = "http://[::192.9.5.5]/";
- int endPos = parser.linkifyUri(text, 0, outputBuffer);
- assertEquals(String.format("%1$s", text), outputBuffer.toString());
- assertEquals(text.length(), endPos);
- }
-
- @Test
- public void testIpv6AddressWithTrailingIp4AndPort() {
- String text = "http://[::192.9.5.5]:80/";
- int endPos = parser.linkifyUri(text, 0, outputBuffer);
- assertEquals(String.format("%1$s", text), outputBuffer.toString());
- assertEquals(text.length(), endPos);
+ void assertLinkify(String uri) {
+ linkify(uri);
+ assertLinkOnly(uri, outputBuffer);
}
}
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
index 40f6281a1..4d81baad5 100644
--- a/k9mail/src/test/java/com/fsck/k9/message/html/UriLinkifierTest.java
+++ b/k9mail/src/test/java/com/fsck/k9/message/html/UriLinkifierTest.java
@@ -6,90 +6,113 @@ 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 {
- @Test
- public void testLinkifyBitcoinAndHttpUri() {
- String text = "bitcoin:19W6QZkx8SYPG7BBCS7odmWGRxqRph5jFU http://example.com/";
+ private StringBuffer outputBuffer = new StringBuffer();
- StringBuffer outputBuffer = new StringBuffer();
- UriLinkifier.linkifyText(text, outputBuffer);
-
- assertEquals("" +
- "bitcoin:19W6QZkx8SYPG7BBCS7odmWGRxqRph5jFU" +
- " " +
- "" +
- "http://example.com/" +
- "", outputBuffer.toString());
- }
@Test
- public void testSimpleHttpUri() {
- String text = "http://www.google.com";
- StringBuffer outputBuffer = new StringBuffer();
- UriLinkifier.linkifyText(text, outputBuffer);
- assertEquals("http://www.google.com", outputBuffer.toString());
- }
+ public void emptyText() {
+ String text = "";
- @Test
- public void testHttpUriWithTrailingSlash() {
- String text = "http://www.google.com/";
- StringBuffer outputBuffer = new StringBuffer();
UriLinkifier.linkifyText(text, outputBuffer);
- assertEquals("http://www.google.com/",
- outputBuffer.toString());
- }
- @Test
- public void testHttpUriWithoutWWW() {
- String text = "http://google.com/";
- StringBuffer outputBuffer = new StringBuffer();
- UriLinkifier.linkifyText(text, outputBuffer);
- assertEquals("http://google.com/", outputBuffer.toString());
- }
-
- @Test
- public void testHttpUriWithTrailingSpace() {
- String text = "http://google.com/ ";
- StringBuffer outputBuffer = new StringBuffer();
- UriLinkifier.linkifyText(text, outputBuffer);
- assertEquals("http://google.com/ ", outputBuffer.toString());
- }
-
- @Test
- public void testHttpUriWithTrailingSpaceNewline() {
- String text = "http://google.com/ \n";
- StringBuffer outputBuffer = new StringBuffer();
- UriLinkifier.linkifyText(text, outputBuffer);
- assertEquals("http://google.com/ \n",
- outputBuffer.toString());
- }
-
- @Test
- public void testHttpUriWithTrailingNewline() {
- String text = "http://google.com/\n";
- StringBuffer outputBuffer = new StringBuffer();
- UriLinkifier.linkifyText(text, outputBuffer);
- assertEquals("http://google.com/\n", outputBuffer.toString());
- }
-
- @Test
- public void testIgnorePartialHttpUriScheme() {
- String text = "myhttp://example.org";
- StringBuffer outputBuffer = new StringBuffer();
- UriLinkifier.linkifyText(text, outputBuffer);
assertEquals(text, outputBuffer.toString());
}
@Test
- public void testPartialHttpUriSchemeWithSeparator() {
- String text = "(http://example.org";
- StringBuffer outputBuffer = new StringBuffer();
+ 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());
+ }
}
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
new file mode 100644
index 000000000..a57ea4b48
--- /dev/null
+++ b/k9mail/src/test/java/com/fsck/k9/message/html/UriParserTestHelper.java
@@ -0,0 +1,38 @@
+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());
+ }
+}