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