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