From 3177a35124acdd82ec30e727fe98297208b3e2eb Mon Sep 17 00:00:00 2001 From: Arun Tyagi Date: Wed, 21 Jan 2026 16:16:07 +0530 Subject: [PATCH 1/3] add java PMD wrapper test to check for custom deprecated rule --- .../sfca/pmdwrapper/PmdWrapperTest.java | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/packages/code-analyzer-pmd-engine/pmd-cpd-wrappers/src/test/java/com/salesforce/sfca/pmdwrapper/PmdWrapperTest.java b/packages/code-analyzer-pmd-engine/pmd-cpd-wrappers/src/test/java/com/salesforce/sfca/pmdwrapper/PmdWrapperTest.java index 02a78f3c..d4ee863f 100644 --- a/packages/code-analyzer-pmd-engine/pmd-cpd-wrappers/src/test/java/com/salesforce/sfca/pmdwrapper/PmdWrapperTest.java +++ b/packages/code-analyzer-pmd-engine/pmd-cpd-wrappers/src/test/java/com/salesforce/sfca/pmdwrapper/PmdWrapperTest.java @@ -373,6 +373,97 @@ void whenCallingRunWithAnInvalidApexFileWithValidApexFile_thenSkipInvalidApexFil assertThat(resultsJsonString, containsString("\"processingErrors\":[{\"file\":")); // Contains the processing error for the invalid file } + @Test + void whenRunningWithNcssCountRule_thenReportsOrExecutesSuccessfully(@TempDir Path tempDir) throws Exception { + // Create a minimal ruleset that references the Apex NcssCount rule with a very low threshold + String rulesetXml = "\n" + + "\n" + + " Run Apex NcssCount\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + String rulesetFile = createTempFile(tempDir, "ncss-ruleset.xml", rulesetXml); + + // Create a simple Apex file with a few statements; the low threshold should trigger a violation + String apexCode = "public class ManyStatements {\n" + + " public static void foo(){\n" + + " Integer a = 1; Integer b = 2; Integer c = 3; // multiple statements\n" + + " }\n" + + "}\n"; + String apexFile = createTempFile(tempDir, "ManyStatements.cls", apexCode); + + String inputJson = "{\n" + + " \"ruleSetInputFile\":\"" + makePathJsonSafe(rulesetFile) + "\",\n" + + " \"runDataPerLanguage\": {\n" + + " \"apex\": {\n" + + " \"filesToScan\": [\"" + makePathJsonSafe(apexFile) + "\"]\n" + + " }\n" + + " }\n" + + "}"; + String inputFile = createTempFile(tempDir, "input.json", inputJson); + + String resultsOutputFile = tempDir.resolve("results.json").toAbsolutePath().toString(); + String[] args = {"run", inputFile, resultsOutputFile}; + callPmdWrapper(args); // Should not error + + String resultsJsonString = new String(Files.readAllBytes(Paths.get(resultsOutputFile))); + JsonElement element = JsonParser.parseString(resultsJsonString); // Should not error + assertThat(element.isJsonObject(), is(true)); + } + + @Test + void whenRunningWithDeprecatedExcessiveClassLengthRule_thenExecutesSuccessfully(@TempDir Path tempDir) throws Exception { + // Create a minimal ruleset referencing the Apex ExcessiveClassLength rule with a low threshold + String rulesetXml = "\n" + + "\n" + + " Run Apex ExcessiveClassLength\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + String rulesetFile = createTempFile(tempDir, "excessive-class-length.xml", rulesetXml); + + // Create an Apex class with enough lines to exceed the small threshold + StringBuilder apexBuilder = new StringBuilder(); + apexBuilder.append("public class LargeClass {\n"); + apexBuilder.append(" public static void m0(){ Integer x0 = 0; }\n"); + apexBuilder.append(" public static void m1(){ Integer x1 = 1; }\n"); + apexBuilder.append(" public static void m2(){ Integer x2 = 2; }\n"); + apexBuilder.append(" public static void m3(){ Integer x3 = 3; }\n"); + apexBuilder.append(" public static void m4(){ Integer x4 = 4; }\n"); + apexBuilder.append("}\n"); + String apexFile = createTempFile(tempDir, "LargeClass.cls", apexBuilder.toString()); + + String inputJson = "{\n" + + " \"ruleSetInputFile\":\"" + makePathJsonSafe(rulesetFile) + "\",\n" + + " \"runDataPerLanguage\": {\n" + + " \"apex\": {\n" + + " \"filesToScan\": [\"" + makePathJsonSafe(apexFile) + "\"]\n" + + " }\n" + + " }\n" + + "}"; + String inputFile = createTempFile(tempDir, "input-excessive-class-length.json", inputJson); + + String resultsOutputFile = tempDir.resolve("results-excessive-class-length.json").toAbsolutePath().toString(); + String[] args = {"run", inputFile, resultsOutputFile}; + callPmdWrapper(args); // Should not error + + String resultsJsonString = new String(Files.readAllBytes(Paths.get(resultsOutputFile))); + JsonElement element = JsonParser.parseString(resultsJsonString); // Should not error + assertThat(element.isJsonObject(), is(true)); + } + private static String createSampleRulesetFile(Path tempDir) throws Exception { String ruleSetContents = "\n" + From 655bc82835c0cb45ca153259c3704ea6d32683b4 Mon Sep 17 00:00:00 2001 From: Arun Tyagi Date: Thu, 22 Jan 2026 12:19:56 +0530 Subject: [PATCH 2/3] tests for describing deperecated rules in pmd --- .../sfca/pmdwrapper/PmdWrapperTest.java | 66 ++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/packages/code-analyzer-pmd-engine/pmd-cpd-wrappers/src/test/java/com/salesforce/sfca/pmdwrapper/PmdWrapperTest.java b/packages/code-analyzer-pmd-engine/pmd-cpd-wrappers/src/test/java/com/salesforce/sfca/pmdwrapper/PmdWrapperTest.java index d4ee863f..49120e8e 100644 --- a/packages/code-analyzer-pmd-engine/pmd-cpd-wrappers/src/test/java/com/salesforce/sfca/pmdwrapper/PmdWrapperTest.java +++ b/packages/code-analyzer-pmd-engine/pmd-cpd-wrappers/src/test/java/com/salesforce/sfca/pmdwrapper/PmdWrapperTest.java @@ -125,6 +125,70 @@ void whenCallingMainWithDescribeWithCustomRulesetsFile_thenRulesetsAreApplied(@T assertThat(ruleInfo2.ruleSetFile, is(sampleRulesetFile2.toAbsolutePath().toString())); } + @Test + void whenCallingMainWithDescribeWithNcssCountRuleset_thenRuleAppearsInDescribe(@TempDir Path tempDir) throws Exception { + // Create a minimal ruleset that references Apex NcssCount (metrics) + String rulesetXml = "\n" + + "\n" + + " Include Apex NcssCount\n" + + " \n" + + ""; + Path ncssRuleset = tempDir.resolve("ncss-ruleset.xml"); + Files.write(ncssRuleset, rulesetXml.getBytes()); + + // Prepare describe args with a custom rulesets list file + Path outputFile = tempDir.resolve("describe-output.json"); + Path rulesetsList = tempDir.resolve("customRulesetsList.txt"); + Files.write(rulesetsList, (ncssRuleset.toAbsolutePath().toString() + "\n").getBytes()); + + String[] args = {"describe", outputFile.toAbsolutePath().toString(), + rulesetsList.toAbsolutePath().toString(), "apex"}; + callPmdWrapper(args); + + // Parse output and assert NcssCount is present and references our ruleset file + String fileContents = Files.readString(outputFile); + Gson gson = new Gson(); + Type pmdRuleInfoListType = new TypeToken>(){}.getType(); + List pmdRuleInfoList = gson.fromJson(fileContents, pmdRuleInfoListType); + PmdRuleInfo ruleInfo = assertContainsOneRuleWithNameAndLanguage(pmdRuleInfoList, "NcssCount", "apex"); + assertThat(ruleInfo.ruleSetFile, is(ncssRuleset.toAbsolutePath().toString())); + } + + @Test + void whenCallingMainWithDescribeWithExcessiveClassLengthRuleset_thenRuleAppearsInDescribe(@TempDir Path tempDir) throws Exception { + // Create a minimal ruleset that references Apex ExcessiveClassLength (design) + String rulesetXml = "\n" + + "\n" + + " Include Apex ExcessiveClassLength\n" + + " \n" + + ""; + Path excessiveClassLengthRuleset = tempDir.resolve("excessive-class-length-ruleset.xml"); + Files.write(excessiveClassLengthRuleset, rulesetXml.getBytes()); + + // Prepare describe args with a custom rulesets list file + Path outputFile = tempDir.resolve("describe-output.json"); + Path rulesetsList = tempDir.resolve("customRulesetsList.txt"); + Files.write(rulesetsList, (excessiveClassLengthRuleset.toAbsolutePath().toString() + "\n").getBytes()); + + String[] args = {"describe", outputFile.toAbsolutePath().toString(), + rulesetsList.toAbsolutePath().toString(), "apex"}; + callPmdWrapper(args); + + // Parse output and assert ExcessiveClassLength is present and references our ruleset file + String fileContents = Files.readString(outputFile); + Gson gson = new Gson(); + Type pmdRuleInfoListType = new TypeToken>(){}.getType(); + List pmdRuleInfoList = gson.fromJson(fileContents, pmdRuleInfoListType); + PmdRuleInfo ruleInfo = assertContainsOneRuleWithNameAndLanguage(pmdRuleInfoList, "ExcessiveClassLength", "apex"); + assertThat(ruleInfo.ruleSetFile, is(excessiveClassLengthRuleset.toAbsolutePath().toString())); + } + @Test void whenCallingMainWithRunAndTwoFewArgs_thenError() { String[] args = {"run", "notEnough"}; @@ -382,7 +446,7 @@ void whenRunningWithNcssCountRule_thenReportsOrExecutesSuccessfully(@TempDir Pat " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" + " xsi:schemaLocation=\"http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd\">\n" + " Run Apex NcssCount\n" + - " \n" + + " \n" + " \n" + " \n" + " \n" + From 9bdf107115d67b9f8052d92a400ce8787f427e84 Mon Sep 17 00:00:00 2001 From: Arun Tyagi Date: Tue, 27 Jan 2026 13:25:47 +0530 Subject: [PATCH 3/3] fix test for warn and error --- .../com/salesforce/sfca/pmdwrapper/PmdRuleDescriber.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/code-analyzer-pmd-engine/pmd-cpd-wrappers/src/main/java/com/salesforce/sfca/pmdwrapper/PmdRuleDescriber.java b/packages/code-analyzer-pmd-engine/pmd-cpd-wrappers/src/main/java/com/salesforce/sfca/pmdwrapper/PmdRuleDescriber.java index 4c14f02d..10337e6c 100644 --- a/packages/code-analyzer-pmd-engine/pmd-cpd-wrappers/src/main/java/com/salesforce/sfca/pmdwrapper/PmdRuleDescriber.java +++ b/packages/code-analyzer-pmd-engine/pmd-cpd-wrappers/src/main/java/com/salesforce/sfca/pmdwrapper/PmdRuleDescriber.java @@ -170,7 +170,11 @@ public void logEx(Level level, @Nullable String s, Object[] objects, @Nullable T throw new RuntimeException("PMD threw an unexpected exception:\n" + message, throwable); } else if (level == Level.WARN && s != null){ String message = MessageFormat.format(s, objects); - System.out.println("[Warning] " + message.replaceAll("\n","{NEWLINE}")); + if (message.contains("Discontinue using Rule ")) { + System.out.println("[Warning] " + message.replaceAll("\n","{NEWLINE}")); + } else { + throw new RuntimeException("PMD threw an unexpected exception:\n" + message); + } }else if (s != null) { String message = MessageFormat.format(s, objects); throw new RuntimeException("PMD threw an unexpected exception:\n" + message);