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", path);
512 assertWithMessage("Main.getOutputStreamOptions return CLOSE on not null Path")
513 .that(option)
514 .isEqualTo(OutputStreamOptions.CLOSE);
515 }
516
517 @Test
518 public void testExistingTargetFilePlainOutput(@SysErr Capturable systemErr,
519 @SysOut Capturable systemOut) {
520 assertMainReturnCode(0, "-c", getPath("InputMainConfig-classname.xml"), "-f", "plain",
521 getPath("InputMain.java"));
522 assertWithMessage("Unexpected output log")
523 .that(systemOut.getCapturedData())
524 .isEqualTo(addEndOfLine(auditStartMessage.getMessage(),
525 auditFinishMessage.getMessage()));
526 assertWithMessage("Unexpected system error log")
527 .that(systemErr.getCapturedData())
528 .isEqualTo("");
529 }
530
531 @Test
532 public void testExistingTargetFileWithViolations(@SysErr Capturable systemErr,
533 @SysOut Capturable systemOut) throws IOException {
534 assertMainReturnCode(0, "-c", getPath("InputMainConfig-classname2.xml"),
535 getPath("InputMain.java"));
536 final Violation invalidPatternMessageMain = new Violation(1,
537 "com.puppycrawl.tools.checkstyle.checks.naming.messages",
538 "name.invalidPattern", new String[] {"InputMain", "^[a-z0-9]*$"},
539 null, getClass(), null);
540 final Violation invalidPatternMessageMainInner = new Violation(1,
541 "com.puppycrawl.tools.checkstyle.checks.naming.messages",
542 "name.invalidPattern", new String[] {"InputMainInner", "^[a-z0-9]*$"},
543 null, getClass(), null);
544 final String expectedPath = getFilePath("InputMain.java");
545 assertWithMessage("Unexpected output log")
546 .that(systemOut.getCapturedData())
547 .isEqualTo(addEndOfLine(auditStartMessage.getMessage(),
548 "[WARN] " + expectedPath + ":3:14: "
549 + invalidPatternMessageMain.getViolation()
550 + " [TypeName]",
551 "[WARN] " + expectedPath + ":5:7: "
552 + invalidPatternMessageMainInner.getViolation()
553 + " [TypeName]",
554 auditFinishMessage.getMessage()));
555 assertWithMessage("Unexpected system error log")
556 .that(systemErr.getCapturedData())
557 .isEqualTo("");
558 }
559
560 @Test
561 public void testViolationsByGoogleAndXpathSuppressions(@SysErr Capturable systemErr,
562 @SysOut Capturable systemOut) {
563 System.setProperty("org.checkstyle.google.suppressionxpathfilter.config",
564 getPath("InputMainViolationsForGoogleXpathSuppressions.xml"));
565 assertMainReturnCode(0, "-c", "/google_checks.xml",
566 getPath("InputMainViolationsForGoogle.java"));
567 assertWithMessage("Unexpected output log")
568 .that(systemOut.getCapturedData())
569 .isEqualTo(noViolationsOutput);
570 assertWithMessage("Unexpected system error log")
571 .that(systemErr.getCapturedData())
572 .isEqualTo("");
573 }
574
575 @Test
576 public void testViolationsByGoogleAndSuppressions(@SysErr Capturable systemErr,
577 @SysOut Capturable systemOut) {
578 System.setProperty("org.checkstyle.google.suppressionfilter.config",
579 getPath("InputMainViolationsForGoogleSuppressions.xml"));
580 assertMainReturnCode(0, "-c", "/google_checks.xml",
581 getPath("InputMainViolationsForGoogle.java"));
582 assertWithMessage("Unexpected output log")
583 .that(systemOut.getCapturedData())
584 .isEqualTo(noViolationsOutput);
585 assertWithMessage("Unexpected system error log")
586 .that(systemErr.getCapturedData())
587 .isEqualTo("");
588 }
589
590 @Test
591 public void testExistingTargetFileWithError(@SysErr Capturable systemErr,
592 @SysOut Capturable systemOut) throws Exception {
593 assertMainReturnCode(2, "-c", getPath("InputMainConfig-classname2-error.xml"),
594 getPath("InputMain.java"));
595 final Violation errorCounterTwoMessage = new Violation(1,
596 Definitions.CHECKSTYLE_BUNDLE, Main.ERROR_COUNTER,
597 new String[] {String.valueOf(2)}, null, getClass(), null);
598 final Violation invalidPatternMessageMain = new Violation(1,
599 "com.puppycrawl.tools.checkstyle.checks.naming.messages",
600 "name.invalidPattern", new String[] {"InputMain", "^[a-z0-9]*$"},
601 null, getClass(), null);
602 final Violation invalidPatternMessageMainInner = new Violation(1,
603 "com.puppycrawl.tools.checkstyle.checks.naming.messages",
604 "name.invalidPattern", new String[] {"InputMainInner", "^[a-z0-9]*$"},
605 null, getClass(), null);
606 final String expectedPath = getFilePath("InputMain.java");
607 assertWithMessage("Unexpected output log")
608 .that(systemOut.getCapturedData())
609 .isEqualTo(addEndOfLine(auditStartMessage.getMessage(),
610 "[ERROR] " + expectedPath + ":3:14: "
611 + invalidPatternMessageMain.getViolation() + " [TypeName]",
612 "[ERROR] " + expectedPath + ":5:7: "
613 + invalidPatternMessageMainInner.getViolation() + " [TypeName]",
614 auditFinishMessage.getMessage()));
615 assertWithMessage("Unexpected system error log")
616 .that(systemErr.getCapturedData())
617 .isEqualTo(addEndOfLine(errorCounterTwoMessage.getViolation()));
618 }
619
620
621
622
623
624
625
626
627 @Test
628 public void testExistingTargetFileWithOneError(@SysErr Capturable systemErr,
629 @SysOut Capturable systemOut) throws Exception {
630 assertMainReturnCode(1, "-c", getPath("InputMainConfig-classname2-error.xml"),
631 getPath("InputMain1.java"));
632 final Violation errorCounterTwoMessage = new Violation(1,
633 Definitions.CHECKSTYLE_BUNDLE, Main.ERROR_COUNTER,
634 new String[] {String.valueOf(1)}, null, getClass(), null);
635 final Violation invalidPatternMessageMain = new Violation(1,
636 "com.puppycrawl.tools.checkstyle.checks.naming.messages",
637 "name.invalidPattern", new String[] {"InputMain1", "^[a-z0-9]*$"},
638 null, getClass(), null);
639 final String expectedPath = getFilePath("InputMain1.java");
640 assertWithMessage("Unexpected output log")
641 .that(systemOut.getCapturedData())
642 .isEqualTo(addEndOfLine(auditStartMessage.getMessage(),
643 "[ERROR] " + expectedPath + ":3:14: "
644 + invalidPatternMessageMain.getViolation() + " [TypeName]",
645 auditFinishMessage.getMessage()));
646 assertWithMessage("Unexpected system error log")
647 .that(systemErr.getCapturedData())
648 .isEqualTo(addEndOfLine(errorCounterTwoMessage.getViolation()));
649 }
650
651 @Test
652 public void testExistingTargetFileWithOneErrorAgainstSunCheck(@SysErr Capturable systemErr,
653 @SysOut Capturable systemOut) throws Exception {
654 assertMainReturnCode(1, "-c", "/sun_checks.xml", getPath("InputMain1.java"));
655 final Violation errorCounterTwoMessage = new Violation(1,
656 Definitions.CHECKSTYLE_BUNDLE, Main.ERROR_COUNTER,
657 new String[] {String.valueOf(1)}, null, getClass(), null);
658 final Violation message = new Violation(1,
659 "com.puppycrawl.tools.checkstyle.checks.javadoc.messages",
660 "javadoc.packageInfo", new String[] {},
661 null, getClass(), null);
662 final String expectedPath = getFilePath("InputMain1.java");
663 assertWithMessage("Unexpected output log")
664 .that(systemOut.getCapturedData())
665 .isEqualTo(addEndOfLine(auditStartMessage.getMessage(),
666 "[ERROR] " + expectedPath + ":1: " + message.getViolation() + " [JavadocPackage]",
667 auditFinishMessage.getMessage()));
668 assertWithMessage("Unexpected system error log")
669 .that(systemErr.getCapturedData())
670 .isEqualTo(addEndOfLine(errorCounterTwoMessage.getViolation()));
671 }
672
673 @Test
674 public void testExistentTargetFilePlainOutputToNonExistentFile(@SysErr Capturable systemErr,
675 @SysOut Capturable systemOut) {
676 assertMainReturnCode(0, "-c", getPath("InputMainConfig-classname.xml"), "-f", "plain",
677 "-o", temporaryFolder + "/output.txt", getPath("InputMain.java"));
678 assertWithMessage("Unexpected output log")
679 .that(systemOut.getCapturedData())
680 .isEqualTo("");
681 assertWithMessage("Unexpected system error log")
682 .that(systemErr.getCapturedData())
683 .isEqualTo("");
684 }
685
686 @Test
687 public void testExistingTargetFilePlainOutputToFile(@SysErr Capturable systemErr,
688 @SysOut Capturable systemOut) throws Exception {
689 final String outputFile =
690 Files.createTempFile(temporaryFolder.toPath(), "file", ".output").toFile()
691 .getCanonicalPath();
692 assertWithMessage("File must exist")
693 .that(new File(outputFile).exists())
694 .isTrue();
695 assertMainReturnCode(0, "-c", getPath("InputMainConfig-classname.xml"), "-f", "plain",
696 "-o", outputFile, getPath("InputMain.java"));
697 assertWithMessage("Unexpected output log")
698 .that(systemOut.getCapturedData())
699 .isEqualTo("");
700 assertWithMessage("Unexpected system error log")
701 .that(systemErr.getCapturedData())
702 .isEqualTo("");
703 }
704
705 @Test
706 public void testCreateNonExistentOutputFile() throws IOException {
707 final String outputFile = new File(temporaryFolder, "nonexistent.out").getCanonicalPath();
708 assertWithMessage("File must not exist")
709 .that(new File(outputFile).exists())
710 .isFalse();
711 assertMainReturnCode(0, "-c", getPath("InputMainConfig-classname.xml"), "-f", "plain",
712 "-o", outputFile, getPath("InputMain.java"));
713 assertWithMessage("File must exist")
714 .that(new File(outputFile).exists())
715 .isTrue();
716 }
717
718 @Test
719 public void testExistingTargetFilePlainOutputProperties(@SysErr Capturable systemErr,
720 @SysOut Capturable systemOut) {
721 assertMainReturnCode(0, "-c", getPath("InputMainConfig-classname-prop.xml"),
722 "-p", getPath("InputMainMycheckstyle.properties"), getPath("InputMain.java"));
723 assertWithMessage("Unexpected output log")
724 .that(systemOut.getCapturedData())
725 .isEqualTo(addEndOfLine(auditStartMessage.getMessage(),
726 auditFinishMessage.getMessage()));
727 assertWithMessage("Unexpected system error log")
728 .that(systemErr.getCapturedData())
729 .isEqualTo("");
730 }
731
732 @Test
733 public void testPropertyFileWithPropertyChaining(@SysErr Capturable systemErr,
734 @SysOut Capturable systemOut) {
735 assertMainReturnCode(0, "-c", getPath("InputMainConfig-classname-prop.xml"),
736 "-p", getPath("InputMainPropertyChaining.properties"), getPath("InputMain.java"));
737
738 assertWithMessage("Unexpected output log")
739 .that(systemOut.getCapturedData())
740 .isEqualTo(addEndOfLine(auditStartMessage.getMessage(),
741 auditFinishMessage.getMessage()));
742 assertWithMessage("Unexpected system error log")
743 .that(systemErr.getCapturedData())
744 .isEqualTo("");
745 }
746
747 @Test
748 public void testPropertyFileWithPropertyChainingUndefinedProperty(@SysErr Capturable systemErr,
749 @SysOut Capturable systemOut) {
750 assertMainReturnCode(-2, "-c", getPath("InputMainConfig-classname-prop.xml"),
751 "-p", getPath("InputMainPropertyChainingUndefinedProperty.properties"),
752 getPath("InputMain.java"));
753
754 assertWithMessage("Invalid error message")
755 .that(systemErr.getCapturedData())
756 .contains(ChainedPropertyUtil.UNDEFINED_PROPERTY_MESSAGE);
757 assertWithMessage("Unexpected output log")
758 .that(systemOut.getCapturedData())
759 .isEqualTo("");
760 }
761
762 @Test
763 public void testExistingTargetFilePlainOutputNonexistentProperties(@SysErr Capturable systemErr,
764 @SysOut Capturable systemOut) {
765 assertMainReturnCode(-1, "-c", getPath("InputMainConfig-classname-prop.xml"),
766 "-p", "nonexistent.properties", getPath("InputMain.java"));
767 assertWithMessage("Unexpected output log")
768 .that(systemOut.getCapturedData())
769 .isEqualTo("Could not find file 'nonexistent.properties'."
770 + System.lineSeparator());
771 assertWithMessage("Unexpected system error log")
772 .that(systemErr.getCapturedData())
773 .isEqualTo("");
774 }
775
776 @Test
777 public void testExistingIncorrectConfigFile(@SysErr Capturable systemErr) {
778 assertMainReturnCode(-2, "-c", getPath("InputMainConfig-Incorrect.xml"),
779 getPath("InputMain.java"));
780 final String errorOutput = "com.puppycrawl.tools.checkstyle.api."
781 + "CheckstyleException: unable to parse configuration stream - ";
782 assertWithMessage("Unexpected system error log")
783 .that(systemErr.getCapturedData())
784 .startsWith(errorOutput);
785 }
786
787 @Test
788 public void testExistingIncorrectChildrenInConfigFile(@SysErr Capturable systemErr) {
789 assertMainReturnCode(-2, "-c", getPath("InputMainConfig-incorrectChildren.xml"),
790 getPath("InputMain.java"));
791 final String errorOutput = "com.puppycrawl.tools.checkstyle.api."
792 + "CheckstyleException: cannot initialize module RegexpSingleline"
793 + " - RegexpSingleline is not allowed as a child in RegexpSingleline";
794 assertWithMessage("Unexpected system error log")
795 .that(systemErr.getCapturedData())
796 .startsWith(errorOutput);
797 }
798
799 @Test
800 public void testExistingIncorrectChildrenInConfigFile2(@SysErr Capturable systemErr) {
801 assertMainReturnCode(-2, "-c", getPath("InputMainConfig-incorrectChildren2.xml"),
802 getPath("InputMain.java"));
803 final String errorOutput = "com.puppycrawl.tools.checkstyle.api."
804 + "CheckstyleException: cannot initialize module TreeWalker - "
805 + "cannot initialize module JavadocMethod - "
806 + "JavadocVariable is not allowed as a child in JavadocMethod";
807 assertWithMessage("Unexpected system error log")
808 .that(systemErr.getCapturedData())
809 .startsWith(errorOutput);
810 }
811
812 @Test
813 public void testLoadPropertiesIoException() throws Exception {
814 final Class<?> cliOptionsClass = Class.forName(Main.class.getName());
815 try {
816 TestUtil.invokeStaticMethod(cliOptionsClass, "loadProperties", new File("."));
817 assertWithMessage("Exception was expected").fail();
818 }
819 catch (ReflectiveOperationException exc) {
820 assertWithMessage("Invalid error cause")
821 .that(exc)
822 .hasCauseThat()
823 .isInstanceOf(CheckstyleException.class);
824
825
826
827 final Violation loadPropertiesMessage = new Violation(1,
828 Definitions.CHECKSTYLE_BUNDLE, Main.LOAD_PROPERTIES_EXCEPTION,
829 new String[] {""}, null, getClass(), null);
830 final String causeMessage = exc.getCause().getLocalizedMessage();
831 final String violation = loadPropertiesMessage.getViolation();
832 final boolean samePrefix = causeMessage.substring(0, causeMessage.indexOf(' '))
833 .equals(violation
834 .substring(0, violation.indexOf(' ')));
835 final boolean sameSuffix =
836 causeMessage.substring(causeMessage.lastIndexOf(' '))
837 .equals(violation
838 .substring(violation.lastIndexOf(' ')));
839 assertWithMessage("Invalid violation")
840 .that(samePrefix || sameSuffix)
841 .isTrue();
842 assertWithMessage("Invalid violation")
843 .that(causeMessage)
844 .contains(".'");
845 }
846 }
847
848 @Test
849 public void testExistingDirectoryWithViolations(@SysErr Capturable systemErr,
850 @SysOut Capturable systemOut) throws IOException {
851
852 final String[][] outputValues = {
853 {"InputMainComplexityOverflow", "1", "172"},
854 };
855
856 final int allowedLength = 170;
857 final String msgKey = "maxLen.file";
858 final String bundle = "com.puppycrawl.tools.checkstyle.checks.sizes.messages";
859
860 assertMainReturnCode(0, "-c", getPath("InputMainConfig-filelength.xml"),
861 getPath(""));
862 final String expectedPath = getFilePath("") + File.separator;
863 final StringBuilder sb = new StringBuilder(28);
864 sb.append(auditStartMessage.getMessage())
865 .append(EOL);
866 final String format = "[WARN] " + expectedPath + outputValues[0][0] + ".java:"
867 + outputValues[0][1] + ": ";
868 for (String[] outputValue : outputValues) {
869 final String violation = new Violation(1, bundle,
870 msgKey, new Integer[] {Integer.valueOf(outputValue[2]), allowedLength},
871 null, getClass(), null).getViolation();
872 final String line = format + violation + " [FileLength]";
873 sb.append(line).append(EOL);
874 }
875 sb.append(auditFinishMessage.getMessage())
876 .append(EOL);
877 assertWithMessage("Unexpected output log")
878 .that(systemOut.getCapturedData())
879 .isEqualTo(sb.toString());
880 assertWithMessage("Unexpected system error log")
881 .that(systemErr.getCapturedData())
882 .isEqualTo("");
883 }
884
885
886
887
888
889
890
891
892 @Test
893 public void testListFilesNotFile() throws Exception {
894 final File fileMock = new File("") {
895 @Serial
896 private static final long serialVersionUID = 1L;
897
898 @Override
899 public boolean canRead() {
900 return true;
901 }
902
903 @Override
904 public boolean isDirectory() {
905 return false;
906 }
907
908 @Override
909 public boolean isFile() {
910 return false;
911 }
912 };
913
914 final List<File> result = TestUtil.invokeStaticMethod(Main.class, "listFiles",
915 fileMock, new ArrayList<>());
916 assertWithMessage("Invalid result size")
917 .that(result)
918 .isEmpty();
919 }
920
921
922
923
924
925
926
927
928 @Test
929 public void testListFilesDirectoryWithNull() throws Exception {
930 final File[] nullResult = null;
931 final File fileMock = new File("") {
932 @Serial
933 private static final long serialVersionUID = 1L;
934
935 @Override
936 public boolean canRead() {
937 return true;
938 }
939
940 @Override
941 public boolean isDirectory() {
942 return true;
943 }
944
945 @Override
946 public File[] listFiles() {
947 return nullResult;
948 }
949 };
950
951 final List<File> result = TestUtil.invokeStaticMethod(Main.class, "listFiles",
952 fileMock, new ArrayList<>());
953 assertWithMessage("Invalid result size")
954 .that(result)
955 .isEmpty();
956 }
957
958 @Test
959 public void testFileReferenceDuringException(@SysErr Capturable systemErr) {
960
961 assertMainReturnCode(-2, "-c", getPath("InputMainConfig-classname.xml"),
962 getNonCompilablePath("InputMainIncorrectClass.java"));
963 final String exceptionMessage = addEndOfLine("com.puppycrawl.tools.checkstyle.api."
964 + "CheckstyleException: Exception was thrown while processing "
965 + new File(getNonCompilablePath("InputMainIncorrectClass.java")).getPath());
966 assertWithMessage("Unexpected system error log")
967 .that(systemErr.getCapturedData())
968 .contains(exceptionMessage);
969 }
970
971 @Test
972 public void testRemoveLexerDefaultErrorListener(@SysErr Capturable systemErr) {
973 assertMainReturnCode(-2, "-t", getNonCompilablePath("InputMainIncorrectClass.java"));
974
975 assertWithMessage("First line of exception message should not contain lexer error.")
976 .that(systemErr.getCapturedData().startsWith("line 2:2 token recognition error"))
977 .isFalse();
978 }
979
980 @Test
981 public void testRemoveParserDefaultErrorListener(@SysErr Capturable systemErr) {
982 assertMainReturnCode(-2, "-t", getNonCompilablePath("InputMainIncorrectClass.java"));
983 final String capturedData = systemErr.getCapturedData();
984
985 assertWithMessage("First line of exception message should not contain parser error.")
986 .that(capturedData.startsWith("line 2:0 no viable alternative"))
987 .isFalse();
988 assertWithMessage("Second line of exception message should not contain parser error.")
989 .that(capturedData.startsWith("line 2:0 no viable alternative",
990 capturedData.indexOf('\n') + 1))
991 .isFalse();
992 }
993
994 @Test
995 public void testPrintTreeOnMoreThanOneFile(@SysErr Capturable systemErr,
996 @SysOut Capturable systemOut) {
997 assertMainReturnCode(-1, "-t", getPath(""));
998 assertWithMessage("Unexpected output log")
999 .that(systemOut.getCapturedData())
1000 .isEqualTo("Printing AST is allowed for only one file." + System.lineSeparator());
1001 assertWithMessage("Unexpected system error log")
1002 .that(systemErr.getCapturedData())
1003 .isEqualTo("");
1004 }
1005
1006 @Test
1007 public void testPrintTreeOption(@SysErr Capturable systemErr, @SysOut Capturable systemOut) {
1008 final String expected = addEndOfLine(
1009 "COMPILATION_UNIT -> COMPILATION_UNIT [1:0]",
1010 "|--PACKAGE_DEF -> package [1:0]",
1011 "| |--ANNOTATIONS -> ANNOTATIONS [1:39]",
1012 "| |--DOT -> . [1:39]",
1013 "| | |--DOT -> . [1:28]",
1014 "| | | |--DOT -> . [1:22]",
1015 "| | | | |--DOT -> . [1:11]",
1016 "| | | | | |--IDENT -> com [1:8]",
1017 "| | | | | `--IDENT -> puppycrawl [1:12]",
1018 "| | | | `--IDENT -> tools [1:23]",
1019 "| | | `--IDENT -> checkstyle [1:29]",
1020 "| | `--IDENT -> main [1:40]",
1021 "| `--SEMI -> ; [1:44]",
1022 "|--CLASS_DEF -> CLASS_DEF [3:0]",
1023 "| |--MODIFIERS -> MODIFIERS [3:0]",
1024 "| | `--LITERAL_PUBLIC -> public [3:0]",
1025 "| |--LITERAL_CLASS -> class [3:7]",
1026 "| |--IDENT -> InputMain [3:13]",
1027 "| `--OBJBLOCK -> OBJBLOCK [3:23]",
1028 "| |--LCURLY -> { [3:23]",
1029 "| `--RCURLY -> } [4:0]",
1030 "`--CLASS_DEF -> CLASS_DEF [5:0]",
1031 " |--MODIFIERS -> MODIFIERS [5:0]",
1032 " |--LITERAL_CLASS -> class [5:0]",
1033 " |--IDENT -> InputMainInner [5:6]",
1034 " `--OBJBLOCK -> OBJBLOCK [5:21]",
1035 " |--LCURLY -> { [5:21]",
1036 " `--RCURLY -> } [6:0]");
1037
1038 assertMainReturnCode(0, "-t", getPath("InputMain.java"));
1039 assertWithMessage("Unexpected output log")
1040 .that(systemOut.getCapturedData())
1041 .isEqualTo(expected);
1042 assertWithMessage("Unexpected system error log")
1043 .that(systemErr.getCapturedData())
1044 .isEqualTo("");
1045 }
1046
1047 @Test
1048 public void testPrintXpathOption(@SysErr Capturable systemErr, @SysOut Capturable systemOut) {
1049 final String expected = addEndOfLine(
1050 "COMPILATION_UNIT -> COMPILATION_UNIT [1:0]",
1051 "|--CLASS_DEF -> CLASS_DEF [3:0]",
1052 "| `--OBJBLOCK -> OBJBLOCK [3:28]",
1053 "| |--METHOD_DEF -> METHOD_DEF [4:4]",
1054 "| | `--SLIST -> { [4:20]",
1055 "| | |--VARIABLE_DEF -> VARIABLE_DEF [5:8]",
1056 "| | | |--IDENT -> a [5:12]");
1057 assertMainReturnCode(0, "-b",
1058 "/COMPILATION_UNIT/CLASS_DEF//METHOD_DEF[./IDENT[@text='methodOne']]"
1059 + "//VARIABLE_DEF/IDENT",
1060 getPath("InputMainXPath.java"));
1061 assertWithMessage("Unexpected output log")
1062 .that(systemOut.getCapturedData())
1063 .isEqualTo(expected);
1064 assertWithMessage("Unexpected system error log")
1065 .that(systemErr.getCapturedData())
1066 .isEqualTo("");
1067 }
1068
1069 @Test
1070 public void testPrintXpathCommentNode(@SysErr Capturable systemErr,
1071 @SysOut Capturable systemOut) {
1072 final String expected = addEndOfLine(
1073 "COMPILATION_UNIT -> COMPILATION_UNIT [1:0]",
1074 "`--CLASS_DEF -> CLASS_DEF [17:0]",
1075 " `--OBJBLOCK -> OBJBLOCK [17:19]",
1076 " |--CTOR_DEF -> CTOR_DEF [19:4]",
1077 " | |--BLOCK_COMMENT_BEGIN -> /* [18:4]");
1078 assertMainReturnCode(0, "-b", "/COMPILATION_UNIT/CLASS_DEF//BLOCK_COMMENT_BEGIN",
1079 getPath("InputMainXPath.java"));
1080 assertWithMessage("Unexpected output log")
1081 .that(systemOut.getCapturedData())
1082 .isEqualTo(expected);
1083 assertWithMessage("Unexpected system error log")
1084 .that(systemErr.getCapturedData())
1085 .isEqualTo("");
1086 }
1087
1088 @Test
1089 public void testPrintXpathNodeParentNull(@SysErr Capturable systemErr,
1090 @SysOut Capturable systemOut) {
1091 final String expected = addEndOfLine("COMPILATION_UNIT -> COMPILATION_UNIT [1:0]");
1092 assertMainReturnCode(0, "-b", "/COMPILATION_UNIT", getPath("InputMainXPath.java"));
1093 assertWithMessage("Unexpected output log")
1094 .that(systemOut.getCapturedData())
1095 .isEqualTo(expected);
1096 assertWithMessage("Unexpected system error log")
1097 .that(systemErr.getCapturedData())
1098 .isEqualTo("");
1099 }
1100
1101 @Test
1102 public void testPrintXpathFullOption(
1103 @SysErr Capturable systemErr, @SysOut Capturable systemOut) {
1104 final String expected = addEndOfLine(
1105 "COMPILATION_UNIT -> COMPILATION_UNIT [1:0]",
1106 "|--CLASS_DEF -> CLASS_DEF [3:0]",
1107 "| `--OBJBLOCK -> OBJBLOCK [3:28]",
1108 "| |--METHOD_DEF -> METHOD_DEF [8:4]",
1109 "| | `--SLIST -> { [8:26]",
1110 "| | |--VARIABLE_DEF -> VARIABLE_DEF [9:8]",
1111 "| | | |--IDENT -> a [9:12]");
1112 final String xpath = "/COMPILATION_UNIT/CLASS_DEF//METHOD_DEF[./IDENT[@text='method']]"
1113 + "//VARIABLE_DEF/IDENT";
1114 assertMainReturnCode(0, "--branch-matching-xpath", xpath, getPath("InputMainXPath.java"));
1115 assertWithMessage("Unexpected output log")
1116 .that(systemOut.getCapturedData())
1117 .isEqualTo(expected);
1118 assertWithMessage("Unexpected system error log")
1119 .that(systemErr.getCapturedData())
1120 .isEqualTo("");
1121 }
1122
1123 @Test
1124 public void testPrintXpathTwoResults(
1125 @SysErr Capturable systemErr, @SysOut Capturable systemOut) {
1126 final String expected = addEndOfLine(
1127 "COMPILATION_UNIT -> COMPILATION_UNIT [1:0]",
1128 "|--CLASS_DEF -> CLASS_DEF [12:0]",
1129 "| `--OBJBLOCK -> OBJBLOCK [12:10]",
1130 "| |--METHOD_DEF -> METHOD_DEF [13:4]",
1131 "---------",
1132 "COMPILATION_UNIT -> COMPILATION_UNIT [1:0]",
1133 "|--CLASS_DEF -> CLASS_DEF [12:0]",
1134 "| `--OBJBLOCK -> OBJBLOCK [12:10]",
1135 "| |--METHOD_DEF -> METHOD_DEF [14:4]");
1136 assertMainReturnCode(0, "--branch-matching-xpath",
1137 "/COMPILATION_UNIT/CLASS_DEF[./IDENT[@text='Two']]//METHOD_DEF",
1138 getPath("InputMainXPath.java"));
1139 assertWithMessage("Unexpected output log")
1140 .that(systemOut.getCapturedData())
1141 .isEqualTo(expected);
1142 assertWithMessage("Unexpected system error log")
1143 .that(systemErr.getCapturedData())
1144 .isEqualTo("");
1145 }
1146
1147 @Test
1148 public void testPrintXpathInvalidXpath(@SysErr Capturable systemErr) throws Exception {
1149 final String invalidXpath = "\\/COMPILATION_UNIT/CLASS_DEF[./IDENT[@text='Two']]"
1150 + "//METHOD_DEF";
1151 final String filePath = getFilePath("InputMainXPath.java");
1152 assertMainReturnCode(-2, "--branch-matching-xpath", invalidXpath, filePath);
1153 final String exceptionFirstLine = addEndOfLine("com.puppycrawl.tools.checkstyle.api."
1154 + "CheckstyleException: Error during evaluation for xpath: " + invalidXpath
1155 + ", file: " + filePath);
1156 assertWithMessage("Unexpected system error log")
1157 .that(systemErr.getCapturedData())
1158 .startsWith(exceptionFirstLine);
1159 }
1160
1161 @Test
1162 public void testPrintTreeCommentsOption(@SysErr Capturable systemErr,
1163 @SysOut Capturable systemOut) {
1164 final String expected = addEndOfLine(
1165 "COMPILATION_UNIT -> COMPILATION_UNIT [1:0]",
1166 "|--PACKAGE_DEF -> package [1:0]",
1167 "| |--ANNOTATIONS -> ANNOTATIONS [1:39]",
1168 "| |--DOT -> . [1:39]",
1169 "| | |--DOT -> . [1:28]",
1170 "| | | |--DOT -> . [1:22]",
1171 "| | | | |--DOT -> . [1:11]",
1172 "| | | | | |--IDENT -> com [1:8]",
1173 "| | | | | `--IDENT -> puppycrawl [1:12]",
1174 "| | | | `--IDENT -> tools [1:23]",
1175 "| | | `--IDENT -> checkstyle [1:29]",
1176 "| | `--IDENT -> main [1:40]",
1177 "| `--SEMI -> ; [1:44]",
1178 "|--CLASS_DEF -> CLASS_DEF [3:0]",
1179 "| |--MODIFIERS -> MODIFIERS [3:0]",
1180 "| | |--BLOCK_COMMENT_BEGIN -> /* [2:0]",
1181 "| | | |--COMMENT_CONTENT -> comment [2:2]",
1182 "| | | `--BLOCK_COMMENT_END -> */ [2:8]",
1183 "| | `--LITERAL_PUBLIC -> public [3:0]",
1184 "| |--LITERAL_CLASS -> class [3:7]",
1185 "| |--IDENT -> InputMain [3:13]",
1186 "| `--OBJBLOCK -> OBJBLOCK [3:23]",
1187 "| |--LCURLY -> { [3:23]",
1188 "| `--RCURLY -> } [4:0]",
1189 "`--CLASS_DEF -> CLASS_DEF [5:0]",
1190 " |--MODIFIERS -> MODIFIERS [5:0]",
1191 " |--LITERAL_CLASS -> class [5:0]",
1192 " |--IDENT -> InputMainInner [5:6]",
1193 " `--OBJBLOCK -> OBJBLOCK [5:21]",
1194 " |--LCURLY -> { [5:21]",
1195 " `--RCURLY -> } [6:0]");
1196
1197 assertMainReturnCode(0, "-T", getPath("InputMain.java"));
1198 assertWithMessage("Unexpected output log")
1199 .that(systemOut.getCapturedData())
1200 .isEqualTo(expected);
1201 assertWithMessage("Unexpected system error log")
1202 .that(systemErr.getCapturedData())
1203 .isEqualTo("");
1204 }
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215 @Test
1216 public void testPrintTreeJavadocOption(@SysErr Capturable systemErr,
1217 @SysOut Capturable systemOut) throws IOException {
1218 final String expected = Files.readString(Path.of(
1219 getPath("InputMainExpectedInputJavadocComment.txt")))
1220 .replaceAll("\\\\r\\\\n", "\\\\n").replaceAll("\r\n", "\n");
1221
1222 assertMainReturnCode(0, "-j", getPath("InputMainJavadocComment.javadoc"));
1223 assertWithMessage("Unexpected output log")
1224 .that(systemOut.getCapturedData().replaceAll("\\\\r\\\\n", "\\\\n")
1225 .replaceAll("\r\n", "\n"))
1226 .isEqualTo(expected);
1227 assertWithMessage("Unexpected system error log")
1228 .that(systemErr.getCapturedData())
1229 .isEqualTo("");
1230 }
1231
1232 @Test
1233 public void testPrintSuppressionOption(@SysErr Capturable systemErr,
1234 @SysOut Capturable systemOut) {
1235 final String expected = addEndOfLine(
1236 "/COMPILATION_UNIT/CLASS_DEF[./IDENT[@text='InputMainSuppressionsStringPrinter']]",
1237 "/COMPILATION_UNIT/CLASS_DEF[./IDENT[@text='InputMainSuppressionsStringPrinter']]"
1238 + "/MODIFIERS",
1239 "/COMPILATION_UNIT/CLASS_DEF[./IDENT[@text='InputMainSuppressionsStringPrinter']"
1240 + "]/LITERAL_CLASS");
1241
1242 assertMainReturnCode(0, getPath("InputMainSuppressionsStringPrinter.java"), "-s", "3:1");
1243 assertWithMessage("Unexpected output log")
1244 .that(systemOut.getCapturedData())
1245 .isEqualTo(expected);
1246 assertWithMessage("Unexpected system error log")
1247 .that(systemErr.getCapturedData())
1248 .isEqualTo("");
1249 }
1250
1251 @Test
1252 public void testPrintSuppressionAndTabWidthOption(@SysErr Capturable systemErr,
1253 @SysOut Capturable systemOut) {
1254 final String expected = addEndOfLine(
1255 "/COMPILATION_UNIT/CLASS_DEF"
1256 + "[./IDENT[@text='InputMainSuppressionsStringPrinter']]/OBJBLOCK"
1257 + "/METHOD_DEF[./IDENT[@text='getName']]"
1258 + "/SLIST/VARIABLE_DEF[./IDENT[@text='var']]",
1259 "/COMPILATION_UNIT/CLASS_DEF"
1260 + "[./IDENT[@text='InputMainSuppressionsStringPrinter']]/OBJBLOCK"
1261 + "/METHOD_DEF[./IDENT[@text='getName']]/SLIST"
1262 + "/VARIABLE_DEF[./IDENT[@text='var']]/MODIFIERS",
1263 "/COMPILATION_UNIT/CLASS_DEF"
1264 + "[./IDENT[@text='InputMainSuppressionsStringPrinter']]/OBJBLOCK"
1265 + "/METHOD_DEF[./IDENT[@text='getName']]/SLIST"
1266 + "/VARIABLE_DEF[./IDENT[@text='var']]/TYPE",
1267 "/COMPILATION_UNIT/CLASS_DEF"
1268 + "[./IDENT[@text='InputMainSuppressionsStringPrinter']]/OBJBLOCK"
1269 + "/METHOD_DEF[./IDENT[@text='getName']]/SLIST"
1270 + "/VARIABLE_DEF[./IDENT[@text='var']]/TYPE/LITERAL_INT");
1271
1272 assertMainReturnCode(0, getPath("InputMainSuppressionsStringPrinter.java"),
1273 "-s", "7:9", "--tabWidth", "2");
1274 assertWithMessage("Unexpected output log")
1275 .that(systemOut.getCapturedData())
1276 .isEqualTo(expected);
1277 assertWithMessage("Unexpected system error log")
1278 .that(systemErr.getCapturedData())
1279 .isEqualTo("");
1280 }
1281
1282 @Test
1283 public void testPrintSuppressionConflictingOptionsTvsC(@SysErr Capturable systemErr,
1284 @SysOut Capturable systemOut) {
1285 assertMainReturnCode(-1, "-c", "/google_checks.xml", getPath(""), "-s", "2:4");
1286 assertWithMessage("Unexpected output log")
1287 .that(systemOut.getCapturedData())
1288 .isEqualTo("Option '-s' cannot be used with other options."
1289 + System.lineSeparator());
1290 assertWithMessage("Unexpected system error log")
1291 .that(systemErr.getCapturedData())
1292 .isEqualTo("");
1293 }
1294
1295 @Test
1296 public void testPrintSuppressionConflictingOptionsTvsP(@SysErr Capturable systemErr,
1297 @SysOut Capturable systemOut) {
1298 assertMainReturnCode(-1, "-p", getPath("InputMainMycheckstyle.properties"), "-s", "2:4",
1299 getPath(""));
1300 assertWithMessage("Unexpected output log")
1301 .that(systemOut.getCapturedData())
1302 .isEqualTo("Option '-s' cannot be used with other options."
1303 + System.lineSeparator());
1304 assertWithMessage("Unexpected system error log")
1305 .that(systemErr.getCapturedData())
1306 .isEqualTo("");
1307 }
1308
1309 @Test
1310 public void testPrintSuppressionConflictingOptionsTvsF(@SysErr Capturable systemErr,
1311 @SysOut Capturable systemOut) {
1312 assertMainReturnCode(-1, "-f", "plain", "-s", "2:4", getPath(""));
1313 assertWithMessage("Unexpected output log")
1314 .that(systemOut.getCapturedData())
1315 .isEqualTo("Option '-s' cannot be used with other options."
1316 + System.lineSeparator());
1317 assertWithMessage("Unexpected system error log")
1318 .that(systemErr.getCapturedData())
1319 .isEqualTo("");
1320 }
1321
1322 @Test
1323 public void testPrintSuppressionConflictingOptionsTvsO(@SysErr Capturable systemErr,
1324 @SysOut Capturable systemOut) throws IOException {
1325 final String outputPath = new File(temporaryFolder, "file.output").getCanonicalPath();
1326
1327 assertMainReturnCode(-1, "-o", outputPath, "-s", "2:4", getPath(""));
1328 assertWithMessage("Unexpected output log")
1329 .that(systemOut.getCapturedData())
1330 .isEqualTo("Option '-s' cannot be used with other options."
1331 + System.lineSeparator());
1332 assertWithMessage("Unexpected system error log")
1333 .that(systemErr.getCapturedData())
1334 .isEqualTo("");
1335 }
1336
1337 @Test
1338 public void testPrintSuppressionOnMoreThanOneFile(@SysErr Capturable systemErr,
1339 @SysOut Capturable systemOut) {
1340 assertMainReturnCode(-1, "-s", "2:4", getPath(""), getPath(""));
1341 assertWithMessage("Unexpected output log")
1342 .that(systemOut.getCapturedData())
1343 .isEqualTo("Printing xpath suppressions is allowed for only one file."
1344 + System.lineSeparator());
1345 assertWithMessage("Unexpected system error log")
1346 .that(systemErr.getCapturedData())
1347 .isEqualTo("");
1348 }
1349
1350 @Test
1351 public void testGenerateXpathSuppressionOptionOne(@SysErr Capturable systemErr,
1352 @SysOut Capturable systemOut) {
1353 final String expected = addEndOfLine(
1354 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
1355 "<!DOCTYPE suppressions PUBLIC",
1356 " \"-//Checkstyle//DTD SuppressionXpathFilter Experimental Configuration 1.2"
1357 + "//EN\"",
1358 " \"https://checkstyle.org/dtds/suppressions_1_2_xpath_experimental.dtd\">",
1359 "<suppressions>",
1360 " <suppress-xpath",
1361 " files=\"InputMainComplexityOverflow.java\"",
1362 " checks=\"MissingJavadocMethodCheck\"",
1363 " query=\"/COMPILATION_UNIT/CLASS_DEF"
1364 + "[./IDENT[@text='InputMainComplexityOverflow']]/OBJBLOCK"
1365 + "/METHOD_DEF[./IDENT[@text='provokeNpathIntegerOverflow']]\"/>",
1366 " <suppress-xpath",
1367 " files=\"InputMainComplexityOverflow.java\"",
1368 " id=\"LeftCurlyEol\"",
1369 " query=\"/COMPILATION_UNIT/CLASS_DEF"
1370 + "[./IDENT[@text='InputMainComplexityOverflow']]/OBJBLOCK"
1371 + "/METHOD_DEF[./IDENT[@text='provokeNpathIntegerOverflow']]/SLIST\"/>",
1372 "</suppressions>");
1373
1374 assertMainReturnCode(0, "-c", "/google_checks.xml", "--generate-xpath-suppression",
1375 getPath("InputMainComplexityOverflow.java"));
1376 assertWithMessage("Unexpected output log")
1377 .that(systemOut.getCapturedData())
1378 .isEqualTo(expected);
1379 assertWithMessage("Unexpected system error log")
1380 .that(systemErr.getCapturedData())
1381 .isEqualTo("");
1382 }
1383
1384 @Test
1385 public void testGenerateXpathSuppressionOptionTwo(@SysErr Capturable systemErr,
1386 @SysOut Capturable systemOut) {
1387 final String expected = addEndOfLine(
1388 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
1389 "<!DOCTYPE suppressions PUBLIC",
1390 " \"-//Checkstyle//DTD SuppressionXpathFilter Experimental Configuration 1.2"
1391 + "//EN\"",
1392 " \"https://checkstyle.org/dtds/suppressions_1_2_xpath_experimental.dtd\">",
1393 "<suppressions>",
1394 " <suppress-xpath",
1395 " files=\"InputMainGenerateXpathSuppressions.java\"",
1396 " checks=\"ExplicitInitializationCheck\"",
1397 " query=\"/COMPILATION_UNIT/CLASS_DEF"
1398 + "[./IDENT[@text='InputMainGenerateXpathSuppressions']]"
1399 + "/OBJBLOCK/VARIABLE_DEF/IDENT[@text='low']\"/>",
1400 " <suppress-xpath",
1401 " files=\"InputMainGenerateXpathSuppressions.java\"",
1402 " checks=\"IllegalThrowsCheck\"",
1403 " query=\"/COMPILATION_UNIT/CLASS_DEF"
1404 + "[./IDENT[@text='InputMainGenerateXpathSuppressions']]"
1405 + "/OBJBLOCK/METHOD_DEF[./IDENT[@text='test']]/LITERAL_THROWS"
1406 + "/IDENT[@text='RuntimeException']\"/>",
1407 " <suppress-xpath",
1408 " files=\"InputMainGenerateXpathSuppressions.java\"",
1409 " checks=\"NestedForDepthCheck\"",
1410 " query=\"/COMPILATION_UNIT/CLASS_DEF"
1411 + "[./IDENT[@text='InputMainGenerateXpathSuppressions']]"
1412 + "/OBJBLOCK/METHOD_DEF[./IDENT[@text='test']]/SLIST/LITERAL_FOR/SLIST"
1413 + "/LITERAL_FOR/SLIST/LITERAL_FOR\"/>",
1414 "</suppressions>");
1415
1416 assertMainReturnCode(0, "-c", getPath("InputMainConfig-xpath-suppressions.xml"),
1417 "--generate-xpath-suppression",
1418 getPath("InputMainGenerateXpathSuppressions.java"));
1419 assertWithMessage("Unexpected output log")
1420 .that(systemOut.getCapturedData())
1421 .isEqualTo(expected);
1422 assertWithMessage("Unexpected system error log")
1423 .that(systemErr.getCapturedData())
1424 .isEqualTo("");
1425 }
1426
1427 @Test
1428 public void testGenerateXpathSuppressionOptionEmptyConfig(@SysErr Capturable systemErr,
1429 @SysOut Capturable systemOut) {
1430 final String expected = "";
1431
1432 assertMainReturnCode(0, "-c", getPath("InputMainConfig-empty.xml"),
1433 "--generate-xpath-suppression", getPath("InputMainComplexityOverflow.java"));
1434 assertWithMessage("Unexpected output log")
1435 .that(systemOut.getCapturedData())
1436 .isEqualTo(expected);
1437 assertWithMessage("Unexpected system error log")
1438 .that(systemErr.getCapturedData())
1439 .isEqualTo("");
1440 }
1441
1442 @Test
1443 public void testGenerateXpathSuppressionOptionCustomOutput(@SysErr Capturable systemErr)
1444 throws IOException {
1445 final String expected = addEndOfLine(
1446 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
1447 "<!DOCTYPE suppressions PUBLIC",
1448 " \"-//Checkstyle//DTD SuppressionXpathFilter Experimental Configuration 1.2"
1449 + "//EN\"",
1450 " \"https://checkstyle.org/dtds/suppressions_1_2_xpath_experimental.dtd\">",
1451 "<suppressions>",
1452 " <suppress-xpath",
1453 " files=\"InputMainGenerateXpathSuppressionsTabWidth.java\"",
1454 " checks=\"ExplicitInitializationCheck\"",
1455 " query=\"/COMPILATION_UNIT/CLASS_DEF[./IDENT["
1456 + "@text='InputMainGenerateXpathSuppressionsTabWidth']]"
1457 + "/OBJBLOCK/VARIABLE_DEF/IDENT[@text='low']\"/>",
1458 "</suppressions>");
1459 final File file = new File(temporaryFolder, "file.output");
1460 assertMainReturnCode(0, "-c", getPath("InputMainConfig-xpath-suppressions.xml"), "-o",
1461 file.getPath(), "--generate-xpath-suppression",
1462 getPath("InputMainGenerateXpathSuppressionsTabWidth.java"));
1463 try (BufferedReader br = Files.newBufferedReader(file.toPath())) {
1464 final String fileContent = br.lines().collect(Collectors.joining(EOL, "", EOL));
1465 assertWithMessage("Unexpected output log")
1466 .that(fileContent)
1467 .isEqualTo(expected);
1468 assertWithMessage("Unexpected system error log")
1469 .that(systemErr.getCapturedData())
1470 .isEqualTo("");
1471 }
1472 }
1473
1474 @Test
1475 public void testGenerateXpathSuppressionOptionDefaultTabWidth(@SysErr Capturable systemErr,
1476 @SysOut Capturable systemOut) {
1477 final String expected = addEndOfLine(
1478 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
1479 "<!DOCTYPE suppressions PUBLIC",
1480 " \"-//Checkstyle//DTD SuppressionXpathFilter Experimental Configuration 1.2"
1481 + "//EN\"",
1482 " \"https://checkstyle.org/dtds/suppressions_1_2_xpath_experimental.dtd\">",
1483 "<suppressions>",
1484 " <suppress-xpath",
1485 " files=\"InputMainGenerateXpathSuppressionsTabWidth.java\"",
1486 " checks=\"ExplicitInitializationCheck\"",
1487 " query=\"/COMPILATION_UNIT/CLASS_DEF[./IDENT["
1488 + "@text='InputMainGenerateXpathSuppressionsTabWidth']]"
1489 + "/OBJBLOCK/VARIABLE_DEF/IDENT[@text='low']\"/>",
1490 "</suppressions>");
1491
1492 assertMainReturnCode(0, "-c", getPath("InputMainConfig-xpath-suppressions.xml"),
1493 "--generate-xpath-suppression",
1494 getPath("InputMainGenerateXpathSuppressionsTabWidth.java"));
1495 assertWithMessage("Unexpected output log")
1496 .that(systemOut.getCapturedData())
1497 .isEqualTo(expected);
1498 assertWithMessage("Unexpected system error log")
1499 .that(systemErr.getCapturedData())
1500 .isEqualTo("");
1501 }
1502
1503 @Test
1504 public void testGenerateXpathSuppressionOptionCustomTabWidth(@SysErr Capturable systemErr,
1505 @SysOut Capturable systemOut) {
1506 final String expected = "";
1507
1508 assertMainReturnCode(0, "-c", getPath("InputMainConfig-xpath-suppressions.xml"),
1509 "--generate-xpath-suppression", "--tabWidth", "20",
1510 getPath("InputMainGenerateXpathSuppressionsTabWidth.java"));
1511 assertWithMessage("Unexpected output log")
1512 .that(systemOut.getCapturedData())
1513 .isEqualTo(expected);
1514 assertWithMessage("Unexpected system error log")
1515 .that(systemErr.getCapturedData())
1516 .isEqualTo("");
1517 }
1518
1519 @Test
1520 public void testGenerateChecksAndFilesSuppressionOptionOne(@SysErr Capturable systemErr,
1521 @SysOut Capturable systemOut) {
1522 final String expected = addEndOfLine(
1523 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
1524 "<!DOCTYPE suppressions PUBLIC",
1525 " \"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN\"",
1526 " \"https://checkstyle.org/dtds/suppressions_1_2.dtd\">",
1527 "<suppressions>",
1528 " <suppress",
1529 " files=\"InputMainComplexityOverflow.java\"",
1530 " checks=\"MissingJavadocMethodCheck\"/>",
1531 " <suppress",
1532 " files=\"InputMainComplexityOverflow.java\"",
1533 " id=\"LeftCurlyEol\"/>",
1534 "</suppressions>");
1535
1536 assertMainReturnCode(0, "-c", "/google_checks.xml",
1537 "--generate-checks-and-files-suppression",
1538 getPath("InputMainComplexityOverflow.java"));
1539 assertWithMessage("Unexpected output log")
1540 .that(systemOut.getCapturedData())
1541 .isEqualTo(expected);
1542 assertWithMessage("Unexpected system error log")
1543 .that(systemErr.getCapturedData())
1544 .isEqualTo("");
1545 }
1546
1547 @Test
1548 public void testGenerateChecksAndFilesSuppressionOptionTwo(@SysErr Capturable systemErr,
1549 @SysOut Capturable systemOut) {
1550 final String expected = addEndOfLine(
1551 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
1552 "<!DOCTYPE suppressions PUBLIC",
1553 " \"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN\"",
1554 " \"https://checkstyle.org/dtds/suppressions_1_2.dtd\">",
1555 "<suppressions>",
1556 " <suppress",
1557 " files=\"InputMainGenerateChecksAndFilesSuppressions.java\"",
1558 " id=\"InitializeViolation\"/>",
1559 " <suppress",
1560 " files=\"InputMainGenerateChecksAndFilesSuppressions.java\"",
1561 " checks=\"IllegalThrowsCheck\"/>",
1562 " <suppress",
1563 " files=\"InputMainGenerateChecksAndFilesSuppressions.java\"",
1564 " checks=\"NestedForDepthCheck\"/>",
1565 " <suppress",
1566 " files=\"InputMainGenerateChecksAndFilesSuppressions.java\"",
1567 " id=\"MethodNaming\"/>",
1568 "</suppressions>");
1569
1570 assertMainReturnCode(0, "-c", getPath("InputMainConfig-Checks-And-Files-suppressions.xml"),
1571 "--generate-checks-and-files-suppression",
1572 getPath("InputMainGenerateChecksAndFilesSuppressions.java"));
1573 assertWithMessage("Unexpected output log")
1574 .that(systemOut.getCapturedData())
1575 .isEqualTo(expected);
1576 assertWithMessage("Unexpected system error log")
1577 .that(systemErr.getCapturedData())
1578 .isEqualTo("");
1579 }
1580
1581 @Test
1582 public void testGenerateChecksAndFilesSuppressionOptionEmptyConfig(@SysErr Capturable systemErr,
1583 @SysOut Capturable systemOut) {
1584 final String expected = "";
1585
1586 assertMainReturnCode(0, "-c", getPath("InputMainConfig-empty.xml"),
1587 "--generate-checks-and-files-suppression",
1588 getPath("InputMainComplexityOverflow.java"));
1589 assertWithMessage("Unexpected output log")
1590 .that(systemOut.getCapturedData())
1591 .isEqualTo(expected);
1592 assertWithMessage("Unexpected system error log")
1593 .that(systemErr.getCapturedData())
1594 .isEqualTo("");
1595 }
1596
1597 @Test
1598 public void testGenerateChecksAndFilesSuppressionOptionCustomOutput(
1599 @SysErr Capturable systemErr) throws IOException {
1600 final String expected = addEndOfLine(
1601 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
1602 "<!DOCTYPE suppressions PUBLIC",
1603 " \"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN\"",
1604 " \"https://checkstyle.org/dtds/suppressions_1_2.dtd\">",
1605 "<suppressions>",
1606 " <suppress",
1607 " files=\"InputMainGenerateChecksAndFilesSuppressionsTabWidth.java\"",
1608 " id=\"InitializeViolation\"/>",
1609 "</suppressions>");
1610 final File file = new File(temporaryFolder, "file.output");
1611 assertMainReturnCode(0, "-c", getPath("InputMainConfig-Checks-And-Files-suppressions.xml"),
1612 "-o", file.getPath(), "--generate-checks-and-files-suppression",
1613 getPath("InputMainGenerateChecksAndFilesSuppressionsTabWidth.java"));
1614 try (BufferedReader br = Files.newBufferedReader(file.toPath())) {
1615 final String fileContent = br.lines().collect(Collectors.joining(EOL, "", EOL));
1616 assertWithMessage("Unexpected output log")
1617 .that(fileContent)
1618 .isEqualTo(expected);
1619 assertWithMessage("Unexpected system error log")
1620 .that(systemErr.getCapturedData())
1621 .isEqualTo("");
1622 }
1623 }
1624
1625 @Test
1626 public void testGenerateChecksAndFilesSuppressionOptionDefaultTabWidth(
1627 @SysErr Capturable systemErr, @SysOut Capturable systemOut) {
1628 final String expected = addEndOfLine(
1629 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
1630 "<!DOCTYPE suppressions PUBLIC",
1631 " \"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN\"",
1632 " \"https://checkstyle.org/dtds/suppressions_1_2.dtd\">",
1633 "<suppressions>",
1634 " <suppress",
1635 " files=\"InputMainGenerateChecksAndFilesSuppressionsTabWidth.java\"",
1636 " id=\"InitializeViolation\"/>",
1637 "</suppressions>");
1638
1639 assertMainReturnCode(0, "-c", getPath("InputMainConfig-Checks-And-Files-suppressions.xml"),
1640 "--generate-checks-and-files-suppression",
1641 getPath("InputMainGenerateChecksAndFilesSuppressionsTabWidth.java"));
1642 assertWithMessage("Unexpected output log")
1643 .that(systemOut.getCapturedData())
1644 .isEqualTo(expected);
1645 assertWithMessage("Unexpected system error log")
1646 .that(systemErr.getCapturedData())
1647 .isEqualTo("");
1648 }
1649
1650 @Test
1651 public void testGenerateChecksAndFilesSuppressionOptionCustomTabWidth(
1652 @SysErr Capturable systemErr, @SysOut Capturable systemOut) {
1653 final String expected = addEndOfLine(
1654 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
1655 "<!DOCTYPE suppressions PUBLIC",
1656 " \"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN\"",
1657 " \"https://checkstyle.org/dtds/suppressions_1_2.dtd\">",
1658 "<suppressions>",
1659 " <suppress",
1660 " files=\"InputMainGenerateChecksAndFilesSuppressionsTabWidth.java\"",
1661 " id=\"InitializeViolation\"/>",
1662 "</suppressions>");
1663
1664 assertMainReturnCode(0, "-c", getPath("InputMainConfig-Checks-And-Files-suppressions.xml"),
1665 "--generate-checks-and-files-suppression", "--tabWidth", "20",
1666 getPath("InputMainGenerateChecksAndFilesSuppressionsTabWidth.java"));
1667 assertWithMessage("Unexpected output log")
1668 .that(systemOut.getCapturedData())
1669 .isEqualTo(expected);
1670 assertWithMessage("Unexpected system error log")
1671 .that(systemErr.getCapturedData())
1672 .isEqualTo("");
1673 }
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684 @Test
1685 public void testPrintFullTreeOption(@SysErr Capturable systemErr, @SysOut Capturable systemOut)
1686 throws IOException {
1687 final String expected = Files.readString(Path.of(
1688 getPath("InputMainExpectedInputAstTreeStringPrinterJavadoc.txt")))
1689 .replaceAll("\\\\r\\\\n", "\\\\n")
1690 .replaceAll("\r\n", "\n");
1691
1692 assertMainReturnCode(0, "-J", getPath("InputMainAstTreeStringPrinterJavadoc.java"));
1693 assertWithMessage("Unexpected output log")
1694 .that(systemOut.getCapturedData().replaceAll("\\\\r\\\\n", "\\\\n")
1695 .replaceAll("\r\n", "\n"))
1696 .isEqualTo(expected);
1697 assertWithMessage("Unexpected system error log")
1698 .that(systemErr.getCapturedData())
1699 .isEqualTo("");
1700 }
1701
1702 @Test
1703 public void testConflictingOptionsTvsC(@SysErr Capturable systemErr,
1704 @SysOut Capturable systemOut) {
1705 assertMainReturnCode(-1, "-c", "/google_checks.xml", "-t", getPath(""));
1706 assertWithMessage("Unexpected output log")
1707 .that(systemOut.getCapturedData())
1708 .isEqualTo("Option '-t' cannot be used with other options." + System.lineSeparator());
1709 assertWithMessage("Unexpected system error log")
1710 .that(systemErr.getCapturedData())
1711 .isEqualTo("");
1712 }
1713
1714 @Test
1715 public void testConflictingOptionsTvsP(@SysErr Capturable systemErr,
1716 @SysOut Capturable systemOut) {
1717 assertMainReturnCode(-1, "-p", getPath("InputMainMycheckstyle.properties"), "-t",
1718 getPath(""));
1719 assertWithMessage("Unexpected output log")
1720 .that(systemOut.getCapturedData())
1721 .isEqualTo("Option '-t' cannot be used with other options." + System.lineSeparator());
1722 assertWithMessage("Unexpected system error log")
1723 .that(systemErr.getCapturedData())
1724 .isEqualTo("");
1725 }
1726
1727 @Test
1728 public void testConflictingOptionsTvsF(@SysErr Capturable systemErr,
1729 @SysOut Capturable systemOut) {
1730 assertMainReturnCode(-1, "-f", "plain", "-t", getPath(""));
1731 assertWithMessage("Unexpected output log")
1732 .that(systemOut.getCapturedData())
1733 .isEqualTo("Option '-t' cannot be used with other options." + System.lineSeparator());
1734 assertWithMessage("Unexpected system error log")
1735 .that(systemErr.getCapturedData())
1736 .isEqualTo("");
1737 }
1738
1739 @Test
1740 public void testConflictingOptionsTvsS(@SysErr Capturable systemErr,
1741 @SysOut Capturable systemOut) throws IOException {
1742 final String outputPath = new File(temporaryFolder, "file.output").getCanonicalPath();
1743
1744 assertMainReturnCode(-1, "-s", outputPath, "-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 testConflictingOptionsTvsO(@SysErr Capturable systemErr,
1755 @SysOut Capturable systemOut) throws IOException {
1756 final String outputPath = new File(temporaryFolder, "file.output").getCanonicalPath();
1757
1758 assertMainReturnCode(-1, "-o", outputPath, "-t", getPath(""));
1759 assertWithMessage("Unexpected output log")
1760 .that(systemOut.getCapturedData())
1761 .isEqualTo("Option '-t' cannot be used with other options." + System.lineSeparator());
1762 assertWithMessage("Unexpected system error log")
1763 .that(systemErr.getCapturedData())
1764 .isEqualTo("");
1765 }
1766
1767 @Test
1768 public void testDebugOption(@SysErr Capturable systemErr, @SysOut Capturable systemOut) {
1769 assertMainReturnCode(0, "-c", "/google_checks.xml", getPath("InputMain.java"), "-d");
1770 assertWithMessage("Unexpected system error log")
1771 .that(systemErr.getCapturedData())
1772 .contains("FINE: Checkstyle debug logging enabled");
1773 assertWithMessage("Unexpected system error log")
1774 .that(systemOut.getCapturedData())
1775 .contains("Audit done.");
1776
1777 }
1778
1779 @Test
1780 public void testExcludeOption(@SysErr Capturable systemErr, @SysOut Capturable systemOut)
1781 throws IOException {
1782 final String filePath = getFilePath("");
1783 assertMainReturnCode(-1, "-c", "/google_checks.xml", filePath, "-e", filePath);
1784 assertWithMessage("Unexpected output log")
1785 .that(systemOut.getCapturedData())
1786 .isEqualTo("Files to process must be specified, found 0." + System.lineSeparator());
1787 assertWithMessage("Unexpected system error log")
1788 .that(systemErr.getCapturedData())
1789 .isEqualTo("");
1790 }
1791
1792 @Test
1793 public void testExcludeOptionFile(@SysErr Capturable systemErr, @SysOut Capturable systemOut)
1794 throws IOException {
1795 final String filePath = getFilePath("InputMain.java");
1796 assertMainReturnCode(-1, "-c", "/google_checks.xml", filePath, "-e", filePath);
1797 assertWithMessage("Unexpected output log")
1798 .that(systemOut.getCapturedData())
1799 .isEqualTo("Files to process must be specified, found 0." + System.lineSeparator());
1800 assertWithMessage("Unexpected system error log")
1801 .that(systemErr.getCapturedData())
1802 .isEqualTo("");
1803 }
1804
1805 @Test
1806 public void testExcludeRegexpOption(@SysErr Capturable systemErr, @SysOut Capturable systemOut)
1807 throws IOException {
1808 final String filePath = getFilePath("");
1809 assertMainReturnCode(-1, "-c", "/google_checks.xml", filePath, "-x", ".");
1810 assertWithMessage("Unexpected output log")
1811 .that(systemOut.getCapturedData())
1812 .isEqualTo("Files to process must be specified, found 0." + System.lineSeparator());
1813 assertWithMessage("Unexpected output log")
1814 .that(systemErr.getCapturedData())
1815 .isEqualTo("");
1816 }
1817
1818 @Test
1819 public void testExcludeRegexpOptionFile(@SysErr Capturable systemErr,
1820 @SysOut Capturable systemOut) throws IOException {
1821 final String filePath = getFilePath("InputMain.java");
1822 assertMainReturnCode(-1, "-c", "/google_checks.xml", filePath, "-x", ".");
1823 assertWithMessage("Unexpected output log")
1824 .that(systemOut.getCapturedData())
1825 .isEqualTo("Files to process must be specified, found 0." + System.lineSeparator());
1826 assertWithMessage("Unexpected output log")
1827 .that(systemErr.getCapturedData())
1828 .isEqualTo("");
1829 }
1830
1831 @Test
1832 public void testExcludeDirectoryNotMatch() throws Exception {
1833 final Class<?> optionsClass = Class.forName(Main.class.getName());
1834 final List<Pattern> list = new ArrayList<>();
1835 list.add(Pattern.compile("BAD_PATH"));
1836
1837 final List<File> result = TestUtil.invokeStaticMethod(
1838 optionsClass, "listFiles", new File(getFilePath("")), list);
1839 assertWithMessage("Invalid result size")
1840 .that(result)
1841 .isNotEmpty();
1842 }
1843
1844 @Test
1845 public void testCustomRootModule(@SysErr Capturable systemErr, @SysOut Capturable systemOut) {
1846 TestRootModuleChecker.reset();
1847
1848 assertMainReturnCode(0, "-c", getPath("InputMainConfig-custom-root-module.xml"),
1849 getPath("InputMain.java"));
1850 assertWithMessage("Unexpected output log")
1851 .that(systemOut.getCapturedData())
1852 .isEqualTo("");
1853 assertWithMessage("Unexpected system error log")
1854 .that(systemErr.getCapturedData())
1855 .isEqualTo("");
1856 assertWithMessage("Invalid Checker state")
1857 .that(TestRootModuleChecker.isProcessed())
1858 .isTrue();
1859 assertWithMessage("RootModule should be destroyed")
1860 .that(TestRootModuleChecker.isDestroyed())
1861 .isTrue();
1862 }
1863
1864 @Test
1865 public void testCustomSimpleRootModule(@SysErr Capturable systemErr) {
1866 TestRootModuleChecker.reset();
1867 assertMainReturnCode(-2, "-c", getPath("InputMainConfig-custom-simple-root-module.xml"),
1868 getPath("InputMain.java"));
1869 final String checkstylePackage = "com.puppycrawl.tools.checkstyle.";
1870 final LocalizedMessage unableToInstantiateExceptionMessage = new LocalizedMessage(
1871 Definitions.CHECKSTYLE_BUNDLE,
1872 getClass(),
1873 "PackageObjectFactory.unableToInstantiateExceptionMessage",
1874 "TestRootModuleChecker",
1875 checkstylePackage
1876 + "TestRootModuleChecker, "
1877 + "TestRootModuleCheckerCheck, " + checkstylePackage
1878 + "TestRootModuleCheckerCheck");
1879 assertWithMessage(
1880 "Unexpected system error log")
1881 .that(systemErr.getCapturedData())
1882 .startsWith(checkstylePackage + "api.CheckstyleException: "
1883 + unableToInstantiateExceptionMessage.getMessage());
1884 assertWithMessage("Invalid checker state")
1885 .that(TestRootModuleChecker.isProcessed())
1886 .isFalse();
1887 }
1888
1889 @Test
1890 public void testExceptionOnExecuteIgnoredModuleWithUnknownModuleName(
1891 @SysErr Capturable systemErr) {
1892 assertMainReturnCode(-2, "-c", getPath("InputMainConfig-non-existent-classname-ignore.xml"),
1893 "--executeIgnoredModules", getPath("InputMain.java"));
1894 final String cause = "com.puppycrawl.tools.checkstyle.api.CheckstyleException:"
1895 + " cannot initialize module TreeWalker - ";
1896 assertWithMessage("Unexpected system error log")
1897 .that(systemErr.getCapturedData())
1898 .startsWith(cause);
1899 }
1900
1901 @Test
1902 public void testExceptionOnExecuteIgnoredModuleWithBadPropertyValue(
1903 @SysErr Capturable systemErr) {
1904 assertMainReturnCode(-2, "-c", getPath("InputMainConfig-TypeName-bad-value.xml"),
1905 "--executeIgnoredModules", getPath("InputMain.java"));
1906 final String cause = "com.puppycrawl.tools.checkstyle.api.CheckstyleException:"
1907 + " cannot initialize module TreeWalker - ";
1908 final String causeDetail = "it is not a boolean";
1909 assertWithMessage("Unexpected system error log")
1910 .that(systemErr.getCapturedData())
1911 .startsWith(cause);
1912 assertWithMessage("Unexpected system error log")
1913 .that(systemErr.getCapturedData())
1914 .contains(causeDetail);
1915 }
1916
1917 @Test
1918 public void testNoProblemOnExecuteIgnoredModuleWithBadPropertyValue(
1919 @SysErr Capturable systemErr) {
1920 assertMainReturnCode(0, "-c", getPath("InputMainConfig-TypeName-bad-value.xml"),
1921 "", getPath("InputMain.java"));
1922 assertWithMessage("Unexpected system error log")
1923 .that(systemErr.getCapturedData())
1924 .isEmpty();
1925 }
1926
1927 @Test
1928 public void testMissingFiles(@SysErr Capturable systemErr, @SysOut Capturable systemOut) {
1929 assertMainReturnCode(-1);
1930 final String usage = "Missing required parameter: '<files or folders>'" + EOL + SHORT_USAGE;
1931 assertWithMessage("Unexpected output log")
1932 .that(systemOut.getCapturedData())
1933 .isEqualTo("");
1934 assertWithMessage("Unexpected system error log")
1935 .that(systemErr.getCapturedData())
1936 .isEqualTo(usage);
1937 }
1938
1939 @Test
1940 public void testOutputFormatToStringLowercase() {
1941 assertWithMessage("expected xml")
1942 .that(Main.OutputFormat.XML.toString())
1943 .isEqualTo("xml");
1944 assertWithMessage("expected plain")
1945 .that(Main.OutputFormat.PLAIN.toString())
1946 .isEqualTo("plain");
1947 }
1948
1949 @Test
1950 public void testXmlOutputFormatCreateListener() throws IOException {
1951 final ByteArrayOutputStream out = new ByteArrayOutputStream();
1952 final AuditListener listener = Main.OutputFormat.XML.createListener(out,
1953 OutputStreamOptions.CLOSE);
1954 assertWithMessage("listener is XMLLogger")
1955 .that(listener)
1956 .isInstanceOf(XMLLogger.class);
1957 }
1958
1959 @Test
1960 public void testSarifOutputFormatCreateListener() throws IOException {
1961 final ByteArrayOutputStream out = new ByteArrayOutputStream();
1962 final AuditListener listener = Main.OutputFormat.SARIF.createListener(out,
1963 OutputStreamOptions.CLOSE);
1964 assertWithMessage("listener is SarifLogger")
1965 .that(listener)
1966 .isInstanceOf(SarifLogger.class);
1967 }
1968
1969 @Test
1970 public void testPlainOutputFormatCreateListener() throws IOException {
1971 final ByteArrayOutputStream out = new ByteArrayOutputStream();
1972 final AuditListener listener = Main.OutputFormat.PLAIN.createListener(out,
1973 OutputStreamOptions.CLOSE);
1974 assertWithMessage("listener is DefaultLogger")
1975 .that(listener)
1976 .isInstanceOf(DefaultLogger.class);
1977 }
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992 private static void assertMainReturnCode(int expectedExitCode, String... arguments) {
1993 final Runtime mock = mock();
1994 try (MockedStatic<Runtime> runtime = mockStatic(Runtime.class)) {
1995 runtime.when(Runtime::getRuntime)
1996 .thenReturn(mock);
1997 Main.main(arguments);
1998 }
1999 catch (IOException exception) {
2000 assertWithMessage("Unexpected exception: %s", exception).fail();
2001 }
2002 verify(mock).exit(expectedExitCode);
2003 }
2004
2005
2006
2007
2008
2009 private static final class ShouldNotBeClosedStream extends PrintStream {
2010
2011 private boolean isClosed;
2012
2013 private ShouldNotBeClosedStream() {
2014 super(new ByteArrayOutputStream(), false, StandardCharsets.UTF_8);
2015 }
2016
2017 @Override
2018 public void close() {
2019 isClosed = true;
2020 super.close();
2021 }
2022
2023 }
2024
2025 }