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

View File

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

View File

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

View File

@ -135,14 +135,18 @@ between different test cases.
The `<test-code>` elements understands the following optional attributes: 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 * **disabled**: By default, it's `false`. Set it to `true`, to ignore and skip a test case.
to `false` to reproduce cases, where the previous run has influences.
* **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. 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 * **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. 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 * java-performance
* [#3625](https://github.com/pmd/pmd/issues/3625): \[java] AddEmptyString - false negative with empty var * [#3625](https://github.com/pmd/pmd/issues/3625): \[java] AddEmptyString - false negative with empty var
* test * 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 * [#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 * [#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. 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 * 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. 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 * Test schema changes:
defining whether a rule test should be skipped or not. * 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: * More information about the rule test framework can be found in the documentation:
[Testing your rules](pmd_userdocs_extending_testing.html) [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. but it is no longer supported with Java 19 Preview.
* The interface {% jdoc core::cpd.renderer.CPDRenderer %} is deprecated. For custom CPD renderers * 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 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 #### 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> ]]></code>
</test-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> <description>JUnit 4 test detection without proper auxclasspath</description>
<expected-problems>1</expected-problems> <expected-problems>1</expected-problems>
<expected-linenumbers>7</expected-linenumbers> <expected-linenumbers>7</expected-linenumbers>

View File

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

View File

@ -298,7 +298,7 @@ public class Foo {
]]></code> ]]></code>
</test-code> </test-code>
<test-code reinitializeRule="true"> <test-code>
<description>invoke an external method that close the resource: bug 2920057</description> <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="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> <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> ]]></code>
</test-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> <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="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> <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> ]]></code>
</test-code> </test-code>
<test-code reinitializeRule="true"> <test-code>
<description>#1011 CloseResource Rule ignores Constructors</description> <description>#1011 CloseResource Rule ignores Constructors</description>
<expected-problems>1</expected-problems> <expected-problems>1</expected-problems>
<code><![CDATA[ <code><![CDATA[
@ -379,7 +379,7 @@ public class Test {
]]></code> ]]></code>
</test-code> </test-code>
<test-code reinitializeRule="true"> <test-code>
<description>#1011 CloseResource Rule ignores Constructors - closed in finally</description> <description>#1011 CloseResource Rule ignores Constructors - closed in finally</description>
<expected-problems>0</expected-problems> <expected-problems>0</expected-problems>
<code><![CDATA[ <code><![CDATA[
@ -399,7 +399,7 @@ public class Test {
]]></code> ]]></code>
</test-code> </test-code>
<test-code reinitializeRule="true"> <test-code>
<description>#1011 CloseResource Rule ignores Constructors - not a problem - instance variable</description> <description>#1011 CloseResource Rule ignores Constructors - not a problem - instance variable</description>
<expected-problems>0</expected-problems> <expected-problems>0</expected-problems>
<code><![CDATA[ <code><![CDATA[
@ -416,7 +416,7 @@ public class Test {
]]></code> ]]></code>
</test-code> </test-code>
<test-code reinitializeRule="true"> <test-code>
<description>#1029 No instance level check in the close resource rule</description> <description>#1029 No instance level check in the close resource rule</description>
<expected-problems>0</expected-problems> <expected-problems>0</expected-problems>
<code><![CDATA[ <code><![CDATA[

View File

@ -29,6 +29,9 @@ import net.sourceforge.pmd.properties.PropertySource;
import net.sourceforge.pmd.test.schema.TestSchemaParser.PmdXmlReporter; import net.sourceforge.pmd.test.schema.TestSchemaParser.PmdXmlReporter;
import com.github.oowekyala.ooxml.DomUtils; 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 * @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(); Element root = doc.getDocumentElement();
Map<String, Element> codeFragments = parseCodeFragments(err, root); Map<String, Element> codeFragments = parseCodeFragments(err, root);
@ -51,7 +55,7 @@ class BaseTestParserImpl {
RuleTestDescriptor descriptor = new RuleTestDescriptor(i, rule.deepCopy()); RuleTestDescriptor descriptor = new RuleTestDescriptor(i, rule.deepCopy());
try (PmdXmlReporter errScope = err.newScope()) { 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()) { if (!errScope.hasError()) {
result.addTest(descriptor); result.addTest(descriptor);
} }
@ -85,6 +89,7 @@ class BaseTestParserImpl {
RuleTestDescriptor descriptor, RuleTestDescriptor descriptor,
Map<String, Element> fragments, Map<String, Element> fragments,
Set<String> usedFragments, Set<String> usedFragments,
XmlPositioner xmlPositioner,
PmdXmlReporter err) { PmdXmlReporter err) {
{ {
String description = getSingleChildText(testCode, "description", true, err); String description = getSingleChildText(testCode, "description", true, err);
@ -102,6 +107,13 @@ class BaseTestParserImpl {
descriptor.setDisabled(disabled); 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); Properties properties = parseRuleProperties(testCode, descriptor.getRule(), err);
descriptor.getProperties().putAll(properties); descriptor.getProperties().putAll(properties);
@ -118,6 +130,9 @@ class BaseTestParserImpl {
if (lversion != null) { if (lversion != null) {
descriptor.setLanguageVersion(lversion); descriptor.setLanguageVersion(lversion);
} }
XmlPosition startPosition = xmlPositioner.startPositionOf(testCode);
descriptor.setLineNumber(startPosition.getLine());
} }
private void parseExpectedProblems(Element testCode, RuleTestDescriptor descriptor, PmdXmlReporter err) { private void parseExpectedProblems(Element testCode, RuleTestDescriptor descriptor, PmdXmlReporter err) {

View File

@ -18,6 +18,7 @@ import java.util.Objects;
public class RuleTestCollection { public class RuleTestCollection {
private final List<RuleTestDescriptor> tests = new ArrayList<>(); private final List<RuleTestDescriptor> tests = new ArrayList<>();
private String absoluteUriToTestXmlFile;
public void addTest(RuleTestDescriptor descriptor) { public void addTest(RuleTestDescriptor descriptor) {
tests.add(Objects.requireNonNull(descriptor)); tests.add(Objects.requireNonNull(descriptor));
@ -28,4 +29,24 @@ public class RuleTestCollection {
return Collections.unmodifiableList(tests); 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 { public class RuleTestDescriptor {
private boolean disabled; private boolean disabled;
private boolean focused;
private String description; private String description;
private LanguageVersion languageVersion; private LanguageVersion languageVersion;
private final Properties properties = new Properties(); private final Properties properties = new Properties();
@ -25,6 +26,7 @@ public class RuleTestDescriptor {
private int expectedProblems; private int expectedProblems;
private List<Integer> expectedLineNumbers; private List<Integer> expectedLineNumbers;
private List<String> expectedMessages; private List<String> expectedMessages;
private int lineNumber;
public RuleTestDescriptor(int index, Rule rule) { public RuleTestDescriptor(int index, Rule rule) {
this.index = index; this.index = index;
@ -106,4 +108,20 @@ public class RuleTestDescriptor {
public List<String> getExpectedMessages() { public List<String> getExpectedMessages() {
return expectedMessages; 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); PositionedXmlDoc doc = ooxml.parse(newDocumentBuilder(), inputSource);
try (PmdXmlReporterImpl err = new PmdXmlReporterImpl(ooxml, doc.getPositioner())) { 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()) { if (err.hasError()) {
// todo maybe add a way not to throw here // todo maybe add a way not to throw here
throw new IllegalStateException("Errors were encountered while parsing XML tests"); throw new IllegalStateException("Errors were encountered while parsing XML tests");

View File

@ -58,7 +58,13 @@
</annotation> </annotation>
</element> </element>
</sequence> </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"> <attribute name="regressionTest" type="boolean" default="true">
<annotation> <annotation>
<documentation> <documentation>
@ -67,7 +73,13 @@
</documentation> </documentation>
</annotation> </annotation>
</attribute> </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"> <attribute name="disabled" type="boolean" default="false">
<annotation> <annotation>
@ -76,6 +88,18 @@
</documentation> </documentation>
</annotation> </annotation>
</attribute> </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>
<complexType name="codeFragmentType"> <complexType name="codeFragmentType">

View File

@ -5,9 +5,7 @@
package net.sourceforge.pmd.testframework; package net.sourceforge.pmd.testframework;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
@ -27,6 +25,8 @@ import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement; import org.junit.runners.model.Statement;
import net.sourceforge.pmd.Rule; 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 * 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 @Override
protected List<TestDescriptor> getChildren() { 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)); rules.sort(Comparator.comparing(Rule::getName));
final List<TestDescriptor> tests = new LinkedList<>(); List<TestDescriptor> tests = new ArrayList<>();
for (final Rule r : rules) { for (Rule r : rules) {
final TestDescriptor[] ruleTests = instance.extractTestsFromXml(r); RuleTestCollection ruleTests = instance.parseTestCollection(r);
Collections.addAll(tests, ruleTests); 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; return tests;

View File

@ -10,12 +10,10 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.StringWriter; import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -33,6 +31,7 @@ import net.sourceforge.pmd.RuleSet;
import net.sourceforge.pmd.RuleSetLoadException; import net.sourceforge.pmd.RuleSetLoadException;
import net.sourceforge.pmd.RuleSetLoader; import net.sourceforge.pmd.RuleSetLoader;
import net.sourceforge.pmd.RuleViolation; import net.sourceforge.pmd.RuleViolation;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.lang.LanguageVersion; import net.sourceforge.pmd.lang.LanguageVersion;
import net.sourceforge.pmd.lang.document.TextFile; import net.sourceforge.pmd.lang.document.TextFile;
import net.sourceforge.pmd.processor.AbstractPMDProcessor; 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.renderers.TextRenderer;
import net.sourceforge.pmd.reporting.GlobalAnalysisListener; import net.sourceforge.pmd.reporting.GlobalAnalysisListener;
import net.sourceforge.pmd.test.schema.RuleTestCollection; 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.test.schema.TestSchemaParser;
import net.sourceforge.pmd.util.IOUtil;
/** /**
* Advanced methods for test cases * Advanced methods for test cases
@ -73,6 +72,8 @@ public abstract class RuleTst {
/** /**
* Find a rule in a certain ruleset by name * Find a rule in a certain ruleset by name
*
* todo make this static
*/ */
public Rule findRule(String ruleSet, String ruleName) { public Rule findRule(String ruleSet, String ruleName) {
try { try {
@ -96,12 +97,13 @@ public abstract class RuleTst {
* violations. * violations.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@InternalApi
@Deprecated
public void runTest(TestDescriptor test) { public void runTest(TestDescriptor test) {
Rule rule = test.getRule(); Rule rule = test.getRule();
if (test.getReinitializeRule()) { // always reinitialize the rule, regardless of test.getReinitializeRule() (#3976 / #3302)
rule = reinitializeRule(rule); rule = reinitializeRule(rule);
}
Map<PropertyDescriptor<?>, Object> oldProperties = rule.getPropertiesByPropertyDescriptor(); Map<PropertyDescriptor<?>, Object> oldProperties = rule.getPropertiesByPropertyDescriptor();
try { try {
@ -229,37 +231,33 @@ public abstract class RuleTst {
} }
private Report processUsingStringReader(TestDescriptor test, Rule rule) { 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 { try {
PMDConfiguration configuration = new PMDConfiguration(); PMDConfiguration configuration = new PMDConfiguration();
configuration.setIgnoreIncrementalAnalysis(true); configuration.setIgnoreIncrementalAnalysis(true);
configuration.setDefaultLanguageVersion(languageVersion); configuration.setDefaultLanguageVersion(languageVersion);
configuration.setThreads(1); configuration.setThreads(1);
// regardless of isUseAuxClasspath the auxclasspath is always used (#3976 / #3302)
if (isUseAuxClasspath) { // configure the "auxclasspath" option for unit testing
// configure the "auxclasspath" option for unit testing // we share a single classloader so that pmd-java doesn't create
// we share a single classloader so that pmd-java doesn't create // a new TypeSystem for every test. This problem will go
// a new TypeSystem for every test. This problem will go // away when languages have a lifecycle.
// away when languages have a lifecycle. configuration.setClassLoader(classpathClassLoader);
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(); try (GlobalReportBuilderListener reportBuilder = new GlobalReportBuilderListener();
// Add a listener that throws when an error occurs: // 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 * getResourceAsStream tries to find the XML file in weird locations if the
* ruleName includes the package, so we strip it here. * ruleName includes the package, so we strip it here.
*/ */
@InternalApi
@Deprecated
protected String getCleanRuleName(Rule rule) { protected String getCleanRuleName(Rule rule) {
String fullClassName = rule.getClass().getName(); String fullClassName = rule.getClass().getName();
if (fullClassName.equals(rule.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 * ./xml/RuleName.xml relative to the test class. The format is defined in
* test-data.xsd. * test-data.xsd.
*/ */
@InternalApi
@Deprecated
public TestDescriptor[] extractTestsFromXml(Rule rule) { public TestDescriptor[] extractTestsFromXml(Rule rule) {
String testsFileName = getCleanRuleName(rule); String testsFileName = getCleanRuleName(rule);
return extractTestsFromXml(rule, testsFileName); 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) { public TestDescriptor[] extractTestsFromXml(Rule rule, String testsFileName) {
return extractTestsFromXml(rule, testsFileName, "xml/"); return extractTestsFromXml(rule, testsFileName, "xml/");
} }
@ -319,55 +339,21 @@ public abstract class RuleTst {
* should be ./xml/[testsFileName].xml relative to the test class. The * should be ./xml/[testsFileName].xml relative to the test class. The
* format is defined in test-data.xsd. * format is defined in test-data.xsd.
*/ */
@InternalApi
@Deprecated
public TestDescriptor[] extractTestsFromXml(Rule rule, String testsFileName, String baseDirectory) { public TestDescriptor[] extractTestsFromXml(Rule rule, String testsFileName, String baseDirectory) {
RuleTestCollection collection = parseTestXml(rule, testsFileName, baseDirectory); RuleTestCollection collection = parseTestXml(rule, testsFileName, baseDirectory);
return toLegacyArray(collection, testsFileName, baseDirectory); return toLegacyArray(collection, testsFileName, baseDirectory);
} }
private TestDescriptor[] toLegacyArray(RuleTestCollection collection, String testsFileName, String 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()]; TestDescriptor[] result = new TestDescriptor[collection.getTests().size()];
for (int i = 0; i < collection.getTests().size(); i++) { 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; 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 * 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 * 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) { private RuleTestCollection parseTestXml(Rule rule, String testsFileName, String baseDirectory) {
String testXmlFileName = baseDirectory + testsFileName + ".xml"; 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)) { try (InputStream inputStream = getClass().getResourceAsStream(testXmlFileName)) {
if (inputStream == null) { if (inputStream == null) {
@ -384,7 +373,9 @@ public abstract class RuleTst {
source.setByteStream(inputStream); source.setByteStream(inputStream);
source.setSystemId(testXmlFileName); source.setSystemId(testXmlFileName);
TestSchemaParser parser = new TestSchemaParser(); TestSchemaParser parser = new TestSchemaParser();
return parser.parse(rule, source); RuleTestCollection ruleTestCollection = parser.parse(rule, source);
ruleTestCollection.setAbsoluteUriToTestXmlFile(absoluteUriToTestXmlFile);
return ruleTestCollection;
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException("Couldn't parse " + testXmlFileName + ", due to: " + e, 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. * Run a set of tests of a certain sourceType.
*/ */
@InternalApi
@Deprecated
public void runTests(TestDescriptor[] tests) { public void runTests(TestDescriptor[] tests) {
for (TestDescriptor test : tests) { for (TestDescriptor test : tests) {
runTest(test); runTest(test);
@ -423,10 +416,17 @@ public abstract class RuleTst {
final List<Rule> rules = new ArrayList<>(getRules()); final List<Rule> rules = new ArrayList<>(getRules());
rules.sort(Comparator.comparing(Rule::getName)); rules.sort(Comparator.comparing(Rule::getName));
final List<TestDescriptor> tests = new LinkedList<>(); List<TestDescriptor> tests = new ArrayList<>();
for (final Rule r : rules) { for (Rule r : rules) {
final TestDescriptor[] ruleTests = extractTestsFromXml(r); RuleTestCollection ruleTests = parseTestCollection(r);
Collections.addAll(tests, ruleTests); 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()); 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. * Stores the information required to run a complete test.
*
* @deprecated Use {@link RuleTestDescriptor} instead
*/ */
@Ignore("this is not a unit test") @Ignore("this is not a unit test")
@Deprecated
public class TestDescriptor { public class TestDescriptor {
private Rule rule; private Rule rule;
private Properties properties; private Properties properties;
@ -54,7 +57,7 @@ public class TestDescriptor {
} }
// for compatibility // for compatibility
TestDescriptor(RuleTestDescriptor td, String absoluteUriToTestXmlFile, int lineNumber) { TestDescriptor(RuleTestDescriptor td, String absoluteUriToTestXmlFile) {
this.rule = td.getRule(); this.rule = td.getRule();
this.code = td.getCode(); this.code = td.getCode();
this.description = td.getDescription(); this.description = td.getDescription();
@ -66,7 +69,7 @@ public class TestDescriptor {
this.properties = td.getProperties(); this.properties = td.getProperties();
this.languageVersion = td.getLanguageVersion(); this.languageVersion = td.getLanguageVersion();
this.numberInDocument = td.getIndex(); this.numberInDocument = td.getIndex();
this.setTestSourceUri(absoluteUriToTestXmlFile, lineNumber); this.setTestSourceUri(absoluteUriToTestXmlFile, td.getLineNumber());
} }
public int getNumberInDocument() { public int getNumberInDocument() {

View File

@ -58,7 +58,13 @@
</annotation> </annotation>
</element> </element>
</sequence> </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"> <attribute name="regressionTest" type="boolean" default="true">
<annotation> <annotation>
<documentation> <documentation>
@ -67,7 +73,13 @@
</documentation> </documentation>
</annotation> </annotation>
</attribute> </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"> <attribute name="disabled" type="boolean" default="false">
<annotation> <annotation>
@ -76,6 +88,18 @@
</documentation> </documentation>
</annotation> </annotation>
</attribute> </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>
<complexType name="codeFragmentType"> <complexType name="codeFragmentType">

View File

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