Skip to content

Commit 546b193

Browse files
CHANGE @W-20736388@ - Add PMD run tests for NcssCount and ExcessiveClassLength (#403)
1 parent 0c8e34c commit 546b193

2 files changed

Lines changed: 160 additions & 1 deletion

File tree

packages/code-analyzer-pmd-engine/pmd-cpd-wrappers/src/main/java/com/salesforce/sfca/pmdwrapper/PmdRuleDescriber.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,11 @@ public void logEx(Level level, @Nullable String s, Object[] objects, @Nullable T
170170
throw new RuntimeException("PMD threw an unexpected exception:\n" + message, throwable);
171171
} else if (level == Level.WARN && s != null){
172172
String message = MessageFormat.format(s, objects);
173-
System.out.println("[Warning] " + message.replaceAll("\n","{NEWLINE}"));
173+
if (message.contains("Discontinue using Rule ")) {
174+
System.out.println("[Warning] " + message.replaceAll("\n","{NEWLINE}"));
175+
} else {
176+
throw new RuntimeException("PMD threw an unexpected exception:\n" + message);
177+
}
174178
}else if (s != null) {
175179
String message = MessageFormat.format(s, objects);
176180
throw new RuntimeException("PMD threw an unexpected exception:\n" + message);

packages/code-analyzer-pmd-engine/pmd-cpd-wrappers/src/test/java/com/salesforce/sfca/pmdwrapper/PmdWrapperTest.java

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,70 @@ void whenCallingMainWithDescribeWithCustomRulesetsFile_thenRulesetsAreApplied(@T
125125
assertThat(ruleInfo2.ruleSetFile, is(sampleRulesetFile2.toAbsolutePath().toString()));
126126
}
127127

128+
@Test
129+
void whenCallingMainWithDescribeWithNcssCountRuleset_thenRuleAppearsInDescribe(@TempDir Path tempDir) throws Exception {
130+
// Create a minimal ruleset that references Apex NcssCount (metrics)
131+
String rulesetXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
132+
"<ruleset name=\"Ruleset for NcssCount\"\n" +
133+
" xmlns=\"http://pmd.sourceforge.net/ruleset/2.0.0\"\n" +
134+
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
135+
" xsi:schemaLocation=\"http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd\">\n" +
136+
" <description>Include Apex NcssCount</description>\n" +
137+
" <rule ref=\"category/apex/design.xml/NcssCount\" />\n" +
138+
"</ruleset>";
139+
Path ncssRuleset = tempDir.resolve("ncss-ruleset.xml");
140+
Files.write(ncssRuleset, rulesetXml.getBytes());
141+
142+
// Prepare describe args with a custom rulesets list file
143+
Path outputFile = tempDir.resolve("describe-output.json");
144+
Path rulesetsList = tempDir.resolve("customRulesetsList.txt");
145+
Files.write(rulesetsList, (ncssRuleset.toAbsolutePath().toString() + "\n").getBytes());
146+
147+
String[] args = {"describe", outputFile.toAbsolutePath().toString(),
148+
rulesetsList.toAbsolutePath().toString(), "apex"};
149+
callPmdWrapper(args);
150+
151+
// Parse output and assert NcssCount is present and references our ruleset file
152+
String fileContents = Files.readString(outputFile);
153+
Gson gson = new Gson();
154+
Type pmdRuleInfoListType = new TypeToken<List<PmdRuleInfo>>(){}.getType();
155+
List<PmdRuleInfo> pmdRuleInfoList = gson.fromJson(fileContents, pmdRuleInfoListType);
156+
PmdRuleInfo ruleInfo = assertContainsOneRuleWithNameAndLanguage(pmdRuleInfoList, "NcssCount", "apex");
157+
assertThat(ruleInfo.ruleSetFile, is(ncssRuleset.toAbsolutePath().toString()));
158+
}
159+
160+
@Test
161+
void whenCallingMainWithDescribeWithExcessiveClassLengthRuleset_thenRuleAppearsInDescribe(@TempDir Path tempDir) throws Exception {
162+
// Create a minimal ruleset that references Apex ExcessiveClassLength (design)
163+
String rulesetXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
164+
"<ruleset name=\"Ruleset for ExcessiveClassLength\"\n" +
165+
" xmlns=\"http://pmd.sourceforge.net/ruleset/2.0.0\"\n" +
166+
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
167+
" xsi:schemaLocation=\"http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd\">\n" +
168+
" <description>Include Apex ExcessiveClassLength</description>\n" +
169+
" <rule ref=\"category/apex/design.xml/ExcessiveClassLength\" />\n" +
170+
"</ruleset>";
171+
Path excessiveClassLengthRuleset = tempDir.resolve("excessive-class-length-ruleset.xml");
172+
Files.write(excessiveClassLengthRuleset, rulesetXml.getBytes());
173+
174+
// Prepare describe args with a custom rulesets list file
175+
Path outputFile = tempDir.resolve("describe-output.json");
176+
Path rulesetsList = tempDir.resolve("customRulesetsList.txt");
177+
Files.write(rulesetsList, (excessiveClassLengthRuleset.toAbsolutePath().toString() + "\n").getBytes());
178+
179+
String[] args = {"describe", outputFile.toAbsolutePath().toString(),
180+
rulesetsList.toAbsolutePath().toString(), "apex"};
181+
callPmdWrapper(args);
182+
183+
// Parse output and assert ExcessiveClassLength is present and references our ruleset file
184+
String fileContents = Files.readString(outputFile);
185+
Gson gson = new Gson();
186+
Type pmdRuleInfoListType = new TypeToken<List<PmdRuleInfo>>(){}.getType();
187+
List<PmdRuleInfo> pmdRuleInfoList = gson.fromJson(fileContents, pmdRuleInfoListType);
188+
PmdRuleInfo ruleInfo = assertContainsOneRuleWithNameAndLanguage(pmdRuleInfoList, "ExcessiveClassLength", "apex");
189+
assertThat(ruleInfo.ruleSetFile, is(excessiveClassLengthRuleset.toAbsolutePath().toString()));
190+
}
191+
128192
@Test
129193
void whenCallingMainWithRunAndTwoFewArgs_thenError() {
130194
String[] args = {"run", "notEnough"};
@@ -373,6 +437,97 @@ void whenCallingRunWithAnInvalidApexFileWithValidApexFile_thenSkipInvalidApexFil
373437
assertThat(resultsJsonString, containsString("\"processingErrors\":[{\"file\":")); // Contains the processing error for the invalid file
374438
}
375439

440+
@Test
441+
void whenRunningWithNcssCountRule_thenReportsOrExecutesSuccessfully(@TempDir Path tempDir) throws Exception {
442+
// Create a minimal ruleset that references the Apex NcssCount rule with a very low threshold
443+
String rulesetXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
444+
"<ruleset name=\"Ruleset for NcssCount\"\n" +
445+
" xmlns=\"http://pmd.sourceforge.net/ruleset/2.0.0\"\n" +
446+
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
447+
" xsi:schemaLocation=\"http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd\">\n" +
448+
" <description>Run Apex NcssCount</description>\n" +
449+
" <rule ref=\"category/apex/design.xml/NcssCount\">\n" +
450+
" <properties>\n" +
451+
" <property name=\"minimum\" value=\"1\"/>\n" +
452+
" </properties>\n" +
453+
" </rule>\n" +
454+
"</ruleset>";
455+
String rulesetFile = createTempFile(tempDir, "ncss-ruleset.xml", rulesetXml);
456+
457+
// Create a simple Apex file with a few statements; the low threshold should trigger a violation
458+
String apexCode = "public class ManyStatements {\n" +
459+
" public static void foo(){\n" +
460+
" Integer a = 1; Integer b = 2; Integer c = 3; // multiple statements\n" +
461+
" }\n" +
462+
"}\n";
463+
String apexFile = createTempFile(tempDir, "ManyStatements.cls", apexCode);
464+
465+
String inputJson = "{\n" +
466+
" \"ruleSetInputFile\":\"" + makePathJsonSafe(rulesetFile) + "\",\n" +
467+
" \"runDataPerLanguage\": {\n" +
468+
" \"apex\": {\n" +
469+
" \"filesToScan\": [\"" + makePathJsonSafe(apexFile) + "\"]\n" +
470+
" }\n" +
471+
" }\n" +
472+
"}";
473+
String inputFile = createTempFile(tempDir, "input.json", inputJson);
474+
475+
String resultsOutputFile = tempDir.resolve("results.json").toAbsolutePath().toString();
476+
String[] args = {"run", inputFile, resultsOutputFile};
477+
callPmdWrapper(args); // Should not error
478+
479+
String resultsJsonString = new String(Files.readAllBytes(Paths.get(resultsOutputFile)));
480+
JsonElement element = JsonParser.parseString(resultsJsonString); // Should not error
481+
assertThat(element.isJsonObject(), is(true));
482+
}
483+
484+
@Test
485+
void whenRunningWithDeprecatedExcessiveClassLengthRule_thenExecutesSuccessfully(@TempDir Path tempDir) throws Exception {
486+
// Create a minimal ruleset referencing the Apex ExcessiveClassLength rule with a low threshold
487+
String rulesetXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
488+
"<ruleset name=\"Ruleset for ExcessiveClassLength\"\n" +
489+
" xmlns=\"http://pmd.sourceforge.net/ruleset/2.0.0\"\n" +
490+
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
491+
" xsi:schemaLocation=\"http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd\">\n" +
492+
" <description>Run Apex ExcessiveClassLength</description>\n" +
493+
" <rule ref=\"category/apex/design.xml/ExcessiveClassLength\">\n" +
494+
" <properties>\n" +
495+
" <property name=\"minimum\" value=\"5\"/>\n" +
496+
" </properties>\n" +
497+
" </rule>\n" +
498+
"</ruleset>";
499+
String rulesetFile = createTempFile(tempDir, "excessive-class-length.xml", rulesetXml);
500+
501+
// Create an Apex class with enough lines to exceed the small threshold
502+
StringBuilder apexBuilder = new StringBuilder();
503+
apexBuilder.append("public class LargeClass {\n");
504+
apexBuilder.append(" public static void m0(){ Integer x0 = 0; }\n");
505+
apexBuilder.append(" public static void m1(){ Integer x1 = 1; }\n");
506+
apexBuilder.append(" public static void m2(){ Integer x2 = 2; }\n");
507+
apexBuilder.append(" public static void m3(){ Integer x3 = 3; }\n");
508+
apexBuilder.append(" public static void m4(){ Integer x4 = 4; }\n");
509+
apexBuilder.append("}\n");
510+
String apexFile = createTempFile(tempDir, "LargeClass.cls", apexBuilder.toString());
511+
512+
String inputJson = "{\n" +
513+
" \"ruleSetInputFile\":\"" + makePathJsonSafe(rulesetFile) + "\",\n" +
514+
" \"runDataPerLanguage\": {\n" +
515+
" \"apex\": {\n" +
516+
" \"filesToScan\": [\"" + makePathJsonSafe(apexFile) + "\"]\n" +
517+
" }\n" +
518+
" }\n" +
519+
"}";
520+
String inputFile = createTempFile(tempDir, "input-excessive-class-length.json", inputJson);
521+
522+
String resultsOutputFile = tempDir.resolve("results-excessive-class-length.json").toAbsolutePath().toString();
523+
String[] args = {"run", inputFile, resultsOutputFile};
524+
callPmdWrapper(args); // Should not error
525+
526+
String resultsJsonString = new String(Files.readAllBytes(Paths.get(resultsOutputFile)));
527+
JsonElement element = JsonParser.parseString(resultsJsonString); // Should not error
528+
assertThat(element.isJsonObject(), is(true));
529+
}
530+
376531

377532
private static String createSampleRulesetFile(Path tempDir) throws Exception {
378533
String ruleSetContents = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +

0 commit comments

Comments
 (0)