1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.rat;
20
21 import java.io.ByteArrayOutputStream;
22 import java.io.File;
23 import java.io.FileReader;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.OutputStream;
27 import java.io.PrintStream;
28 import java.nio.charset.StandardCharsets;
29 import java.nio.file.Files;
30 import java.util.Arrays;
31 import java.util.Collections;
32 import java.util.List;
33 import java.util.concurrent.atomic.AtomicBoolean;
34 import java.util.regex.Pattern;
35 import javax.xml.xpath.XPath;
36 import org.apache.commons.cli.Option;
37 import org.apache.commons.cli.Options;
38 import org.apache.commons.io.IOUtils;
39 import org.apache.commons.lang3.tuple.ImmutablePair;
40 import org.apache.commons.lang3.tuple.Pair;
41 import org.apache.commons.xml.secure.SecureXPathFactory;
42 import org.apache.rat.api.RatException;
43 import org.apache.rat.commandline.Arg;
44 import org.apache.rat.commandline.StyleSheets;
45 import org.apache.rat.config.exclusion.StandardCollection;
46 import org.apache.rat.config.results.ClaimValidator;
47 import org.apache.rat.configuration.builders.SpdxBuilder;
48 import org.apache.rat.help.Help;
49 import org.apache.rat.license.ILicense;
50 import org.apache.rat.license.ILicenseFamily;
51 import org.apache.rat.license.LicenseSetFactory;
52 import org.apache.rat.report.claim.ClaimStatistic;
53 import org.apache.rat.test.AbstractOptionsProvider;
54 import org.apache.rat.test.utils.OptionFormatter;
55 import org.apache.rat.test.utils.Resources;
56 import org.apache.rat.utils.FileUtils;
57 import org.apache.rat.testhelpers.TestingLog;
58 import org.apache.rat.testhelpers.TextUtils;
59 import org.apache.rat.testhelpers.XmlUtils;
60 import org.apache.rat.utils.DefaultLog;
61 import org.apache.rat.utils.Log;
62 import org.junit.jupiter.params.provider.ArgumentsProvider;
63 import org.w3c.dom.Document;
64
65 import static org.apache.rat.commandline.Arg.HELP_LICENSES;
66 import static org.assertj.core.api.Assertions.assertThat;
67 import static org.assertj.core.api.Assertions.assertThatThrownBy;
68 import static org.assertj.core.api.Fail.fail;
69 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
70
71
72
73
74 class ReporterOptionsProvider extends AbstractOptionsProvider implements ArgumentsProvider {
75 static File sourceDir;
76
77
78
79
80 final AtomicBoolean helpCalled = new AtomicBoolean(false);
81
82 public ReporterOptionsProvider() {
83 super("ReporterOptionsProvider", ReporterOptionsTest.testPath.toFile());
84 processTestFunctionAnnotations();
85 testMap.put("addLicense", this::addLicenseTest);
86 testMap.remove("add-license");
87 testMap.put("dir", () -> DefaultLog.getInstance().info("--dir has no valid test"));
88 super.validate(Collections.emptyList());
89 }
90
91
92
93
94
95
96
97
98
99 @Override
100 protected final ReportConfiguration generateConfig(List<Pair<Option, String[]>> args) throws IOException {
101 return generateConfig(args, false);
102 }
103
104 protected final ReportConfiguration generateConfig(List<Pair<Option, String[]>> args, boolean helpExpected) throws IOException {
105 if (sourceDir == null) {
106 throw new IOException("sourceDir not set");
107 }
108 helpCalled.set(false);
109 ReportConfiguration config = OptionCollection.parseCommands(sourceDir, extractArgs(args), o -> helpCalled.set(true), true);
110 assertThat(helpCalled.get()).as("Help was called").isEqualTo(helpExpected);
111 if (config != null && !config.hasSource()) {
112 config.addSource(OptionCollection.getReportable(sourceDir, config));
113 }
114 return config;
115 }
116
117
118
119
120
121 private File configureRatDir(Option option) {
122 configureSourceDir(option);
123 File ratDir = new File(sourceDir, ".rat");
124 FileUtils.mkDir(ratDir);
125 return ratDir;
126 }
127
128
129
130
131
132 private void configureSourceDir(Option option) {
133 sourceDir = new File(baseDir, OptionFormatter.getName(option));
134 FileUtils.mkDir(sourceDir);
135 }
136
137
138
139
140 private void validateNoArgSetup() throws IOException, RatException {
141 TestingLog log = new TestingLog();
142 DefaultLog.setInstance(log);
143 try {
144 ReportConfiguration config = generateConfig(Collections.emptyList());
145 Reporter reporter = new Reporter(config);
146 Reporter.Output output = reporter.execute();
147 ClaimValidator validator = config.getClaimValidator();
148 assertThat(validator.listIssues(output.getStatistic())).isEmpty();
149 } finally {
150 DefaultLog.setInstance(null);
151 }
152 }
153
154 @OptionCollectionTest.TestFunction
155 protected void addLicenseTest() {
156 editLicenseTest(Arg.EDIT_ADD.find("addLicense"));
157 }
158
159 @OptionCollectionTest.TestFunction
160 protected void editLicenseTest() {
161 editLicenseTest(Arg.EDIT_ADD.find("edit-license"));
162 }
163
164 private void editLicenseTest(final Option option) {
165 assertDoesNotThrow(() -> {
166 configureSourceDir(option);
167 ReportConfiguration config = generateConfig(ImmutablePair.of(option, null));
168 File testFile = writeFile("NoLicense.java", "class NoLicense {}");
169 File resultFile = new File(sourceDir, "NoLicense.java.new");
170 FileUtils.delete(resultFile);
171
172 Reporter reporter = new Reporter(config);
173 Reporter.Output output = reporter.execute();
174 assertThat(output.getStatistic()).isNotNull();
175 String contents = String.join("\n", IOUtils.readLines(new FileReader(testFile)));
176 assertThat(contents).isEqualTo("class NoLicense {}");
177 assertThat(resultFile).exists();
178 contents = String.join("\n", IOUtils.readLines(new FileReader(resultFile)));
179 assertThat(contents).isEqualTo("""
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199 class NoLicense {}""");
200 });
201 }
202
203 protected File writeFile(String name) {
204 return FileUtils.writeFile(sourceDir, name, Collections.singletonList(name));
205 }
206
207 protected File writeFile(String name, String content) {
208 return FileUtils.writeFile(sourceDir, name, Collections.singletonList(content));
209 }
210
211 protected File writeFile(String name, Iterable<String> content) {
212 return FileUtils.writeFile(sourceDir, name, content);
213 }
214
215 @OptionCollectionTest.TestFunction
216 private void execLicensesDeniedTest(final Option option, final String[] args) {
217 assertDoesNotThrow(() -> {
218 configureSourceDir(option);
219 File illumosFile = writeFile("illumousFile.java", "The contents of this file are " +
220 "subject to the terms of the Common Development and Distribution License (the \"License\") You " +
221 "may not use this file except in compliance with the License.");
222
223 validateNoArgSetup();
224
225 ReportConfiguration config = generateConfig(ImmutablePair.of(option, args));
226 Reporter reporter = new Reporter(config);
227 Reporter.Output output = reporter.execute();
228 ClaimValidator validator = config.getClaimValidator();
229 assertThat(validator.listIssues(output.getStatistic())).containsExactly("UNAPPROVED");
230 });
231 }
232
233 @OptionCollectionTest.TestFunction
234 protected void licensesDeniedTest() {
235 execLicensesDeniedTest(Arg.LICENSES_DENIED.find("licenses-denied"), new String[]{"ILLUMOS"});
236 }
237
238 @OptionCollectionTest.TestFunction
239 protected void licensesDeniedFileTest() {
240 Option option = Arg.LICENSES_DENIED_FILE.find("licenses-denied-file");
241 File outputFile = FileUtils.writeFile(configureRatDir(option), "licensesDenied.txt", Collections.singletonList("ILLUMOS"));
242 execLicensesDeniedTest(option, new String[]{outputFile.getAbsolutePath()});
243 }
244
245 private void noDefaultsTest(final Option option) {
246 assertDoesNotThrow(() -> {
247 configureSourceDir(option);
248 File testFile = writeFile("Test.java", Arrays.asList("/*\n", "SPDX-License-Identifier: Apache-2.0\n",
249 "*/\n\n", "class Test {}\n"));
250
251 validateNoArgSetup();
252 ReportConfiguration config = generateConfig(ImmutablePair.of(option, null));
253 Reporter reporter = new Reporter(config);
254 assertThatThrownBy(reporter::execute)
255 .isInstanceOf(RatException.class);
256 });
257 }
258
259 @OptionCollectionTest.TestFunction
260 protected void noDefaultLicensesTest() {
261 noDefaultsTest(Arg.CONFIGURATION_NO_DEFAULTS.find("no-default-licenses"));
262 }
263
264 @OptionCollectionTest.TestFunction
265 protected void configurationNoDefaultsTest() {
266 noDefaultsTest(Arg.CONFIGURATION_NO_DEFAULTS.find("configuration-no-defaults"));
267 }
268
269 @OptionCollectionTest.TestFunction
270 protected void counterMaxTest() {
271 Option option = Arg.COUNTER_MAX.option();
272 String[] arg = {null};
273
274 assertDoesNotThrow(() -> {
275 configureSourceDir(option);
276 File testFile = writeFile("Test.java", Arrays.asList("/*\n", "SPDX-License-Identifier: Unapproved\n",
277 "*/\n\n", "class Test {}\n"));
278
279 ReportConfiguration config = generateConfig(Collections.emptyList());
280 Reporter reporter = new Reporter(config);
281 Reporter.Output output = reporter.execute();
282 ClaimValidator validator = config.getClaimValidator();
283 assertThat(validator.listIssues(output.getStatistic())).containsExactly("UNAPPROVED");
284
285 arg[0] = "Unapproved:1";
286 config = generateConfig(ImmutablePair.of(option, arg));
287 reporter = new Reporter(config);
288 output = reporter.execute();
289 validator = config.getClaimValidator();
290 assertThat(validator.listIssues(output.getStatistic())).isEmpty();
291 });
292 }
293
294 @OptionCollectionTest.TestFunction
295 protected void counterMinTest() {
296 Option option = Arg.COUNTER_MIN.option();
297 String[] arg = {null};
298
299 assertDoesNotThrow(() -> {
300 configureSourceDir(option);
301 File testFile = writeFile("Test.java", Arrays.asList("/*\n", "SPDX-License-Identifier: Unapproved\n",
302 "*/\n\n", "class Test {}\n"));
303
304 ReportConfiguration config = generateConfig(Collections.emptyList());
305 Reporter reporter = new Reporter(config);
306 Reporter.Output output = reporter.execute();
307 ClaimValidator validator = config.getClaimValidator();
308 assertThat(validator.listIssues(output.getStatistic())).containsExactly("UNAPPROVED");
309
310 arg[0] = "Unapproved:1";
311 config = generateConfig(ImmutablePair.of(option, arg));
312 reporter = new Reporter(config);
313 output = reporter.execute();
314 validator = config.getClaimValidator();
315 assertThat(validator.listIssues(output.getStatistic())).isEmpty();
316 });
317 }
318
319
320
321
322
323
324
325 private void execExcludeTest(final Option option, final String[] args, final boolean includesRatDir) {
326 String[] notExcluded = {"notbaz", "well._afile"};
327 String[] excluded = {"some.foo", "B.bar", "justbaz"};
328
329 assertDoesNotThrow(() -> {
330 configureSourceDir(option);
331 writeFile("notbaz");
332 writeFile("well._afile");
333 writeFile("some.foo");
334 writeFile("B.bar");
335 writeFile("justbaz");
336
337 ReportConfiguration config = generateConfig(Collections.emptyList());
338 Reporter reporter = new Reporter(config);
339 Reporter.Output output = reporter.execute();
340 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(5);
341 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(includesRatDir ? 1 : 0);
342
343
344 config = generateConfig(ImmutablePair.of(option, args));
345 reporter = new Reporter(config);
346 output = reporter.execute();
347 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(2);
348 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(includesRatDir ? 4 : 3);
349 });
350 }
351
352 private void excludeFileTest(final Option option) {
353 File outputFile = FileUtils.writeFile(configureRatDir(option), "exclude.txt", Arrays.asList(EXCLUDE_ARGS));
354 execExcludeTest(option, new String[]{outputFile.getAbsolutePath()}, true);
355 }
356
357 @OptionCollectionTest.TestFunction
358 protected void excludeFileTest() {
359 excludeFileTest(Arg.EXCLUDE_FILE.find("exclude-file"));
360 }
361
362 @OptionCollectionTest.TestFunction
363 protected void inputExcludeFileTest() {
364 excludeFileTest(Arg.EXCLUDE_FILE.find("input-exclude-file"));
365 }
366
367 @OptionCollectionTest.TestFunction
368 protected void excludeTest() {
369 execExcludeTest(Arg.EXCLUDE.find("exclude"), EXCLUDE_ARGS, false);
370 }
371
372 @OptionCollectionTest.TestFunction
373 protected void inputExcludeTest() {
374 execExcludeTest(Arg.EXCLUDE.find("input-exclude"), EXCLUDE_ARGS, false);
375 }
376
377 @OptionCollectionTest.TestFunction
378 protected void inputExcludeSizeTest() {
379 Option option = Arg.EXCLUDE_SIZE.option();
380 String[] args = {"5"};
381
382 assertDoesNotThrow(() -> {
383 configureSourceDir(option);
384 writeFile("Hi.txt", "Hi");
385 writeFile("Hello.txt", "Hello");
386 writeFile("HelloWorld.txt", "HelloWorld");
387
388 ReportConfiguration config = generateConfig(Collections.emptyList());
389 Reporter reporter = new Reporter(config);
390 Reporter.Output output = reporter.execute();
391 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(3);
392 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isZero();
393
394
395 config = generateConfig(ImmutablePair.of(option, args));
396 reporter = new Reporter(config);
397 output = reporter.execute();
398 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(2);
399 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(1);
400 });
401 }
402
403 @OptionCollectionTest.TestFunction
404 protected void inputExcludeStdTest() {
405 Option option = Arg.EXCLUDE_STD.find("input-exclude-std");
406 String[] args = {StandardCollection.MAVEN.name()};
407
408
409
410 assertDoesNotThrow(() -> {
411 configureSourceDir(option);
412 writeFile("afile~");
413 writeFile(".#afile");
414 writeFile("%afile%");
415 writeFile("._afile");
416 writeFile("afile~more");
417 writeFile("what.#afile");
418 writeFile("%afile%withMore");
419 writeFile("well._afile");
420 writeFile("build.log");
421
422 ReportConfiguration config = generateConfig(Collections.emptyList());
423 Reporter reporter = new Reporter(config);
424 Reporter.Output output = reporter.execute();
425 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(5);
426 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(4);
427
428 config = generateConfig(ImmutablePair.of(option, args));
429 reporter = new Reporter(config);
430 output = reporter.execute();
431 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(4);
432 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(5);
433 });
434 }
435
436 @OptionCollectionTest.TestFunction
437 protected void inputExcludeParsedScmTest() {
438 Option option = Arg.EXCLUDE_PARSE_SCM.find("input-exclude-parsed-scm");
439 String[] args = {"GIT"};
440 String[] lines = {
441 "# somethings",
442 "!thingone", "thing*", System.lineSeparator(),
443 "# some fish",
444 "**/fish", "*_fish",
445 "# some colorful directories",
446 "red/", "blue/*/"};
447
448 assertDoesNotThrow(() -> {
449 configureSourceDir(option);
450
451 writeFile(".gitignore", Arrays.asList(lines));
452 writeFile("thingone");
453 writeFile("thingtwo");
454
455 File dir = new File(sourceDir, "dir");
456 FileUtils.mkDir(dir);
457 FileUtils.writeFile(dir, "fish_two");
458 FileUtils.writeFile(dir, "fish");
459
460 dir = new File(sourceDir, "red");
461 FileUtils.mkDir(dir);
462 FileUtils.writeFile(dir, "fish");
463
464 dir = new File(sourceDir, "blue/fish");
465 FileUtils.mkDir(dir);
466 FileUtils.writeFile(dir, "dory");
467
468 dir = new File(sourceDir, "some");
469 FileUtils.mkDir(dir);
470 FileUtils.writeFile(dir, "fish");
471 FileUtils.writeFile(dir, "things");
472 FileUtils.writeFile(dir, "thingone");
473
474 dir = new File(sourceDir, "another");
475 FileUtils.mkDir(dir);
476 FileUtils.writeFile(dir, "red_fish");
477
478 ReportConfiguration config = generateConfig(Collections.emptyList());
479 Reporter reporter = new Reporter(config);
480 Reporter.Output output = reporter.execute();
481 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(11);
482
483 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isZero();
484
485 config = generateConfig(ImmutablePair.of(option, args));
486 reporter = new Reporter(config);
487 output = reporter.execute();
488 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(3);
489 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(8);
490 });
491 }
492
493
494
495
496
497
498
499 private void execIncludeTest(final Option option, final String[] args, final boolean includesRatDir) {
500 Option excludeOption = Arg.EXCLUDE.option();
501 String[] notExcluded = {"B.bar", "justbaz", "notbaz"};
502 String[] excluded = {"some.foo"};
503
504 assertDoesNotThrow(() -> {
505 configureSourceDir(option);
506 writeFile("notbaz");
507 writeFile("some.foo");
508 writeFile("B.bar");
509 writeFile("justbaz");
510
511 ReportConfiguration config = generateConfig(Collections.emptyList());
512 Reporter reporter = new Reporter(config);
513 Reporter.Output output = reporter.execute();
514 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(4);
515 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(includesRatDir ? 1 : 0);
516
517
518 config = generateConfig(ImmutablePair.of(excludeOption, EXCLUDE_ARGS));
519 reporter = new Reporter(config);
520 output = reporter.execute();
521 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(1);
522
523 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(includesRatDir ? 4 : 3);
524
525
526 config = generateConfig(ImmutablePair.of(option, args), ImmutablePair.of(excludeOption, EXCLUDE_ARGS));
527 reporter = new Reporter(config);
528 output = reporter.execute();
529 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(3);
530
531 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(includesRatDir ? 2 : 1 );
532 });
533 }
534
535 private void includeFileTest(final Option option) {
536 File outputFile = FileUtils.writeFile(configureRatDir(option), "include.txt", Arrays.asList(INCLUDE_ARGS));
537 execIncludeTest(option, new String[]{outputFile.getAbsolutePath()}, true);
538 }
539
540 @OptionCollectionTest.TestFunction
541 protected void inputIncludeFileTest() {
542 includeFileTest(Arg.INCLUDE_FILE.find("input-include-file"));
543 }
544
545 @OptionCollectionTest.TestFunction
546 protected void includesFileTest() {
547 includeFileTest(Arg.INCLUDE_FILE.find("includes-file"));
548 }
549
550 @OptionCollectionTest.TestFunction
551 protected void includeTest() {
552 execIncludeTest(Arg.INCLUDE.find("include"), INCLUDE_ARGS, false);
553 }
554
555 @OptionCollectionTest.TestFunction
556 protected void inputIncludeTest() {
557 execIncludeTest(Arg.INCLUDE.find("input-include"), INCLUDE_ARGS, false);
558 }
559
560 @OptionCollectionTest.TestFunction
561 protected void inputIncludeStdTest() {
562 Option option = Arg.INCLUDE_STD.find("input-include-std");
563 String[] args = {StandardCollection.MISC.name()};
564
565 assertDoesNotThrow(() -> {
566 configureSourceDir(option);
567
568 writeFile("afile~more");
569 writeFile("afile~");
570 writeFile(".#afile");
571 writeFile("%afile%");
572 writeFile("._afile");
573 writeFile("what.#afile");
574 writeFile("%afile%withMore");
575 writeFile("well._afile");
576
577 ImmutablePair<Option, String[]> excludes = ImmutablePair.of(Arg.EXCLUDE.find("input-exclude"),
578 new String[]{"*~more", "*~"});
579
580 ReportConfiguration config = generateConfig(Collections.singletonList(excludes));
581 Reporter reporter = new Reporter(config);
582 Reporter.Output output = reporter.execute();
583 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(3);
584 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(5);
585
586 config = generateConfig(excludes, ImmutablePair.of(option, args));
587 reporter = new Reporter(config);
588 output = reporter.execute();
589 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(7);
590 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(1);
591 });
592 }
593
594 @OptionCollectionTest.TestFunction
595 protected void inputSourceTest() {
596 Option option = Arg.SOURCE.find("input-source");
597
598 assertDoesNotThrow(() -> {
599 configureSourceDir(option);
600
601 writeFile("codefile");
602 File inputFile = writeFile("intput.txt", "codefile");
603 writeFile("notcodFile");
604
605 ReportConfiguration config = generateConfig();
606 Reporter reporter = new Reporter(config);
607 Reporter.Output output = reporter.execute();
608 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(3);
609 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isZero();
610
611 config = generateConfig(ImmutablePair.of(option, new String[]{inputFile.getAbsolutePath()}));
612 reporter = new Reporter(config);
613 output = reporter.execute();
614 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(1);
615 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isZero();
616 });
617 }
618
619 private ReportConfiguration addCatzLicense(ReportConfiguration config) {
620 String catz = ILicenseFamily.makeCategory("catz");
621 config.addFamily(ILicenseFamily.builder().setLicenseFamilyCategory(catz).setLicenseFamilyName("catz").build());
622 config.addLicense(ILicense.builder().setFamily(catz)
623 .setMatcher(new SpdxBuilder().setName("catz")));
624 return config;
625 }
626
627 private void execLicenseFamiliesApprovedTest(final Option option, final String[] args) {
628 Pair<Option, String[]> arg1 = ImmutablePair.of(option, args);
629
630 assertDoesNotThrow(() -> {
631 configureSourceDir(option);
632
633 writeFile("catz.txt", "SPDX-License-Identifier: catz");
634
635 ReportConfiguration config = addCatzLicense(generateConfig());
636 Reporter reporter = new Reporter(config);
637 Reporter.Output output = reporter.execute();
638
639 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(1);
640 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.APPROVED)).isZero();
641 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(1);
642
643 config = addCatzLicense(generateConfig(arg1));
644 reporter = new Reporter(config);
645 output = reporter.execute();
646 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(1);
647 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.APPROVED)).isEqualTo(1);
648 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.UNAPPROVED)).isZero();
649 });
650 }
651
652 @OptionCollectionTest.TestFunction
653 protected void licenseFamiliesApprovedFileTest() {
654 Option option = Arg.FAMILIES_APPROVED_FILE.find("license-families-approved-file");
655 File outputFile = FileUtils.writeFile(configureRatDir(option), "familiesApproved.txt", Collections.singletonList("catz"));
656 execLicenseFamiliesApprovedTest(option, new String[]{outputFile.getAbsolutePath()});
657 }
658
659 @OptionCollectionTest.TestFunction
660 protected void licenseFamiliesApprovedTest() {
661 execLicenseFamiliesApprovedTest(Arg.FAMILIES_APPROVED.find("license-families-approved"),
662 new String[]{"catz"});
663 }
664
665 private void execLicenseFamiliesDeniedTest(final Option option, final String[] args) {
666 Pair<Option, String[]> arg1 = ImmutablePair.of(option, args);
667 String bsd = ILicenseFamily.makeCategory("BSD-3");
668
669 assertDoesNotThrow(() -> {
670 configureSourceDir(option);
671 writeFile("bsd.txt", "SPDX-License-Identifier: BSD-3-Clause");
672
673 ReportConfiguration config = generateConfig();
674 Reporter reporter = new Reporter(config);
675 Reporter.Output output = reporter.execute();
676 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(1);
677 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.APPROVED)).isEqualTo(1);
678 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.UNAPPROVED)).isZero();
679
680 config = generateConfig(arg1);
681 reporter = new Reporter(config);
682 output = reporter.execute();
683 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(1);
684 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.APPROVED)).isZero();
685 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(1);
686 });
687 }
688
689 @OptionCollectionTest.TestFunction
690 protected void licenseFamiliesDeniedFileTest() {
691 Option option = Arg.FAMILIES_DENIED_FILE.find("license-families-denied-file");
692 File outputFile = FileUtils.writeFile(configureRatDir(option), "familiesDenied.txt", Collections.singletonList("BSD-3"));
693 execLicenseFamiliesDeniedTest(option, new String[]{outputFile.getAbsolutePath()});
694 }
695
696 @OptionCollectionTest.TestFunction
697 protected void licenseFamiliesDeniedTest() {
698 execLicenseFamiliesDeniedTest(Arg.FAMILIES_DENIED.find("license-families-denied"),
699 new String[]{"BSD-3"});
700 }
701
702 private void configTest(final Option option) {
703 assertDoesNotThrow(() -> {
704 configureSourceDir(option);
705 String[] args = {
706 Resources.getResourceFile("OptionTools/One.xml").getAbsolutePath(),
707 Resources.getResourceFile("OptionTools/Two.xml").getAbsolutePath()};
708 Pair<Option, String[]> arg1 = ImmutablePair.of(option, args);
709
710 writeFile("bsd.txt", "SPDX-License-Identifier: BSD-3-Clause");
711 writeFile("one.txt", "one is the loneliest number");
712
713 ReportConfiguration config = generateConfig();
714 Reporter reporter = new Reporter(config);
715 Reporter.Output output = reporter.execute();
716 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(2);
717 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.APPROVED)).isEqualTo(1);
718 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(1);
719
720 config = generateConfig(arg1);
721 reporter = new Reporter(config);
722 output = reporter.execute();
723 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(2);
724 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.APPROVED)).isEqualTo(2);
725 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.UNAPPROVED)).isZero();
726
727 Pair<Option, String[]> arg2 = ImmutablePair.of(Arg.CONFIGURATION_NO_DEFAULTS.find("configuration-no-defaults"), null);
728
729 config = generateConfig(arg1, arg2);
730 reporter = new Reporter(config);
731 output = reporter.execute();
732 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(2);
733 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.APPROVED)).isEqualTo(1);
734 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(1);
735 });
736 }
737
738 @OptionCollectionTest.TestFunction
739 protected void licensesTest() {
740 configTest(Arg.CONFIGURATION.find("licenses"));
741 }
742
743 @OptionCollectionTest.TestFunction
744 protected void configTest() {
745 configTest(Arg.CONFIGURATION.find("config"));
746 }
747
748 @OptionCollectionTest.TestFunction
749 protected void execLicensesApprovedTest(final Option option, String[] args) {
750 Pair<Option, String[]> arg1 = ImmutablePair.of(option, args);
751
752 assertDoesNotThrow(() -> {
753 configureSourceDir(option);
754
755 writeFile("gpl.txt", "SPDX-License-Identifier: GPL-1.0-only");
756 writeFile("apl.txt", "SPDX-License-Identifier: Apache-2.0");
757
758 ReportConfiguration config = generateConfig();
759 Reporter reporter = new Reporter(config);
760 Reporter.Output output = reporter.execute();
761 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(2);
762 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.APPROVED)).isEqualTo(1);
763 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(1);
764
765 config = generateConfig(arg1);
766 reporter = new Reporter(config);
767 output = reporter.execute();
768 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(2);
769 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.APPROVED)).isEqualTo(2);
770 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.UNAPPROVED)).isZero();
771 });
772 }
773
774 @OptionCollectionTest.TestFunction
775 protected void licensesApprovedFileTest() {
776 Option option = Arg.LICENSES_APPROVED_FILE.find("licenses-approved-file");
777 File outputFile = FileUtils.writeFile(configureRatDir(option), "licensesApproved.txt", Collections.singletonList("GPL1"));
778 execLicensesApprovedTest(option, new String[]{outputFile.getAbsolutePath()});
779 }
780
781 @OptionCollectionTest.TestFunction
782 protected void licensesApprovedTest() {
783 execLicensesApprovedTest(Arg.LICENSES_APPROVED.find("licenses-approved"),
784 new String[]{"GPL1"});
785 }
786
787 @OptionCollectionTest.TestFunction
788 protected void scanHiddenDirectoriesTest() {
789 Option option = Arg.INCLUDE_STD.find("scan-hidden-directories");
790 Pair<Option, String[]> arg1 = ImmutablePair.of(option, null);
791
792 assertDoesNotThrow(() -> {
793 configureSourceDir(option);
794
795 writeFile("apl.txt", "SPDX-License-Identifier: Apache-2.0");
796
797 File hiddenDir = new File(sourceDir, ".hiddendir");
798 FileUtils.mkDir(hiddenDir);
799 FileUtils.writeFile(hiddenDir, "gpl.txt", Collections.singletonList("SPDX-License-Identifier: GPL-1.0-only"));
800
801 ReportConfiguration config = generateConfig();
802 Reporter reporter = new Reporter(config);
803 Reporter.Output output = reporter.execute();
804 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(1);
805 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.APPROVED)).isEqualTo(1);
806 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.UNAPPROVED)).isZero();
807
808 config = generateConfig(arg1);
809 reporter = new Reporter(config);
810 output = reporter.execute();
811 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(2);
812 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.APPROVED)).isEqualTo(1);
813 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(1);
814 });
815 }
816
817 private void outTest(final Option option) {
818 assertDoesNotThrow(() -> {
819 configureSourceDir(option);
820 writeFile("apl.txt", "SPDX-License-Identifier: Apache-2.0");
821 File outFile = new File(sourceDir, "outexample");
822 FileUtils.delete(outFile);
823 String[] args = new String[]{outFile.getAbsolutePath()};
824
825 ReportConfiguration config = generateConfig(ImmutablePair.of(option, args));
826 Reporter reporter = new Reporter(config);
827 Reporter.Output output = reporter.execute();
828 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(1);
829 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.APPROVED)).isEqualTo(1);
830 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.UNAPPROVED)).isZero();
831 output.format(config);
832 String actualText = TextUtils.readFile(outFile);
833 assertThat(actualText).containsOnlyOnce("Apache License 2.0: 1 ")
834 .containsOnlyOnce("STANDARD: 1 ");
835 });
836 }
837
838 @OptionCollectionTest.TestFunction
839 protected void outTest() {
840 outTest(Arg.OUTPUT_FILE.find("out"));
841 }
842
843 @OptionCollectionTest.TestFunction
844 protected void outputFileTest() {
845 outTest(Arg.OUTPUT_FILE.find("output-file"));
846 }
847
848 private void styleSheetTest(final Option option) {
849 PrintStream origin = System.out;
850 ByteArrayOutputStream baos = new ByteArrayOutputStream();
851 try (PrintStream out = new PrintStream(baos)) {
852 System.setOut(out);
853 configureSourceDir(option);
854
855 File file = writeFile("stylesheet", """
856 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
857 <xsl:template match="@*|node()">
858 Hello world
859 </xsl:template>
860 </xsl:stylesheet>""");
861
862 String[] args = {null};
863 for (StyleSheets sheet : StyleSheets.values()) {
864 args[0] = sheet.arg();
865 ReportConfiguration config = generateConfig(ImmutablePair.of(option, args));
866 Reporter reporter = new Reporter(config);
867 Reporter.Output output = reporter.execute();
868 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(1);
869 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.APPROVED)).isZero();
870 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(1);
871 output.format(config);
872 String actualText = baos.toString(StandardCharsets.UTF_8);
873 switch (sheet) {
874 case MISSING_HEADERS:
875 assertThat(actualText).containsOnlyOnce("Files with missing headers:" + System.lineSeparator() +
876 " /stylesheet");
877 break;
878 case PLAIN:
879 assertThat(actualText).containsOnlyOnce("Unknown license: 1 ");
880 assertThat(actualText).containsOnlyOnce("?????: 1 ");
881 break;
882 case XML:
883 assertThat(actualText).containsOnlyOnce("<resource encoding=\"windows-1252\" mediaType=\"text/plain\" name=\"/stylesheet\" type=\"STANDARD\">");
884 break;
885 case UNAPPROVED_LICENSES:
886 assertThat(actualText).containsOnlyOnce("Files with unapproved licenses:" + System.lineSeparator() + " /stylesheet");
887 break;
888 case XHTML5:
889 assertThat(actualText).containsPattern("<td>Approved</td>\\s+<td>\\d+</td>\\s+<td>A count of approved licenses.</td>");
890 break;
891 default:
892 fail("No test for stylesheet " + sheet);
893 break;
894 }
895 baos.reset();
896 }
897 args[0] = file.getAbsolutePath();
898 ReportConfiguration config = generateConfig(ImmutablePair.of(option, args));
899 Reporter reporter = new Reporter(config);
900 Reporter.Output output = reporter.execute();
901 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(1);
902 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.APPROVED)).isZero();
903 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(1);
904 output.format(config);
905 String actualText = baos.toString(StandardCharsets.UTF_8);
906 assertThat(actualText).containsOnlyOnce("Hello world");
907 } catch (IOException | RatException e) {
908 fail(e.getMessage(), e);
909 } finally {
910 System.setOut(origin);
911 }
912 }
913
914 @OptionCollectionTest.TestFunction
915 protected void stylesheetTest() {
916 styleSheetTest(Arg.OUTPUT_STYLE.find("stylesheet"));
917 }
918
919 @OptionCollectionTest.TestFunction
920 protected void outputStyleTest() {
921 styleSheetTest(Arg.OUTPUT_STYLE.find("output-style"));
922 }
923
924 @OptionCollectionTest.TestFunction
925 protected void xmlTest() {
926 PrintStream origin = System.out;
927 Option option = Arg.OUTPUT_STYLE.find("xml");
928 ByteArrayOutputStream baos = new ByteArrayOutputStream();
929 try (PrintStream out = new PrintStream(baos)) {
930 System.setOut(out);
931 configureSourceDir(option);
932
933 File file = writeFile("stylesheet", """
934 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
935 <xsl:template match="@*|node()">
936 Hello world
937 </xsl:template>
938 </xsl:stylesheet>""");
939
940 ReportConfiguration config = generateConfig(ImmutablePair.of(option, null));
941 Reporter reporter = new Reporter(config);
942 Reporter.Output output = reporter.execute();
943 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(1);
944 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.APPROVED)).isZero();
945 assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(1);
946 output.format(config);
947 String actualText = baos.toString(StandardCharsets.UTF_8);
948 assertThat(actualText)
949 .containsOnlyOnce("<resource encoding=\"windows-1252\" mediaType=\"text/plain\" name=\"/stylesheet\" type=\"STANDARD\">");
950
951 try (InputStream expected = StyleSheets.getStyleSheet("xml", null).ioSupplier().get();
952 InputStream actual = config.getStyleSheet().get()) {
953 assertThat(IOUtils.contentEquals(expected, actual)).as("'xml' does not match").isTrue();
954 }
955 } catch (IOException | RatException e) {
956 fail(e.getMessage(), e);
957 } finally {
958 System.setOut(origin);
959 }
960 }
961
962 @OptionCollectionTest.TestFunction
963 protected void logLevelTest() {
964 PrintStream origin = System.out;
965 Option option = Arg.LOG_LEVEL.find("log-level");
966 ByteArrayOutputStream baos = new ByteArrayOutputStream();
967 Log.Level oldLevel = DefaultLog.getInstance().getLevel();
968 try (PrintStream out = new PrintStream(baos)) {
969 System.setOut(out);
970 configureSourceDir(option);
971
972 ReportConfiguration config = generateConfig();
973 Reporter reporter = new Reporter(config);
974 reporter.execute();
975 assertThat(baos.toString(StandardCharsets.UTF_8)).doesNotContain("DEBUG");
976
977 config = generateConfig(ImmutablePair.of(option, new String[]{"debug"}));
978 reporter = new Reporter(config);
979 reporter.execute();
980 assertThat(baos.toString(StandardCharsets.UTF_8)).contains("DEBUG");
981 } catch (IOException | RatException e) {
982 fail(e.getMessage(), e);
983 } finally {
984 System.setOut(origin);
985 DefaultLog.getInstance().setLevel(oldLevel);
986 }
987 }
988
989 private void listLicenses(final Option option) {
990 XPath xPath = SecureXPathFactory.newInstance().newXPath();
991 String[] args = {null};
992
993 assertDoesNotThrow(() -> {
994 configureSourceDir(option);
995 for (LicenseSetFactory.LicenseFilter filter : LicenseSetFactory.LicenseFilter.values()) {
996 args[0] = filter.name();
997 ReportConfiguration config = generateConfig(ImmutablePair.of(option, args));
998 Reporter reporter = new Reporter(config);
999 Reporter.Output output = reporter.execute();
1000 Document document = output.getDocument();
1001 switch (filter) {
1002 case ALL:
1003 XmlUtils.assertIsPresent(filter.name(), document, xPath, "/rat-report/rat-config/licenses/license[@id='AL2.0']");
1004 XmlUtils.assertIsPresent(filter.name(), document, xPath, "/rat-report/rat-config/licenses/license[@id='GPL1']");
1005 break;
1006 case APPROVED:
1007 XmlUtils.assertIsPresent(filter.name(), document, xPath, "/rat-report/rat-config/licenses/license[@id='AL2.0']");
1008 XmlUtils.assertIsNotPresent(filter.name(), document, xPath, "/rat-report/rat-config/licenses/license[@id='GPL1']");
1009 break;
1010 case NONE:
1011 XmlUtils.assertIsNotPresent(filter.name(), document, xPath, "/rat-report/rat-config/licenses/license[@id='AL2.0']");
1012 XmlUtils.assertIsNotPresent(filter.name(), document, xPath, "/rat-report/rat-config/licenses/license[@id='GPL1']");
1013 break;
1014 default:
1015 throw new IllegalArgumentException("Unexpected filter: " + filter);
1016 }
1017 }
1018 });
1019 }
1020
1021 @OptionCollectionTest.TestFunction
1022 protected void listLicensesTest() {
1023 listLicenses(Arg.OUTPUT_LICENSES.find("list-licenses"));
1024 }
1025
1026 @OptionCollectionTest.TestFunction
1027 protected void outputLicensesTest() {
1028 listLicenses(Arg.OUTPUT_LICENSES.find("output-licenses"));
1029 }
1030
1031 private void listFamilies(final Option option) {
1032 XPath xPath = SecureXPathFactory.newInstance().newXPath();
1033 String[] args = {null};
1034
1035 assertDoesNotThrow(() -> {
1036 configureSourceDir(option);
1037 for (LicenseSetFactory.LicenseFilter filter : LicenseSetFactory.LicenseFilter.values()) {
1038 args[0] = filter.name();
1039 ReportConfiguration config = generateConfig(ImmutablePair.of(option, args));
1040 Reporter reporter = new Reporter(config);
1041 Reporter.Output output = reporter.execute();
1042 Document document = output.getDocument();
1043 switch (filter) {
1044 case ALL:
1045 XmlUtils.assertIsPresent(filter.name(), document, xPath, "/rat-report/rat-config/families/family[@id='AL']");
1046 XmlUtils.assertIsPresent(filter.name(), document, xPath, "/rat-report/rat-config/families/family[@id='GPL']");
1047 break;
1048 case APPROVED:
1049 XmlUtils.assertIsPresent(filter.name(), document, xPath, "/rat-report/rat-config/families/family[@id='AL']");
1050 XmlUtils.assertIsNotPresent(filter.name(), document, xPath, "/rat-report/rat-config/families/family[@id='GPL']");
1051 break;
1052 case NONE:
1053 XmlUtils.assertIsNotPresent(filter.name(), document, xPath, "/rat-report/rat-config/families/family[@id='AL']");
1054 XmlUtils.assertIsNotPresent(filter.name(), document, xPath, "/rat-report/rat-config/families/family[@id='GPL']");
1055 break;
1056 default:
1057 throw new IllegalArgumentException("Unexpected filter: " + filter);
1058 }
1059 }
1060 });
1061 }
1062
1063 @OptionCollectionTest.TestFunction
1064 protected void listFamiliesTest() {
1065 listFamilies(Arg.OUTPUT_FAMILIES.find("list-families"));
1066 }
1067
1068 @OptionCollectionTest.TestFunction
1069 protected void outputFamiliesTest() {
1070 listFamilies(Arg.OUTPUT_FAMILIES.find("output-families"));
1071 }
1072
1073 private void archiveTest(final Option option) {
1074 XPath xPath = SecureXPathFactory.newInstance().newXPath();
1075 String[] args = {null};
1076
1077 assertDoesNotThrow(() -> {
1078 configureSourceDir(option);
1079 File outFile = new File(sourceDir, "out.xml");
1080 FileUtils.delete(outFile);
1081 ImmutablePair<Option, String[]> outputFile = ImmutablePair.of(Arg.OUTPUT_FILE.option(), new String[]{outFile.getAbsolutePath()});
1082 ImmutablePair<Option, String[]> stylesheet = ImmutablePair.of(Arg.OUTPUT_STYLE.option(), new String[]{StyleSheets.XML.arg()});
1083 File archive = Resources.getResourceFile("tikaFiles/archive/dummy.jar");
1084 File localArchive = new File(sourceDir, "dummy.jar");
1085 try (InputStream in = Files.newInputStream(archive.toPath());
1086 OutputStream out = Files.newOutputStream(localArchive.toPath())) {
1087 IOUtils.copy(in, out);
1088 }
1089
1090 for (ReportConfiguration.Processing proc : ReportConfiguration.Processing.values()) {
1091 args[0] = proc.name();
1092 ReportConfiguration config = generateConfig(outputFile, stylesheet, ImmutablePair.of(option, args));
1093 Reporter reporter = new Reporter(config);
1094 reporter.execute().format(config);
1095
1096 Document document = reporter.execute().getDocument();
1097 XmlUtils.assertIsPresent(proc.name(), document, xPath, "/rat-report/resource[@name='/dummy.jar']");
1098 switch (proc) {
1099 case ABSENCE:
1100 XmlUtils.assertIsPresent(proc.name(), document, xPath, "/rat-report/resource[@name='/dummy.jar']/license[@family='AL ']");
1101 XmlUtils.assertIsPresent(proc.name(), document, xPath, "/rat-report/resource[@name='/dummy.jar']/license[@family='?????']");
1102 break;
1103 case PRESENCE:
1104 XmlUtils.assertIsPresent(proc.name(), document, xPath, "/rat-report/resource[@name='/dummy.jar']/license[@family='AL ']");
1105 XmlUtils.assertIsNotPresent(proc.name(), document, xPath, "/rat-report/resource[@name='/dummy.jar']/license[@family='?????']");
1106 break;
1107 case NOTIFICATION:
1108 XmlUtils.assertIsNotPresent(proc.name(), document, xPath, "/rat-report/resource[@name='/dummy.jar']/license[@family='AL ']");
1109 XmlUtils.assertIsNotPresent(proc.name(), document, xPath, "/rat-report/resource[@name='/dummy.jar']/license[@family='?????']");
1110 break;
1111 default:
1112 throw new IllegalArgumentException("Unexpected processing " + proc);
1113 }
1114 }
1115 });
1116 }
1117
1118 @OptionCollectionTest.TestFunction
1119 protected void outputArchiveTest() {
1120 archiveTest(Arg.OUTPUT_ARCHIVE.find("output-archive"));
1121 }
1122
1123 private void standardTest(final Option option) {
1124 XPath xPath = SecureXPathFactory.newInstance().newXPath();
1125 String[] args = {null};
1126
1127 assertDoesNotThrow(() -> {
1128 configureSourceDir(option);
1129 File outFile = new File(sourceDir, "out.xml");
1130 ImmutablePair<Option, String[]> outputFile = ImmutablePair.of(Arg.OUTPUT_FILE.option(), new String[]{outFile.getAbsolutePath()});
1131 ImmutablePair<Option, String[]> stylesheet = ImmutablePair.of(Arg.OUTPUT_STYLE.option(), new String[]{StyleSheets.XML.arg()});
1132
1133 writeFile("Test.java", Arrays.asList("/*\n", "SPDX-License-Identifier: Apache-2.0\n",
1134 "*/\n\n", "class Test {}\n"));
1135 writeFile("Missing.java", Arrays.asList("/* no license */\n\n", "class Test {}\n"));
1136
1137 String testDoc = "/rat-report/resource[@name='/Test.java']";
1138 String missingDoc = "/rat-report/resource[@name='/Missing.java']";
1139
1140 for (ReportConfiguration.Processing proc : ReportConfiguration.Processing.values()) {
1141 args[0] = proc.name();
1142 ReportConfiguration config = generateConfig(outputFile, stylesheet, ImmutablePair.of(option, args));
1143 Reporter reporter = new Reporter(config);
1144 Reporter.Output output = reporter.execute();
1145
1146 Document document = output.getDocument();
1147 XmlUtils.assertIsPresent(proc.name(), document, xPath, testDoc);
1148 XmlUtils.assertIsPresent(proc.name(), document, xPath, missingDoc);
1149
1150 switch (proc) {
1151 case ABSENCE:
1152 XmlUtils.assertIsPresent(proc.name(), document, xPath, testDoc + "/license[@family='AL ']");
1153 XmlUtils.assertIsPresent(proc.name(), document, xPath, missingDoc + "/license[@family='?????']");
1154 break;
1155 case PRESENCE:
1156 XmlUtils.assertIsPresent(proc.name(), document, xPath, testDoc + "/license[@family='AL ']");
1157 XmlUtils.assertIsNotPresent(proc.name(), document, xPath, missingDoc + "/license[@family='?????']");
1158 break;
1159 case NOTIFICATION:
1160 XmlUtils.assertIsNotPresent(proc.name(), document, xPath, testDoc + "/license[@family='AL ']");
1161 XmlUtils.assertIsNotPresent(proc.name(), document, xPath, missingDoc + "/license[@family='?????']");
1162 break;
1163 default:
1164 throw new IllegalArgumentException("Unexpected processing " + proc);
1165 }
1166 }
1167 });
1168 }
1169
1170 @OptionCollectionTest.TestFunction
1171 protected void outputStandardTest() {
1172 standardTest(Arg.OUTPUT_STANDARD.find("output-standard"));
1173 }
1174
1175 private void editCopyrightTest(final Option option, final Option extraOption) {
1176 final String myCopyright = "MyCopyright";
1177 Pair<Option, String[]> arg1 = ImmutablePair.of(option, new String[]{myCopyright});
1178 final boolean forced = Arg.EDIT_OVERWRITE.option().equals(extraOption);
1179 final boolean dryRun = Arg.DRY_RUN.option().equals(extraOption);
1180
1181 assertDoesNotThrow(() -> {
1182 Pair<Option, String[]> extraArg = null;
1183 if (forced || dryRun) {
1184 extraArg = ImmutablePair.of(extraOption, null);
1185 }
1186
1187 configureSourceDir(option);
1188 File javaFile = writeFile("Missing.java", Arrays.asList("/* no license */\n\n", "class Test {}\n"));
1189 File newJavaFile = new File(sourceDir, "Missing.java.new");
1190 FileUtils.delete(newJavaFile);
1191
1192 ReportConfiguration config = extraArg != null ? generateConfig(arg1, extraArg) : generateConfig(arg1);
1193 Reporter reporter = new Reporter(config);
1194 reporter.execute();
1195
1196 String actualText = TextUtils.readFile(javaFile);
1197 assertThat(actualText).doesNotContain(myCopyright);
1198
1199 Pair<Option, String[]> arg2 = ImmutablePair.of(Arg.EDIT_ADD.find("edit-license"), null);
1200 config = extraArg != null ? generateConfig(arg1, arg2, extraArg) : generateConfig(arg1, arg2);
1201 reporter = new Reporter(config);
1202 reporter.execute();
1203
1204 actualText = TextUtils.readFile(javaFile);
1205 if (forced) {
1206 assertThat(actualText).contains(myCopyright);
1207 assertThat(newJavaFile).doesNotExist();
1208 } else if (dryRun) {
1209 assertThat(actualText).doesNotContain(myCopyright);
1210 assertThat(newJavaFile).doesNotExist();
1211 } else {
1212 assertThat(actualText).doesNotContain(myCopyright);
1213 assertThat(newJavaFile).exists();
1214 }
1215 });
1216 }
1217
1218 @OptionCollectionTest.TestFunction
1219 protected void copyrightTest() {
1220 editCopyrightTest(Arg.EDIT_COPYRIGHT.find("copyright"), null);
1221 }
1222
1223 @OptionCollectionTest.TestFunction
1224 protected void editCopyrightTest() {
1225 editCopyrightTest(Arg.EDIT_COPYRIGHT.find("edit-copyright"), null);
1226 }
1227
1228 @OptionCollectionTest.TestFunction
1229 protected void forceTest() {
1230 editCopyrightTest(Arg.EDIT_COPYRIGHT.find("edit-copyright"), Arg.EDIT_OVERWRITE.find("force"));
1231 }
1232
1233 @OptionCollectionTest.TestFunction
1234 protected void editOverwriteTest() {
1235 editCopyrightTest(Arg.EDIT_COPYRIGHT.find("edit-copyright"), Arg.EDIT_OVERWRITE.find("edit-overwrite"));
1236 }
1237
1238 @OptionCollectionTest.TestFunction
1239 public void helpTest() {
1240 PrintStream origin = System.out;
1241 Options options = OptionCollection.buildOptions();
1242 Pair<Option, String[]> arg1 = ImmutablePair.of(OptionCollection.HELP, null);
1243 ByteArrayOutputStream baos = new ByteArrayOutputStream();
1244 String actualText = null;
1245 try (PrintStream out = new PrintStream(baos)) {
1246 System.setOut(out);
1247 configureSourceDir(OptionCollection.HELP);
1248
1249 generateConfig(List.of(arg1), true);
1250 assertThat(helpCalled.get()).as("Help was not called").isTrue();
1251 new Help(System.out).printUsage(options);
1252 actualText = baos.toString(StandardCharsets.UTF_8);
1253 } catch (IOException e) {
1254 fail(e.getMessage(), e);
1255 } finally {
1256 System.setOut(origin);
1257 }
1258
1259
1260 assertThat(actualText).contains("====== Available Options ======");
1261 for (Option option : options.getOptions()) {
1262 StringBuilder regex = new StringBuilder();
1263 if (option.getOpt() != null) {
1264 regex.append("-").append(option.getOpt());
1265 if (option.hasLongOpt()) {
1266 regex.append(",");
1267 }
1268 }
1269 if (option.hasLongOpt()) {
1270 regex.append("--").append(option.getLongOpt());
1271 }
1272 if (option.hasArg()) {
1273 String name = option.getArgName() == null ? "arg" : option.getArgName();
1274 regex.append(".+\\<").append(name).append("\\>");
1275 }
1276 if (option.isDeprecated()) {
1277 regex.append(".+\\[Deprecated ");
1278 }
1279 assertThat(Pattern.compile(regex.toString()).matcher(actualText).find()).as("missing '" + regex + "'").isTrue();
1280 }
1281
1282 assertThat(actualText).contains("====== Argument Types ======");
1283 assertThat(actualText).contains("====== Standard Collections ======");
1284 for (StandardCollection collection : StandardCollection.values()) {
1285 assertThat(actualText).contains("<" + collection.name() + ">");
1286 }
1287 }
1288
1289 @OptionCollectionTest.TestFunction
1290 protected void helpLicensesTest() {
1291 PrintStream origin = System.out;
1292 Option option = HELP_LICENSES.option();
1293 Pair<Option, String[]> arg1 = ImmutablePair.of(option, null);
1294 ByteArrayOutputStream baos = new ByteArrayOutputStream();
1295 String actualText = null;
1296 try (PrintStream out = new PrintStream(baos)) {
1297 System.setOut(out);
1298 configureSourceDir(option);
1299 generateConfig(arg1);
1300 actualText = baos.toString(StandardCharsets.UTF_8);
1301 } catch (IOException e) {
1302 fail(e.getMessage(), e);
1303 } finally {
1304 System.setOut(origin);
1305 }
1306
1307 assertThat(actualText).isNotNull()
1308 .contains("====== Licenses ======", "====== Defined Matchers ======", "====== Defined Families ======");
1309 }
1310
1311 @OptionCollectionTest.TestFunction
1312 protected void dryRunTest() {
1313 editCopyrightTest(Arg.EDIT_COPYRIGHT.find("edit-copyright"), Arg.DRY_RUN.find("dry-run"));
1314 }
1315 }