| /******************************************************************************* |
| * Copyright (c) 2007, 2013 David Green and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * David Green - initial API and implementation |
| * Torkild U. Resheim - Handle links when transforming, bug 325006 |
| * Jeremie Bresson - Bug 492302 |
| *******************************************************************************/ |
| package org.eclipse.mylyn.wikitext.parser.builder; |
| |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.io.Reader; |
| import java.io.StringWriter; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.net.URL; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.regex.Pattern; |
| |
| import org.eclipse.mylyn.wikitext.parser.Attributes; |
| import org.eclipse.mylyn.wikitext.parser.DocumentBuilder.BlockType; |
| import org.eclipse.mylyn.wikitext.parser.DocumentBuilder.SpanType; |
| import org.eclipse.mylyn.wikitext.parser.LinkAttributes; |
| import org.eclipse.mylyn.wikitext.parser.MarkupParser; |
| import org.eclipse.mylyn.wikitext.parser.builder.HtmlDocumentBuilder.Stylesheet; |
| import org.eclipse.mylyn.wikitext.textile.TextileLanguage; |
| |
| import junit.framework.TestCase; |
| |
| /** |
| * @author David Green |
| * @author Torkild U. Resheim |
| */ |
| public class HtmlDocumentBuilder2Test extends TestCase { |
| |
| private MarkupParser parser; |
| |
| private StringWriter out; |
| |
| private HtmlDocumentBuilder builder; |
| |
| private final Map<File, URL> fileToUrl = new HashMap<File, URL>(); |
| |
| @Override |
| public void setUp() { |
| parser = new MarkupParser(); |
| parser.setMarkupLanguage(new TextileLanguage()); |
| out = new StringWriter(); |
| builder = new HtmlDocumentBuilder(out) { |
| @Override |
| protected void checkFileReadable(File file) { |
| if (!fileToUrl.containsKey(file)) { |
| super.checkFileReadable(file); |
| } |
| } |
| |
| @Override |
| protected Reader getReader(File inputFile) throws FileNotFoundException { |
| URL url = fileToUrl.get(inputFile); |
| if (url != null) { |
| try { |
| return new InputStreamReader(url.openStream()); |
| } catch (IOException e) { |
| throw new FileNotFoundException(String.format("%s (%s)", inputFile, url)); |
| } |
| } |
| return super.getReader(inputFile); |
| } |
| }; |
| parser.setBuilder(builder); |
| } |
| |
| private void assertContainsPattern(String pattern) { |
| Pattern p = Pattern.compile(pattern); |
| String html = out.toString(); |
| |
| assertTrue(p.matcher(html).find()); |
| } |
| |
| public void testRelativeUrlWithBase() throws URISyntaxException { |
| builder.setBase(new URI("http://www.foo.bar/baz")); |
| parser.parse("\"An URL\":foo/bar.html"); |
| String html = out.toString(); |
| |
| assertTrue(html.contains("<a href=\"http://www.foo.bar/baz/foo/bar.html\">An URL</a>")); |
| } |
| |
| public void testAbsoluteUrlWithBase() throws URISyntaxException { |
| builder.setBase(new URI("http://www.foo.bar/baz")); |
| parser.parse("\"An URL\":http://www.baz.ca/foo/bar.html"); |
| String html = out.toString(); |
| |
| assertTrue(html.contains("<a href=\"http://www.baz.ca/foo/bar.html\">An URL</a>")); |
| } |
| |
| public void testRelativeUrlWithFileBase() throws URISyntaxException { |
| final File file = new File("/base/2/with space/"); |
| builder.setBase(file.toURI()); |
| parser.parse("\"An URL\":foo/bar.html"); |
| String html = out.toString(); |
| |
| Pattern pattern = Pattern.compile("<a href=\"file:(/[A-Z]{1}:)?/base/2/with%20space/foo/bar.html\">An URL</a>"); |
| assertTrue(pattern.matcher(html).find()); |
| } |
| |
| public void testHtmlFilenameFormat() throws URISyntaxException { |
| final File file = new File("/base/2/with space/"); |
| builder.setHtmlFilenameFormat("$1.html"); |
| builder.setBase(file.toURI()); |
| parser.parse("\"An URL\":foo.bar/bar"); |
| assertContainsPattern("<a href=\"file:(/[A-Z]{1}:)?/base/2/with%20space/foo.bar/bar.html\">An URL</a>"); |
| } |
| |
| public void testHtmlFilenameFormat_Image() throws URISyntaxException { |
| final File file = new File("/base/2/with space/"); |
| builder.setHtmlFilenameFormat("$1.html"); |
| builder.setBase(file.toURI()); |
| parser.parse("\"An URL\":foo.bar/bar.jpg"); |
| assertContainsPattern("<a href=\"file:(/[A-Z]{1}:)?/base/2/with%20space/foo.bar/bar.jpg\">An URL</a>"); |
| } |
| |
| public void testHtmlFilenameFormat_WithAnchor() throws URISyntaxException { |
| final File file = new File("/base/2/with space/"); |
| builder.setHtmlFilenameFormat("$1.html"); |
| builder.setBase(file.toURI()); |
| parser.parse("\"An URL\":foo/bar#bar"); |
| assertContainsPattern("<a href=\"file:(/[A-Z]{1}:)?/base/2/with%20space/foo/bar.html#bar\">An URL</a>"); |
| } |
| |
| public void testHtmlFilenameFormat_Internal() throws URISyntaxException { |
| builder.setHtmlFilenameFormat("$1.html"); |
| parser.parse("\"An URL\":#bar"); |
| assertContainsPattern("<a href=\"#bar\">An URL</a>"); |
| } |
| |
| public void testHtmlFilenameFormat_Directory() throws URISyntaxException { |
| builder.setHtmlFilenameFormat("$1.html"); |
| parser.parse("\"An URL\":one/two/"); |
| assertContainsPattern("<a href=\"one/two/\">An URL</a>"); |
| } |
| |
| public void testHtmlFilenameFormat_Absolute() throws URISyntaxException { |
| builder.setHtmlFilenameFormat("$1.html"); |
| parser.parse("\"An URL\":http://example.com/one/two"); |
| assertContainsPattern("<a href=\"http://example.com/one/two\">An URL</a>"); |
| } |
| |
| public void testHtmlLinkWithNullHref() { |
| //Bug 492302 |
| LinkAttributes attributes = new LinkAttributes(); |
| attributes.setId("lorem"); |
| builder.link(attributes, null, ""); |
| assertContainsPattern("<a id=\"lorem\"></a>"); |
| } |
| |
| public void testHtmlBeginSpanWithId() { |
| //Bug 492302 |
| LinkAttributes attributes = new LinkAttributes(); |
| attributes.setId("lorem"); |
| builder.beginSpan(SpanType.LINK, attributes); |
| builder.endSpan(); |
| assertContainsPattern("<a id=\"lorem\"></a>"); |
| } |
| |
| public void testSetHtmlFilenameFormat() { |
| builder.setHtmlFilenameFormat("$1.thtml"); |
| assertEquals("$1.thtml", builder.getHtmlFilenameFormat()); |
| |
| builder.setHtmlFilenameFormat(null); |
| assertNull(builder.getHtmlFilenameFormat()); |
| |
| try { |
| builder.setHtmlFilenameFormat("$.html"); |
| fail("expected exception"); |
| } catch (IllegalArgumentException e) { |
| assertNull(builder.getHtmlFilenameFormat()); |
| } |
| } |
| |
| public void testNoGratuitousWhitespace() { |
| builder.beginDocument(); |
| builder.beginBlock(BlockType.PARAGRAPH, new Attributes()); |
| builder.characters("some para text"); |
| builder.lineBreak(); |
| builder.characters("more para text"); |
| builder.endBlock(); |
| builder.beginBlock(BlockType.PARAGRAPH, new Attributes()); |
| builder.characters("second para"); |
| builder.endBlock(); |
| builder.endDocument(); |
| |
| String html = out.toString(); |
| |
| |
| |
| assertTrue(html.indexOf('\r') == -1); |
| assertTrue(html.indexOf('\n') == -1); |
| assertEquals( |
| "<?xml version='1.0' encoding='utf-8' ?><html xmlns=\"http://www.w3.org/1999/xhtml\"><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/></head><body><p>some para text<br/>more para text</p><p>second para</p></body></html>", |
| html); |
| } |
| |
| public void testCssStylesheetAsLink() { |
| builder.addCssStylesheet(new Stylesheet("styles/test.css")); |
| builder.beginDocument(); |
| builder.beginBlock(BlockType.PARAGRAPH, new Attributes()); |
| builder.characters("some para text"); |
| builder.endBlock(); |
| builder.endDocument(); |
| |
| String html = out.toString(); |
| |
| |
| assertTrue(html.contains("<head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/><link type=\"text/css\" rel=\"stylesheet\" href=\"styles/test.css\"/></head>")); |
| } |
| |
| public void testCssStylesheetEmbedded() throws Exception { |
| URL cssResource = HtmlDocumentBuilder2Test.class.getResource("resources/test.css"); |
| File cssFile = new File(cssResource.toURI().getPath()); |
| |
| fileToUrl.put(cssFile, cssResource); |
| |
| |
| |
| builder.addCssStylesheet(new Stylesheet(cssFile)); |
| builder.beginDocument(); |
| builder.beginBlock(BlockType.PARAGRAPH, new Attributes()); |
| builder.characters("some para text"); |
| builder.endBlock(); |
| builder.endDocument(); |
| |
| String html = out.toString(); |
| |
| |
| html = html.replace("
", ""); |
| |
| assertTrue(Pattern.compile( |
| "<head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/><style type=\"text/css\">\\s*body\\s+\\{\\s+background-image: test-content.png;\\s+\\}\\s*</style></head>", |
| Pattern.MULTILINE) |
| .matcher(html) |
| .find()); |
| } |
| |
| public void testDefaultTargetForExternalLinks() throws Exception { |
| builder.setDefaultAbsoluteLinkTarget("_external"); |
| builder.beginDocument(); |
| builder.beginBlock(BlockType.PARAGRAPH, new Attributes()); |
| builder.link("http://www.example.com", "test"); |
| builder.endBlock(); |
| builder.endDocument(); |
| |
| String html = out.toString(); |
| |
| |
| |
| assertTrue(html.contains("<a href=\"http://www.example.com\" target=\"_external\">test</a>")); |
| } |
| |
| public void testDefaultTargetForExternalLinks2() throws Exception { |
| builder.setBase(new URI("http://www.notexample.com")); |
| builder.setDefaultAbsoluteLinkTarget("_external"); |
| builder.beginDocument(); |
| builder.beginBlock(BlockType.PARAGRAPH, new Attributes()); |
| builder.link("http://www.example.com", "test"); |
| builder.endBlock(); |
| builder.endDocument(); |
| |
| String html = out.toString(); |
| |
| |
| |
| assertTrue(html.contains("<a href=\"http://www.example.com\" target=\"_external\">test</a>")); |
| } |
| |
| public void testDefaultTargetForInternalLinks() throws Exception { |
| builder.setDefaultAbsoluteLinkTarget("_external"); |
| builder.beginDocument(); |
| builder.beginBlock(BlockType.PARAGRAPH, new Attributes()); |
| builder.link("foo", "test"); |
| builder.endBlock(); |
| builder.endDocument(); |
| |
| String html = out.toString(); |
| |
| |
| |
| assertTrue(html.contains("<a href=\"foo\">test</a>")); |
| } |
| |
| public void testDefaultTargetForInternalLinks2() throws Exception { |
| builder.setBase(new URI("http://www.example.com/")); |
| builder.setDefaultAbsoluteLinkTarget("_external"); |
| builder.beginDocument(); |
| builder.beginBlock(BlockType.PARAGRAPH, new Attributes()); |
| builder.link("http://www.example.com/foo.html", "test"); |
| builder.endBlock(); |
| builder.endDocument(); |
| |
| String html = out.toString(); |
| |
| |
| |
| assertTrue(html.contains("<a href=\"http://www.example.com/foo.html\">test</a>")); |
| } |
| |
| public void testSuppressInlineStyles() throws Exception { |
| StringWriter out = new StringWriter(); |
| HtmlDocumentBuilder builder = new HtmlDocumentBuilder(out); |
| builder.setUseInlineStyles(false); |
| builder.beginDocument(); |
| builder.beginBlock(BlockType.NOTE, new Attributes()); |
| builder.beginBlock(BlockType.PARAGRAPH, new Attributes()); |
| builder.characters("foo"); |
| builder.endBlock(); |
| builder.endBlock(); |
| builder.endDocument(); |
| |
| String html = out.toString(); |
| |
| |
| |
| assertTrue(html.contains("<body><div class=\"note\"><p>foo</p></div></body>")); |
| assertTrue(html.contains("<style type=\"text/css\">")); |
| } |
| |
| public void testSuppressBuiltInlineStyles() throws Exception { |
| StringWriter out = new StringWriter(); |
| HtmlDocumentBuilder builder = new HtmlDocumentBuilder(out); |
| builder.setSuppressBuiltInStyles(true); |
| builder.beginDocument(); |
| builder.beginBlock(BlockType.NOTE, new Attributes()); |
| builder.beginBlock(BlockType.PARAGRAPH, new Attributes()); |
| builder.characters("foo"); |
| builder.endBlock(); |
| builder.endBlock(); |
| builder.endDocument(); |
| |
| String html = out.toString(); |
| |
| |
| |
| assertTrue(html.contains("<body><div class=\"note\"><p>foo</p></div></body>")); |
| assertTrue(!html.contains("<style type=\"text/css\">")); |
| } |
| |
| public void testLinkRel() throws Exception { |
| // link-specific rel |
| StringWriter out = new StringWriter(); |
| HtmlDocumentBuilder builder = new HtmlDocumentBuilder(out); |
| builder.beginDocument(); |
| builder.beginBlock(BlockType.PARAGRAPH, new Attributes()); |
| LinkAttributes attributes = new LinkAttributes(); |
| attributes.setRel("nofollow"); |
| builder.link(attributes, "http://www.foo.bar", "Foo Bar"); |
| builder.endBlock(); |
| builder.endDocument(); |
| |
| String html = out.toString(); |
| |
| |
| |
| assertTrue(html.contains("<a href=\"http://www.foo.bar\" rel=\"nofollow\">Foo Bar</a>")); |
| |
| // default link rel |
| out = new StringWriter(); |
| builder = new HtmlDocumentBuilder(out); |
| builder.setLinkRel("nofollow"); |
| builder.beginDocument(); |
| builder.beginBlock(BlockType.PARAGRAPH, new Attributes()); |
| attributes = new LinkAttributes(); |
| builder.link(attributes, "http://www.foo.bar", "Foo Bar"); |
| builder.endBlock(); |
| builder.endDocument(); |
| |
| html = out.toString(); |
| |
| |
| |
| assertTrue(html.contains("<a href=\"http://www.foo.bar\" rel=\"nofollow\">Foo Bar</a>")); |
| |
| // both link-specific and default link ref |
| out = new StringWriter(); |
| builder = new HtmlDocumentBuilder(out); |
| builder.setLinkRel("nofollow"); |
| builder.beginDocument(); |
| builder.beginBlock(BlockType.PARAGRAPH, new Attributes()); |
| attributes = new LinkAttributes(); |
| attributes.setRel("foobar"); |
| builder.link(attributes, "http://www.foo.bar", "Foo Bar"); |
| builder.endBlock(); |
| builder.endDocument(); |
| |
| html = out.toString(); |
| |
| |
| |
| assertTrue(html.contains("<a href=\"http://www.foo.bar\" rel=\"foobar nofollow\">Foo Bar</a>")); |
| |
| // no rel at all |
| out = new StringWriter(); |
| builder = new HtmlDocumentBuilder(out); |
| builder.beginDocument(); |
| builder.beginBlock(BlockType.PARAGRAPH, new Attributes()); |
| attributes = new LinkAttributes(); |
| builder.link(attributes, "http://www.foo.bar", "Foo Bar"); |
| builder.endBlock(); |
| builder.endDocument(); |
| |
| html = out.toString(); |
| |
| |
| |
| assertTrue(html.contains("<a href=\"http://www.foo.bar\">Foo Bar</a>")); |
| } |
| |
| public void testStylesheetWithAttributes() { |
| Stylesheet stylesheet = new Stylesheet("a/test.css"); |
| stylesheet.getAttributes().put("foo", "bar"); |
| builder.addCssStylesheet(stylesheet); |
| |
| builder.beginDocument(); |
| builder.endDocument(); |
| |
| String html = out.toString(); |
| |
| |
| |
| assertTrue(html.contains("<link type=\"text/css\" rel=\"stylesheet\" href=\"a/test.css\" foo=\"bar\"/>")); |
| } |
| |
| public void testStylesheetWithNoAttributes() { |
| builder.addCssStylesheet(new Stylesheet("a/test.css")); |
| |
| builder.beginDocument(); |
| builder.endDocument(); |
| |
| String html = out.toString(); |
| |
| |
| |
| assertTrue(html.contains("<link type=\"text/css\" rel=\"stylesheet\" href=\"a/test.css\"/>")); |
| } |
| |
| public void testFilterEntityReferences_FiltersKnown() { |
| builder.setFilterEntityReferences(true); |
| |
| doEntityReferenceTest("yen", "¥"); |
| } |
| |
| public void testFilterEntityReferences_DisabledFilter() { |
| doEntityReferenceTest("yen", "¥"); |
| } |
| |
| public void testFilterEntityReferences_FiltersUnknown() { |
| builder.setFilterEntityReferences(true); |
| |
| doEntityReferenceTest("unlikely", "&unlikely;"); |
| } |
| |
| private void doEntityReferenceTest(String entityReference, String expected) { |
| builder.beginDocument(); |
| builder.entityReference(entityReference); |
| builder.endDocument(); |
| |
| String html = out.toString(); |
| |
| |
| |
| assertTrue(html.contains(expected)); |
| } |
| } |