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