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