forked from phoedos/pmd
Most of the work to extract module
Need a release of nice-xml-messages Need an update to pmd-test Need to add the 'ignored' attribute to schema
This commit is contained in:
parent
9d23d79802
commit
60139c8f4a
39
pmd-test-schema/pom.xml
Normal file
39
pmd-test-schema/pom.xml
Normal file
@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>pmd-test-schema</artifactId>
|
||||
<name>PMD Test Schema</name>
|
||||
<description>
|
||||
Parser for the XML test description format. The module has no dependency
|
||||
on junit or other test-only dependencies.
|
||||
</description>
|
||||
|
||||
<parent>
|
||||
<artifactId>pmd</artifactId>
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<version>6.46.0-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<java.version>8</java.version>
|
||||
</properties>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.oowekyala.ooxml</groupId>
|
||||
<artifactId>nice-xml-messages</artifactId>
|
||||
<version>2.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
||||
</project>
|
@ -0,0 +1,277 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.test.schema;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import net.sourceforge.pmd.Rule;
|
||||
import net.sourceforge.pmd.lang.LanguageRegistry;
|
||||
import net.sourceforge.pmd.lang.LanguageVersion;
|
||||
import net.sourceforge.pmd.properties.PropertyDescriptor;
|
||||
import net.sourceforge.pmd.properties.PropertySource;
|
||||
import net.sourceforge.pmd.test.schema.TestSchemaParser.PmdXmlReporter;
|
||||
|
||||
import com.github.oowekyala.ooxml.DomUtils;
|
||||
|
||||
/**
|
||||
* @author Clément Fournier
|
||||
*/
|
||||
class BaseTestParserImpl {
|
||||
|
||||
static class ParserV1 extends BaseTestParserImpl {
|
||||
|
||||
}
|
||||
|
||||
public TestCollection parseDocument(Rule rule, Document doc, PmdXmlReporter err) {
|
||||
Element root = doc.getDocumentElement();
|
||||
|
||||
Map<String, Element> codeFragments = parseCodeFragments(err, root);
|
||||
|
||||
Set<String> usedFragments = new HashSet<>();
|
||||
NodeList testCodes = root.getElementsByTagName("test-code");
|
||||
TestCollection result = new TestCollection();
|
||||
for (int i = 0; i < testCodes.getLength(); i++) {
|
||||
TestDescriptor descriptor = new TestDescriptor(i, rule.deepCopy());
|
||||
|
||||
PmdXmlReporter errScope = err.newScope();
|
||||
parseSingleTest((Element) testCodes.item(i), descriptor, codeFragments, usedFragments, errScope);
|
||||
if (!errScope.hasError()) {
|
||||
result.addTest(descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
codeFragments.keySet().removeAll(usedFragments);
|
||||
codeFragments.forEach((id, node) -> err.at(node).warn("Unused code fragment"));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Map<String, Element> parseCodeFragments(PmdXmlReporter err, Element root) {
|
||||
Map<String, Element> codeFragments = new HashMap<>();
|
||||
|
||||
for (Node node : DomUtils.asList(root.getElementsByTagName("code-fragment"))) {
|
||||
Attr id = getRequiredAttribute("id", (Element) node, err);
|
||||
if (id == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Element prev = codeFragments.put(id.getValue(), (Element) node);
|
||||
if (prev != null) {
|
||||
err.at(prev).error("Fragment with duplicate id ''{0}'' is ignored", id.getValue());
|
||||
}
|
||||
}
|
||||
return codeFragments;
|
||||
}
|
||||
|
||||
private void parseSingleTest(Element testCode, TestDescriptor descriptor, Map<String, Element> fragments, Set<String> usedFragments, PmdXmlReporter err) {
|
||||
{
|
||||
String description = getSingleChildText(testCode, "description", true, err);
|
||||
if (description == null) {
|
||||
return;
|
||||
}
|
||||
descriptor.setDescription(description);
|
||||
}
|
||||
|
||||
parseBoolAttribute(testCode, "reinitializeRule", true, err, "Attribute 'reinitializeRule' is deprecated and ignored, assumed true");
|
||||
parseBoolAttribute(testCode, "useAuxClasspath", true, err, "Attribute 'useAuxClasspath' is deprecated and ignored, assumed true");
|
||||
|
||||
boolean ignored = parseBoolAttribute(testCode, "ignored", false, err, null)
|
||||
&& !parseBoolAttribute(testCode, "regressionTest", true, err, "Attribute ''regressionTest'' is deprecated, use ''ignored'' with inverted value");
|
||||
|
||||
descriptor.setIgnored(ignored);
|
||||
|
||||
Properties properties = parseRuleProperties(testCode, descriptor.getRule(), err);
|
||||
descriptor.getProperties().putAll(properties);
|
||||
|
||||
parseExpectedProblems(testCode, descriptor, err);
|
||||
|
||||
String code = getTestCode(testCode, fragments, err);
|
||||
if (code == null) {
|
||||
return;
|
||||
}
|
||||
descriptor.setCode(code);
|
||||
|
||||
|
||||
LanguageVersion lversion = parseLanguageVersion(testCode, err);
|
||||
descriptor.setLanguageVersion(lversion);
|
||||
}
|
||||
|
||||
private void parseExpectedProblems(Element testCode, TestDescriptor descriptor, PmdXmlReporter err) {
|
||||
Node expectedProblemsNode = getSingleChild(testCode, "expected-problems", true, err);
|
||||
if (expectedProblemsNode == null) {
|
||||
return;
|
||||
}
|
||||
int expectedProblems = Integer.parseInt(parseTextNode(expectedProblemsNode));
|
||||
|
||||
List<String> expectedMessages = null;
|
||||
{
|
||||
Element messagesNode = getSingleChild(testCode, "expected-messages", false, err);
|
||||
if (messagesNode != null) {
|
||||
expectedMessages = new ArrayList<>();
|
||||
List<Node> messageNodes = DomUtils.asList(messagesNode.getElementsByTagName("message"));
|
||||
if (messageNodes.size() != expectedProblems) {
|
||||
err.at(expectedProblemsNode).error("Number of ''expected-messages'' ({0}) does not match", messageNodes.size());
|
||||
return;
|
||||
}
|
||||
|
||||
for (Node message : messageNodes) {
|
||||
expectedMessages.add(parseTextNode(message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<Integer> expectedLineNumbers = null;
|
||||
{
|
||||
Element lineNumbers = getSingleChild(testCode, "expected-linenumbers", false, err);
|
||||
if (lineNumbers != null) {
|
||||
expectedLineNumbers = new ArrayList<>();
|
||||
String[] linenos = parseTextNode(lineNumbers).split(",");
|
||||
if (linenos.length != expectedProblems) {
|
||||
err.at(expectedProblemsNode).error("Number of ''expected-linenumbers'' ({0}) does not match", linenos.length);
|
||||
return;
|
||||
}
|
||||
for (String num : linenos) {
|
||||
expectedLineNumbers.add(Integer.valueOf(num.trim()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
descriptor.recordExpectedViolations(
|
||||
expectedProblems,
|
||||
expectedLineNumbers,
|
||||
expectedMessages
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
private String getTestCode(Element testCode, Map<String, Element> fragments, PmdXmlReporter err) {
|
||||
String code = getSingleChildText(testCode, "code", false, err);
|
||||
if (code == null) {
|
||||
// Should have a coderef
|
||||
NodeList coderefs = testCode.getElementsByTagName("code-ref");
|
||||
if (coderefs.getLength() == 0) {
|
||||
throw new RuntimeException(
|
||||
"Required tag is missing from the test-xml. Supply either a code or a code-ref tag");
|
||||
}
|
||||
Element coderef = (Element) coderefs.item(0);
|
||||
Attr id = getRequiredAttribute("id", coderef, err);
|
||||
if (id == null) {
|
||||
return null;
|
||||
}
|
||||
Element fragment = fragments.get(id.getValue());
|
||||
if (fragment == null) {
|
||||
err.at(id).error("Unknown id, known IDs are {0}", fragments.keySet());
|
||||
return null;
|
||||
}
|
||||
code = parseTextNodeNoTrim(fragment);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
private LanguageVersion parseLanguageVersion(Element testCode, PmdXmlReporter err) {
|
||||
Node sourceTypeNode = getSingleChild(testCode, "source-type", false, err);
|
||||
if (sourceTypeNode == null) {
|
||||
return null;
|
||||
}
|
||||
String languageVersionString = parseTextNode(sourceTypeNode);
|
||||
LanguageVersion languageVersion = LanguageRegistry.findLanguageVersionByTerseName(languageVersionString);
|
||||
if (languageVersion != null) {
|
||||
return languageVersion;
|
||||
}
|
||||
|
||||
err.at(sourceTypeNode).error("Unknown language version ''{0}''", languageVersionString);
|
||||
return null;
|
||||
}
|
||||
|
||||
private Properties parseRuleProperties(Element testCode, PropertySource knownProps, PmdXmlReporter err) {
|
||||
Properties properties = new Properties();
|
||||
for (Node ruleProperty : DomUtils.asList(testCode.getElementsByTagName("rule-property"))) {
|
||||
Node nameAttr = getRequiredAttribute("name", (Element) ruleProperty, err);
|
||||
if (nameAttr == null) {
|
||||
continue;
|
||||
}
|
||||
String propertyName = nameAttr.getNodeValue();
|
||||
if (knownProps.getPropertyDescriptor(propertyName) == null) {
|
||||
Stream<String> knownNames = knownProps.getPropertyDescriptors().stream().map(PropertyDescriptor::name);
|
||||
err.at(nameAttr).error("Unknown property, known property names are {0}", knownNames);
|
||||
continue;
|
||||
}
|
||||
properties.setProperty(propertyName, parseTextNode(ruleProperty));
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
private Attr getRequiredAttribute(String name, Element ruleProperty, PmdXmlReporter err) {
|
||||
Attr nameAttr = (Attr) ruleProperty.getAttributes().getNamedItem(name);
|
||||
if (nameAttr == null) {
|
||||
err.at(ruleProperty).error("Missing ''{0}'' attribute", name);
|
||||
return null;
|
||||
}
|
||||
return nameAttr;
|
||||
}
|
||||
|
||||
private boolean parseBoolAttribute(Element testCode, String attrName, boolean defaultValue, PmdXmlReporter err, String deprecationMessage) {
|
||||
Attr attrNode = testCode.getAttributeNode(attrName);
|
||||
if (attrNode != null) {
|
||||
if (deprecationMessage != null) {
|
||||
err.at(attrNode).warn(deprecationMessage);
|
||||
}
|
||||
return Boolean.parseBoolean(attrNode.getNodeValue());
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
|
||||
private String getSingleChildText(Element parentElm, String nodeName, boolean required, PmdXmlReporter err) {
|
||||
Node node = getSingleChild(parentElm, nodeName, required, err);
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
return parseTextNode(node);
|
||||
}
|
||||
|
||||
private Element getSingleChild(Element parentElm, String nodeName, boolean required, PmdXmlReporter err) {
|
||||
NodeList nodes = parentElm.getElementsByTagName(nodeName);
|
||||
if (nodes.getLength() == 0) {
|
||||
if (required) {
|
||||
err.at(parentElm).error("Required child ''{0}'' is missing", nodeName);
|
||||
}
|
||||
return null;
|
||||
} else if (nodes.getLength() > 1) {
|
||||
err.at(nodes.item(1)).error("Duplicate tag ''{0}'' is ignored", nodeName);
|
||||
}
|
||||
return (Element) nodes.item(0);
|
||||
}
|
||||
|
||||
private static String parseTextNode(Node exampleNode) {
|
||||
return parseTextNodeNoTrim(exampleNode).trim();
|
||||
}
|
||||
|
||||
private static String parseTextNodeNoTrim(Node exampleNode) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
for (int i = 0; i < exampleNode.getChildNodes().getLength(); i++) {
|
||||
Node node = exampleNode.getChildNodes().item(i);
|
||||
if (node.getNodeType() == Node.CDATA_SECTION_NODE || node.getNodeType() == Node.TEXT_NODE) {
|
||||
buffer.append(node.getNodeValue());
|
||||
}
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.test.schema;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author Clément Fournier
|
||||
*/
|
||||
public class TestCollection {
|
||||
|
||||
private List<TestDescriptor> tests;
|
||||
|
||||
|
||||
public void addTest(TestDescriptor descriptor) {
|
||||
tests.add(Objects.requireNonNull(descriptor));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.test.schema;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.sourceforge.pmd.Rule;
|
||||
import net.sourceforge.pmd.lang.LanguageVersion;
|
||||
|
||||
/**
|
||||
* @author Clément Fournier
|
||||
*/
|
||||
public class TestDescriptor {
|
||||
|
||||
private boolean ignored;
|
||||
private String description;
|
||||
private LanguageVersion languageVersion;
|
||||
private Properties properties = new Properties();
|
||||
private int index;
|
||||
private final Rule rule;
|
||||
private String code;
|
||||
private int expectedProblems;
|
||||
private List<Integer> expectedLineNumbers;
|
||||
private List<String> expectedMessages;
|
||||
|
||||
public TestDescriptor(int index, Rule rule) {
|
||||
this.index = index;
|
||||
this.rule = rule;
|
||||
}
|
||||
|
||||
public Rule getRule() {
|
||||
return rule;
|
||||
}
|
||||
|
||||
public Properties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public boolean isIgnored() {
|
||||
return ignored;
|
||||
}
|
||||
|
||||
public void setIgnored(boolean ignored) {
|
||||
this.ignored = ignored;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public LanguageVersion getLanguageVersion() {
|
||||
return languageVersion;
|
||||
}
|
||||
|
||||
public void setLanguageVersion(LanguageVersion languageVersion) {
|
||||
this.languageVersion = languageVersion;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public void recordExpectedViolations(int expectedProblems, List<Integer> expectedLineNumbers, List<String> expectedMessages) {
|
||||
this.expectedProblems = expectedProblems;
|
||||
this.expectedLineNumbers = expectedLineNumbers;
|
||||
this.expectedMessages = expectedMessages;
|
||||
}
|
||||
}
|
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.test.schema;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.function.Consumer;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import net.sourceforge.pmd.Rule;
|
||||
import net.sourceforge.pmd.annotation.Experimental;
|
||||
|
||||
import com.github.oowekyala.ooxml.messages.NiceXmlMessageSpec;
|
||||
import com.github.oowekyala.ooxml.messages.OoxmlFacade;
|
||||
import com.github.oowekyala.ooxml.messages.PositionedXmlDoc;
|
||||
import com.github.oowekyala.ooxml.messages.XmlException;
|
||||
import com.github.oowekyala.ooxml.messages.XmlMessageReporter;
|
||||
import com.github.oowekyala.ooxml.messages.XmlMessageReporterBase;
|
||||
import com.github.oowekyala.ooxml.messages.XmlPosition;
|
||||
import com.github.oowekyala.ooxml.messages.XmlPositioner;
|
||||
import com.github.oowekyala.ooxml.messages.XmlSeverity;
|
||||
|
||||
|
||||
/**
|
||||
* Entry point to parse a test file.
|
||||
*
|
||||
* @author Clément Fournier
|
||||
*/
|
||||
@Experimental
|
||||
public class TestSchemaParser {
|
||||
|
||||
private final TestSchemaVersion version;
|
||||
|
||||
public TestSchemaParser(TestSchemaVersion version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry point to parse a test file.
|
||||
*
|
||||
* @param rule Rule which owns the tests
|
||||
* @param inputSource Where to access the test file to parse
|
||||
*
|
||||
* @return A test collection, possibly incomplete
|
||||
*
|
||||
* @throws IOException If parsing throws this
|
||||
* @throws XmlException If parsing throws this
|
||||
*/
|
||||
public TestCollection parse(Rule rule, InputSource inputSource) throws IOException, XmlException {
|
||||
OoxmlFacade ooxml = new OoxmlFacade();
|
||||
PositionedXmlDoc doc = ooxml.parse(newDocumentBuilder(), inputSource);
|
||||
|
||||
try (PmdXmlReporterImpl err = new PmdXmlReporterImpl(ooxml, doc.getPositioner())) {
|
||||
TestCollection collection = version.getParserImpl().parseDocument(rule, doc.getDocument(), err);
|
||||
if (err.hasError()) {
|
||||
// todo maybe add a way not to throw here
|
||||
throw new IllegalStateException("Errors were encountered while parsing XML tests");
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
}
|
||||
|
||||
interface PmdXmlReporter extends XmlMessageReporter<Reporter> {
|
||||
|
||||
boolean hasError();
|
||||
|
||||
PmdXmlReporter newScope();
|
||||
}
|
||||
|
||||
private static class PmdXmlReporterImpl
|
||||
extends XmlMessageReporterBase<Reporter>
|
||||
implements PmdXmlReporter {
|
||||
|
||||
private boolean hasError;
|
||||
|
||||
protected PmdXmlReporterImpl(OoxmlFacade ooxml,
|
||||
XmlPositioner positioner) {
|
||||
super(ooxml, positioner);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Reporter create2ndStage(XmlPosition position, XmlPositioner positioner, Consumer<XmlException> handleEx) {
|
||||
return new Reporter(position, positioner, ooxml, handleEx.andThen(this::consumeEx));
|
||||
}
|
||||
|
||||
protected void consumeEx(XmlException e) {
|
||||
hasError |= e.getSeverity() == XmlSeverity.ERROR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PmdXmlReporter newScope() {
|
||||
return new PmdXmlReporterImpl(ooxml, positioner) {
|
||||
@Override
|
||||
protected void consumeEx(XmlException e) {
|
||||
super.consumeEx(e);
|
||||
PmdXmlReporterImpl.this.consumeEx(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasError() {
|
||||
return hasError;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
}
|
||||
|
||||
private DocumentBuilder newDocumentBuilder() {
|
||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
try {
|
||||
dbf.setSchema(version.getSchema());
|
||||
dbf.setNamespaceAware(true);
|
||||
return dbf.newDocumentBuilder();
|
||||
} catch (ParserConfigurationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class Reporter {
|
||||
|
||||
private final XmlPosition position;
|
||||
private final XmlPositioner positioner;
|
||||
private final OoxmlFacade ooxml;
|
||||
|
||||
private final Consumer<XmlException> handler;
|
||||
|
||||
private Reporter(XmlPosition position, XmlPositioner positioner, OoxmlFacade ooxml, Consumer<XmlException> handler) {
|
||||
this.position = position;
|
||||
this.positioner = positioner;
|
||||
this.ooxml = ooxml;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
public void warn(String messageFormat, Object... args) {
|
||||
reportImpl(XmlSeverity.WARNING, MessageFormat.format(messageFormat, args));
|
||||
|
||||
}
|
||||
|
||||
public void error(String messageFormat, Object... args) {
|
||||
reportImpl(XmlSeverity.ERROR, MessageFormat.format(messageFormat, args));
|
||||
}
|
||||
|
||||
private void reportImpl(XmlSeverity severity, String formattedMessage) {
|
||||
NiceXmlMessageSpec spec =
|
||||
new NiceXmlMessageSpec(position, formattedMessage)
|
||||
.withSeverity(severity);
|
||||
String fullMessage = ooxml.getFormatter().formatSpec(ooxml, spec, positioner);
|
||||
XmlException ex = new XmlException(spec, fullMessage);
|
||||
handler.accept(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.test.schema;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Objects;
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.validation.Schema;
|
||||
import javax.xml.validation.SchemaFactory;
|
||||
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* @author Clément Fournier
|
||||
*/
|
||||
public enum TestSchemaVersion {
|
||||
V1("rule-tests_1_0_0.xsd", new BaseTestParserImpl.ParserV1());
|
||||
|
||||
private final Schema schema;
|
||||
private String schemaLoc;
|
||||
private BaseTestParserImpl parser;
|
||||
|
||||
TestSchemaVersion(String schemaLoc, BaseTestParserImpl parser) {
|
||||
this.schemaLoc = schemaLoc;
|
||||
this.parser = parser;
|
||||
this.schema = parseSchema();
|
||||
}
|
||||
|
||||
BaseTestParserImpl getParserImpl() {
|
||||
return parser;
|
||||
}
|
||||
|
||||
public Schema getSchema() {
|
||||
return schema;
|
||||
}
|
||||
|
||||
private Schema parseSchema() {
|
||||
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
|
||||
try {
|
||||
return schemaFactory.newSchema(locateSchema());
|
||||
} catch (SAXException e) {
|
||||
throw new RuntimeException("Cannot parse schema " + this, e);
|
||||
}
|
||||
}
|
||||
|
||||
private URL locateSchema() {
|
||||
URL resource = TestSchemaVersion.class.getResource(schemaLoc);
|
||||
return Objects.requireNonNull(resource, "Cannot find schema location " + schemaLoc);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
/**
|
||||
* Contains a parser for the XML test format.
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.test.schema;
|
@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<schema
|
||||
xmlns="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://pmd.sourceforge.net/rule-tests"
|
||||
xmlns:tns="http://pmd.sourceforge.net/rule-tests"
|
||||
elementFormDefault="qualified">
|
||||
|
||||
<element name="test-data">
|
||||
<complexType>
|
||||
<group ref="tns:testCodeOrCodeFragment" minOccurs="1" maxOccurs="unbounded"/>
|
||||
</complexType>
|
||||
</element>
|
||||
|
||||
<group name="testCodeOrCodeFragment">
|
||||
<sequence>
|
||||
<element name="test-code" minOccurs="0" maxOccurs="unbounded" type="tns:testCodeType"/>
|
||||
<element name="code-fragment" minOccurs="0" maxOccurs="unbounded" type="tns:codeFragmentType"/>
|
||||
</sequence>
|
||||
</group>
|
||||
|
||||
<complexType name="testCodeType">
|
||||
<sequence>
|
||||
<element name="description" type="string"/>
|
||||
<element name="rule-property" minOccurs="0" maxOccurs="unbounded">
|
||||
<complexType>
|
||||
<simpleContent>
|
||||
<extension base="string">
|
||||
<attribute name="name" type="string" use="required"/>
|
||||
</extension>
|
||||
</simpleContent>
|
||||
</complexType>
|
||||
</element>
|
||||
<element name="expected-problems" type="integer"/>
|
||||
<element name="expected-linenumbers" type="string" minOccurs="0"/>
|
||||
<element name="expected-messages" minOccurs="0">
|
||||
<complexType>
|
||||
<sequence>
|
||||
<element name="message" type="string" maxOccurs="unbounded"/>
|
||||
</sequence>
|
||||
</complexType>
|
||||
</element>
|
||||
<choice>
|
||||
<element name="code"/>
|
||||
<element name="code-ref">
|
||||
<complexType>
|
||||
<attribute name="id" type="IDREF" use="required"/>
|
||||
</complexType>
|
||||
</element>
|
||||
</choice>
|
||||
<element name="source-type" minOccurs="0" default="java" type="string"/>
|
||||
</sequence>
|
||||
<attribute name="reinitializeRule" type="boolean" default="true"/>
|
||||
<attribute name="regressionTest" type="boolean" default="true"/>
|
||||
<attribute name="useAuxClasspath" type="boolean" default="true"/>
|
||||
</complexType>
|
||||
|
||||
<complexType name="codeFragmentType">
|
||||
<simpleContent>
|
||||
<extension base="string">
|
||||
<attribute name="id" type="ID" use="required"/>
|
||||
</extension>
|
||||
</simpleContent>
|
||||
</complexType>
|
||||
</schema>
|
@ -12,6 +12,10 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<java.version>8</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!--
|
||||
hamcrest and junit are scope compile,
|
||||
|
Loading…
x
Reference in New Issue
Block a user