diff --git a/src/lib/pmd/PmdEngine.ts b/src/lib/pmd/PmdEngine.ts
index 45ac6128b..239aa0a43 100644
--- a/src/lib/pmd/PmdEngine.ts
+++ b/src/lib/pmd/PmdEngine.ts
@@ -100,7 +100,7 @@ export class PmdEngine implements RuleEngine {
}
}
- private xmlToRuleResults(pmdXml: string): RuleResult[] {
+ protected xmlToRuleResults(pmdXml: string): RuleResult[] {
// If the results were just an empty string, we can return it.
if (pmdXml === '') {
this.logger.trace('No PMD results to convert');
@@ -108,7 +108,15 @@ export class PmdEngine implements RuleEngine {
}
const pmdJson = xml2js(pmdXml, {compact: false, ignoreDeclaration: true});
- return pmdJson.elements[0].elements.map(
+
+ // Only provide results for nodes that are files. Other nodes are filtered out and logged.
+ const fileNodes = pmdJson.elements[0].elements.filter(e => 'file' === e.name);
+ const otherNodes = pmdJson.elements[0].elements.filter(e => 'file' !== e.name);
+ for (const otherNode of otherNodes) {
+ this.logger.trace(`Skipping non-file node ${JSON.stringify(otherNode)}`);
+ }
+
+ return fileNodes.map(
(f): RuleResult => {
return {
engine: PmdEngine.NAME,
diff --git a/test/code-fixtures/pmd-results/result-with-configerror.xml b/test/code-fixtures/pmd-results/result-with-configerror.xml
new file mode 100644
index 000000000..2f7f73d63
--- /dev/null
+++ b/test/code-fixtures/pmd-results/result-with-configerror.xml
@@ -0,0 +1,48 @@
+
+
+
+
+Avoid unused imports such as 'sfdc.sfdx.scanner.messaging.SfdxMessager'
+
+
+Enum comments are required
+
+
+Comment is too large: Line too long
+
+
+Field comments are required
+
+
+Field comments are required
+
+
+Field comments are required
+
+
+Field comments are required
+
+
+Field comments are required
+
+
+Parameter 'argCount' is not assigned and could be declared final
+
+
+Parameter 'messageHandler' is not assigned and could be declared final
+
+
+Parameter 'messageKey' is not assigned and could be declared final
+
+
+Parameter 'messageType' is not assigned and could be declared final
+
+
+Parameter 'verbose' is not assigned and could be declared final
+
+
+
+
diff --git a/test/lib/pmd/PmdEngine.test.ts b/test/lib/pmd/PmdEngine.test.ts
new file mode 100644
index 000000000..f82d49824
--- /dev/null
+++ b/test/lib/pmd/PmdEngine.test.ts
@@ -0,0 +1,45 @@
+import "reflect-metadata";
+import {FileHandler} from '../../../src/lib/util/FileHandler';
+import {RuleResult} from '../../../src/types';
+import path = require('path');
+import {expect} from 'chai';
+import Sinon = require('sinon');
+import {container} from 'tsyringe'
+import {Services} from '../../../src/ioc.config';
+import {RuleEngine} from '../../../src/lib/services/RuleEngine'
+import { PmdEngine } from '../../../src/lib/pmd/PmdEngine'
+
+class TestPmdEngine extends PmdEngine {
+ public xmlToRuleResults(pmdXml: string): RuleResult[] {
+ return super.xmlToRuleResults(pmdXml);
+ }
+}
+
+describe('PmdEngine', () => {
+ before(() => {
+ Sinon.createSandbox();
+ // Bootstrap the container.
+ // Avoids 'Cannot register a type name as a singleton without a "to" token' exception
+ container.resolveAll(Services.RuleEngine);
+ });
+ after(() => {
+ Sinon.restore();
+ });
+ describe('xmlToRuleResults()', () => {
+ it('Unknown XML nodes are ignored', async () => {
+ // This xml file contains a 'configerror' node that is a direct child of the pmd node.
+ // The configerror node should be filtered out of the results without causing any errors.
+ const xmlPath = path.join('test', 'code-fixtures', 'pmd-results', 'result-with-configerror.xml');
+ const fileHandler: FileHandler = new FileHandler();
+ const xml: string = await fileHandler.readFile(xmlPath);
+ expect(xml).to.not.be.null;
+
+ const testPmdEngine = new TestPmdEngine();
+ await testPmdEngine.init();
+
+ const results = testPmdEngine.xmlToRuleResults(xml);
+ expect(results).to.be.length(1, 'Results should be for be a single file');
+ expect(results[0].violations).to.be.length(13, 'The file should have 13 violations');
+ });
+ });
+});