/******************************************************************************* * 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("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" // + "<TaskRepositories OutputVersion=\"1\">" // + "<TaskRepository url=\"%s\" kind=\"%s\" %s=\"%s\"/>" // + "</TaskRepositories>", firstUrl, kind, labelPropertyKey, labelPropertyValue); private final String version1RepositoryXmlMultiple = String.format( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" // + "<TaskRepositories OutputVersion=\"1\">" // + "<TaskRepository url=\"%s\" kind=\"%s\" %s=\"%s\"/>" // + "<TaskRepository url=\"%s\" kind=\"%s\" %s=\"%s\"/>" // + "</TaskRepositories>", 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( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" // + "<TaskRepositories OutputVersion=\"1\">" // + "<TaskRepository url=\"%s\" kind=\"%s\" %s=\"%s\"/>" // + "</TaskRepositories>", escapeXml(escapeXml(urlCharacters)), escapeXml(escapeXml(kindCharacters)), labelPropertyKey, escapeXml(escapeXml(labelPropertyCharacters))); private final String version2RepositoryXml = String.format("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" // + "<TaskRepositories OutputVersion=\"2\">" // + "<TaskRepository url=\"%s\" kind=\"%s\"><Property key=\"%s\" value=\"%s\"/></TaskRepository>" // + "</TaskRepositories>" // , firstUrl, kind, labelPropertyKey, labelPropertyValue); private final String version2RepositoryXmlMultiple = String.format( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" // + "<TaskRepositories OutputVersion=\"2\">" // + "<TaskRepository url=\"%s\" kind=\"%s\"><Property key=\"%s\" value=\"%s\"/></TaskRepository>" // + "<TaskRepository url=\"%s\" kind=\"%s\"><Property key=\"%s\" value=\"%s\"/></TaskRepository>" // + "</TaskRepositories>", firstUrl, kind, labelPropertyKey, labelPropertyValue, secondUrl, kind, labelPropertyKey, labelPropertyValue); private final String version2RepositoryXmlSpecialCharacters = String.format( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" // + "<TaskRepositories OutputVersion=\"2\">" // + "<TaskRepository url=\"%s\" kind=\"%s\"><Property key=\"%s\" value=\"%s\"/></TaskRepository>" // + "</TaskRepositories>", escapeXml(escapeXml(urlCharacters)), escapeXml(escapeXml(kindCharacters)), escapeXml(labelPropertyKeyCharacters), escapeXml(labelPropertyCharacters)); private final String version1AndVersion2RepositoryXmlMultiple = String.format( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" // + "<TaskRepositories OutputVersion=\"2\">" // + "<TaskRepository url=\"%s\" kind=\"%s\" %s=\"%s\"><Property key=\"%s\" value=\"%s\"/></TaskRepository>" // + "<TaskRepository url=\"%s\" kind=\"%s\" %s=\"%s\"><Property key=\"%s\" value=\"%s\"/></TaskRepository>" // + "</TaskRepositories>", // 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<TaskRepository> expectedRepositories) throws SAXException, IOException { assertRead(xml, expectedRepositories, labelPropertyKey, labelPropertyValue); } private void assertRead(String xml, Set<TaskRepository> expectedRepositories, String labelPropertyKey, String labelPropertyValue) throws SAXException, IOException { parse(xml); Set<TaskRepository> 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<TaskRepository> 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); } }