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'); + }); + }); +});