1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.puppycrawl.tools.checkstyle;
21
22 import static com.google.common.truth.Truth.assertWithMessage;
23 import static com.puppycrawl.tools.checkstyle.AbstractPathTestSupport.addEndOfLine;
24 import static com.puppycrawl.tools.checkstyle.internal.utils.TestUtil.isUtilsClassHasPrivateConstructor;
25 import static org.junit.jupiter.api.Assumptions.assumeTrue;
26 import static org.mockito.Mockito.mock;
27 import static org.mockito.Mockito.mockStatic;
28 import static org.mockito.Mockito.verify;
29
30 import java.io.BufferedReader;
31 import java.io.ByteArrayOutputStream;
32 import java.io.File;
33 import java.io.IOException;
34 import java.io.PrintStream;
35 import java.io.Serial;
36 import java.nio.charset.StandardCharsets;
37 import java.nio.file.Files;
38 import java.nio.file.Path;
39 import java.util.ArrayList;
40 import java.util.List;
41 import java.util.Locale;
42 import java.util.logging.Handler;
43 import java.util.logging.Level;
44 import java.util.logging.Logger;
45 import java.util.regex.Matcher;
46 import java.util.regex.Pattern;
47 import java.util.stream.Collectors;
48
49 import org.itsallcode.io.Capturable;
50 import org.itsallcode.junit.sysextensions.SystemErrGuard;
51 import org.itsallcode.junit.sysextensions.SystemErrGuard.SysErr;
52 import org.itsallcode.junit.sysextensions.SystemOutGuard;
53 import org.itsallcode.junit.sysextensions.SystemOutGuard.SysOut;
54 import org.junit.jupiter.api.BeforeEach;
55 import org.junit.jupiter.api.Test;
56 import org.junit.jupiter.api.extension.ExtendWith;
57 import org.junit.jupiter.api.io.TempDir;
58 import org.mockito.MockedStatic;
59 import org.mockito.Mockito;
60
61 import com.puppycrawl.tools.checkstyle.AbstractAutomaticBean.OutputStreamOptions;
62 import com.puppycrawl.tools.checkstyle.api.AuditListener;
63 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
64 import com.puppycrawl.tools.checkstyle.api.Violation;
65 import com.puppycrawl.tools.checkstyle.internal.testmodules.TestRootModuleChecker;
66 import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
67 import com.puppycrawl.tools.checkstyle.utils.ChainedPropertyUtil;
68
69 @ExtendWith({SystemErrGuard.class, SystemOutGuard.class})
70 public class MainTest {
71
72 private static final String SHORT_USAGE = String.format(Locale.ROOT,
73 "Usage: checkstyle [OPTIONS]... file(s) or folder(s) ...%n"
74 + "Try 'checkstyle --help' for more information.%n");
75
76 private static final String USAGE = String.format(Locale.ROOT,
77 "Usage: checkstyle [-dEgGhjJtTV] [-b=<xpath>] [-c=<configurationFile>] "
78 + "[-f=<format>]%n"
79 + " [-o=<outputPath>] [-p=<propertiesFile>] "
80 + "[-s=<suppressionLineColumnNumber>]%n"
81 + " [-w=<tabWidth>] [-e=<exclude>]... [-x=<excludeRegex>]... "
82 + "<files or folders>...%n"
83 + "Checkstyle verifies that the specified source code files adhere to the"
84 + " specified rules. By default,%n"
85 + "violations are reported to standard out in plain format. Checkstyle requires"
86 + " a configuration XML%n"
87 + "file that configures the checks to apply.%n"
88 + " <files or folders>... One or more source files to verify%n"
89 + " -b, --branch-matching-xpath=<xpath>%n"
90 + " Shows Abstract Syntax Tree(AST) branches that"
91 + " match given XPath query.%n"
92 + " -c=<configurationFile> Specifies the location of the file that defines"
93 + " the configuration%n"
94 + " modules. The location can either be a"
95 + " filesystem location, or a name%n"
96 + " passed to the ClassLoader.getResource()"
97 + " method.%n"
98 + " -d, --debug Prints all debug logging of CheckStyle utility.%n"
99 + " -e, --exclude=<exclude> Directory/file to exclude from CheckStyle. The"
100 + " path can be the full,%n"
101 + " absolute path, or relative to the current"
102 + " path. Multiple excludes are%n"
103 + " allowed.%n"
104 + " -E, --executeIgnoredModules%n"
105 + " Allows ignored modules to be run.%n"
106 + " -f=<format> Specifies the output format. Valid values: "
107 + "xml, sarif, plain for%n"
108 + " XMLLogger, SarifLogger, and "
109 + "DefaultLogger respectively. Defaults to%n"
110 + " plain.%n"
111 + " -g, --generate-xpath-suppression%n"
112 + " Generates to output a xpath suppression xml to use"
113 + " to suppress all%n"
114 + " violations from user's config. Instead of"
115 + " printing every violation,%n"
116 + " all violations will be catched and single"
117 + " suppressions xml file will%n"
118 + " be printed out. Used only with -c option. Output"
119 + " location can be%n"
120 + " specified with -o option.%n"
121 + " -G, --generate-checks-and-files-suppression%n"
122 + " Generates to output a suppression xml that will"
123 + " have suppress elements%n"
124 + " with \"checks\" and \"files\" attributes only to"
125 + " use to suppress all%n"
126 + " violations from user's config. Instead of"
127 + " printing every violation,%n"
128 + " all violations will be catched and single"
129 + " suppressions xml file will%n"
130 + " be printed out. Used only with -c option. Output"
131 + " location can be%n"
132 + " specified with -o option.%n"
133 + " -h, --help Show this help message and exit.%n"
134 + " -j, --javadocTree This option is used to print the Parse Tree of"
135 + " the Javadoc comment. The%n"
136 + " file has to contain only Javadoc comment"
137 + " content excluding '/**' and%n"
138 + " '*/' at the beginning and at the end"
139 + " respectively. It can only be%n"
140 + " used on a single file and cannot be"
141 + " combined with other options.%n"
142 + " -J, --treeWithJavadoc This option is used to display the Abstract"
143 + " Syntax Tree (AST) with%n"
144 + " Javadoc nodes of the specified file. It can"
145 + " only be used on a single%n"
146 + " file and cannot be combined"
147 + " with other options.%n"
148 + " -o=<outputPath> Sets the output file. Defaults to stdout.%n"
149 + " -p=<propertiesFile> Sets the property files to load.%n"
150 + " -s=<suppressionLineColumnNumber>%n"
151 + " Prints xpath suppressions at the file's line and"
152 + " column position.%n"
153 + " Argument is the line and column number"
154 + " (separated by a : ) in the%n"
155 + " file that the suppression should be generated"
156 + " for. The option cannot%n"
157 + " be used with other options and requires exactly"
158 + " one file to run on to%n"
159 + " be specified. Note that the generated result"
160 + " will have few queries,%n"
161 + " joined by pipe(|). Together they will match all"
162 + " AST nodes on%n"
163 + " specified line and column. You need to choose"
164 + " only one and recheck%n"
165 + " that it works. Usage of all of them is also ok,"
166 + " but might result in%n"
167 + " undesirable matching and suppress other"
168 + " issues.%n"
169 + " -t, --tree This option is used to display the Abstract"
170 + " Syntax Tree (AST) without%n"
171 + " any comments of the specified file. It can"
172 + " only be used on a single%n"
173 + " file and cannot be combined with"
174 + " other options.%n"
175 + " -T, --treeWithComments This option is used to display the Abstract"
176 + " Syntax Tree (AST) with%n"
177 + " comment nodes excluding Javadoc of the"
178 + " specified file. It can only be%n"
179 + " used on a single file and cannot be combined"
180 + " with other options.%n"
181 + " -V, --version Print version information and exit.%n"
182 + " -w, --tabWidth=<tabWidth> Sets the length of the tab character. Used only"
183 + " with -s option. Default%n"
184 + " value is 8.%n"
185 + " -x, --exclude-regexp=<excludeRegex>%n"
186 + " Directory/file pattern to exclude from CheckStyle."
187 + " Multiple excludes%n"
188 + " are allowed.%n");
189
190 private static final Logger LOG = Logger.getLogger(MainTest.class.getName()).getParent();
191 private static final Handler[] HANDLERS = LOG.getHandlers();
192 private static final Level ORIGINAL_LOG_LEVEL = LOG.getLevel();
193
194 private static final String EOL = System.lineSeparator();
195
196 @TempDir
197 public File temporaryFolder;
198
199 private final LocalizedMessage auditStartMessage = new LocalizedMessage(
200 Definitions.CHECKSTYLE_BUNDLE, getClass(),
201 "DefaultLogger.auditStarted");
202
203 private final LocalizedMessage auditFinishMessage = new LocalizedMessage(
204 Definitions.CHECKSTYLE_BUNDLE, getClass(),
205 "DefaultLogger.auditFinished");
206
207 private final String noViolationsOutput = auditStartMessage.getMessage() + EOL
208 + auditFinishMessage.getMessage() + EOL;
209
210 private static String getPath(String filename) {
211 return "src/test/resources/com/puppycrawl/tools/checkstyle/main/" + filename;
212 }
213
214 private static String getNonCompilablePath(String filename) {
215 return "src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/main/" + filename;
216 }
217
218 private static String getFilePath(String filename) throws IOException {
219 return new File(getPath(filename)).getCanonicalPath();
220 }
221
222
223
224
225
226
227
228
229
230
231
232
233 @BeforeEach
234 public void setUp(@SysErr Capturable systemErr, @SysOut Capturable systemOut) {
235 systemErr.captureMuted();
236 systemOut.captureMuted();
237
238 System.setProperty("picocli.ansi", "false");
239
240 LOG.setLevel(ORIGINAL_LOG_LEVEL);
241
242 for (Handler handler : LOG.getHandlers()) {
243 boolean found = false;
244
245 for (Handler savedHandler : HANDLERS) {
246 if (handler == savedHandler) {
247 found = true;
248 break;
249 }
250 }
251
252 if (!found) {
253 LOG.removeHandler(handler);
254 }
255 }
256 }
257
258 @Test
259 public void testIsProperUtilsClass() throws ReflectiveOperationException {
260 assertWithMessage("Constructor is not private")
261 .that(isUtilsClassHasPrivateConstructor(Main.class))
262 .isTrue();
263 }
264
265 @Test
266 public void testVersionPrint(@SysErr Capturable systemErr, @SysOut Capturable systemOut) {
267 assertMainReturnCode(0, "-V");
268 assertWithMessage("Unexpected output log")
269 .that(systemOut.getCapturedData())
270 .isEqualTo("Checkstyle version: null" + System.lineSeparator());
271 assertWithMessage("Unexpected system error log")
272 .that(systemErr.getCapturedData())
273 .isEqualTo("");
274 }
275
276 @Test
277 public void testUsageHelpPrint(@SysErr Capturable systemErr, @SysOut Capturable systemOut) {
278 assertMainReturnCode(0, "-h");
279 assertWithMessage("Unexpected output log")
280 .that(systemOut.getCapturedData())
281 .isEqualTo(USAGE);
282 assertWithMessage("Unexpected system error log")
283 .that(systemErr.getCapturedData())
284 .isEqualTo("");
285 }
286
287 @Test
288 public void testWrongArgument(@SysErr Capturable systemErr, @SysOut Capturable systemOut) {
289
290
291
292 assertMainReturnCode(-1, "-q", "file");
293 final String usage = "Unknown option: '-q'" + EOL + SHORT_USAGE;
294 assertWithMessage("Unexpected output log")
295 .that(systemOut.getCapturedData())
296 .isEqualTo("");
297 assertWithMessage("Unexpected system error log")
298 .that(systemErr.getCapturedData())
299 .isEqualTo(usage);
300 }
301
302 @Test
303 public void testWrongArgumentMissingFiles(@SysErr Capturable systemErr,
304 @SysOut Capturable systemOut) {
305 assertMainReturnCode(-1, "-q");
306
307
308 final String usage = "Missing required parameter: '<files or folders>'" + EOL + SHORT_USAGE;
309 assertWithMessage("Unexpected output log")
310 .that(systemOut.getCapturedData())
311 .isEqualTo("");
312 assertWithMessage("Unexpected system error log")
313 .that(systemErr.getCapturedData())
314 .isEqualTo(usage);
315 }
316
317 @Test
318 public void testNoConfigSpecified(@SysErr Capturable systemErr, @SysOut Capturable systemOut) {
319 assertMainReturnCode(-1, getPath("InputMain.java"));
320 assertWithMessage("Unexpected output log")
321 .that(systemOut.getCapturedData())
322 .isEqualTo("Must specify a config XML file." + System.lineSeparator());
323 assertWithMessage("Unexpected system error log")
324 .that(systemErr.getCapturedData())
325 .isEqualTo("");
326 }
327
328 @Test
329 public void testNonExistentTargetFile(@SysErr Capturable systemErr,
330 @SysOut Capturable systemOut) {
331 assertMainReturnCode(-1, "-c", "/google_checks.xml", "NonExistentFile.java");
332 assertWithMessage("Unexpected output log")
333 .that(systemOut.getCapturedData())
334 .isEqualTo("Files to process must be specified, found 0." + System.lineSeparator());
335 assertWithMessage("Unexpected system error log")
336 .that(systemErr.getCapturedData())
337 .isEqualTo("");
338 }
339
340 @Test
341 public void testExistingTargetFileButWithoutReadAccess(
342 @SysErr Capturable systemErr, @SysOut Capturable systemOut) throws IOException {
343 final File file = Files.createTempFile(temporaryFolder.toPath(),
344 "testExistingTargetFileButWithoutReadAccess", null).toFile();
345
346
347 assumeTrue(file.setReadable(false), "file is still readable");
348
349 final String canonicalPath = file.getCanonicalPath();
350 assertMainReturnCode(-1, "-c", "/google_checks.xml", canonicalPath);
351 assertWithMessage("Unexpected output log")
352 .that(systemOut.getCapturedData())
353 .isEqualTo("Files to process must be specified, found 0." + System.lineSeparator());
354 assertWithMessage("Unexpected system error log")
355 .that(systemErr.getCapturedData())
356 .isEqualTo("");
357 }
358
359 @Test
360 public void testCustomSeverityVariableForGoogleConfig(@SysOut Capturable systemOut) {
361 assertMainReturnCode(1, "-c", "/google_checks.xml",
362 "-p", getPath("InputMainCustomSeverityForGoogleConfig.properties"),
363 getPath("InputMainCustomSeverityForGoogleConfig.java"));
364
365 final String expectedOutputStart = addEndOfLine(auditStartMessage.getMessage())
366 + "[ERROR] ";
367 final String expectedOutputEnd = addEndOfLine(
368 "InputMainCustomSeverityForGoogleConfig.java:3:1:"
369 + " Missing a Javadoc comment. [MissingJavadocType]",
370 auditFinishMessage.getMessage());
371 assertWithMessage("Unexpected output log")
372 .that(systemOut.getCapturedData())
373 .startsWith(expectedOutputStart);
374 assertWithMessage("Unexpected output log")
375 .that(systemOut.getCapturedData())
376 .endsWith(expectedOutputEnd);
377 }
378
379 @Test
380 public void testDefaultSeverityVariableForGoogleConfig(@SysOut Capturable systemOut) {
381 assertMainReturnCode(0, "-c", "/google_checks.xml",
382 getPath("InputMainCustomSeverityForGoogleConfig.java"));
383
384 final String expectedOutputStart = addEndOfLine(auditStartMessage.getMessage())
385 + "[WARN] ";
386 final String expectedOutputEnd = addEndOfLine(
387 "InputMainCustomSeverityForGoogleConfig.java:3:1:"
388 + " Missing a Javadoc comment. [MissingJavadocType]",
389 auditFinishMessage.getMessage());
390 assertWithMessage("Unexpected output log")
391 .that(systemOut.getCapturedData())
392 .startsWith(expectedOutputStart);
393 assertWithMessage("Unexpected output log")
394 .that(systemOut.getCapturedData())
395 .endsWith(expectedOutputEnd);
396 }
397
398 @Test
399 public void testNonExistentConfigFile(@SysErr Capturable systemErr,
400 @SysOut Capturable systemOut) {
401 assertMainReturnCode(-1, "-c", "src/main/resources/non_existent_config.xml",
402 getPath("InputMain.java"));
403 assertWithMessage("Unexpected output log")
404 .that(systemOut.getCapturedData())
405 .isEqualTo(addEndOfLine("Could not find config XML file "
406 + "'src/main/resources/non_existent_config.xml'."));
407 assertWithMessage("Unexpected system error log")
408 .that(systemErr.getCapturedData())
409 .isEqualTo("");
410 }
411
412 @Test
413 public void testNonExistentOutputFormat(@SysErr Capturable systemErr,
414 @SysOut Capturable systemOut) {
415 assertMainReturnCode(-1, "-c", "/google_checks.xml", "-f", "xmlp",
416 getPath("InputMain.java"));
417 assertWithMessage("Unexpected output log")
418 .that(systemOut.getCapturedData())
419 .isEqualTo("");
420 assertWithMessage("Unexpected system error log")
421 .that(systemErr.getCapturedData())
422 .isEqualTo("Invalid value for option '-f': expected one of [XML, SARIF, PLAIN]"
423 + " (case-insensitive) but was 'xmlp'" + EOL + SHORT_USAGE);
424 }
425
426 @Test
427 public void testNonExistentClass(@SysErr Capturable systemErr) {
428 assertMainReturnCode(-2, "-c", getPath("InputMainConfig-non-existent-classname.xml"),
429 getPath("InputMain.java"));
430 final String cause = "com.puppycrawl.tools.checkstyle.api.CheckstyleException:"
431 + " cannot initialize module TreeWalker - ";
432 assertWithMessage("Unexpected system error log")
433 .that(systemErr.getCapturedData())
434 .startsWith(cause);
435 }
436
437 @Test
438 public void testExistingTargetFile(@SysErr Capturable systemErr, @SysOut Capturable systemOut) {
439 assertMainReturnCode(0, "-c", getPath("InputMainConfig-classname.xml"),
440 getPath("InputMain.java"));
441 assertWithMessage("Unexpected output log")
442 .that(systemOut.getCapturedData())
443 .isEqualTo(addEndOfLine(auditStartMessage.getMessage(),
444 auditFinishMessage.getMessage()));
445 assertWithMessage("Unexpected system error log")
446 .that(systemErr.getCapturedData())
447 .isEqualTo("");
448 }
449
450 @Test
451 public void testExistingTargetFileXmlOutput(@SysErr Capturable systemErr,
452 @SysOut Capturable systemOut) throws IOException {
453 assertMainReturnCode(0, "-c", getPath("InputMainConfig-classname.xml"), "-f", "xml",
454 getPath("InputMain.java"));
455 final String expectedPath = getFilePath("InputMain.java");
456 final String version = Main.class.getPackage().getImplementationVersion();
457 assertWithMessage("Unexpected output log")
458 .that(systemOut.getCapturedData())
459 .isEqualTo(addEndOfLine(
460 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
461 "<checkstyle version=\"" + version + "\">",
462 "<file name=\"" + expectedPath + "\">",
463 "</file>",
464 "</checkstyle>"));
465 assertWithMessage("Unexpected system error log")
466 .that(systemErr.getCapturedData())
467 .isEqualTo("");
468 }
469
470
471
472
473
474
475
476
477
478
479 @Test
480 public void testNonClosedSystemStreams(@SysErr Capturable systemErr,
481 @SysOut Capturable systemOut) {
482 try (ShouldNotBeClosedStream stream = new ShouldNotBeClosedStream()) {
483 System.setOut(stream);
484 System.setErr(stream);
485 assertMainReturnCode(0, "-c", getPath("InputMainConfig-classname.xml"), "-f", "xml",
486 getPath("InputMain.java"));
487 assertWithMessage("stream should not be closed")
488 .that(stream.isClosed)
489 .isFalse();
490 assertWithMessage("System.err should be not used")
491 .that(systemErr.getCapturedData())
492 .isEmpty();
493 assertWithMessage("System.out should be not used")
494 .that(systemOut.getCapturedData())
495 .isEmpty();
496 }
497 }
498
499
500
501
502
503
504
505
506
507
508 @Test
509 public void testGetOutputStreamOptionsMethod() throws Exception {
510 final Path path = new File(getPath("InputMain.java")).toPath();
511 final OutputStreamOptions option =
512 TestUtil.invokeStaticMethod(Main.class, "getOutputStreamOptions",
513 OutputStreamOptions.class, path);
514 assertWithMessage("Main.getOutputStreamOptions return CLOSE on not null Path")
515 .that(option)
516 .isEqualTo(OutputStreamOptions.CLOSE);
517 }
518
519 @Test
520 public void testExistingTargetFilePlainOutput(@SysErr Capturable systemErr,
521 @SysOut Capturable systemOut) {
522 assertMainReturnCode(0, "-c", getPath("InputMainConfig-classname.xml"), "-f", "plain",
523 getPath("InputMain.java"));
524 assertWithMessage("Unexpected output log")
525 .that(systemOut.getCapturedData())
526 .isEqualTo(addEndOfLine(auditStartMessage.getMessage(),
527 auditFinishMessage.getMessage()));
528 assertWithMessage("Unexpected system error log")
529 .that(systemErr.getCapturedData())
530 .isEqualTo("");
531 }
532
533 @Test
534 public void testExistingTargetFileWithViolations(@SysErr Capturable systemErr,
535 @SysOut Capturable systemOut) throws IOException {
536 assertMainReturnCode(0, "-c", getPath("InputMainConfig-classname2.xml"),
537 getPath("InputMain.java"));
538 final Violation invalidPatternMessageMain = new Violation(1,
539 "com.puppycrawl.tools.checkstyle.checks.naming.messages",
540 "name.invalidPattern", new String[] {"InputMain", "^[a-z0-9]*$"},
541 null, getClass(), null);
542 final Violation invalidPatternMessageMainInner = new Violation(1,
543 "com.puppycrawl.tools.checkstyle.checks.naming.messages",
544 "name.invalidPattern", new String[] {"InputMainInner", "^[a-z0-9]*$"},
545 null, getClass(), null);
546 final String expectedPath = getFilePath("InputMain.java");
547 assertWithMessage("Unexpected output log")
548 .that(systemOut.getCapturedData())
549 .isEqualTo(addEndOfLine(auditStartMessage.getMessage(),
550 "[WARN] " + expectedPath + ":3:14: "
551 + invalidPatternMessageMain.getViolation()
552 + " [TypeName]",
553 "[WARN] " + expectedPath + ":5:7: "
554 + invalidPatternMessageMainInner.getViolation()
555 + " [TypeName]",
556 auditFinishMessage.getMessage()));
557 assertWithMessage("Unexpected system error log")
558 .that(systemErr.getCapturedData())
559 .isEqualTo("");
560 }
561
562 @Test
563 public void testViolationsByGoogleAndXpathSuppressions(@SysErr Capturable systemErr,
564 @SysOut Capturable systemOut) {
565 System.setProperty("org.checkstyle.google.suppressionxpathfilter.config",
566 getPath("InputMainViolationsForGoogleXpathSuppressions.xml"));
567 assertMainReturnCode(0, "-c", "/google_checks.xml",
568 getPath("InputMainViolationsForGoogle.java"));
569 assertWithMessage("Unexpected output log")
570 .that(systemOut.getCapturedData())
571 .isEqualTo(noViolationsOutput);
572 assertWithMessage("Unexpected system error log")
573 .that(systemErr.getCapturedData())
574 .isEqualTo("");
575 }
576
577 @Test
578 public void testViolationsByGoogleAndSuppressions(@SysErr Capturable systemErr,
579 @SysOut Capturable systemOut) {
580 System.setProperty("org.checkstyle.google.suppressionfilter.config",
581 getPath("InputMainViolationsForGoogleSuppressions.xml"));
582 assertMainReturnCode(0, "-c", "/google_checks.xml",
583 getPath("InputMainViolationsForGoogle.java"));
584 assertWithMessage("Unexpected output log")
585 .that(systemOut.getCapturedData())
586 .isEqualTo(noViolationsOutput);
587 assertWithMessage("Unexpected system error log")
588 .that(systemErr.getCapturedData())
589 .isEqualTo("");
590 }
591
592 @Test
593 public void testExistingTargetFileWithError(@SysErr Capturable systemErr,
594 @SysOut Capturable systemOut) throws Exception {
595 assertMainReturnCode(2, "-c", getPath("InputMainConfig-classname2-error.xml"),
596 getPath("InputMain.java"));
597 final Violation errorCounterTwoMessage = new Violation(1,
598 Definitions.CHECKSTYLE_BUNDLE, Main.ERROR_COUNTER,
599 new String[] {String.valueOf(2)}, null, getClass(), null);
600 final Violation invalidPatternMessageMain = new Violation(1,
601 "com.puppycrawl.tools.checkstyle.checks.naming.messages",
602 "name.invalidPattern", new String[] {"InputMain", "^[a-z0-9]*$"},
603 null, getClass(), null);
604 final Violation invalidPatternMessageMainInner = new Violation(1,
605 "com.puppycrawl.tools.checkstyle.checks.naming.messages",
606 "name.invalidPattern", new String[] {"InputMainInner", "^[a-z0-9]*$"},
607 null, getClass(), null);
608 final String expectedPath = getFilePath("InputMain.java");
609 assertWithMessage("Unexpected output log")
610 .that(systemOut.getCapturedData())
611 .isEqualTo(addEndOfLine(auditStartMessage.getMessage(),
612 "[ERROR] " + expectedPath + ":3:14: "
613 + invalidPatternMessageMain.getViolation() + " [TypeName]",
614 "[ERROR] " + expectedPath + ":5:7: "
615 + invalidPatternMessageMainInner.getViolation() + " [TypeName]",
616 auditFinishMessage.getMessage()));
617 assertWithMessage("Unexpected system error log")
618 .that(systemErr.getCapturedData())
619 .isEqualTo(addEndOfLine(errorCounterTwoMessage.getViolation()));
620 }
621
622
623
624
625
626
627
628
629 @Test
630 public void testExistingTargetFileWithOneError(@SysErr Capturable systemErr,
631 @SysOut Capturable systemOut) throws Exception {
632 assertMainReturnCode(1, "-c", getPath("InputMainConfig-classname2-error.xml"),
633 getPath("InputMain1.java"));
634 final Violation errorCounterTwoMessage = new Violation(1,
635 Definitions.CHECKSTYLE_BUNDLE, Main.ERROR_COUNTER,
636 new String[] {String.valueOf(1)}, null, getClass(), null);
637 final Violation invalidPatternMessageMain = new Violation(1,
638 "com.puppycrawl.tools.checkstyle.checks.naming.messages",
639 "name.invalidPattern", new String[] {"InputMain1", "^[a-z0-9]*$"},
640 null, getClass(), null);
641 final String expectedPath = getFilePath("InputMain1.java");
642 assertWithMessage("Unexpected output log")
643 .that(systemOut.getCapturedData())
644 .isEqualTo(addEndOfLine(auditStartMessage.getMessage(),
645 "[ERROR] " + expectedPath + ":3:14: "
646 + invalidPatternMessageMain.getViolation() + " [TypeName]",
647 auditFinishMessage.getMessage()));
648 assertWithMessage("Unexpected system error log")
649 .that(systemErr.getCapturedData())
650 .isEqualTo(addEndOfLine(errorCounterTwoMessage.getViolation()));
651 }
652
653 @Test
654 public void testExistingTargetFileWithOneErrorAgainstSunCheck(@SysErr Capturable systemErr,
655 @SysOut Capturable systemOut) throws Exception {
656 assertMainReturnCode(1, "-c", "/sun_checks.xml", getPath("InputMain1.java"));
657 final Violation errorCounterTwoMessage = new Violation(1,
658 Definitions.CHECKSTYLE_BUNDLE, Main.ERROR_COUNTER,
659 new String[] {String.valueOf(1)}, null, getClass(), null);
660 final Violation message = new Violation(1,
661 "com.puppycrawl.tools.checkstyle.checks.javadoc.messages",
662 "javadoc.packageInfo", new String[] {},
663 null, getClass(), null);
664 final String expectedPath = getFilePath("InputMain1.java");
665 assertWithMessage("Unexpected output log")
666 .that(systemOut.getCapturedData())
667 .isEqualTo(addEndOfLine(auditStartMessage.getMessage(),
668 "[ERROR] " + expectedPath + ":1: " + message.getViolation() + " [JavadocPackage]",
669 auditFinishMessage.getMessage()));
670 assertWithMessage("Unexpected system error log")
671 .that(systemErr.getCapturedData())
672 .isEqualTo(addEndOfLine(errorCounterTwoMessage.getViolation()));
673 }
674
675 @Test
676 public void testExistentTargetFilePlainOutputToNonExistentFile(@SysErr Capturable systemErr,
677 @SysOut Capturable systemOut) {
678 assertMainReturnCode(0, "-c", getPath("InputMainConfig-classname.xml"), "-f", "plain",
679 "-o", temporaryFolder + "/output.txt", getPath("InputMain.java"));
680 assertWithMessage("Unexpected output log")
681 .that(systemOut.getCapturedData())
682 .isEqualTo("");
683 assertWithMessage("Unexpected system error log")
684 .that(systemErr.getCapturedData())
685 .isEqualTo("");
686 }
687
688 @Test
689 public void testExistingTargetFilePlainOutputToFile(@SysErr Capturable systemErr,
690 @SysOut Capturable systemOut) throws Exception {
691 final String outputFile =
692 Files.createTempFile(temporaryFolder.toPath(), "file", ".output").toFile()
693 .getCanonicalPath();
694 assertWithMessage("File must exist")
695 .that(new File(outputFile).exists())
696 .isTrue();
697 assertMainReturnCode(0, "-c", getPath("InputMainConfig-classname.xml"), "-f", "plain",
698 "-o", outputFile, getPath("InputMain.java"));
699 assertWithMessage("Unexpected output log")
700 .that(systemOut.getCapturedData())
701 .isEqualTo("");
702 assertWithMessage("Unexpected system error log")
703 .that(systemErr.getCapturedData())
704 .isEqualTo("");
705 }
706
707 @Test
708 public void testCreateNonExistentOutputFile() throws IOException {
709 final String outputFile = new File(temporaryFolder, "nonexistent.out").getCanonicalPath();
710 assertWithMessage("File must not exist")
711 .that(new File(outputFile).exists())
712 .isFalse();
713 assertMainReturnCode(0, "-c", getPath("InputMainConfig-classname.xml"), "-f", "plain",
714 "-o", outputFile, getPath("InputMain.java"));
715 assertWithMessage("File must exist")
716 .that(new File(outputFile).exists())
717 .isTrue();
718 }
719
720 @Test
721 public void testExistingTargetFilePlainOutputProperties(@SysErr Capturable systemErr,
722 @SysOut Capturable systemOut) {
723 assertMainReturnCode(0, "-c", getPath("InputMainConfig-classname-prop.xml"),
724 "-p", getPath("InputMainMycheckstyle.properties"), getPath("InputMain.java"));
725 assertWithMessage("Unexpected output log")
726 .that(systemOut.getCapturedData())
727 .isEqualTo(addEndOfLine(auditStartMessage.getMessage(),
728 auditFinishMessage.getMessage()));
729 assertWithMessage("Unexpected system error log")
730 .that(systemErr.getCapturedData())
731 .isEqualTo("");
732 }
733
734 @Test
735 public void testPropertyFileWithPropertyChaining(@SysErr Capturable systemErr,
736 @SysOut Capturable systemOut) {
737 assertMainReturnCode(0, "-c", getPath("InputMainConfig-classname-prop.xml"),
738 "-p", getPath("InputMainPropertyChaining.properties"), getPath("InputMain.java"));
739
740 assertWithMessage("Unexpected output log")
741 .that(systemOut.getCapturedData())
742 .isEqualTo(addEndOfLine(auditStartMessage.getMessage(),
743 auditFinishMessage.getMessage()));
744 assertWithMessage("Unexpected system error log")
745 .that(systemErr.getCapturedData())
746 .isEqualTo("");
747 }
748
749 @Test
750 public void testPropertyFileWithPropertyChainingUndefinedProperty(@SysErr Capturable systemErr,
751 @SysOut Capturable systemOut) {
752 assertMainReturnCode(-2, "-c", getPath("InputMainConfig-classname-prop.xml"),
753 "-p", getPath("InputMainPropertyChainingUndefinedProperty.properties"),
754 getPath("InputMain.java"));
755
756 assertWithMessage("Invalid error message")
757 .that(systemErr.getCapturedData())
758 .contains(ChainedPropertyUtil.UNDEFINED_PROPERTY_MESSAGE);
759 assertWithMessage("Unexpected output log")
760 .that(systemOut.getCapturedData())
761 .isEqualTo("");
762 }
763
764 @Test
765 public void testExistingTargetFilePlainOutputNonexistentProperties(@SysErr Capturable systemErr,
766 @SysOut Capturable systemOut) {
767 assertMainReturnCode(-1, "-c", getPath("InputMainConfig-classname-prop.xml"),
768 "-p", "nonexistent.properties", getPath("InputMain.java"));
769 assertWithMessage("Unexpected output log")
770 .that(systemOut.getCapturedData())
771 .isEqualTo("Could not find file 'nonexistent.properties'."
772 + System.lineSeparator());
773 assertWithMessage("Unexpected system error log")
774 .that(systemErr.getCapturedData())
775 .isEqualTo("");
776 }
777
778 @Test
779 public void testExistingIncorrectConfigFile(@SysErr Capturable systemErr) {
780 assertMainReturnCode(-2, "-c", getPath("InputMainConfig-Incorrect.xml"),
781 getPath("InputMain.java"));
782 final String errorOutput = "com.puppycrawl.tools.checkstyle.api."
783 + "CheckstyleException: unable to parse configuration stream - ";
784 assertWithMessage("Unexpected system error log")
785 .that(systemErr.getCapturedData())
786 .startsWith(errorOutput);
787 }
788
789 @Test
790 public void testExistingIncorrectChildrenInConfigFile(@SysErr Capturable systemErr) {
791 assertMainReturnCode(-2, "-c", getPath("InputMainConfig-incorrectChildren.xml"),
792 getPath("InputMain.java"));
793 final String errorOutput = "com.puppycrawl.tools.checkstyle.api."
794 + "CheckstyleException: cannot initialize module RegexpSingleline"
795 + " - RegexpSingleline is not allowed as a child in RegexpSingleline";
796 assertWithMessage("Unexpected system error log")
797 .that(systemErr.getCapturedData())
798 .startsWith(errorOutput);
799 }
800
801 @Test
802 public void testExistingIncorrectChildrenInConfigFile2(@SysErr Capturable systemErr) {
803 assertMainReturnCode(-2, "-c", getPath("InputMainConfig-incorrectChildren2.xml"),
804 getPath("InputMain.java"));
805 final String errorOutput = "com.puppycrawl.tools.checkstyle.api."
806 + "CheckstyleException: cannot initialize module TreeWalker - "
807 + "cannot initialize module JavadocMethod";
808 assertWithMessage("Unexpected system error log")
809 .that(systemErr.getCapturedData())
810 .startsWith(errorOutput);
811 }
812
813 @Test
814 public void testLoadPropertiesIoException() throws Exception {
815 final Class<?> cliOptionsClass = Class.forName(Main.class.getName());
816 try {
817 TestUtil.invokeVoidStaticMethod(cliOptionsClass,
818 "loadProperties", new File("."));
819 assertWithMessage("Exception was expected").fail();
820 }
821 catch (ReflectiveOperationException exc) {
822 assertWithMessage("Invalid error cause")
823 .that(exc)
824 .hasCauseThat()
825 .isInstanceOf(CheckstyleException.class);
826
827
828
829 final Violation loadPropertiesMessage = new Violation(1,
830 Definitions.CHECKSTYLE_BUNDLE, Main.LOAD_PROPERTIES_EXCEPTION,
831 new String[] {""}, null, getClass(), null);
832 final String causeMessage = exc.getCause().getLocalizedMessage();
833 final String violation = loadPropertiesMessage.getViolation();
834 final boolean samePrefix = causeMessage.substring(0, causeMessage.indexOf(' '))
835 .equals(violation
836 .substring(0, violation.indexOf(' ')));
837 final boolean sameSuffix =
838 causeMessage.substring(causeMessage.lastIndexOf(' '))
839 .equals(violation
840 .substring(violation.lastIndexOf(' ')));
841 assertWithMessage("Invalid violation")
842 .that(samePrefix || sameSuffix)
843 .isTrue();
844 assertWithMessage("Invalid violation")
845 .that(causeMessage)
846 .contains(".'");
847 }
848 }
849
850 @Test
851 public void testExistingDirectoryWithViolations(@SysErr Capturable systemErr,
852 @SysOut Capturable systemOut) throws IOException {
853
854 final String[][] outputValues = {
855 {"InputMainComplexityOverflow", "1", "172"},
856 };
857
858 final int allowedLength = 170;
859 final String msgKey = "maxLen.file";
860 final String bundle = "com.puppycrawl.tools.checkstyle.checks.sizes.messages";
861
862 assertMainReturnCode(0, "-c", getPath("InputMainConfig-filelength.xml"),
863 getPath(""));
864 final String expectedPath = getFilePath("") + File.separator;
865 final StringBuilder sb = new StringBuilder(28);
866 sb.append(auditStartMessage.getMessage())
867 .append(EOL);
868 final String format = "[WARN] " + expectedPath + outputValues[0][0] + ".java:"
869 + outputValues[0][1] + ": ";
870 for (String[] outputValue : outputValues) {
871 final String violation = new Violation(1, bundle,
872 msgKey, new Integer[] {Integer.valueOf(outputValue[2]), allowedLength},
873 null, getClass(), null).getViolation();
874 final String line = format + violation + " [FileLength]";
875 sb.append(line).append(EOL);
876 }
877 sb.append(auditFinishMessage.getMessage())
878 .append(EOL);
879 assertWithMessage("Unexpected output log")
880 .that(systemOut.getCapturedData())
881 .isEqualTo(sb.toString());
882 assertWithMessage("Unexpected system error log")
883 .that(systemErr.getCapturedData())
884 .isEqualTo("");
885 }
886
887
888
889
890
891
892
893
894 @Test
895 public void testListFilesNotFile() throws Exception {
896 final File fileMock = new File("") {
897 @Serial
898 private static final long serialVersionUID = 1L;
899
900 @Override
901 public boolean canRead() {
902 return true;
903 }
904
905 @Override
906 public boolean isDirectory() {
907 return false;
908 }
909
910 @Override
911 public boolean isFile() {
912 return false;
913 }
914 };
915
916 final List<File> result = TestUtil.invokeStaticMethodList(Main.class, "listFiles",
917 fileMock, new ArrayList<>());
918 assertWithMessage("Invalid result size")
919 .that(result)
920 .isEmpty();
921 }
922
923
924
925
926
927
928
929
930 @Test
931 public void testListFilesDirectoryWithNull() throws Exception {
932 final File[] nullResult = null;
933 final File fileMock = new File("") {
934 @Serial
935 private static final long serialVersionUID = 1L;
936
937 @Override
938 public boolean canRead() {
939 return true;
940 }
941
942 @Override
943 public boolean isDirectory() {
944 return true;
945 }
946
947 @Override
948 public File[] listFiles() {
949 return nullResult;
950 }
951 };
952
953 final List<File> result = TestUtil.invokeStaticMethodList(Main.class, "listFiles",
954 fileMock, new ArrayList<>());
955 assertWithMessage("Invalid result size")
956 .that(result)
957 .isEmpty();
958 }
959
960 @Test
961 public void testFileReferenceDuringException(@SysErr Capturable systemErr) {
962
963 assertMainReturnCode(-2, "-c", getPath("InputMainConfig-classname.xml"),
964 getNonCompilablePath("InputMainIncorrectClass.java"));
965 final String exceptionMessage = addEndOfLine("com.puppycrawl.tools.checkstyle.api."
966 + "CheckstyleException: Exception was thrown while processing "
967 + new File(getNonCompilablePath("InputMainIncorrectClass.java")).getPath());
968 assertWithMessage("Unexpected system error log")
969 .that(systemErr.getCapturedData())
970 .contains(exceptionMessage);
971 }
972
973 @Test
974 public void testRemoveLexerDefaultErrorListener(@SysErr Capturable systemErr) {
975 assertMainReturnCode(-2, "-t", getNonCompilablePath("InputMainIncorrectClass.java"));
976
977 assertWithMessage("First line of exception message should not contain lexer error.")
978 .that(systemErr.getCapturedData().startsWith("line 2:2 token recognition error"))
979 .isFalse();
980 }
981
982 @Test
983 public void testRemoveParserDefaultErrorListener(@SysErr Capturable systemErr) {
984 assertMainReturnCode(-2, "-t", getNonCompilablePath("InputMainIncorrectClass.java"));
985 final String capturedData = systemErr.getCapturedData();
986
987 assertWithMessage("First line of exception message should not contain parser error.")
988 .that(capturedData.startsWith("line 2:0 no viable alternative"))
989 .isFalse();
990 assertWithMessage("Second line of exception message should not contain parser error.")
991 .that(capturedData.startsWith("line 2:0 no viable alternative",
992 capturedData.indexOf('\n') + 1))
993 .isFalse();
994 }
995
996 @Test
997 public void testPrintTreeOnMoreThanOneFile(@SysErr Capturable systemErr,
998 @SysOut Capturable systemOut) {
999 assertMainReturnCode(-1, "-t", getPath(""));
1000 assertWithMessage("Unexpected output log")
1001 .that(systemOut.getCapturedData())
1002 .isEqualTo("Printing AST is allowed for only one file." + System.lineSeparator());
1003 assertWithMessage("Unexpected system error log")
1004 .that(systemErr.getCapturedData())
1005 .isEqualTo("");
1006 }
1007
1008 @Test
1009 public void testPrintTreeOption(@SysErr Capturable systemErr, @SysOut Capturable systemOut) {
1010 final String expected = addEndOfLine(
1011 "COMPILATION_UNIT -> COMPILATION_UNIT [1:1]",
1012 "|--PACKAGE_DEF -> package [1:1]",
1013 "| |--ANNOTATIONS -> ANNOTATIONS [1:40]",
1014 "| |--DOT -> . [1:40]",
1015 "| | |--DOT -> . [1:29]",
1016 "| | | |--DOT -> . [1:23]",
1017 "| | | | |--DOT -> . [1:12]",
1018 "| | | | | |--IDENT -> com [1:9]",
1019 "| | | | | `--IDENT -> puppycrawl [1:13]",
1020 "| | | | `--IDENT -> tools [1:24]",
1021 "| | | `--IDENT -> checkstyle [1:30]",
1022 "| | `--IDENT -> main [1:41]",
1023 "| `--SEMI -> ; [1:45]",
1024 "|--CLASS_DEF -> CLASS_DEF [3:1]",
1025 "| |--MODIFIERS -> MODIFIERS [3:1]",
1026 "| | `--LITERAL_PUBLIC -> public [3:1]",
1027 "| |--LITERAL_CLASS -> class [3:8]",
1028 "| |--IDENT -> InputMain [3:14]",
1029 "| `--OBJBLOCK -> OBJBLOCK [3:24]",
1030 "| |--LCURLY -> { [3:24]",
1031 "| `--RCURLY -> } [4:1]",
1032 "`--CLASS_DEF -> CLASS_DEF [5:1]",
1033 " |--MODIFIERS -> MODIFIERS [5:1]",
1034 " |--LITERAL_CLASS -> class [5:1]",
1035 " |--IDENT -> InputMainInner [5:7]",
1036 " `--OBJBLOCK -> OBJBLOCK [5:22]",
1037 " |--LCURLY -> { [5:22]",
1038 " `--RCURLY -> } [6:1]");
1039
1040 assertMainReturnCode(0, "-t", getPath("InputMain.java"));
1041 assertWithMessage("Unexpected output log")
1042 .that(systemOut.getCapturedData())
1043 .isEqualTo(expected);
1044 assertWithMessage("Unexpected system error log")
1045 .that(systemErr.getCapturedData())
1046 .isEqualTo("");
1047 }
1048
1049 @Test
1050 public void testPrintXpathOption(@SysErr Capturable systemErr, @SysOut Capturable systemOut) {
1051 final String expected = addEndOfLine(
1052 "COMPILATION_UNIT -> COMPILATION_UNIT [1:1]",
1053 "|--CLASS_DEF -> CLASS_DEF [3:1]",
1054 "| `--OBJBLOCK -> OBJBLOCK [3:29]",
1055 "| |--METHOD_DEF -> METHOD_DEF [4:5]",
1056 "| | `--SLIST -> { [4:21]",
1057 "| | |--VARIABLE_DEF -> VARIABLE_DEF [5:9]",
1058 "| | | |--IDENT -> a [5:13]");
1059 assertMainReturnCode(0, "-b",
1060 "/COMPILATION_UNIT/CLASS_DEF//METHOD_DEF[./IDENT[@text='methodOne']]"
1061 + "//VARIABLE_DEF/IDENT",
1062 getPath("InputMainXPath.java"));
1063 assertWithMessage("Unexpected output log")
1064 .that(systemOut.getCapturedData())
1065 .isEqualTo(expected);
1066 assertWithMessage("Unexpected system error log")
1067 .that(systemErr.getCapturedData())
1068 .isEqualTo("");
1069 }
1070
1071 @Test
1072 public void testCliTreeAndSuppressionConsistency(@SysOut Capturable systemOut) {
1073 final String filePath = getPath("InputMain.java");
1074
1075 assertMainReturnCode(0, "-t", filePath);
1076
1077 final String treeOutput = systemOut.getCapturedData();
1078
1079 final Pattern pattern = Pattern.compile("(\\w+) -> .*?\\[(\\d+:\\d+)]");
1080 final Matcher matcher = pattern.matcher(treeOutput);
1081
1082 boolean foundAtLeastOne = false;
1083 while (matcher.find()) {
1084 foundAtLeastOne = true;
1085 final String tokenName = matcher.group(1);
1086
1087 if (!"COMPILATION_UNIT".equals(tokenName)) {
1088 final String coordinates = matcher.group(2);
1089
1090 final int previousLength = systemOut.getCapturedData().length();
1091
1092 assertMainReturnCode(0, "-s", coordinates, filePath);
1093
1094 final String allOutput = systemOut.getCapturedData();
1095 final String newOutput = allOutput.substring(previousLength);
1096
1097 assertWithMessage("CLI -s should return XPath ending in /%s for coordinates %s",
1098 tokenName, coordinates)
1099 .that(newOutput)
1100 .contains("/" + tokenName);
1101 }
1102 }
1103
1104 assertWithMessage("Should have found at least one token in -t output")
1105 .that(foundAtLeastOne)
1106 .isTrue();
1107 }
1108
1109 @Test
1110 public void testPrintXpathCommentNode(@SysErr Capturable systemErr,
1111 @SysOut Capturable systemOut) {
1112 final String expected = addEndOfLine(
1113 "COMPILATION_UNIT -> COMPILATION_UNIT [1:1]",
1114 "`--CLASS_DEF -> CLASS_DEF [17:1]",
1115 " `--OBJBLOCK -> OBJBLOCK [17:20]",
1116 " |--CTOR_DEF -> CTOR_DEF [19:5]",
1117 " | |--BLOCK_COMMENT_BEGIN -> /* [18:5]");
1118 assertMainReturnCode(0, "-b", "/COMPILATION_UNIT/CLASS_DEF//BLOCK_COMMENT_BEGIN",
1119 getPath("InputMainXPath.java"));
1120 assertWithMessage("Unexpected output log")
1121 .that(systemOut.getCapturedData())
1122 .isEqualTo(expected);
1123 assertWithMessage("Unexpected system error log")
1124 .that(systemErr.getCapturedData())
1125 .isEqualTo("");
1126 }
1127
1128 @Test
1129 public void testPrintXpathNodeParentNull(@SysErr Capturable systemErr,
1130 @SysOut Capturable systemOut) {
1131 final String expected = addEndOfLine("COMPILATION_UNIT -> COMPILATION_UNIT [1:1]");
1132 assertMainReturnCode(0, "-b", "/COMPILATION_UNIT", getPath("InputMainXPath.java"));
1133 assertWithMessage("Unexpected output log")
1134 .that(systemOut.getCapturedData())
1135 .isEqualTo(expected);
1136 assertWithMessage("Unexpected system error log")
1137 .that(systemErr.getCapturedData())
1138 .isEqualTo("");
1139 }
1140
1141 @Test
1142 public void testPrintXpathFullOption(
1143 @SysErr Capturable systemErr, @SysOut Capturable systemOut) {
1144 final String expected = addEndOfLine(
1145 "COMPILATION_UNIT -> COMPILATION_UNIT [1:1]",
1146 "|--CLASS_DEF -> CLASS_DEF [3:1]",
1147 "| `--OBJBLOCK -> OBJBLOCK [3:29]",
1148 "| |--METHOD_DEF -> METHOD_DEF [8:5]",
1149 "| | `--SLIST -> { [8:27]",
1150 "| | |--VARIABLE_DEF -> VARIABLE_DEF [9:9]",
1151 "| | | |--IDENT -> a [9:13]");
1152 final String xpath = "/COMPILATION_UNIT/CLASS_DEF//METHOD_DEF[./IDENT[@text='method']]"
1153 + "//VARIABLE_DEF/IDENT";
1154 assertMainReturnCode(0, "--branch-matching-xpath", xpath, getPath("InputMainXPath.java"));
1155 assertWithMessage("Unexpected output log")
1156 .that(systemOut.getCapturedData())
1157 .isEqualTo(expected);
1158 assertWithMessage("Unexpected system error log")
1159 .that(systemErr.getCapturedData())
1160 .isEqualTo("");
1161 }
1162
1163 @Test
1164 public void testPrintXpathTwoResults(
1165 @SysErr Capturable systemErr, @SysOut Capturable systemOut) {
1166 final String expected = addEndOfLine(
1167 "COMPILATION_UNIT -> COMPILATION_UNIT [1:1]",
1168 "|--CLASS_DEF -> CLASS_DEF [12:1]",
1169 "| `--OBJBLOCK -> OBJBLOCK [12:11]",
1170 "| |--METHOD_DEF -> METHOD_DEF [13:5]",
1171 "---------",
1172 "COMPILATION_UNIT -> COMPILATION_UNIT [1:1]",
1173 "|--CLASS_DEF -> CLASS_DEF [12:1]",
1174 "| `--OBJBLOCK -> OBJBLOCK [12:11]",
1175 "| |--METHOD_DEF -> METHOD_DEF [14:5]");
1176 assertMainReturnCode(0, "--branch-matching-xpath",
1177 "/COMPILATION_UNIT/CLASS_DEF[./IDENT[@text='Two']]//METHOD_DEF",
1178 getPath("InputMainXPath.java"));
1179 assertWithMessage("Unexpected output log")
1180 .that(systemOut.getCapturedData())
1181 .isEqualTo(expected);
1182 assertWithMessage("Unexpected system error log")
1183 .that(systemErr.getCapturedData())
1184 .isEqualTo("");
1185 }
1186
1187 @Test
1188 public void testPrintXpathInvalidXpath(@SysErr Capturable systemErr) throws Exception {
1189 final String invalidXpath = "\\/COMPILATION_UNIT/CLASS_DEF[./IDENT[@text='Two']]"
1190 + "//METHOD_DEF";
1191 final String filePath = getFilePath("InputMainXPath.java");
1192 assertMainReturnCode(-2, "--branch-matching-xpath", invalidXpath, filePath);
1193 final String exceptionFirstLine = addEndOfLine("com.puppycrawl.tools.checkstyle.api."
1194 + "CheckstyleException: Error during evaluation for xpath: " + invalidXpath
1195 + ", file: " + filePath);
1196 assertWithMessage("Unexpected system error log")
1197 .that(systemErr.getCapturedData())
1198 .startsWith(exceptionFirstLine);
1199 }
1200
1201 @Test
1202 public void testPrintTreeCommentsOption(@SysErr Capturable systemErr,
1203 @SysOut Capturable systemOut) {
1204 final String expected = addEndOfLine(
1205 "COMPILATION_UNIT -> COMPILATION_UNIT [1:1]",
1206 "|--PACKAGE_DEF -> package [1:1]",
1207 "| |--ANNOTATIONS -> ANNOTATIONS [1:40]",
1208 "| |--DOT -> . [1:40]",
1209 "| | |--DOT -> . [1:29]",
1210 "| | | |--DOT -> . [1:23]",
1211 "| | | | |--DOT -> . [1:12]",
1212 "| | | | | |--IDENT -> com [1:9]",
1213 "| | | | | `--IDENT -> puppycrawl [1:13]",
1214 "| | | | `--IDENT -> tools [1:24]",
1215 "| | | `--IDENT -> checkstyle [1:30]",
1216 "| | `--IDENT -> main [1:41]",
1217 "| `--SEMI -> ; [1:45]",
1218 "|--CLASS_DEF -> CLASS_DEF [3:1]",
1219 "| |--MODIFIERS -> MODIFIERS [3:1]",
1220 "| | |--BLOCK_COMMENT_BEGIN -> /* [2:1]",
1221 "| | | |--COMMENT_CONTENT -> comment [2:3]",
1222 "| | | `--BLOCK_COMMENT_END -> */ [2:9]",
1223 "| | `--LITERAL_PUBLIC -> public [3:1]",
1224 "| |--LITERAL_CLASS -> class [3:8]",
1225 "| |--IDENT -> InputMain [3:14]",
1226 "| `--OBJBLOCK -> OBJBLOCK [3:24]",
1227 "| |--LCURLY -> { [3:24]",
1228 "| `--RCURLY -> } [4:1]",
1229 "`--CLASS_DEF -> CLASS_DEF [5:1]",
1230 " |--MODIFIERS -> MODIFIERS [5:1]",
1231 " |--LITERAL_CLASS -> class [5:1]",
1232 " |--IDENT -> InputMainInner [5:7]",
1233 " `--OBJBLOCK -> OBJBLOCK [5:22]",
1234 " |--LCURLY -> { [5:22]",
1235 " `--RCURLY -> } [6:1]");
1236
1237 assertMainReturnCode(0, "-T", getPath("InputMain.java"));
1238 assertWithMessage("Unexpected output log")
1239 .that(systemOut.getCapturedData())
1240 .isEqualTo(expected);
1241 assertWithMessage("Unexpected system error log")
1242 .that(systemErr.getCapturedData())
1243 .isEqualTo("");
1244 }
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255 @Test
1256 public void testPrintTreeJavadocOption(@SysErr Capturable systemErr,
1257 @SysOut Capturable systemOut) throws IOException {
1258 final String expected = Files.readString(Path.of(
1259 getPath("InputMainExpectedInputJavadocComment.txt")))
1260 .replaceAll("\\\\r\\\\n", "\\\\n").replaceAll("\r\n", "\n");
1261
1262 assertMainReturnCode(0, "-j", getPath("InputMainJavadocComment.javadoc"));
1263 assertWithMessage("Unexpected output log")
1264 .that(systemOut.getCapturedData().replaceAll("\\\\r\\\\n", "\\\\n")
1265 .replaceAll("\r\n", "\n"))
1266 .isEqualTo(expected);
1267 assertWithMessage("Unexpected system error log")
1268 .that(systemErr.getCapturedData())
1269 .isEqualTo("");
1270 }
1271
1272 @Test
1273 public void testPrintSuppressionOption(@SysErr Capturable systemErr,
1274 @SysOut Capturable systemOut) {
1275 final String expected = addEndOfLine(
1276 "/COMPILATION_UNIT/CLASS_DEF[./IDENT[@text='InputMainSuppressionsStringPrinter']]",
1277 "/COMPILATION_UNIT/CLASS_DEF[./IDENT[@text='InputMainSuppressionsStringPrinter']]"
1278 + "/MODIFIERS",
1279 "/COMPILATION_UNIT/CLASS_DEF[./IDENT[@text='InputMainSuppressionsStringPrinter']"
1280 + "]/LITERAL_CLASS");
1281
1282 assertMainReturnCode(0, getPath("InputMainSuppressionsStringPrinter.java"), "-s", "3:1");
1283 assertWithMessage("Unexpected output log")
1284 .that(systemOut.getCapturedData())
1285 .isEqualTo(expected);
1286 assertWithMessage("Unexpected system error log")
1287 .that(systemErr.getCapturedData())
1288 .isEqualTo("");
1289 }
1290
1291 @Test
1292 public void testPrintSuppressionAndTabWidthOption(@SysErr Capturable systemErr,
1293 @SysOut Capturable systemOut) {
1294 final String expected = addEndOfLine(
1295 "/COMPILATION_UNIT/CLASS_DEF"
1296 + "[./IDENT[@text='InputMainSuppressionsStringPrinter']]/OBJBLOCK"
1297 + "/METHOD_DEF[./IDENT[@text='getName']]"
1298 + "/SLIST/VARIABLE_DEF[./IDENT[@text='var']]",
1299 "/COMPILATION_UNIT/CLASS_DEF"
1300 + "[./IDENT[@text='InputMainSuppressionsStringPrinter']]/OBJBLOCK"
1301 + "/METHOD_DEF[./IDENT[@text='getName']]/SLIST"
1302 + "/VARIABLE_DEF[./IDENT[@text='var']]/MODIFIERS",
1303 "/COMPILATION_UNIT/CLASS_DEF"
1304 + "[./IDENT[@text='InputMainSuppressionsStringPrinter']]/OBJBLOCK"
1305 + "/METHOD_DEF[./IDENT[@text='getName']]/SLIST"
1306 + "/VARIABLE_DEF[./IDENT[@text='var']]/TYPE",
1307 "/COMPILATION_UNIT/CLASS_DEF"
1308 + "[./IDENT[@text='InputMainSuppressionsStringPrinter']]/OBJBLOCK"
1309 + "/METHOD_DEF[./IDENT[@text='getName']]/SLIST"
1310 + "/VARIABLE_DEF[./IDENT[@text='var']]/TYPE/LITERAL_INT");
1311
1312 assertMainReturnCode(0, getPath("InputMainSuppressionsStringPrinter.java"),
1313 "-s", "7:9", "--tabWidth", "2");
1314 assertWithMessage("Unexpected output log")
1315 .that(systemOut.getCapturedData())
1316 .isEqualTo(expected);
1317 assertWithMessage("Unexpected system error log")
1318 .that(systemErr.getCapturedData())
1319 .isEqualTo("");
1320 }
1321
1322 @Test
1323 public void testPrintSuppressionConflictingOptionsTvsC(@SysErr Capturable systemErr,
1324 @SysOut Capturable systemOut) {
1325 assertMainReturnCode(-1, "-c", "/google_checks.xml", getPath(""), "-s", "2:4");
1326 assertWithMessage("Unexpected output log")
1327 .that(systemOut.getCapturedData())
1328 .isEqualTo("Option '-s' cannot be used with other options."
1329 + System.lineSeparator());
1330 assertWithMessage("Unexpected system error log")
1331 .that(systemErr.getCapturedData())
1332 .isEqualTo("");
1333 }
1334
1335 @Test
1336 public void testPrintSuppressionConflictingOptionsTvsP(@SysErr Capturable systemErr,
1337 @SysOut Capturable systemOut) {
1338 assertMainReturnCode(-1, "-p", getPath("InputMainMycheckstyle.properties"), "-s", "2:4",
1339 getPath(""));
1340 assertWithMessage("Unexpected output log")
1341 .that(systemOut.getCapturedData())
1342 .isEqualTo("Option '-s' cannot be used with other options."
1343 + System.lineSeparator());
1344 assertWithMessage("Unexpected system error log")
1345 .that(systemErr.getCapturedData())
1346 .isEqualTo("");
1347 }
1348
1349 @Test
1350 public void testPrintSuppressionConflictingOptionsTvsF(@SysErr Capturable systemErr,
1351 @SysOut Capturable systemOut) {
1352 assertMainReturnCode(-1, "-f", "plain", "-s", "2:4", getPath(""));
1353 assertWithMessage("Unexpected output log")
1354 .that(systemOut.getCapturedData())
1355 .isEqualTo("Option '-s' cannot be used with other options."
1356 + System.lineSeparator());
1357 assertWithMessage("Unexpected system error log")
1358 .that(systemErr.getCapturedData())
1359 .isEqualTo("");
1360 }
1361
1362 @Test
1363 public void testPrintSuppressionConflictingOptionsTvsO(@SysErr Capturable systemErr,
1364 @SysOut Capturable systemOut) throws IOException {
1365 final String outputPath = new File(temporaryFolder, "file.output").getCanonicalPath();
1366
1367 assertMainReturnCode(-1, "-o", outputPath, "-s", "2:4", getPath(""));
1368 assertWithMessage("Unexpected output log")
1369 .that(systemOut.getCapturedData())
1370 .isEqualTo("Option '-s' cannot be used with other options."
1371 + System.lineSeparator());
1372 assertWithMessage("Unexpected system error log")
1373 .that(systemErr.getCapturedData())
1374 .isEqualTo("");
1375 }
1376
1377 @Test
1378 public void testPrintSuppressionOnMoreThanOneFile(@SysErr Capturable systemErr,
1379 @SysOut Capturable systemOut) {
1380 assertMainReturnCode(-1, "-s", "2:4", getPath(""), getPath(""));
1381 assertWithMessage("Unexpected output log")
1382 .that(systemOut.getCapturedData())
1383 .isEqualTo("Printing xpath suppressions is allowed for only one file."
1384 + System.lineSeparator());
1385 assertWithMessage("Unexpected system error log")
1386 .that(systemErr.getCapturedData())
1387 .isEqualTo("");
1388 }
1389
1390 @Test
1391 public void testGenerateXpathSuppressionOptionOne(@SysErr Capturable systemErr,
1392 @SysOut Capturable systemOut) {
1393 final String expected = addEndOfLine(
1394 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
1395 "<!DOCTYPE suppressions PUBLIC",
1396 " \"-//Checkstyle//DTD SuppressionXpathFilter Experimental Configuration 1.2"
1397 + "//EN\"",
1398 " \"https://checkstyle.org/dtds/suppressions_1_2_xpath_experimental.dtd\">",
1399 "<suppressions>",
1400 " <suppress-xpath",
1401 " files=\"InputMainComplexityOverflow.java\"",
1402 " checks=\"MissingJavadocMethodCheck\"",
1403 " query=\"/COMPILATION_UNIT/CLASS_DEF"
1404 + "[./IDENT[@text='InputMainComplexityOverflow']]/OBJBLOCK"
1405 + "/METHOD_DEF[./IDENT[@text='provokeNpathIntegerOverflow']]\"/>",
1406 " <suppress-xpath",
1407 " files=\"InputMainComplexityOverflow.java\"",
1408 " id=\"LeftCurlyEol\"",
1409 " query=\"/COMPILATION_UNIT/CLASS_DEF"
1410 + "[./IDENT[@text='InputMainComplexityOverflow']]/OBJBLOCK"
1411 + "/METHOD_DEF[./IDENT[@text='provokeNpathIntegerOverflow']]/SLIST\"/>",
1412 "</suppressions>");
1413
1414 assertMainReturnCode(0, "-c", "/google_checks.xml", "--generate-xpath-suppression",
1415 getPath("InputMainComplexityOverflow.java"));
1416 assertWithMessage("Unexpected output log")
1417 .that(systemOut.getCapturedData())
1418 .isEqualTo(expected);
1419 assertWithMessage("Unexpected system error log")
1420 .that(systemErr.getCapturedData())
1421 .isEqualTo("");
1422 }
1423
1424 @Test
1425 public void testGenerateXpathSuppressionOptionTwo(@SysErr Capturable systemErr,
1426 @SysOut Capturable systemOut) {
1427 final String expected = addEndOfLine(
1428 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
1429 "<!DOCTYPE suppressions PUBLIC",
1430 " \"-//Checkstyle//DTD SuppressionXpathFilter Experimental Configuration 1.2"
1431 + "//EN\"",
1432 " \"https://checkstyle.org/dtds/suppressions_1_2_xpath_experimental.dtd\">",
1433 "<suppressions>",
1434 " <suppress-xpath",
1435 " files=\"InputMainGenerateXpathSuppressions.java\"",
1436 " checks=\"ExplicitInitializationCheck\"",
1437 " query=\"/COMPILATION_UNIT/CLASS_DEF"
1438 + "[./IDENT[@text='InputMainGenerateXpathSuppressions']]"
1439 + "/OBJBLOCK/VARIABLE_DEF/IDENT[@text='low']\"/>",
1440 " <suppress-xpath",
1441 " files=\"InputMainGenerateXpathSuppressions.java\"",
1442 " checks=\"IllegalThrowsCheck\"",
1443 " query=\"/COMPILATION_UNIT/CLASS_DEF"
1444 + "[./IDENT[@text='InputMainGenerateXpathSuppressions']]"
1445 + "/OBJBLOCK/METHOD_DEF[./IDENT[@text='test']]/LITERAL_THROWS"
1446 + "/IDENT[@text='RuntimeException']\"/>",
1447 " <suppress-xpath",
1448 " files=\"InputMainGenerateXpathSuppressions.java\"",
1449 " checks=\"NestedForDepthCheck\"",
1450 " query=\"/COMPILATION_UNIT/CLASS_DEF"
1451 + "[./IDENT[@text='InputMainGenerateXpathSuppressions']]"
1452 + "/OBJBLOCK/METHOD_DEF[./IDENT[@text='test']]/SLIST/LITERAL_FOR/SLIST"
1453 + "/LITERAL_FOR/SLIST/LITERAL_FOR\"/>",
1454 "</suppressions>");
1455
1456 assertMainReturnCode(0, "-c", getPath("InputMainConfig-xpath-suppressions.xml"),
1457 "--generate-xpath-suppression",
1458 getPath("InputMainGenerateXpathSuppressions.java"));
1459 assertWithMessage("Unexpected output log")
1460 .that(systemOut.getCapturedData())
1461 .isEqualTo(expected);
1462 assertWithMessage("Unexpected system error log")
1463 .that(systemErr.getCapturedData())
1464 .isEqualTo("");
1465 }
1466
1467 @Test
1468 public void testGenerateXpathSuppressionOptionEmptyConfig(@SysErr Capturable systemErr,
1469 @SysOut Capturable systemOut) {
1470 final String expected = "";
1471
1472 assertMainReturnCode(0, "-c", getPath("InputMainConfig-empty.xml"),
1473 "--generate-xpath-suppression", getPath("InputMainComplexityOverflow.java"));
1474 assertWithMessage("Unexpected output log")
1475 .that(systemOut.getCapturedData())
1476 .isEqualTo(expected);
1477 assertWithMessage("Unexpected system error log")
1478 .that(systemErr.getCapturedData())
1479 .isEqualTo("");
1480 }
1481
1482 @Test
1483 public void testGenerateXpathSuppressionOptionCustomOutput(@SysErr Capturable systemErr)
1484 throws IOException {
1485 final String expected = addEndOfLine(
1486 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
1487 "<!DOCTYPE suppressions PUBLIC",
1488 " \"-//Checkstyle//DTD SuppressionXpathFilter Experimental Configuration 1.2"
1489 + "//EN\"",
1490 " \"https://checkstyle.org/dtds/suppressions_1_2_xpath_experimental.dtd\">",
1491 "<suppressions>",
1492 " <suppress-xpath",
1493 " files=\"InputMainGenerateXpathSuppressionsTabWidth.java\"",
1494 " checks=\"ExplicitInitializationCheck\"",
1495 " query=\"/COMPILATION_UNIT/CLASS_DEF[./IDENT["
1496 + "@text='InputMainGenerateXpathSuppressionsTabWidth']]"
1497 + "/OBJBLOCK/VARIABLE_DEF/IDENT[@text='low']\"/>",
1498 "</suppressions>");
1499 final File file = new File(temporaryFolder, "file.output");
1500 assertMainReturnCode(0, "-c", getPath("InputMainConfig-xpath-suppressions.xml"), "-o",
1501 file.getPath(), "--generate-xpath-suppression",
1502 getPath("InputMainGenerateXpathSuppressionsTabWidth.java"));
1503 try (BufferedReader br = Files.newBufferedReader(file.toPath())) {
1504 final String fileContent = br.lines().collect(Collectors.joining(EOL, "", EOL));
1505 assertWithMessage("Unexpected output log")
1506 .that(fileContent)
1507 .isEqualTo(expected);
1508 assertWithMessage("Unexpected system error log")
1509 .that(systemErr.getCapturedData())
1510 .isEqualTo("");
1511 }
1512 }
1513
1514 @Test
1515 public void testGenerateXpathSuppressionOptionDefaultTabWidth(@SysErr Capturable systemErr,
1516 @SysOut Capturable systemOut) {
1517 final String expected = addEndOfLine(
1518 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
1519 "<!DOCTYPE suppressions PUBLIC",
1520 " \"-//Checkstyle//DTD SuppressionXpathFilter Experimental Configuration 1.2"
1521 + "//EN\"",
1522 " \"https://checkstyle.org/dtds/suppressions_1_2_xpath_experimental.dtd\">",
1523 "<suppressions>",
1524 " <suppress-xpath",
1525 " files=\"InputMainGenerateXpathSuppressionsTabWidth.java\"",
1526 " checks=\"ExplicitInitializationCheck\"",
1527 " query=\"/COMPILATION_UNIT/CLASS_DEF[./IDENT["
1528 + "@text='InputMainGenerateXpathSuppressionsTabWidth']]"
1529 + "/OBJBLOCK/VARIABLE_DEF/IDENT[@text='low']\"/>",
1530 "</suppressions>");
1531
1532 assertMainReturnCode(0, "-c", getPath("InputMainConfig-xpath-suppressions.xml"),
1533 "--generate-xpath-suppression",
1534 getPath("InputMainGenerateXpathSuppressionsTabWidth.java"));
1535 assertWithMessage("Unexpected output log")
1536 .that(systemOut.getCapturedData())
1537 .isEqualTo(expected);
1538 assertWithMessage("Unexpected system error log")
1539 .that(systemErr.getCapturedData())
1540 .isEqualTo("");
1541 }
1542
1543 @Test
1544 public void testGenerateXpathSuppressionOptionCustomTabWidth(@SysErr Capturable systemErr,
1545 @SysOut Capturable systemOut) {
1546 final String expected = "";
1547
1548 assertMainReturnCode(0, "-c", getPath("InputMainConfig-xpath-suppressions.xml"),
1549 "--generate-xpath-suppression", "--tabWidth", "20",
1550 getPath("InputMainGenerateXpathSuppressionsTabWidth.java"));
1551 assertWithMessage("Unexpected output log")
1552 .that(systemOut.getCapturedData())
1553 .isEqualTo(expected);
1554 assertWithMessage("Unexpected system error log")
1555 .that(systemErr.getCapturedData())
1556 .isEqualTo("");
1557 }
1558
1559 @Test
1560 public void testGenerateChecksAndFilesSuppressionOptionOne(@SysErr Capturable systemErr,
1561 @SysOut Capturable systemOut) {
1562 final String expected = addEndOfLine(
1563 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
1564 "<!DOCTYPE suppressions PUBLIC",
1565 " \"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN\"",
1566 " \"https://checkstyle.org/dtds/suppressions_1_2.dtd\">",
1567 "<suppressions>",
1568 " <suppress",
1569 " files=\"InputMainComplexityOverflow.java\"",
1570 " checks=\"MissingJavadocMethodCheck\"/>",
1571 " <suppress",
1572 " files=\"InputMainComplexityOverflow.java\"",
1573 " id=\"LeftCurlyEol\"/>",
1574 "</suppressions>");
1575
1576 assertMainReturnCode(0, "-c", "/google_checks.xml",
1577 "--generate-checks-and-files-suppression",
1578 getPath("InputMainComplexityOverflow.java"));
1579 assertWithMessage("Unexpected output log")
1580 .that(systemOut.getCapturedData())
1581 .isEqualTo(expected);
1582 assertWithMessage("Unexpected system error log")
1583 .that(systemErr.getCapturedData())
1584 .isEqualTo("");
1585 }
1586
1587 @Test
1588 public void testGenerateChecksAndFilesSuppressionOptionTwo(@SysErr Capturable systemErr,
1589 @SysOut Capturable systemOut) {
1590 final String expected = addEndOfLine(
1591 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
1592 "<!DOCTYPE suppressions PUBLIC",
1593 " \"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN\"",
1594 " \"https://checkstyle.org/dtds/suppressions_1_2.dtd\">",
1595 "<suppressions>",
1596 " <suppress",
1597 " files=\"InputMainGenerateChecksAndFilesSuppressions.java\"",
1598 " id=\"InitializeViolation\"/>",
1599 " <suppress",
1600 " files=\"InputMainGenerateChecksAndFilesSuppressions.java\"",
1601 " checks=\"IllegalThrowsCheck\"/>",
1602 " <suppress",
1603 " files=\"InputMainGenerateChecksAndFilesSuppressions.java\"",
1604 " checks=\"NestedForDepthCheck\"/>",
1605 " <suppress",
1606 " files=\"InputMainGenerateChecksAndFilesSuppressions.java\"",
1607 " id=\"MethodNaming\"/>",
1608 "</suppressions>");
1609
1610 assertMainReturnCode(0, "-c", getPath("InputMainConfig-Checks-And-Files-suppressions.xml"),
1611 "--generate-checks-and-files-suppression",
1612 getPath("InputMainGenerateChecksAndFilesSuppressions.java"));
1613 assertWithMessage("Unexpected output log")
1614 .that(systemOut.getCapturedData())
1615 .isEqualTo(expected);
1616 assertWithMessage("Unexpected system error log")
1617 .that(systemErr.getCapturedData())
1618 .isEqualTo("");
1619 }
1620
1621 @Test
1622 public void testGenerateChecksAndFilesSuppressionOptionEmptyConfig(@SysErr Capturable systemErr,
1623 @SysOut Capturable systemOut) {
1624 final String expected = "";
1625
1626 assertMainReturnCode(0, "-c", getPath("InputMainConfig-empty.xml"),
1627 "--generate-checks-and-files-suppression",
1628 getPath("InputMainComplexityOverflow.java"));
1629 assertWithMessage("Unexpected output log")
1630 .that(systemOut.getCapturedData())
1631 .isEqualTo(expected);
1632 assertWithMessage("Unexpected system error log")
1633 .that(systemErr.getCapturedData())
1634 .isEqualTo("");
1635 }
1636
1637 @Test
1638 public void testGenerateChecksAndFilesSuppressionOptionCustomOutput(
1639 @SysErr Capturable systemErr) throws IOException {
1640 final String expected = addEndOfLine(
1641 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
1642 "<!DOCTYPE suppressions PUBLIC",
1643 " \"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN\"",
1644 " \"https://checkstyle.org/dtds/suppressions_1_2.dtd\">",
1645 "<suppressions>",
1646 " <suppress",
1647 " files=\"InputMainGenerateChecksAndFilesSuppressionsTabWidth.java\"",
1648 " id=\"InitializeViolation\"/>",
1649 "</suppressions>");
1650 final File file = new File(temporaryFolder, "file.output");
1651 assertMainReturnCode(0, "-c", getPath("InputMainConfig-Checks-And-Files-suppressions.xml"),
1652 "-o", file.getPath(), "--generate-checks-and-files-suppression",
1653 getPath("InputMainGenerateChecksAndFilesSuppressionsTabWidth.java"));
1654 try (BufferedReader br = Files.newBufferedReader(file.toPath())) {
1655 final String fileContent = br.lines().collect(Collectors.joining(EOL, "", EOL));
1656 assertWithMessage("Unexpected output log")
1657 .that(fileContent)
1658 .isEqualTo(expected);
1659 assertWithMessage("Unexpected system error log")
1660 .that(systemErr.getCapturedData())
1661 .isEqualTo("");
1662 }
1663 }
1664
1665 @Test
1666 public void testGenerateChecksAndFilesSuppressionOptionDefaultTabWidth(
1667 @SysErr Capturable systemErr, @SysOut Capturable systemOut) {
1668 final String expected = addEndOfLine(
1669 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
1670 "<!DOCTYPE suppressions PUBLIC",
1671 " \"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN\"",
1672 " \"https://checkstyle.org/dtds/suppressions_1_2.dtd\">",
1673 "<suppressions>",
1674 " <suppress",
1675 " files=\"InputMainGenerateChecksAndFilesSuppressionsTabWidth.java\"",
1676 " id=\"InitializeViolation\"/>",
1677 "</suppressions>");
1678
1679 assertMainReturnCode(0, "-c", getPath("InputMainConfig-Checks-And-Files-suppressions.xml"),
1680 "--generate-checks-and-files-suppression",
1681 getPath("InputMainGenerateChecksAndFilesSuppressionsTabWidth.java"));
1682 assertWithMessage("Unexpected output log")
1683 .that(systemOut.getCapturedData())
1684 .isEqualTo(expected);
1685 assertWithMessage("Unexpected system error log")
1686 .that(systemErr.getCapturedData())
1687 .isEqualTo("");
1688 }
1689
1690 @Test
1691 public void testGenerateChecksAndFilesSuppressionOptionCustomTabWidth(
1692 @SysErr Capturable systemErr, @SysOut Capturable systemOut) {
1693 final String expected = addEndOfLine(
1694 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
1695 "<!DOCTYPE suppressions PUBLIC",
1696 " \"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN\"",
1697 " \"https://checkstyle.org/dtds/suppressions_1_2.dtd\">",
1698 "<suppressions>",
1699 " <suppress",
1700 " files=\"InputMainGenerateChecksAndFilesSuppressionsTabWidth.java\"",
1701 " id=\"InitializeViolation\"/>",
1702 "</suppressions>");
1703
1704 assertMainReturnCode(0, "-c", getPath("InputMainConfig-Checks-And-Files-suppressions.xml"),
1705 "--generate-checks-and-files-suppression", "--tabWidth", "20",
1706 getPath("InputMainGenerateChecksAndFilesSuppressionsTabWidth.java"));
1707 assertWithMessage("Unexpected output log")
1708 .that(systemOut.getCapturedData())
1709 .isEqualTo(expected);
1710 assertWithMessage("Unexpected system error log")
1711 .that(systemErr.getCapturedData())
1712 .isEqualTo("");
1713 }
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724 @Test
1725 public void testPrintFullTreeOption(@SysErr Capturable systemErr, @SysOut Capturable systemOut)
1726 throws IOException {
1727 final String expected = Files.readString(Path.of(
1728 getPath("InputMainExpectedInputAstTreeStringPrinterJavadoc.txt")))
1729 .replaceAll("\\\\r\\\\n", "\\\\n")
1730 .replaceAll("\r\n", "\n");
1731
1732 assertMainReturnCode(0, "-J", getPath("InputMainAstTreeStringPrinterJavadoc.java"));
1733 assertWithMessage("Unexpected output log")
1734 .that(systemOut.getCapturedData().replaceAll("\\\\r\\\\n", "\\\\n")
1735 .replaceAll("\r\n", "\n"))
1736 .isEqualTo(expected);
1737 assertWithMessage("Unexpected system error log")
1738 .that(systemErr.getCapturedData())
1739 .isEqualTo("");
1740 }
1741
1742 @Test
1743 public void testConflictingOptionsTvsC(@SysErr Capturable systemErr,
1744 @SysOut Capturable systemOut) {
1745 assertMainReturnCode(-1, "-c", "/google_checks.xml", "-t", getPath(""));
1746 assertWithMessage("Unexpected output log")
1747 .that(systemOut.getCapturedData())
1748 .isEqualTo("Option '-t' cannot be used with other options." + System.lineSeparator());
1749 assertWithMessage("Unexpected system error log")
1750 .that(systemErr.getCapturedData())
1751 .isEqualTo("");
1752 }
1753
1754 @Test
1755 public void testConflictingOptionsTvsP(@SysErr Capturable systemErr,
1756 @SysOut Capturable systemOut) {
1757 assertMainReturnCode(-1, "-p", getPath("InputMainMycheckstyle.properties"), "-t",
1758 getPath(""));
1759 assertWithMessage("Unexpected output log")
1760 .that(systemOut.getCapturedData())
1761 .isEqualTo("Option '-t' cannot be used with other options." + System.lineSeparator());
1762 assertWithMessage("Unexpected system error log")
1763 .that(systemErr.getCapturedData())
1764 .isEqualTo("");
1765 }
1766
1767 @Test
1768 public void testConflictingOptionsTvsF(@SysErr Capturable systemErr,
1769 @SysOut Capturable systemOut) {
1770 assertMainReturnCode(-1, "-f", "plain", "-t", getPath(""));
1771 assertWithMessage("Unexpected output log")
1772 .that(systemOut.getCapturedData())
1773 .isEqualTo("Option '-t' cannot be used with other options." + System.lineSeparator());
1774 assertWithMessage("Unexpected system error log")
1775 .that(systemErr.getCapturedData())
1776 .isEqualTo("");
1777 }
1778
1779 @Test
1780 public void testConflictingOptionsTvsS(@SysErr Capturable systemErr,
1781 @SysOut Capturable systemOut) throws IOException {
1782 final String outputPath = new File(temporaryFolder, "file.output").getCanonicalPath();
1783
1784 assertMainReturnCode(-1, "-s", outputPath, "-t", getPath(""));
1785 assertWithMessage("Unexpected output log")
1786 .that(systemOut.getCapturedData())
1787 .isEqualTo("Option '-t' cannot be used with other options." + System.lineSeparator());
1788 assertWithMessage("Unexpected system error log")
1789 .that(systemErr.getCapturedData())
1790 .isEqualTo("");
1791 }
1792
1793 @Test
1794 public void testConflictingOptionsTvsO(@SysErr Capturable systemErr,
1795 @SysOut Capturable systemOut) throws IOException {
1796 final String outputPath = new File(temporaryFolder, "file.output").getCanonicalPath();
1797
1798 assertMainReturnCode(-1, "-o", outputPath, "-t", getPath(""));
1799 assertWithMessage("Unexpected output log")
1800 .that(systemOut.getCapturedData())
1801 .isEqualTo("Option '-t' cannot be used with other options." + System.lineSeparator());
1802 assertWithMessage("Unexpected system error log")
1803 .that(systemErr.getCapturedData())
1804 .isEqualTo("");
1805 }
1806
1807 @Test
1808 public void testDebugOption(@SysErr Capturable systemErr, @SysOut Capturable systemOut) {
1809 assertMainReturnCode(0, "-c", "/google_checks.xml", getPath("InputMain.java"), "-d");
1810 assertWithMessage("Unexpected system error log")
1811 .that(systemErr.getCapturedData())
1812 .contains("FINE: Checkstyle debug logging enabled");
1813 assertWithMessage("Unexpected system error log")
1814 .that(systemOut.getCapturedData())
1815 .contains("Audit done.");
1816
1817 }
1818
1819 @Test
1820 public void testExcludeOption(@SysErr Capturable systemErr, @SysOut Capturable systemOut)
1821 throws IOException {
1822 final String filePath = getFilePath("");
1823 assertMainReturnCode(-1, "-c", "/google_checks.xml", filePath, "-e", filePath);
1824 assertWithMessage("Unexpected output log")
1825 .that(systemOut.getCapturedData())
1826 .isEqualTo("Files to process must be specified, found 0." + System.lineSeparator());
1827 assertWithMessage("Unexpected system error log")
1828 .that(systemErr.getCapturedData())
1829 .isEqualTo("");
1830 }
1831
1832 @Test
1833 public void testExcludeOptionFile(@SysErr Capturable systemErr, @SysOut Capturable systemOut)
1834 throws IOException {
1835 final String filePath = getFilePath("InputMain.java");
1836 assertMainReturnCode(-1, "-c", "/google_checks.xml", filePath, "-e", filePath);
1837 assertWithMessage("Unexpected output log")
1838 .that(systemOut.getCapturedData())
1839 .isEqualTo("Files to process must be specified, found 0." + System.lineSeparator());
1840 assertWithMessage("Unexpected system error log")
1841 .that(systemErr.getCapturedData())
1842 .isEqualTo("");
1843 }
1844
1845 @Test
1846 public void testExcludeRegexpOption(@SysErr Capturable systemErr, @SysOut Capturable systemOut)
1847 throws IOException {
1848 final String filePath = getFilePath("");
1849 assertMainReturnCode(-1, "-c", "/google_checks.xml", filePath, "-x", ".");
1850 assertWithMessage("Unexpected output log")
1851 .that(systemOut.getCapturedData())
1852 .isEqualTo("Files to process must be specified, found 0." + System.lineSeparator());
1853 assertWithMessage("Unexpected output log")
1854 .that(systemErr.getCapturedData())
1855 .isEqualTo("");
1856 }
1857
1858 @Test
1859 public void testExcludeRegexpOptionFile(@SysErr Capturable systemErr,
1860 @SysOut Capturable systemOut) throws IOException {
1861 final String filePath = getFilePath("InputMain.java");
1862 assertMainReturnCode(-1, "-c", "/google_checks.xml", filePath, "-x", ".");
1863 assertWithMessage("Unexpected output log")
1864 .that(systemOut.getCapturedData())
1865 .isEqualTo("Files to process must be specified, found 0." + System.lineSeparator());
1866 assertWithMessage("Unexpected output log")
1867 .that(systemErr.getCapturedData())
1868 .isEqualTo("");
1869 }
1870
1871 @Test
1872 public void testExcludeDirectoryNotMatch() throws Exception {
1873 final Class<?> optionsClass = Class.forName(Main.class.getName());
1874 final List<Pattern> list = new ArrayList<>();
1875 list.add(Pattern.compile("BAD_PATH"));
1876
1877 final List<File> result = TestUtil.invokeStaticMethodList(
1878 optionsClass, "listFiles", new File(getFilePath("")), list);
1879 assertWithMessage("Invalid result size")
1880 .that(result)
1881 .isNotEmpty();
1882 }
1883
1884 @Test
1885 public void testCustomRootModule(@SysErr Capturable systemErr, @SysOut Capturable systemOut) {
1886 TestRootModuleChecker.reset();
1887
1888 assertMainReturnCode(0, "-c", getPath("InputMainConfig-custom-root-module.xml"),
1889 getPath("InputMain.java"));
1890 assertWithMessage("Unexpected output log")
1891 .that(systemOut.getCapturedData())
1892 .isEqualTo("");
1893 assertWithMessage("Unexpected system error log")
1894 .that(systemErr.getCapturedData())
1895 .isEqualTo("");
1896 assertWithMessage("Invalid Checker state")
1897 .that(TestRootModuleChecker.isProcessed())
1898 .isTrue();
1899 assertWithMessage("RootModule should be destroyed")
1900 .that(TestRootModuleChecker.isDestroyed())
1901 .isTrue();
1902 }
1903
1904 @Test
1905 public void testCustomSimpleRootModule(@SysErr Capturable systemErr) {
1906 TestRootModuleChecker.reset();
1907 assertMainReturnCode(-2, "-c", getPath("InputMainConfig-custom-simple-root-module.xml"),
1908 getPath("InputMain.java"));
1909 final String checkstylePackage = "com.puppycrawl.tools.checkstyle.";
1910 final LocalizedMessage unableToInstantiateExceptionMessage = new LocalizedMessage(
1911 Definitions.CHECKSTYLE_BUNDLE,
1912 getClass(),
1913 "PackageObjectFactory.unableToInstantiateExceptionMessage",
1914 "TestRootModuleChecker",
1915 checkstylePackage
1916 + "TestRootModuleChecker, "
1917 + "TestRootModuleCheckerCheck, " + checkstylePackage
1918 + "TestRootModuleCheckerCheck");
1919 assertWithMessage(
1920 "Unexpected system error log")
1921 .that(systemErr.getCapturedData())
1922 .startsWith(checkstylePackage + "api.CheckstyleException: "
1923 + unableToInstantiateExceptionMessage.getMessage());
1924 assertWithMessage("Invalid checker state")
1925 .that(TestRootModuleChecker.isProcessed())
1926 .isFalse();
1927 }
1928
1929 @Test
1930 public void testExceptionOnExecuteIgnoredModuleWithUnknownModuleName(
1931 @SysErr Capturable systemErr) {
1932 assertMainReturnCode(-2, "-c", getPath("InputMainConfig-non-existent-classname-ignore.xml"),
1933 "--executeIgnoredModules", getPath("InputMain.java"));
1934 final String cause = "com.puppycrawl.tools.checkstyle.api.CheckstyleException:"
1935 + " cannot initialize module TreeWalker - ";
1936 assertWithMessage("Unexpected system error log")
1937 .that(systemErr.getCapturedData())
1938 .startsWith(cause);
1939 }
1940
1941 @Test
1942 public void testExceptionOnExecuteIgnoredModuleWithBadPropertyValue(
1943 @SysErr Capturable systemErr) {
1944 assertMainReturnCode(-2, "-c", getPath("InputMainConfig-TypeName-bad-value.xml"),
1945 "--executeIgnoredModules", getPath("InputMain.java"));
1946 final String cause = "com.puppycrawl.tools.checkstyle.api.CheckstyleException:"
1947 + " cannot initialize module TreeWalker - ";
1948 final String causeDetail = "it is not a boolean";
1949 assertWithMessage("Unexpected system error log")
1950 .that(systemErr.getCapturedData())
1951 .startsWith(cause);
1952 assertWithMessage("Unexpected system error log")
1953 .that(systemErr.getCapturedData())
1954 .contains(causeDetail);
1955 }
1956
1957 @Test
1958 public void testNoProblemOnExecuteIgnoredModuleWithBadPropertyValue(
1959 @SysErr Capturable systemErr) {
1960 assertMainReturnCode(0, "-c", getPath("InputMainConfig-TypeName-bad-value.xml"),
1961 "", getPath("InputMain.java"));
1962 assertWithMessage("Unexpected system error log")
1963 .that(systemErr.getCapturedData())
1964 .isEmpty();
1965 }
1966
1967 @Test
1968 public void testMissingFiles(@SysErr Capturable systemErr, @SysOut Capturable systemOut) {
1969 assertMainReturnCode(-1);
1970 final String usage = "Missing required parameter: '<files or folders>'" + EOL + SHORT_USAGE;
1971 assertWithMessage("Unexpected output log")
1972 .that(systemOut.getCapturedData())
1973 .isEqualTo("");
1974 assertWithMessage("Unexpected system error log")
1975 .that(systemErr.getCapturedData())
1976 .isEqualTo(usage);
1977 }
1978
1979 @Test
1980 public void testOutputFormatToStringLowercase() {
1981 assertWithMessage("expected xml")
1982 .that(Main.OutputFormat.XML.toString())
1983 .isEqualTo("xml");
1984 assertWithMessage("expected plain")
1985 .that(Main.OutputFormat.PLAIN.toString())
1986 .isEqualTo("plain");
1987 }
1988
1989 @Test
1990 public void testXmlOutputFormatCreateListener() throws IOException {
1991 final ByteArrayOutputStream out = new ByteArrayOutputStream();
1992 final AuditListener listener = Main.OutputFormat.XML.createListener(out,
1993 OutputStreamOptions.CLOSE);
1994 assertWithMessage("listener is XMLLogger")
1995 .that(listener)
1996 .isInstanceOf(XMLLogger.class);
1997 }
1998
1999 @Test
2000 public void testSarifOutputFormatCreateListener() throws IOException {
2001 final ByteArrayOutputStream out = new ByteArrayOutputStream();
2002 final AuditListener listener = Main.OutputFormat.SARIF.createListener(out,
2003 OutputStreamOptions.CLOSE);
2004 assertWithMessage("listener is SarifLogger")
2005 .that(listener)
2006 .isInstanceOf(SarifLogger.class);
2007 }
2008
2009 @Test
2010 public void testPlainOutputFormatCreateListener() throws IOException {
2011 final ByteArrayOutputStream out = new ByteArrayOutputStream();
2012 final AuditListener listener = Main.OutputFormat.PLAIN.createListener(out,
2013 OutputStreamOptions.CLOSE);
2014 assertWithMessage("listener is DefaultLogger")
2015 .that(listener)
2016 .isInstanceOf(DefaultLogger.class);
2017 }
2018
2019 @Test
2020 public void testExcludeOptionDirectoryWithPlusInName(@SysErr Capturable systemErr,
2021 @SysOut Capturable systemOut)
2022 throws IOException {
2023
2024 final File specialDir = new File(temporaryFolder, "dir+name");
2025 assertWithMessage("Directory must be created")
2026 .that(specialDir.mkdirs())
2027 .isTrue();
2028
2029 final File inputFile = new File(specialDir, "InputMainExclude.java");
2030 Files.writeString(inputFile.toPath(),
2031 "public class InputMainExclude { }" + System.lineSeparator());
2032
2033 final String dirPath = specialDir.getCanonicalPath();
2034
2035 assertMainReturnCode(-1, "-c", "/google_checks.xml", dirPath,
2036 "-e", dirPath);
2037
2038 assertWithMessage("Unexpected output log")
2039 .that(systemOut.getCapturedData())
2040 .isEqualTo("Files to process must be specified, found 0."
2041 + System.lineSeparator());
2042 assertWithMessage("Unexpected system error log")
2043 .that(systemErr.getCapturedData())
2044 .isEqualTo("");
2045 }
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060 private static void assertMainReturnCode(int expectedExitCode, String... arguments) {
2061 final Runtime mock = mock();
2062 try (MockedStatic<Runtime> runtime = mockStatic(Runtime.class)) {
2063 runtime.when(Runtime::getRuntime)
2064 .thenReturn(mock);
2065 Main.main(arguments);
2066 }
2067 catch (IOException exception) {
2068 assertWithMessage("Unexpected exception: %s", exception).fail();
2069 }
2070 verify(mock).exit(expectedExitCode);
2071 }
2072
2073
2074
2075
2076
2077 private static final class ShouldNotBeClosedStream extends PrintStream {
2078
2079 private boolean isClosed;
2080
2081 private ShouldNotBeClosedStream() {
2082 super(new ByteArrayOutputStream(), false, StandardCharsets.UTF_8);
2083 }
2084
2085 @Override
2086 public void close() {
2087 isClosed = true;
2088 super.close();
2089 }
2090
2091 }
2092 }