466649: Ampersands not escaped when emitting text as characters in Markdown

Change-Id: I69cc5c8bba57bbd3e5788d5f7fb2e1f332ff5cc8
Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=466649
Signed-off-by: Myles Feichtinger <myles.feichtinger@tasktop.com>
diff --git a/org.eclipse.mylyn.wikitext.markdown.core/src/org/eclipse/mylyn/internal/wikitext/markdown/core/MarkdownDocumentBuilder.java b/org.eclipse.mylyn.wikitext.markdown.core/src/org/eclipse/mylyn/internal/wikitext/markdown/core/MarkdownDocumentBuilder.java
index 8ae4498..3c4ca94 100644
--- a/org.eclipse.mylyn.wikitext.markdown.core/src/org/eclipse/mylyn/internal/wikitext/markdown/core/MarkdownDocumentBuilder.java
+++ b/org.eclipse.mylyn.wikitext.markdown.core/src/org/eclipse/mylyn/internal/wikitext/markdown/core/MarkdownDocumentBuilder.java
@@ -346,6 +346,7 @@
 
 	@Override
 	public void characters(String text) {
+		text = escapeAmpersand(text);
 		assertOpenBlock();
 		try {
 			currentBlock.write(text);
@@ -354,6 +355,10 @@
 		}
 	}
 
+	private String escapeAmpersand(String text) {
+		return text.replace("&","&amp;"); //$NON-NLS-1$ //$NON-NLS-2$
+	}
+
 	@Override
 	public void entityReference(String entity) {
 		assertOpenBlock();
diff --git a/org.eclipse.mylyn.wikitext.markdown.tests/src/org/eclipse/mylyn/internal/wikitext/markdown/tests/MarkdownRoundTripTest.java b/org.eclipse.mylyn.wikitext.markdown.tests/src/org/eclipse/mylyn/internal/wikitext/markdown/tests/MarkdownRoundTripTest.java
new file mode 100644
index 0000000..d6e1ef7
--- /dev/null
+++ b/org.eclipse.mylyn.wikitext.markdown.tests/src/org/eclipse/mylyn/internal/wikitext/markdown/tests/MarkdownRoundTripTest.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 David Green and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     David Green - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.wikitext.markdown.tests;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.StringWriter;
+
+import org.eclipse.mylyn.wikitext.core.parser.DocumentBuilder;
+import org.eclipse.mylyn.wikitext.core.parser.MarkupParser;
+import org.eclipse.mylyn.wikitext.core.parser.builder.HtmlDocumentBuilder;
+import org.eclipse.mylyn.wikitext.markdown.core.MarkdownLanguage;
+import org.junit.Test;
+
+public class MarkdownRoundTripTest {
+
+	private final MarkdownLanguage language = new MarkdownLanguage();
+
+	@Test
+	public void roundTripCharacterEscaping() {
+		assertCharactersRoundTrip("<p>abc</p>", "abc\n\n", "abc");
+		assertCharactersRoundTrip("<p>a&amp;b</p>", "a&amp;b\n\n", "a&b");
+		assertCharactersRoundTrip("<p>a&amp;amp;b</p>", "a&amp;amp;b\n\n", "a&amp;b");
+		assertCharactersRoundTrip("<p>a&amp;#160;b</p>", "a&amp;#160;b\n\n", "a&#160;b");
+	}
+
+	private void assertCharactersRoundTrip(String expectedHtml, String expectedMarkdown, String characters) {
+		String markdownContent = emitAsMarkdown(characters);
+		assertEquals(expectedMarkdown, markdownContent);
+
+		String html = parseMarkdownToHtml(markdownContent);
+		assertEquals(expectedHtml, html);
+	}
+
+	private String parseMarkdownToHtml(String markupContent) {
+		StringWriter htmlWriter = new StringWriter();
+		HtmlDocumentBuilder htmlDocumentBuilder = new HtmlDocumentBuilder(htmlWriter);
+		htmlDocumentBuilder.setEmitAsDocument(false);
+
+		MarkupParser markupParser = new MarkupParser(language, htmlDocumentBuilder);
+		markupParser.parse(markupContent);
+
+		return htmlWriter.toString();
+	}
+
+	private String emitAsMarkdown(String characters) {
+		StringWriter markupWriter = new StringWriter();
+		DocumentBuilder documentBuilder = language.createDocumentBuilder(markupWriter);
+
+		documentBuilder.characters(characters);
+		documentBuilder.flush();
+		return markupWriter.toString();
+	}
+}