// =====================================================================
//
// Copyright (C) 2012 - 2016, Philip Graf
//
// 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
//
// =====================================================================
package ch.acanda.eclipse.pmd.repository;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.getOnlyElement;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringReader;
import java.util.Arrays;
import javax.xml.XMLConstants;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.junit.Test;
import org.xml.sax.SAXException;
import ch.acanda.eclipse.pmd.domain.Location;
import ch.acanda.eclipse.pmd.domain.LocationContext;
import ch.acanda.eclipse.pmd.domain.ProjectModel;
import ch.acanda.eclipse.pmd.domain.RuleSetModel;
import com.google.common.base.Charsets;
import com.google.common.base.Predicate;
/**
* Unit tests for {@link ProjectModelSerializer}.
*
* @author Philip Graf
*/
public final class ProjectModelSerializerTest {
/**
* Verifies that {@link ProjectModelSerializer#serialize(ProjectModel)} serializes a {@link ProjectModel} correctly.
*/
@Test
public void serialize() throws SAXException, IOException {
final ProjectModel projectModel = new ProjectModel("TestProjectName");
projectModel.setPMDEnabled(true);
projectModel.setRuleSets(createRuleSets());
final String actual = new ProjectModelSerializer().serialize(projectModel);
final String expected = createXmlConfiguration();
assertEquals("Serialized project model", expected, actual);
assertValid(actual);
}
/**
* Verifies that {@link ProjectModelSerializer#serialize(ProjectModel)} serializes a {@link ProjectModel} without
* rule sets correctly, i.e. without a {@code <rulesets>} tag.
*/
@Test
public void serializeWithoutRuleSets() throws SAXException, IOException {
final ProjectModel projectModel = new ProjectModel("TestProjectName");
projectModel.setPMDEnabled(false);
final String actual = new ProjectModelSerializer().serialize(projectModel);
final String expected = createXmlConfigurationWithoutRuleSets();
assertEquals("Serialized project model", expected, actual);
assertValid(actual);
}
private String createXmlConfiguration() {
final String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<eclipse-pmd xmlns=\"http://acanda.ch/eclipse-pmd/0.8\""
+ " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
+ " xsi:schemaLocation=\"http://acanda.ch/eclipse-pmd/0.8 http://acanda.ch/eclipse-pmd/eclipse-pmd-0.8.xsd\">\n"
+ " <analysis enabled=\"true\" />\n"
+ " <rulesets>\n"
+ " <ruleset name=\"Project Rule Set\" ref=\"pmd.xml\" refcontext=\"project\" />\n"
+ " <ruleset name=\"Workspace Rule Set\" ref=\"Projext X/pmd.xml\" refcontext=\"workspace\" />\n"
+ " <ruleset name=\"Filesystem Rule Set\" ref=\"x:\\pmx.xml\" refcontext=\"filesystem\" />\n"
+ " <ruleset name=\"Remote Rule Set\" ref=\"http://example.org/pmd.xml\" refcontext=\"remote\" />\n"
+ " </rulesets>\n"
+ "</eclipse-pmd>";
return expected;
}
private String createXmlConfigurationWithoutRuleSets() {
final String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<eclipse-pmd xmlns=\"http://acanda.ch/eclipse-pmd/0.8\""
+ " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
+ " xsi:schemaLocation=\"http://acanda.ch/eclipse-pmd/0.8 http://acanda.ch/eclipse-pmd/eclipse-pmd-0.8.xsd\">\n"
+ " <analysis enabled=\"false\" />\n"
+ "</eclipse-pmd>";
return expected;
}
private Iterable<RuleSetModel> createRuleSets() {
return Arrays.asList(new RuleSetModel("Project Rule Set", new Location("pmd.xml", LocationContext.PROJECT)),
new RuleSetModel("Workspace Rule Set", new Location("Projext X/pmd.xml", LocationContext.WORKSPACE)),
new RuleSetModel("Filesystem Rule Set", new Location("x:\\pmx.xml", LocationContext.FILE_SYSTEM)),
new RuleSetModel("Remote Rule Set", new Location("http://example.org/pmd.xml", LocationContext.REMOTE)));
}
private void assertValid(final String actual) throws SAXException, IOException {
final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
final Source schemaSource = new StreamSource(ProjectModelSerializerTest.class.getResourceAsStream("eclipse-pmd-0.8.xsd"));
final Schema schema = schemaFactory.newSchema(schemaSource);
final Validator validator = schema.newValidator();
final Source xmlSource = new StreamSource(new StringReader(actual));
validator.validate(xmlSource);
}
/**
* Verifies that {@link ProjectModelSerializer#deserialize(java.io.InputStream, String)} deserializes the attributes
* of {@link ProjectModel} correctly.
*/
@Test
public void deserializeProjectModel() throws IOException {
final ByteArrayInputStream stream = new ByteArrayInputStream(createXmlConfiguration().getBytes(Charsets.UTF_8));
final ProjectModel projectModel = new ProjectModelSerializer().deserialize(stream, "TestProjectName");
assertEquals("Project name", "TestProjectName", projectModel.getProjectName());
assertTrue("PMD should be enabled", projectModel.isPMDEnabled());
assertEquals("Number of rule sets", 4, projectModel.getRuleSets().size());
}
/**
* Verifies that {@link ProjectModelSerializer#deserialize(java.io.InputStream, String)} deserializes the attributes
* of {@link ProjectModel} correctly.
*/
@Test
public void deserializeProjectModelWithoutRuleSets() throws IOException {
final ByteArrayInputStream stream = new ByteArrayInputStream(createXmlConfigurationWithoutRuleSets().getBytes(Charsets.UTF_8));
final ProjectModel projectModel = new ProjectModelSerializer().deserialize(stream, "TestProjectName");
assertEquals("Project name", "TestProjectName", projectModel.getProjectName());
assertFalse("PMD should be disabled", projectModel.isPMDEnabled());
assertEquals("Number of rule sets", 0, projectModel.getRuleSets().size());
}
/**
* Verifies that {@link ProjectModelSerializer#deserialize(java.io.InputStream, String)} deserializes the attributes
* of a project {@link RuleSetModel} correctly.
*/
@Test
public void deserializeProjectRuleSetModel() throws IOException {
final ByteArrayInputStream stream = new ByteArrayInputStream(createXmlConfiguration().getBytes(Charsets.UTF_8));
final ProjectModel projectModel = new ProjectModelSerializer().deserialize(stream, "TestProjectName");
assertRuleSetModel(projectModel, LocationContext.PROJECT, "Project Rule Set", "pmd.xml");
}
/**
* Verifies that {@link ProjectModelSerializer#deserialize(java.io.InputStream, String)} deserializes the attributes
* of a workspace {@link RuleSetModel} correctly.
*/
@Test
public void deserializeWorkspaceRuleSetModel() throws IOException {
final ByteArrayInputStream stream = new ByteArrayInputStream(createXmlConfiguration().getBytes(Charsets.UTF_8));
final ProjectModel projectModel = new ProjectModelSerializer().deserialize(stream, "TestProjectName");
assertRuleSetModel(projectModel, LocationContext.WORKSPACE, "Workspace Rule Set", "Projext X/pmd.xml");
}
/**
* Verifies that {@link ProjectModelSerializer#deserialize(java.io.InputStream, String)} deserializes the attributes
* of a filesystem {@link RuleSetModel} correctly.
*/
@Test
public void deserializeFilesystemRuleSetModel() throws IOException {
final ByteArrayInputStream stream = new ByteArrayInputStream(createXmlConfiguration().getBytes(Charsets.UTF_8));
final ProjectModel projectModel = new ProjectModelSerializer().deserialize(stream, "TestProjectName");
assertRuleSetModel(projectModel, LocationContext.FILE_SYSTEM, "Filesystem Rule Set", "x:\\pmx.xml");
}
/**
* Verifies that {@link ProjectModelSerializer#deserialize(java.io.InputStream, String)} deserializes the attributes
* of a remote {@link RuleSetModel} correctly.
*/
@Test
public void deserializeRemoteRuleSetModel() throws IOException {
final ByteArrayInputStream stream = new ByteArrayInputStream(createXmlConfiguration().getBytes(Charsets.UTF_8));
final ProjectModel projectModel = new ProjectModelSerializer().deserialize(stream, "TestProjectName");
assertRuleSetModel(projectModel, LocationContext.REMOTE, "Remote Rule Set", "http://example.org/pmd.xml");
}
private void assertRuleSetModel(final ProjectModel projectModel, final LocationContext context, final String name, final String path) {
final RuleSetModel remoteRuleSet = extractRuleSetModel(projectModel, context);
assertEquals("Name of the " + context + " rule set", name, remoteRuleSet.getName());
assertEquals("Path of the " + context + " rule set", path, remoteRuleSet.getLocation().getPath());
}
/**
* Extracts a rule set model from a project model depending on its location context. This method also verifies that
* only one rule set model with the provided location context exists ({@code getOnlyElement(...)} throws an
* {@code IllegalArgumentException} if there is more than one model with the provided location context).
*/
private RuleSetModel extractRuleSetModel(final ProjectModel model, final LocationContext context) {
return getOnlyElement(filter(model.getRuleSets(), new LocationContextFilter(context)));
}
private static final class LocationContextFilter implements Predicate<RuleSetModel> {
private final LocationContext context;
public LocationContextFilter(final LocationContext context) {
this.context = context;
}
@Override
public boolean apply(final RuleSetModel model) {
return model.getLocation().getContext() == context;
}
}
}