Merge branch 'master' into pmd/7.0.x

This commit is contained in:
Andreas Dangel
2022-07-23 20:01:58 +02:00
19 changed files with 263 additions and 188 deletions

View File

@ -43,11 +43,11 @@ GEM
faraday-em_http (1.0.0)
faraday-em_synchrony (1.0.0)
faraday-excon (1.1.0)
faraday-http-cache (2.2.0)
faraday-http-cache (2.4.0)
faraday (>= 0.8)
faraday-httpclient (1.0.1)
faraday-multipart (1.0.3)
multipart-post (>= 1.2, < 3)
faraday-multipart (1.0.4)
multipart-post (~> 2)
faraday-net_http (1.0.1)
faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0)
@ -65,15 +65,15 @@ GEM
liquid (5.3.0)
logger-colors (1.0.0)
mini_portile2 (2.8.0)
multipart-post (2.1.1)
multipart-post (2.2.3)
nap (1.1.0)
no_proxy_fix (0.1.2)
nokogiri (1.13.6)
nokogiri (1.13.7)
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
octokit (4.22.0)
faraday (>= 0.9)
sawyer (~> 0.8.0, >= 0.5.3)
octokit (4.25.1)
faraday (>= 1, < 3)
sawyer (~> 0.9)
open4 (1.3.4)
pmdtester (1.5.1)
differ (~> 0.1)
@ -87,20 +87,20 @@ GEM
racc (1.6.0)
rchardet (1.8.0)
rexml (3.2.5)
rouge (3.28.0)
rouge (3.29.0)
ruby2_keywords (0.0.5)
rufus-scheduler (3.8.1)
rufus-scheduler (3.8.2)
fugit (~> 1.1, >= 1.1.6)
safe_yaml (1.0.5)
sawyer (0.8.2)
sawyer (0.9.2)
addressable (>= 2.3.5)
faraday (> 0.8, < 2.0)
faraday (>= 0.17.3, < 3)
slop (4.9.2)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
tzinfo (2.0.4)
tzinfo (2.0.5)
concurrent-ruby (~> 1.0)
unicode-display_width (2.1.0)
unicode-display_width (2.2.0)
PLATFORMS
ruby

View File

@ -1,7 +1,7 @@
GEM
remote: https://rubygems.org/
specs:
activesupport (6.0.5)
activesupport (6.0.5.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
@ -14,7 +14,7 @@ GEM
execjs
coffee-script-source (1.11.1)
colorator (1.1.0)
commonmarker (0.23.4)
commonmarker (0.23.5)
concurrent-ruby (1.1.10)
dnsruby (1.61.9)
simpleidn (~> 0.1)
@ -25,33 +25,14 @@ GEM
ffi (>= 1.15.0)
eventmachine (1.2.7)
execjs (2.8.1)
faraday (1.10.0)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
faraday-httpclient (~> 1.0)
faraday-multipart (~> 1.0)
faraday-net_http (~> 1.0)
faraday-net_http_persistent (~> 1.0)
faraday-patron (~> 1.0)
faraday-rack (~> 1.0)
faraday-retry (~> 1.0)
faraday (2.3.0)
faraday-net_http (~> 2.0)
ruby2_keywords (>= 0.0.4)
faraday-em_http (1.0.0)
faraday-em_synchrony (1.0.0)
faraday-excon (1.1.0)
faraday-httpclient (1.0.1)
faraday-multipart (1.0.3)
multipart-post (>= 1.2, < 3)
faraday-net_http (1.0.1)
faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0)
faraday-rack (1.0.0)
faraday-retry (1.0.3)
faraday-net_http (2.0.3)
ffi (1.15.5)
forwardable-extended (2.6.0)
gemoji (3.0.1)
github-pages (226)
github-pages (227)
github-pages-health-check (= 1.17.9)
jekyll (= 3.9.2)
jekyll-avatar (= 0.7.0)
@ -93,7 +74,7 @@ GEM
liquid (= 4.0.3)
mercenary (~> 0.3)
minima (= 2.5.1)
nokogiri (>= 1.13.4, < 2.0)
nokogiri (>= 1.13.6, < 2.0)
rouge (= 3.26.0)
terminal-table (~> 1.4)
github-pages-health-check (1.17.9)
@ -102,7 +83,7 @@ GEM
octokit (~> 4.0)
public_suffix (>= 3.0, < 5.0)
typhoeus (~> 1.3)
html-pipeline (2.14.1)
html-pipeline (2.14.2)
activesupport (>= 2)
nokogiri (>= 1.4)
http_parser.rb (0.8.0)
@ -230,14 +211,13 @@ GEM
jekyll (>= 3.5, < 5.0)
jekyll-feed (~> 0.9)
jekyll-seo-tag (~> 2.1)
minitest (5.15.0)
multipart-post (2.1.1)
nokogiri (1.13.6)
minitest (5.16.2)
nokogiri (1.13.7)
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
octokit (4.22.0)
faraday (>= 0.9)
sawyer (~> 0.8.0, >= 0.5.3)
octokit (4.25.1)
faraday (>= 1, < 3)
sawyer (~> 0.9)
pathutil (0.16.2)
forwardable-extended (~> 2.6)
public_suffix (4.0.7)
@ -255,9 +235,9 @@ GEM
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
sawyer (0.8.2)
sawyer (0.9.2)
addressable (>= 2.3.5)
faraday (> 0.8, < 2.0)
faraday (>= 0.17.3, < 3)
simpleidn (0.2.1)
unf (~> 0.1.4)
terminal-table (1.8.0)
@ -265,13 +245,13 @@ GEM
thread_safe (0.3.6)
typhoeus (1.4.0)
ethon (>= 0.9.0)
tzinfo (1.2.9)
tzinfo (1.2.10)
thread_safe (~> 0.1)
unf (0.1.4)
unf_ext
unf_ext (0.0.8.1)
unf_ext (0.0.8.2)
unicode-display_width (1.8.0)
zeitwerk (2.5.4)
zeitwerk (2.6.0)
PLATFORMS
ruby

View File

@ -102,7 +102,7 @@ class JDocNamespaceDeclaration < Liquid::Tag
RESERVED_NSPACES = ['apex', 'core', 'cpp', 'cs', 'dart', 'dist', 'doc', 'fortran', 'go', 'groovy', 'java',
'javascript', 'jsp',
'kotlin', 'lua', 'matlab', 'objectivec', 'perl', 'php', 'plsql', 'python', 'ruby', 'scala', 'swift',
'test', 'ui',
'test', 'test-schema', 'ui',
'modelica', 'visualforce', 'vm', 'xml'].flat_map {|m| [m, "pmd-" + m]}
def self.make_base_namespaces

View File

@ -135,14 +135,18 @@ between different test cases.
The `<test-code>` elements understands the following optional attributes:
* **reinitializeRule**: By default, it's `true`, so each test case starts with a fresh instantiated rule. Set it
to `false` to reproduce cases, where the previous run has influences.
* **disabled**: By default, it's `false`. Set it to `true`, to ignore and skip a test case.
* **disabled**: By default, it's `false`. Set ti to `true`, to ignore and skip a test case.
* **focused**: By default, it's `false`. Set it to `true`, to ignore all other test cases.
* **useAuxClasspath**: By default, it's `true`. Set it to `false` to reproduce issues which only
* **useAuxClasspath**: _deprecated since PMD 6.48.0: assumed true, has no effect anymore._
By default, it's `true`. Set it to `false` to reproduce issues which only
appear without type resolution.
* **reinitializeRule**: _deprecated since PMD 6.48.0: assumed true, has no effect anymore._
By default, it's `true`, so each test case starts with a fresh instantiated rule. Set it
to `false` to reproduce cases, where the previous run has influences.
* **regressionTest**: _deprecated since PMD 6.48.0: Use `disabled` instead. Note: It has the opposite boolean
semantic._ By default, it's `true`. Set it to `false`, to ignore and skip a test case.

View File

@ -59,6 +59,7 @@ Being based on a proper Antlr grammar, CPD can:
* java-performance
* [#3625](https://github.com/pmd/pmd/issues/3625): \[java] AddEmptyString - false negative with empty var
* test
* [#3302](https://github.com/pmd/pmd/pull/3302): \[test] Improve xml test schema
* [#3758](https://github.com/pmd/pmd/issues/3758): \[test] Move pmd-test to java 8
* [#3976](https://github.com/pmd/pmd/pull/3976): \[test] Extract xml schema module
@ -70,8 +71,12 @@ Being based on a proper Antlr grammar, CPD can:
this module for testing your own custom rules, you'll need to make sure to use at least Java 8.
* The new module "pmd-test-schema" contains now the XSD schema and the code to parse the rule test XML files. The
schema has been extracted in order to easily share it with other tools like the Rule Designer or IDE plugins.
* The attribute `isRegressionTest` is deprecated and the new attribute `disabled` should be used instead for
defining whether a rule test should be skipped or not.
* Test schema changes:
* The attribute `isRegressionTest` of `test-code` is deprecated. The new
attribute `disabled` should be used instead for defining whether a rule test should be skipped or not.
* The attributes `reinitializeRule` and `useAuxClasspath` of `test-code` are deprecated and assumed true.
They will not be replaced.
* The new attribute `focused` of `test-code` allows disabling all tests except the focused one temporarily.
* More information about the rule test framework can be found in the documentation:
[Testing your rules](pmd_userdocs_extending_testing.html)
@ -82,6 +87,8 @@ Being based on a proper Antlr grammar, CPD can:
but it is no longer supported with Java 19 Preview.
* The interface {% jdoc core::cpd.renderer.CPDRenderer %} is deprecated. For custom CPD renderers
the new interface {% jdoc core::cpd.renderer.CPDReportRenderer %} should be used.
* The class {% jdoc test::testframework.TestDescriptor %} is deprecated, replaced with {% jdoc test-schema::testframework.RuleTestDescriptor %}.
* Many methods of {% jdoc test::testframework.RuleTst %} have been deprecated as internal API.
#### Experimental APIs

View File

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<test-data
xmlns="http://pmd.sourceforge.net/rule-tests"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd">
<test-code>
<description><![CDATA[
XPath should match Foo
]]></description>
<expected-problems>1</expected-problems>
<code><![CDATA[
public class Foo {}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
XPath should not match Bar
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Bar {}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
XPath should match Flo
]]></description>
<expected-problems>1</expected-problems>
<code><![CDATA[
public class Flo {}
]]></code>
</test-code>
</test-data>

View File

@ -150,7 +150,8 @@ public class TournamentTest extends TestCase {
]]></code>
</test-code>
<test-code useAuxClasspath="false">
<!-- it's not possible anymore to test without auxclasspath. junit4 is always on the test auxclasspath -->
<test-code disabled="true">
<description>JUnit 4 test detection without proper auxclasspath</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>7</expected-linenumbers>

View File

@ -149,7 +149,7 @@ public class Test {
<code-ref id="constructor-violation"/>
</test-code>
<test-code reinitializeRule="true">
<test-code>
<description>#985 Suppressed methods shouldn't affect avg CyclomaticComplexity</description>
<rule-property name="methodReportLevel">2</rule-property>
<expected-problems>0</expected-problems>

View File

@ -298,7 +298,7 @@ public class Foo {
]]></code>
</test-code>
<test-code reinitializeRule="true">
<test-code>
<description>invoke an external method that close the resource: bug 2920057</description>
<rule-property name="closeTargets">closeStatement,closeStatement,closeResultSet,closeConnexion</rule-property>
<rule-property name="types">java.sql.Connection,java.sql.Statement,java.sql.ResultSet,java.sql.PreparedStatement</rule-property>
@ -329,7 +329,7 @@ public class StructureFactory {
]]></code>
</test-code>
<test-code reinitializeRule="true">
<test-code>
<description>invoke an external method that closes the resource, but one is not the right method and an another is not the right variable: see bug 2920057</description>
<rule-property name="closeTargets">closeStatement,closeStatement,closeResultSet,closeConnexion</rule-property>
<rule-property name="types">java.sql.Connection,java.sql.Statement,java.sql.ResultSet,java.sql.PreparedStatement</rule-property>
@ -364,7 +364,7 @@ public class StructureFactory {
]]></code>
</test-code>
<test-code reinitializeRule="true">
<test-code>
<description>#1011 CloseResource Rule ignores Constructors</description>
<expected-problems>1</expected-problems>
<code><![CDATA[
@ -379,7 +379,7 @@ public class Test {
]]></code>
</test-code>
<test-code reinitializeRule="true">
<test-code>
<description>#1011 CloseResource Rule ignores Constructors - closed in finally</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
@ -399,7 +399,7 @@ public class Test {
]]></code>
</test-code>
<test-code reinitializeRule="true">
<test-code>
<description>#1011 CloseResource Rule ignores Constructors - not a problem - instance variable</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
@ -416,7 +416,7 @@ public class Test {
]]></code>
</test-code>
<test-code reinitializeRule="true">
<test-code>
<description>#1029 No instance level check in the close resource rule</description>
<expected-problems>0</expected-problems>
<code><![CDATA[

View File

@ -29,6 +29,9 @@ import net.sourceforge.pmd.properties.PropertySource;
import net.sourceforge.pmd.test.schema.TestSchemaParser.PmdXmlReporter;
import com.github.oowekyala.ooxml.DomUtils;
import com.github.oowekyala.ooxml.messages.PositionedXmlDoc;
import com.github.oowekyala.ooxml.messages.XmlPosition;
import com.github.oowekyala.ooxml.messages.XmlPositioner;
/**
* @author Clément Fournier
@ -39,7 +42,8 @@ class BaseTestParserImpl {
}
public RuleTestCollection parseDocument(Rule rule, Document doc, PmdXmlReporter err) {
public RuleTestCollection parseDocument(Rule rule, PositionedXmlDoc positionedXmlDoc, PmdXmlReporter err) {
Document doc = positionedXmlDoc.getDocument();
Element root = doc.getDocumentElement();
Map<String, Element> codeFragments = parseCodeFragments(err, root);
@ -51,7 +55,7 @@ class BaseTestParserImpl {
RuleTestDescriptor descriptor = new RuleTestDescriptor(i, rule.deepCopy());
try (PmdXmlReporter errScope = err.newScope()) {
parseSingleTest(testCodes.get(i), descriptor, codeFragments, usedFragments, errScope);
parseSingleTest(testCodes.get(i), descriptor, codeFragments, usedFragments, positionedXmlDoc.getPositioner(), errScope);
if (!errScope.hasError()) {
result.addTest(descriptor);
}
@ -85,6 +89,7 @@ class BaseTestParserImpl {
RuleTestDescriptor descriptor,
Map<String, Element> fragments,
Set<String> usedFragments,
XmlPositioner xmlPositioner,
PmdXmlReporter err) {
{
String description = getSingleChildText(testCode, "description", true, err);
@ -102,6 +107,13 @@ class BaseTestParserImpl {
descriptor.setDisabled(disabled);
boolean focused = parseBoolAttribute(testCode, "focused", false, err,
"Attribute focused is used, do not forget to remove it when checking in sources");
descriptor.setFocused(focused);
Properties properties = parseRuleProperties(testCode, descriptor.getRule(), err);
descriptor.getProperties().putAll(properties);
@ -118,6 +130,9 @@ class BaseTestParserImpl {
if (lversion != null) {
descriptor.setLanguageVersion(lversion);
}
XmlPosition startPosition = xmlPositioner.startPositionOf(testCode);
descriptor.setLineNumber(startPosition.getLine());
}
private void parseExpectedProblems(Element testCode, RuleTestDescriptor descriptor, PmdXmlReporter err) {

View File

@ -18,6 +18,7 @@ import java.util.Objects;
public class RuleTestCollection {
private final List<RuleTestDescriptor> tests = new ArrayList<>();
private String absoluteUriToTestXmlFile;
public void addTest(RuleTestDescriptor descriptor) {
tests.add(Objects.requireNonNull(descriptor));
@ -28,4 +29,24 @@ public class RuleTestCollection {
return Collections.unmodifiableList(tests);
}
/**
* Returns the last test of the collection which is focused.
*/
public RuleTestDescriptor getFocusedTestOrNull() {
RuleTestDescriptor focused = null;
for (RuleTestDescriptor test : tests) {
if (test.isFocused()) {
focused = test;
}
}
return focused;
}
public String getAbsoluteUriToTestXmlFile() {
return absoluteUriToTestXmlFile;
}
public void setAbsoluteUriToTestXmlFile(String absoluteUriToTestXmlFile) {
this.absoluteUriToTestXmlFile = absoluteUriToTestXmlFile;
}
}

View File

@ -16,6 +16,7 @@ import net.sourceforge.pmd.lang.LanguageVersion;
public class RuleTestDescriptor {
private boolean disabled;
private boolean focused;
private String description;
private LanguageVersion languageVersion;
private final Properties properties = new Properties();
@ -25,6 +26,7 @@ public class RuleTestDescriptor {
private int expectedProblems;
private List<Integer> expectedLineNumbers;
private List<String> expectedMessages;
private int lineNumber;
public RuleTestDescriptor(int index, Rule rule) {
this.index = index;
@ -106,4 +108,20 @@ public class RuleTestDescriptor {
public List<String> getExpectedMessages() {
return expectedMessages;
}
public boolean isFocused() {
return focused;
}
public void setFocused(boolean focused) {
this.focused = focused;
}
public int getLineNumber() {
return lineNumber;
}
public void setLineNumber(int lineNumber) {
this.lineNumber = lineNumber;
}
}

View File

@ -64,7 +64,7 @@ public class TestSchemaParser {
PositionedXmlDoc doc = ooxml.parse(newDocumentBuilder(), inputSource);
try (PmdXmlReporterImpl err = new PmdXmlReporterImpl(ooxml, doc.getPositioner())) {
RuleTestCollection collection = version.getParserImpl().parseDocument(rule, doc.getDocument(), err);
RuleTestCollection collection = version.getParserImpl().parseDocument(rule, doc, err);
if (err.hasError()) {
// todo maybe add a way not to throw here
throw new IllegalStateException("Errors were encountered while parsing XML tests");

View File

@ -58,7 +58,13 @@
</annotation>
</element>
</sequence>
<attribute name="reinitializeRule" type="boolean" default="true"/>
<attribute name="reinitializeRule" type="boolean" default="true">
<annotation>
<documentation>
This attribute is deprecated, it is assumed true and ignored.
</documentation>
</annotation>
</attribute>
<attribute name="regressionTest" type="boolean" default="true">
<annotation>
<documentation>
@ -67,7 +73,13 @@
</documentation>
</annotation>
</attribute>
<attribute name="useAuxClasspath" type="boolean" default="true"/>
<attribute name="useAuxClasspath" type="boolean" default="true">
<annotation>
<documentation>
This attribute is deprecated, it is assumed true and ignored.
</documentation>
</annotation>
</attribute>
<attribute name="disabled" type="boolean" default="false">
<annotation>
@ -76,6 +88,18 @@
</documentation>
</annotation>
</attribute>
<attribute name="focused" type="boolean" default="false">
<annotation>
<documentation>
If true, only this test will be executed, and all others will be disabled.
If several tests in the same file are focused, then the last one wins, in
document order.
This attribute is provided as a way for developers to temporarily focus on a single test.
Test files with a focused test should not be checked in. For this reason,
using this attribute produces a warning.
</documentation>
</annotation>
</attribute>
</complexType>
<complexType name="codeFragmentType">

View File

@ -5,9 +5,7 @@
package net.sourceforge.pmd.testframework;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@ -27,6 +25,8 @@ import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;
import net.sourceforge.pmd.Rule;
import net.sourceforge.pmd.test.schema.RuleTestCollection;
import net.sourceforge.pmd.test.schema.RuleTestDescriptor;
/**
* A JUnit Runner, that executes all declared rule tests in the class. It supports Before and After methods as well as
@ -67,13 +67,20 @@ public class RuleTestRunner extends ParentRunner<TestDescriptor> {
@Override
protected List<TestDescriptor> getChildren() {
final List<Rule> rules = new ArrayList<>(instance.getRules());
List<Rule> rules = new ArrayList<>(instance.getRules());
rules.sort(Comparator.comparing(Rule::getName));
final List<TestDescriptor> tests = new LinkedList<>();
for (final Rule r : rules) {
final TestDescriptor[] ruleTests = instance.extractTestsFromXml(r);
Collections.addAll(tests, ruleTests);
List<TestDescriptor> tests = new ArrayList<>();
for (Rule r : rules) {
RuleTestCollection ruleTests = instance.parseTestCollection(r);
RuleTestDescriptor focused = ruleTests.getFocusedTestOrNull();
for (RuleTestDescriptor t : ruleTests.getTests()) {
TestDescriptor td = new TestDescriptor(t, ruleTests.getAbsoluteUriToTestXmlFile());
if (focused != null && !focused.equals(t)) {
td.setRegressionTest(false); // disable it
}
tests.add(td);
}
}
return tests;

View File

@ -10,12 +10,10 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@ -33,6 +31,7 @@ import net.sourceforge.pmd.RuleSet;
import net.sourceforge.pmd.RuleSetLoadException;
import net.sourceforge.pmd.RuleSetLoader;
import net.sourceforge.pmd.RuleViolation;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.lang.LanguageVersion;
import net.sourceforge.pmd.lang.document.TextFile;
import net.sourceforge.pmd.processor.AbstractPMDProcessor;
@ -40,8 +39,8 @@ import net.sourceforge.pmd.properties.PropertyDescriptor;
import net.sourceforge.pmd.renderers.TextRenderer;
import net.sourceforge.pmd.reporting.GlobalAnalysisListener;
import net.sourceforge.pmd.test.schema.RuleTestCollection;
import net.sourceforge.pmd.test.schema.RuleTestDescriptor;
import net.sourceforge.pmd.test.schema.TestSchemaParser;
import net.sourceforge.pmd.util.IOUtil;
/**
* Advanced methods for test cases
@ -73,6 +72,8 @@ public abstract class RuleTst {
/**
* Find a rule in a certain ruleset by name
*
* todo make this static
*/
public Rule findRule(String ruleSet, String ruleName) {
try {
@ -96,12 +97,13 @@ public abstract class RuleTst {
* violations.
*/
@SuppressWarnings("unchecked")
@InternalApi
@Deprecated
public void runTest(TestDescriptor test) {
Rule rule = test.getRule();
if (test.getReinitializeRule()) {
// always reinitialize the rule, regardless of test.getReinitializeRule() (#3976 / #3302)
rule = reinitializeRule(rule);
}
Map<PropertyDescriptor<?>, Object> oldProperties = rule.getPropertiesByPropertyDescriptor();
try {
@ -229,37 +231,33 @@ public abstract class RuleTst {
}
private Report processUsingStringReader(TestDescriptor test, Rule rule) {
return runTestFromString(test.getCode(), rule, test.getLanguageVersion(), test.isUseAuxClasspath());
return runTestFromString(test.getCode(), rule, test.getLanguageVersion());
}
public Report runTestFromString(String code, Rule rule, LanguageVersion languageVersion, boolean isUseAuxClasspath) {
/**
* Run the rule on the given code and put the violations in the report.
*/
@InternalApi
@Deprecated
public Report runTestFromString(String code, Rule rule, LanguageVersion languageVersion) {
return runTestFromString(code, rule, languageVersion, true);
}
@InternalApi
@Deprecated
public Report runTestFromString(String code, Rule rule, LanguageVersion languageVersion,
boolean isUseAuxClasspath) {
try {
PMDConfiguration configuration = new PMDConfiguration();
configuration.setIgnoreIncrementalAnalysis(true);
configuration.setDefaultLanguageVersion(languageVersion);
configuration.setThreads(1);
if (isUseAuxClasspath) {
// regardless of isUseAuxClasspath the auxclasspath is always used (#3976 / #3302)
// configure the "auxclasspath" option for unit testing
// we share a single classloader so that pmd-java doesn't create
// a new TypeSystem for every test. This problem will go
// away when languages have a lifecycle.
configuration.setClassLoader(classpathClassLoader);
} else {
// simple class loader, that doesn't delegate to parent.
// this allows us in the tests to simulate PMD run without
// auxclasspath, not even the classes from the test dependencies
// will be found.
configuration.setClassLoader(new ClassLoader() {
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
if (name.startsWith("java.") || name.startsWith("javax.")) {
return super.loadClass(name, resolve);
}
throw new ClassNotFoundException(name);
}
});
}
try (GlobalReportBuilderListener reportBuilder = new GlobalReportBuilderListener();
// Add a listener that throws when an error occurs:
@ -283,10 +281,18 @@ public abstract class RuleTst {
}
}
@InternalApi
@Deprecated
public Report runTestFromString(TestDescriptor test, Rule rule) {
return runTestFromString(test.getCode(), rule, test.getLanguageVersion(), test.isUseAuxClasspath());
}
/**
* getResourceAsStream tries to find the XML file in weird locations if the
* ruleName includes the package, so we strip it here.
*/
@InternalApi
@Deprecated
protected String getCleanRuleName(Rule rule) {
String fullClassName = rule.getClass().getName();
if (fullClassName.equals(rule.getName())) {
@ -304,12 +310,26 @@ public abstract class RuleTst {
* ./xml/RuleName.xml relative to the test class. The format is defined in
* test-data.xsd.
*/
@InternalApi
@Deprecated
public TestDescriptor[] extractTestsFromXml(Rule rule) {
String testsFileName = getCleanRuleName(rule);
return extractTestsFromXml(rule, testsFileName);
}
/**
* Extract a set of tests from an XML file. The file should be
* ./xml/RuleName.xml relative to the test class. The format is defined in
* rule-tests_1_0_0.xsd in pmd-test-schema.
*/
RuleTestCollection parseTestCollection(Rule rule) {
String testsFileName = getCleanRuleName(rule);
return parseTestXml(rule, testsFileName, "xml/");
}
@InternalApi
@Deprecated
public TestDescriptor[] extractTestsFromXml(Rule rule, String testsFileName) {
return extractTestsFromXml(rule, testsFileName, "xml/");
}
@ -319,55 +339,21 @@ public abstract class RuleTst {
* should be ./xml/[testsFileName].xml relative to the test class. The
* format is defined in test-data.xsd.
*/
@InternalApi
@Deprecated
public TestDescriptor[] extractTestsFromXml(Rule rule, String testsFileName, String baseDirectory) {
RuleTestCollection collection = parseTestXml(rule, testsFileName, baseDirectory);
return toLegacyArray(collection, testsFileName, baseDirectory);
}
private TestDescriptor[] toLegacyArray(RuleTestCollection collection, String testsFileName, String baseDirectory) {
String testXmlFileName = baseDirectory + testsFileName + ".xml";
List<Integer> lineNumbersForTests;
try (InputStream inputStream = getClass().getResourceAsStream(testXmlFileName)) {
String testXml = IOUtil.readToString(inputStream, StandardCharsets.UTF_8);
lineNumbersForTests = determineLineNumbers(testXml);
} catch (Exception e) {
throw new RuntimeException("Couldn't parse " + testXmlFileName + ", due to: " + e, e);
}
if (lineNumbersForTests.size() != collection.getTests().size()) {
throw new IllegalStateException("Test to line number mapping doesn't work!");
}
String absoluteUriToTestXmlFile = new File(".").getAbsoluteFile().toURI() + "/src/test/resources/"
+ this.getClass().getPackage().getName().replaceAll("\\.", "/")
+ "/" + testXmlFileName;
TestDescriptor[] result = new TestDescriptor[collection.getTests().size()];
for (int i = 0; i < collection.getTests().size(); i++) {
result[i] = new TestDescriptor(collection.getTests().get(i), absoluteUriToTestXmlFile, lineNumbersForTests.get(i));
result[i] = new TestDescriptor(collection.getTests().get(i), collection.getAbsoluteUriToTestXmlFile());
}
return result;
}
private List<Integer> determineLineNumbers(String testXml) {
List<Integer> tests = new ArrayList<>();
int lineNumber = 1;
int index = 0;
while (index < testXml.length()) {
char c = testXml.charAt(index);
if (c == '\n') {
lineNumber++;
} else if (c == '<') {
if (testXml.startsWith("<test-code", index)) {
tests.add(lineNumber);
}
}
index++;
}
return tests;
}
/**
* Extract a set of tests from an XML file with the given name. The file
* should be ./xml/[testsFileName].xml relative to the test class. The
@ -375,6 +361,9 @@ public abstract class RuleTst {
*/
private RuleTestCollection parseTestXml(Rule rule, String testsFileName, String baseDirectory) {
String testXmlFileName = baseDirectory + testsFileName + ".xml";
String absoluteUriToTestXmlFile = new File(".").getAbsoluteFile().toURI() + "/src/test/resources/"
+ this.getClass().getPackage().getName().replaceAll("\\.", "/")
+ "/" + testXmlFileName;
try (InputStream inputStream = getClass().getResourceAsStream(testXmlFileName)) {
if (inputStream == null) {
@ -384,7 +373,9 @@ public abstract class RuleTst {
source.setByteStream(inputStream);
source.setSystemId(testXmlFileName);
TestSchemaParser parser = new TestSchemaParser();
return parser.parse(rule, source);
RuleTestCollection ruleTestCollection = parser.parse(rule, source);
ruleTestCollection.setAbsoluteUriToTestXmlFile(absoluteUriToTestXmlFile);
return ruleTestCollection;
} catch (Exception e) {
throw new RuntimeException("Couldn't parse " + testXmlFileName + ", due to: " + e, e);
}
@ -411,6 +402,8 @@ public abstract class RuleTst {
/**
* Run a set of tests of a certain sourceType.
*/
@InternalApi
@Deprecated
public void runTests(TestDescriptor[] tests) {
for (TestDescriptor test : tests) {
runTest(test);
@ -423,10 +416,17 @@ public abstract class RuleTst {
final List<Rule> rules = new ArrayList<>(getRules());
rules.sort(Comparator.comparing(Rule::getName));
final List<TestDescriptor> tests = new LinkedList<>();
for (final Rule r : rules) {
final TestDescriptor[] ruleTests = extractTestsFromXml(r);
Collections.addAll(tests, ruleTests);
List<TestDescriptor> tests = new ArrayList<>();
for (Rule r : rules) {
RuleTestCollection ruleTests = parseTestCollection(r);
RuleTestDescriptor focused = ruleTests.getFocusedTestOrNull();
for (RuleTestDescriptor t : ruleTests.getTests()) {
TestDescriptor td = new TestDescriptor(t, ruleTests.getAbsoluteUriToTestXmlFile());
if (focused != null && !focused.equals(t)) {
td.setRegressionTest(false); // disable it
}
tests.add(td);
}
}
return tests.stream().map(this::toDynamicTest).collect(Collectors.toList());

View File

@ -17,8 +17,11 @@ import net.sourceforge.pmd.test.schema.RuleTestDescriptor;
/**
* Stores the information required to run a complete test.
*
* @deprecated Use {@link RuleTestDescriptor} instead
*/
@Ignore("this is not a unit test")
@Deprecated
public class TestDescriptor {
private Rule rule;
private Properties properties;
@ -54,7 +57,7 @@ public class TestDescriptor {
}
// for compatibility
TestDescriptor(RuleTestDescriptor td, String absoluteUriToTestXmlFile, int lineNumber) {
TestDescriptor(RuleTestDescriptor td, String absoluteUriToTestXmlFile) {
this.rule = td.getRule();
this.code = td.getCode();
this.description = td.getDescription();
@ -66,7 +69,7 @@ public class TestDescriptor {
this.properties = td.getProperties();
this.languageVersion = td.getLanguageVersion();
this.numberInDocument = td.getIndex();
this.setTestSourceUri(absoluteUriToTestXmlFile, lineNumber);
this.setTestSourceUri(absoluteUriToTestXmlFile, td.getLineNumber());
}
public int getNumberInDocument() {

View File

@ -58,7 +58,13 @@
</annotation>
</element>
</sequence>
<attribute name="reinitializeRule" type="boolean" default="true"/>
<attribute name="reinitializeRule" type="boolean" default="true">
<annotation>
<documentation>
This attribute is deprecated, it is assumed true and ignored.
</documentation>
</annotation>
</attribute>
<attribute name="regressionTest" type="boolean" default="true">
<annotation>
<documentation>
@ -67,7 +73,13 @@
</documentation>
</annotation>
</attribute>
<attribute name="useAuxClasspath" type="boolean" default="true"/>
<attribute name="useAuxClasspath" type="boolean" default="true">
<annotation>
<documentation>
This attribute is deprecated, it is assumed true and ignored.
</documentation>
</annotation>
</attribute>
<attribute name="disabled" type="boolean" default="false">
<annotation>
@ -76,6 +88,18 @@
</documentation>
</annotation>
</attribute>
<attribute name="focused" type="boolean" default="false">
<annotation>
<documentation>
If true, only this test will be executed, and all others will be disabled.
If several tests in the same file are focused, then the last one wins, in
document order.
This attribute is provided as a way for developers to temporarily focus on a single test.
Test files with a focused test should not be checked in. For this reason,
using this attribute produces a warning.
</documentation>
</annotation>
</attribute>
</complexType>
<complexType name="codeFragmentType">

View File

@ -30,6 +30,10 @@ public class RuleTstTest {
private Rule rule = mock(Rule.class);
private RuleTst ruleTester = new RuleTst() {
@Override
public Rule findRule(String ruleSet, String ruleName) {
return rule;
}
};
@Test