From fa141daf3c63f922b8997c67cccabe91b2978648 Mon Sep 17 00:00:00 2001 From: Jaxsun McCarthy Huggan Date: Fri, 17 Jul 2015 13:28:29 -0700 Subject: 472975: Mylyn escapes special characters before writing repository properties Change-Id: I8228411b427631b0e1ffd8f6bf6566e49af71098 Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=472975 Signed-off-by: Jaxsun McCarthy Huggan --- .../tasks/core/LegacySaxRepositoriesTest.java | 139 ++++++++++++ .../internal/tasks/core/SaxRepositoriesTest.java | 237 +++++++++++++++++++++ 2 files changed, 376 insertions(+) create mode 100644 org.eclipse.mylyn.tasks.core.tests/src/org/eclipse/mylyn/internal/tasks/core/LegacySaxRepositoriesTest.java create mode 100644 org.eclipse.mylyn.tasks.core.tests/src/org/eclipse/mylyn/internal/tasks/core/SaxRepositoriesTest.java (limited to 'org.eclipse.mylyn.tasks.core.tests') diff --git a/org.eclipse.mylyn.tasks.core.tests/src/org/eclipse/mylyn/internal/tasks/core/LegacySaxRepositoriesTest.java b/org.eclipse.mylyn.tasks.core.tests/src/org/eclipse/mylyn/internal/tasks/core/LegacySaxRepositoriesTest.java new file mode 100644 index 000000000..ecd98525b --- /dev/null +++ b/org.eclipse.mylyn.tasks.core.tests/src/org/eclipse/mylyn/internal/tasks/core/LegacySaxRepositoriesTest.java @@ -0,0 +1,139 @@ +/******************************************************************************* + * Copyright (c) 2016 Tasktop Technologies 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: + * Tasktop Technologies - initial API and implementation + *******************************************************************************/ + +package org.eclipse.mylyn.internal.tasks.core; + +import static org.junit.Assert.assertEquals; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.mylyn.tasks.core.TaskRepository; +import org.junit.Test; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; + +import com.google.common.collect.ImmutableSet; + +public class LegacySaxRepositoriesTest { + + private class SaxRepositoriesContentHandlerVersion1 extends DefaultHandler { + + private final Set taskRepositories = new HashSet(); + + @SuppressWarnings({ "deprecation", "restriction" }) + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { + try { + if (localName.equals(TaskRepositoriesExternalizer.ELEMENT_TASK_REPOSITORY) && attributes != null) { + String kind = org.eclipse.mylyn.internal.commons.core.XmlStringConverter + .convertXmlToString(attributes.getValue(IRepositoryConstants.PROPERTY_CONNECTOR_KIND)); + String url = org.eclipse.mylyn.internal.commons.core.XmlStringConverter + .convertXmlToString(attributes.getValue(IRepositoryConstants.PROPERTY_URL)); + if (kind != null && kind.length() > 0 && url != null && url.length() > 0) { + TaskRepository repository = new TaskRepository(kind, url); + for (int index = 0; index < attributes.getLength(); index++) { + String key = org.eclipse.mylyn.internal.commons.core.XmlStringConverter + .convertXmlToString(attributes.getLocalName(index)); + String value = org.eclipse.mylyn.internal.commons.core.XmlStringConverter + .convertXmlToString(attributes.getValue(index)); + repository.setProperty(key, value); + } + taskRepositories.add(repository); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + } + + public Set getRepositories() { + return taskRepositories; + } + } + + private static final String kind = "connector.kind"; + + private static final String firstUrl = "http://first.url"; + + private static final String secondUrl = "http://second.url"; + + private static final String labelPropertyValue = "test repository"; + + private static final String labelPropertyValueAlternate = "test repository alternate"; + + private static final String labelPropertyKey = "label"; + + private final String repositoryXmlVersion2 = String.format("" // + + "" // + + "" // + + "" // + + "", // + firstUrl, kind, labelPropertyKey, labelPropertyValue, labelPropertyKey, labelPropertyValueAlternate, + secondUrl, kind, labelPropertyKey, labelPropertyValue, labelPropertyKey, labelPropertyValueAlternate); + + @Test + public void version1ReaderCanReadVersion2Xml() throws Exception { + Set expectedRepositories = ImmutableSet.of( + createTestRepository(kind, firstUrl, labelPropertyKey, labelPropertyValue), + createTestRepository(kind, secondUrl, labelPropertyKey, labelPropertyValue)); + Set repositories = parseRepositoriesWithVersion1Parser(repositoryXmlVersion2); + assertEquals(expectedRepositories, repositories); + for (TaskRepository repository : repositories) { + assertEquals(labelPropertyValue, repository.getProperty(labelPropertyKey)); + } + } + + @Test + public void version1CanReadLatestOutput() throws Exception { + TaskRepository initialRepository = createTestRepository(kind, firstUrl, labelPropertyKey, labelPropertyValue); + String xml = writeToXmlWithCurrentVersion(ImmutableSet.of(initialRepository)); + Set parsed = parseRepositoriesWithVersion1Parser(xml); + assertEquals(1, parsed.size()); + TaskRepository parsedRepository = parsed.iterator().next(); + assertEquals(initialRepository, parsedRepository); + assertEquals(labelPropertyValue, parsedRepository.getProperty(labelPropertyKey)); + + } + + private String writeToXmlWithCurrentVersion(Set repositories) throws IOException { + ByteArrayOutputStream output = new ByteArrayOutputStream(1000 * repositories.size()); + SaxRepositoriesWriter writer = new SaxRepositoriesWriter(); + writer.setOutputStream(output); + writer.writeRepositoriesToStream(repositories); + return output.toString("UTF-8"); + } + + private Set parseRepositoriesWithVersion1Parser(String xml) throws Exception { + SaxRepositoriesContentHandlerVersion1 handler = new SaxRepositoriesContentHandlerVersion1(); + XMLReader reader = XmlReaderUtil.createXmlReader(); + reader.setContentHandler(handler); + reader.parse(new InputSource(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)))); + return handler.getRepositories(); + } + + private TaskRepository createTestRepository(String kind, String url, String labelPropertyKey, + String labelProperty) { + TaskRepository repository = new TaskRepository(kind, url); + repository.setProperty(labelPropertyKey, labelProperty); + return repository; + } + +} diff --git a/org.eclipse.mylyn.tasks.core.tests/src/org/eclipse/mylyn/internal/tasks/core/SaxRepositoriesTest.java b/org.eclipse.mylyn.tasks.core.tests/src/org/eclipse/mylyn/internal/tasks/core/SaxRepositoriesTest.java new file mode 100644 index 000000000..de9d60df8 --- /dev/null +++ b/org.eclipse.mylyn.tasks.core.tests/src/org/eclipse/mylyn/internal/tasks/core/SaxRepositoriesTest.java @@ -0,0 +1,237 @@ +/******************************************************************************* + * Copyright (c) 2015 Tasktop Technologies 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: + * Tasktop Technologies - initial API and implementation + *******************************************************************************/ + +package org.eclipse.mylyn.internal.tasks.core; + +import static org.eclipse.mylyn.internal.commons.core.XmlStringConverter.convertToXmlString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Set; + +import org.eclipse.mylyn.tasks.core.TaskRepository; +import org.junit.Before; +import org.junit.Test; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + +public class SaxRepositoriesTest { + + private static final String kind = "connector.kind"; + + private static final String kindCharacters = "connector.kind-`~!@#$%^&*()_+-=[{}]\\|'\";:/?.>,<"; + + private static final String firstUrl = "http://first.url"; + + private static final String secondUrl = "http://second.url"; + + private static final String urlCharacters = "http://some.url--`~!@#$%^&*()_+-=[{}]\\|'\";:/?.>,<"; + + private static final String labelPropertyValue = "test repository"; + + private static final String labelPropertyValueAlternate = "test repository alternate"; + + private static final String labelPropertyKey = "label"; + + private static final String labelPropertyCharacters = "`~!@#$%^&*()_+-=[{}]\\|'\";:/?.>,<"; + + private static final String labelPropertyKeyCharacters = "label-`~!@#$%^&*()_+-=[{}]\\|'\";:/?.>,<"; + + private SaxRepositoriesContentHandler handler; + + private final String version1RepositoryXml = String.format("" // + + "" // + + "" // + + "", firstUrl, kind, labelPropertyKey, labelPropertyValue); + + private final String version1RepositoryXmlMultiple = String.format( + "" // + + "" // + + "" // + + "" // + + "", + firstUrl, kind, labelPropertyKey, labelPropertyValue, secondUrl, kind, labelPropertyKey, + labelPropertyValue); + + /** + * The old xml is escaped twice: once by the xml library and once within mylyn + */ + private final String version1RepositoryXmlSpecialCharacters = String.format( + "" // + + "" // + + "" // + + "", + escapeXml(escapeXml(urlCharacters)), escapeXml(escapeXml(kindCharacters)), labelPropertyKey, + escapeXml(escapeXml(labelPropertyCharacters))); + + private final String version2RepositoryXml = String.format("" // + + "" // + + "" // + + "" // + , firstUrl, kind, labelPropertyKey, labelPropertyValue); + + private final String version2RepositoryXmlMultiple = String.format( + "" // + + "" // + + "" // + + "" // + + "", + firstUrl, kind, labelPropertyKey, labelPropertyValue, secondUrl, kind, labelPropertyKey, + labelPropertyValue); + + private final String version2RepositoryXmlSpecialCharacters = String.format( + "" // + + "" // + + "" // + + "", + escapeXml(escapeXml(urlCharacters)), escapeXml(escapeXml(kindCharacters)), + escapeXml(labelPropertyKeyCharacters), escapeXml(labelPropertyCharacters)); + + private final String version1AndVersion2RepositoryXmlMultiple = String.format( + "" // + + "" // + + "" // + + "" // + + "", // + firstUrl, kind, labelPropertyKey, labelPropertyValueAlternate, labelPropertyKey, labelPropertyValue, + secondUrl, kind, labelPropertyKey, labelPropertyValueAlternate, labelPropertyKey, labelPropertyValue); + + @Before + public void setUp() { + handler = new SaxRepositoriesContentHandler(); + } + + @Test + public void readVersion1() throws SAXException, IOException { + assertRead(version1RepositoryXml, Sets.newHashSet(createTestRepository(firstUrl))); + } + + @Test + public void readVersion1Multiple() throws SAXException, IOException { + assertRead(version1RepositoryXmlMultiple, + Sets.newHashSet(createTestRepository(firstUrl), createTestRepository(secondUrl))); + } + + @Test + public void readVersion1Characters() throws SAXException, IOException { + assertRead(version1RepositoryXmlSpecialCharacters, + Sets.newHashSet( + createTestRepository(kindCharacters, urlCharacters, labelPropertyKey, labelPropertyCharacters)), + labelPropertyKey, labelPropertyCharacters); + } + + @Test + public void readVersion2() throws SAXException, IOException { + assertRead(version2RepositoryXml, Sets.newHashSet(createTestRepository(firstUrl))); + } + + @Test + public void readVersion2Multiple() throws SAXException, IOException { + assertRead(version2RepositoryXmlMultiple, + Sets.newHashSet(createTestRepository(firstUrl), createTestRepository(secondUrl))); + } + + @Test + public void readVersion2Characters() throws SAXException, IOException { + assertRead( + version2RepositoryXmlSpecialCharacters, Sets.newHashSet(createTestRepository(kindCharacters, + urlCharacters, labelPropertyKeyCharacters, labelPropertyCharacters)), + labelPropertyKeyCharacters, labelPropertyCharacters); + } + + @Test + public void write() throws SAXException, IOException { + OutputStream output = new ByteArrayOutputStream(); + write(output, ImmutableList.of(createTestRepository(firstUrl))); + assertRead(output.toString(), Sets.newHashSet(createTestRepository(firstUrl))); + } + + @Test + public void writeMultiple() throws SAXException, IOException { + OutputStream output = new ByteArrayOutputStream(); + write(output, ImmutableList.of(createTestRepository(firstUrl), createTestRepository(secondUrl))); + assertRead(output.toString(), Sets.newHashSet(createTestRepository(firstUrl), createTestRepository(secondUrl))); + } + + @Test + public void readMixed() throws Exception { + assertRead(version1AndVersion2RepositoryXmlMultiple, + Sets.newHashSet(createTestRepository(firstUrl), createTestRepository(secondUrl))); + } + + @Test + public void writeMixedBadCharacters() throws Exception { + OutputStream output = new ByteArrayOutputStream(); + write(output, Lists + .newArrayList(createTestRepository(kind, firstUrl, labelPropertyKeyCharacters, labelPropertyValue))); + String serialized = output.toString(); + // the Mylyn escaping utility turns ' into apos, but this is not done during the actual serialization + assertTrue( + serialized.contains(("key=\"" + escapeXml(labelPropertyKeyCharacters) + "\"").replace("'", "'"))); + assertTrue(serialized.contains("value=\"" + escapeXml(labelPropertyValue) + "\"")); + // the property should have only been written once + assertEquals(serialized.lastIndexOf(labelPropertyValue), serialized.indexOf(labelPropertyValue)); + } + + private void assertRead(String xml, Set expectedRepositories) throws SAXException, IOException { + assertRead(xml, expectedRepositories, labelPropertyKey, labelPropertyValue); + } + + private void assertRead(String xml, Set expectedRepositories, String labelPropertyKey, + String labelPropertyValue) throws SAXException, IOException { + parse(xml); + Set repositories = handler.getRepositories(); + assertEquals(expectedRepositories, repositories); + for (TaskRepository repository : repositories) { + assertEquals(labelPropertyValue, repository.getProperty(labelPropertyKey)); + } + } + + private void parse(String xml) throws SAXException, IOException { + XMLReader reader = XmlReaderUtil.createXmlReader(); + reader.setContentHandler(handler); + reader.parse(new InputSource(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)))); + } + + private void write(OutputStream output, List repositories) throws IOException { + SaxRepositoriesWriter writer = new SaxRepositoriesWriter(); + writer.setOutputStream(output); + writer.writeRepositoriesToStream(repositories); + } + + private TaskRepository createTestRepository(String url) { + return createTestRepository(kind, url, labelPropertyKey, labelPropertyValue); + } + + private TaskRepository createTestRepository(String kind, String url, String labelPropertyKey, + String labelProperty) { + TaskRepository repository = new TaskRepository(kind, url); + repository.setProperty(labelPropertyKey, labelProperty); + return repository; + } + + @SuppressWarnings({ "restriction", "deprecation" }) + private String escapeXml(String stringToEscape) { + return convertToXmlString(stringToEscape); + } + +} -- cgit v1.2.3