Clean up URI parsing code and tests

This commit is contained in:
cketti 2017-03-17 03:17:16 +01:00
parent 0d3d9aab32
commit 0f9bc4867a
8 changed files with 370 additions and 292 deletions

View file

@ -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;
}

View file

@ -10,8 +10,10 @@ import java.util.regex.Pattern;
/**
* Parses and "linkifies" http links.
* <p>
* 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
* <a href="https://github.com/square/okhttp/blob/master/okhttp/src/main/java/okhttp3/HttpUrl.java">HttpUrl</a>.
* But much of the parsing parts have been left out.
* </p>
*/
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("<a href=\"%1$s\">%1$s</a>", text.substring(startPos, currentPos));
outputBuffer.append(linkifiedUri);
String httpUri = text.substring(startPos, currentPos);
outputBuffer.append("<a href=\"")
.append(httpUri)
.append("\">")
.append(httpUri)
.append("</a>");
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;
}

View file

@ -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<String, UriParser> 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
* <tt>outputBuffer</tt>. <tt>text</tt> 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);
}
}

View file

@ -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);
}

View file

@ -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);
}
}

View file

@ -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("<a href=\"%1$s\">%1$s</a>", 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("<a href=\"%1$s\">%1$s</a>", text), outputBuffer.toString());
assertEquals(text.length(), endPos);
public void domainWithoutWww() {
assertLinkify("http://google.com/");
}
@Test
public void testDomainWithoutWWW() {
public void query() {
assertLinkify("http://google.com/give/me/?q=mode&c=information");
}
@Test
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(String.format("<a href=\"%1$s\">%1$s</a>", text), outputBuffer.toString());
assertEquals(text.length(), endPos);
}
@Test
public void testDomainWithTrailingSpace() {
String text = "http://google.com/ ";
int endPos = parser.linkifyUri(text, 0, outputBuffer);
assertEquals("<a href=\"http://google.com/\">http://google.com/</a>", outputBuffer.toString());
assertLinkOnly("http://google.com/", outputBuffer);
assertEquals(text.length() - 1, endPos);
}
@Test
public void testDomainWithTrailingSpaceNewline() {
public void domainWithTrailingNewline() {
String text = "http://google.com/\n";
int endPos = parser.linkifyUri(text, 0, outputBuffer);
assertEquals("<a href=\"http://google.com/\">http://google.com/</a>", outputBuffer.toString());
assertEquals(text.length() - 2, endPos);
}
@Test
public void testDomainWithTrailingNewline() {
String text = "http://google.com/\n";
int endPos = parser.linkifyUri(text, 0, outputBuffer);
assertEquals("<a href=\"http://google.com/\">http://google.com/</a>", 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(
"<a href=\"http://google.com/give/me/?q=mode&c=information#only-the-best\">http://google.com/give/me/?q=mode&c=information#only-the-best</a>",
outputBuffer.toString());
assertEquals(text.length(), endPos);
}
public void domainWithTrailingAngleBracket() {
String text = "<http://google.com/>";
@Test
public void testDomainsWithQuery() {
String text = "http://google.com/give/me/?q=mode&c=information";
int endPos = parser.linkifyUri(text, 0, outputBuffer);
assertEquals(
"<a href=\"http://google.com/give/me/?q=mode&c=information\">http://google.com/give/me/?q=mode&c=information</a>",
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(
"<a href=\"http://google.com/give/me#only-the-best\">http://google.com/give/me#only-the-best</a>",
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(
"<a href=\"http://google.com/give/me/?q=mode+c=information#only-the-best\">http://google.com/give/me/?q=mode+c=information#only-the-best</a>",
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("<a href=\"%1$s\">%1$s</a>", 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("<a href=\"%1$s\">%1$s</a>", 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("<a href=\"%1$s\">%1$s</a>", 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("<a href=\"%1$s\">%1$s</a>", 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("<a href=\"%1$s\">%1$s</a>", 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("<a href=\"%1$s\">%1$s</a>", 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("<a href=\"%1$s\">%1$s</a>", 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("<a href=\"%1$s\">%1$s</a>", 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("<a href=\"%1$s\">%1$s</a>", 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("<a href=\"%1$s\">%1$s</a>", 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("<a href=\"%1$s\">%1$s</a>", 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("<a href=\"%1$s\">%1$s</a>", 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("<a href=\"%1$s\">%1$s</a>", text), outputBuffer.toString());
assertEquals(text.length(), endPos);
void assertLinkify(String uri) {
linkify(uri);
assertLinkOnly(uri, outputBuffer);
}
}

View file

@ -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("<a href=\"bitcoin:19W6QZkx8SYPG7BBCS7odmWGRxqRph5jFU\">" +
"bitcoin:19W6QZkx8SYPG7BBCS7odmWGRxqRph5jFU" +
"</a> " +
"<a href=\"http://example.com/\">" +
"http://example.com/" +
"</a>", outputBuffer.toString());
}
@Test
public void testSimpleHttpUri() {
String text = "http://www.google.com";
StringBuffer outputBuffer = new StringBuffer();
UriLinkifier.linkifyText(text, outputBuffer);
assertEquals("<a href=\"http://www.google.com\">http://www.google.com</a>", 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("<a href=\"http://www.google.com/\">http://www.google.com/</a>",
outputBuffer.toString());
}
@Test
public void testHttpUriWithoutWWW() {
String text = "http://google.com/";
StringBuffer outputBuffer = new StringBuffer();
UriLinkifier.linkifyText(text, outputBuffer);
assertEquals("<a href=\"http://google.com/\">http://google.com/</a>", outputBuffer.toString());
}
@Test
public void testHttpUriWithTrailingSpace() {
String text = "http://google.com/ ";
StringBuffer outputBuffer = new StringBuffer();
UriLinkifier.linkifyText(text, outputBuffer);
assertEquals("<a href=\"http://google.com/\">http://google.com/</a> ", outputBuffer.toString());
}
@Test
public void testHttpUriWithTrailingSpaceNewline() {
String text = "http://google.com/ \n";
StringBuffer outputBuffer = new StringBuffer();
UriLinkifier.linkifyText(text, outputBuffer);
assertEquals("<a href=\"http://google.com/\">http://google.com/</a> \n",
outputBuffer.toString());
}
@Test
public void testHttpUriWithTrailingNewline() {
String text = "http://google.com/\n";
StringBuffer outputBuffer = new StringBuffer();
UriLinkifier.linkifyText(text, outputBuffer);
assertEquals("<a href=\"http://google.com/\">http://google.com/</a>\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(" <a href=\"http://example.org\">http://example.org</a>", outputBuffer.toString());
}
@Test
public void uriPrecededByOpeningParenthesis() {
String text = "(http://example.org";
UriLinkifier.linkifyText(text, outputBuffer);
assertEquals("(<a href=\"http://example.org\">http://example.org</a>", 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: <a href=\"http://example.org\">http://example.org</a>",
outputBuffer.toString());
}
@Test
public void uriWithTrailingText() {
String uri = "http://example.org/ is the best";
UriLinkifier.linkifyText(uri, outputBuffer);
assertEquals("<a href=\"http://example.org/\">http://example.org/</a> is the best", outputBuffer.toString());
}
@Test
public void uriEmbeddedInText() {
String uri = "prefix http://example.org/ suffix";
UriLinkifier.linkifyText(uri, outputBuffer);
assertEquals("prefix <a href=\"http://example.org/\">http://example.org/</a> suffix", outputBuffer.toString());
}
@Test
public void uriWithUppercaseScheme() {
String uri = "HTTP://example.org/";
UriLinkifier.linkifyText(uri, outputBuffer);
assertEquals("<a href=\"HTTP://example.org/\">HTTP://example.org/</a>", 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: <a href=\"http://example.org\">http://example.org</a>", outputBuffer.toString());
}
}

View file

@ -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 <a> 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 <a> 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("<a> element is surrounded by text", document.body().textNodes().isEmpty());
}
}