@@ -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