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