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