1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.rat.annotation;
20
21 import static org.junit.jupiter.api.Assertions.assertEquals;
22 import static org.junit.jupiter.api.Assertions.assertFalse;
23 import static org.junit.jupiter.api.Assertions.assertTrue;
24
25 import java.io.BufferedReader;
26 import java.io.File;
27 import java.io.FileInputStream;
28 import java.io.FileReader;
29 import java.io.FileWriter;
30 import java.io.IOException;
31 import java.io.Writer;
32 import java.nio.charset.Charset;
33
34 import org.apache.commons.io.FileUtils;
35 import org.apache.commons.io.IOUtils;
36 import org.apache.rat.test.utils.Resources;
37 import org.junit.jupiter.api.Test;
38 import org.junit.jupiter.api.io.TempDir;
39
40 public class TestLicenseAppender {
41
42 @TempDir
43 private File baseTempFolder;
44
45 private static final String FIRST_LICENSE_LINE = " Licensed to the Apache Software Foundation (ASF) under one";
46
47 @FunctionalInterface
48 private interface FileCreator {
49 void createFile(Writer w) throws IOException;
50 }
51
52 private interface NewFileReader {
53 void readFile(BufferedReader r) throws IOException;
54 }
55
56 private String getTemporaryFileWithName(String fileName) throws IOException {
57 if (fileName != null) {
58 return new File(baseTempFolder, fileName).getAbsolutePath();
59 }
60 return File.createTempFile("tla", null, baseTempFolder).getAbsolutePath();
61 }
62
63 private static void createTestFile(String fileName, FileCreator creator) throws IOException {
64 try (FileWriter w = new FileWriter(fileName)) {
65 creator.createFile(w);
66 }
67 }
68
69 private void commonTestTemplate(String relativeName, FileCreator creator, NewFileReader reader) throws IOException {
70 String name = getTemporaryFileWithName(relativeName);
71
72 createTestFile(name, creator);
73
74 ApacheV2LicenseAppender appender = new ApacheV2LicenseAppender();
75 appender.append(new File(name));
76
77 try (BufferedReader r = new BufferedReader(new FileReader(name + ".new"))) {
78 reader.readFile(r);
79 }
80 FileUtils.delete(new File(name + ".new"));
81 FileUtils.delete(new File(name));
82 }
83
84 private static NewFileReader checkLines(final String... lines) {
85 return r -> {
86 for (int i = 0; i < lines.length; i++) {
87 String line = r.readLine();
88 assertEquals(lines[i], line, String.format("Line %s is incorrect", i));
89 }
90 };
91 }
92
93 @Test
94 public void addLicenseToUnknownFile() throws IOException {
95 String filename = getTemporaryFileWithName(null);
96 createTestFile(filename, writer -> writer.write("Unknown file type\n"));
97
98 File file = new File(filename);
99 file.deleteOnExit();
100 ApacheV2LicenseAppender appender = new ApacheV2LicenseAppender();
101 appender.append(file);
102
103 File newFile = new File(filename + ".new");
104 newFile.deleteOnExit();
105 assertFalse(newFile.exists(), "No new file should have been written");
106 }
107
108 @Test
109 public void addLicenseToJava() throws IOException {
110 String filename = "tmp.java";
111 final String firstLine = "package foo;";
112 final String secondLine = "";
113 final String thirdLine = "/*";
114 commonTestTemplate(filename, writer -> {
115 writer.write(firstLine + "\n");
116 writer.write("\n");
117 writer.write("public class test {\n");
118 writer.write("}\n");
119 }, checkLines(firstLine, secondLine, thirdLine));
120 }
121
122 @Test
123 public void addLicenseToJavaWithoutPackage() throws IOException {
124 String filename = "tmp.java";
125 String commentLine = "/*";
126 commonTestTemplate(filename, writer -> {
127 writer.write("public class test {\n");
128 writer.write("}\n");
129 }, checkLines(commentLine));
130 }
131
132 @Test
133 public void addLicenseToXML() throws IOException {
134 String filename = "tmp.xml";
135 final String firstLine = "<?xml version='1.0'?>";
136 final String secondLine = "";
137 final String thirdLine = "<!--";
138
139 commonTestTemplate(filename, writer -> {
140 writer.write(firstLine + "\n");
141 writer.write("\n");
142 writer.write("<xml>\n");
143 writer.write("</xml>\n");
144 }, checkLines(firstLine, secondLine, thirdLine));
145 }
146
147 @Test
148 public void addLicenseToXMLWithoutDecl() throws IOException {
149 String filename = "tmp.xml";
150 final String firstLine = "<?xml version='1.0'?>";
151 final String secondLine = "<!--";
152
153 commonTestTemplate(filename, writer -> {
154 writer.write("<xml>\n");
155 writer.write("</xml>\n");
156 }, checkLines(firstLine, secondLine));
157 }
158
159 @Test
160 public void addLicenseToHTML() throws IOException {
161 String filename = "tmp.html";
162 String commentLine = "<!--";
163
164 commonTestTemplate(filename, writer -> {
165 writer.write("<html>\n");
166 writer.write("\n");
167 writer.write("</html>\n");
168 }, checkLines(commentLine));
169 }
170
171 @Test
172 public void addLicenseToCSS() throws IOException {
173 String filename = "tmp.css";
174 String firstLine = "/*";
175
176 commonTestTemplate(filename, writer -> {
177 writer.write(".class {\n");
178 writer.write(" background-color: red;");
179 writer.write("}\n");
180 }, checkLines(firstLine));
181 }
182
183 @Test
184 public void addLicenseToJavascript() throws IOException {
185 String filename = "tmp.js";
186 String firstLine = "/*";
187
188 commonTestTemplate(filename, writer -> {
189 writer.write("if (a ==b) {>\n");
190 writer.write(" alert(\"how useful!\");");
191 writer.write("}\n");
192 }, checkLines(firstLine));
193 }
194
195 @Test
196 public void addLicenseToAPT() throws IOException {
197 String filename = "tmp.apt";
198 String firstLine = "~~" + FIRST_LICENSE_LINE;
199
200 commonTestTemplate(filename, writer -> {
201 writer.write("A Simple APT file");
202 writer.write(" This file contains nothing\n");
203 writer.write(" of any importance\n");
204 }, checkLines(firstLine));
205 }
206
207 @Test
208 public void addLicenseToProperties() throws IOException {
209 String filename = "tmp.properties";
210 String firstLine = "#" + FIRST_LICENSE_LINE;
211
212 commonTestTemplate(filename, writer -> {
213 writer.write("property = value\n");
214 writer.write("fun = true\n");
215 writer.write("cool = true\n");
216 }, checkLines(firstLine));
217 }
218
219 @Test
220 public void addLicenseToScala() throws IOException {
221 String filename = "tmp.scala";
222 final String firstLine = "package foo {";
223 final String newFirstLine = "/*";
224
225 commonTestTemplate(filename, writer -> {
226 writer.write(firstLine + "\n");
227 writer.write("\n");
228 writer.write(" object X { val x = 1; }\n");
229 writer.write("}\n");
230 }, reader -> {
231 String line = reader.readLine();
232 assertEquals(newFirstLine, line, "First line is incorrect");
233 while ((line = reader.readLine()) != null) {
234 if (line.isEmpty()) {
235 line = reader.readLine();
236 break;
237 }
238 }
239 assertEquals(firstLine, line, "Package line is incorrect");
240 });
241 }
242
243 @Test
244 public void addLicenseToRubyWithoutHashBang() throws IOException {
245 String filename = "tmp.rb";
246 String firstLine = "#" + FIRST_LICENSE_LINE;
247
248 commonTestTemplate(filename, writer -> {
249 writer.write("class Foo\n");
250 writer.write("end\n");
251 }, checkLines(firstLine));
252 }
253
254 @Test
255 public void addLicenseToRubyWithHashBang() throws IOException {
256 String filename = "tmp.rb";
257 final String firstLine = "#!/usr/bin/env ruby";
258 String secondLine = "#" + FIRST_LICENSE_LINE;
259
260 commonTestTemplate(filename, writer -> {
261 writer.write(firstLine + "\n");
262 writer.write("class Foo\n");
263 writer.write("end\n");
264 }, checkLines(firstLine, secondLine));
265 }
266
267 @Test
268 public void addLicenseToPerlWithoutHashBang() throws IOException {
269 String filename = "tmp.pl";
270 String firstLine = "#" + FIRST_LICENSE_LINE;
271
272 commonTestTemplate(filename, writer -> writer.write("print \"Hello world\"\n"), checkLines(firstLine));
273 }
274
275 @Test
276 public void addLicenseToPerlWithHashBang() throws IOException {
277 String filename = "tmp.pl";
278 final String firstLine = "#!/usr/bin/env perl";
279 String secondLine = "#" + FIRST_LICENSE_LINE;
280
281 commonTestTemplate(filename, writer -> {
282 writer.write(firstLine + "\n");
283 writer.write("print \"Hello world\"\n");
284 }, checkLines(firstLine, secondLine));
285 }
286
287 @Test
288 public void addLicenseToPerlModule() throws IOException {
289 String filename = "tmp.pm";
290 final String firstLine = "package API::TestAPI;";
291 final String secondLine = "";
292 final String thirdLine = "#" + FIRST_LICENSE_LINE;
293
294 commonTestTemplate(filename, writer -> {
295 writer.write(firstLine + "\n");
296 writer.write("print \"Hello world\"\n");
297 }, checkLines(firstLine, secondLine, thirdLine));
298 }
299
300 @Test
301 public void addLicenseToTclWithoutHashBang() throws IOException {
302 String filename = "tmp.tcl";
303 String firstLine = "#" + FIRST_LICENSE_LINE;
304
305 commonTestTemplate(filename, writer -> writer.write("puts \"Hello world\"\n"), checkLines(firstLine));
306 }
307
308 @Test
309 public void addLicenseToTclWithHashBang() throws IOException {
310 String filename = "tmp.tcl";
311 final String firstLine = "#!/usr/bin/env tcl";
312 String secondLine = "#" + FIRST_LICENSE_LINE;
313
314 commonTestTemplate(filename, writer -> {
315 writer.write(firstLine + "\n");
316 writer.write("puts \"Hello world\"\n");
317 }, checkLines(firstLine, secondLine));
318 }
319
320 @Test
321 public void addLicenseToPHP() throws IOException {
322 String filename = "tmp.php";
323 final String firstLine = "<?php";
324 final String secondLine = "";
325 final String thirdLine = "/*";
326
327 commonTestTemplate(filename, writer -> {
328 writer.write(firstLine + "\n");
329 writer.write("echo 'Hello World'\n");
330 writer.write("?>\n");
331 }, checkLines(firstLine, secondLine, thirdLine));
332 }
333
334 @Test
335 public void addLicenseToCSharp() throws IOException {
336 String filename = "tmp.cs";
337 String firstLine = "/*";
338
339 commonTestTemplate(filename, writer -> {
340 writer.write("namespace org.example {\n");
341 writer.write(" public class Foo {\n");
342 writer.write(" }\n");
343 writer.write("}\n");
344 }, checkLines(firstLine));
345 }
346
347 @Test
348 public void addLicenseToGroovy() throws IOException {
349 String filename = "tmp.groovy";
350 String firstLine = "/*";
351
352 commonTestTemplate(filename, writer -> {
353 writer.write("package org.example \n");
354 writer.write(" class Foo {\n");
355 writer.write(" }\n");
356 }, checkLines(firstLine));
357 }
358
359 @Test
360 public void addLicenseToCPlusPlus() throws IOException {
361 String filename = "tmp.cpp";
362 String firstLine = "/*";
363
364 commonTestTemplate(filename, writer -> {
365 writer.write("namespace org.example {\n");
366 writer.write(" public class Foo {\n");
367 writer.write(" }\n");
368 writer.write("}\n");
369 }, checkLines(firstLine));
370 }
371
372 @Test
373 public void addLicenseToGo() throws IOException {
374 String filename = "tmp.go";
375 final String firstLine = "package main";
376 String secondLine = "";
377 String thirdLine = "/*";
378
379 commonTestTemplate(filename, writer -> {
380 writer.write(firstLine + "\n");
381 writer.write("import (\n");
382 writer.write(" log\n");
383 writer.write(")\n");
384 }, checkLines(firstLine, secondLine, thirdLine));
385 }
386
387 @Test
388 public void fileWithBOM() throws IOException {
389 File f = Resources.getResourceFile("violations/FilterTest.cs");
390
391 ApacheV2LicenseAppender appender = new ApacheV2LicenseAppender();
392 appender.append(f);
393
394 try (BufferedReader r = new BufferedReader(new FileReader(f.getAbsolutePath() + ".new"))) {
395 assertEquals("/*", r.readLine());
396 String line = null;
397 while ((line = r.readLine()) != null) {
398 if (line.trim().isEmpty()) {
399 break;
400 }
401 }
402 assertEquals("#if NET_2_0", r.readLine());
403 }
404 }
405
406 @Test
407 public void addLicenseToVS2003solution() throws IOException {
408 String filename = "tmp.sln";
409 final String firstLine = "Microsoft Visual Studio Solution File," + " Format Version 8.0";
410 String secondLine = "#" + FIRST_LICENSE_LINE;
411
412 commonTestTemplate(filename, writer -> {
413 writer.write(firstLine + "\n");
414 writer.write(
415 "Project(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ConsoleApp\", \"Tutorials\\ConsoleApp\\cs\\src\\ConsoleApp.csproj\", \"{933969DF-2BC5-44E6-8B1A-400FC276A23F}\"\n");
416 writer.write("\tProjectSection(WebsiteProperties) = preProject\n");
417 writer.write("\t\tDebug.AspNetCompiler.Debug = \"True\"\n");
418 writer.write("\t\tRelease.AspNetCompiler.Debug = \"False\"\n");
419 writer.write("\tEndProjectSection\n");
420 writer.write("EndProject\n");
421 }, checkLines(firstLine, secondLine));
422 }
423
424 @Test
425 public void addLicenseToVS2005solution() throws IOException {
426 String filename = "tmp.sln";
427 final String firstLine = "Microsoft Visual Studio Solution File," + " Format Version 9.0";
428 final String secondLine = "# Visual Studio 2005";
429 final String thirdLine = "#" + FIRST_LICENSE_LINE;
430
431 commonTestTemplate(filename, writer -> {
432 writer.write(firstLine + "\n");
433 writer.write(secondLine + "\n");
434 writer.write(
435 "Project(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ConsoleApp\", \"Tutorials\\ConsoleApp\\cs\\src\\ConsoleApp.csproj\", \"{933969DF-2BC5-44E6-8B1A-400FC276A23F}\"\n");
436 writer.write("\tProjectSection(WebsiteProperties) = preProject\n");
437 writer.write("\t\tDebug.AspNetCompiler.Debug = \"True\"\n");
438 writer.write("\t\tRelease.AspNetCompiler.Debug = \"False\"\n");
439 writer.write("\tEndProjectSection\n");
440 writer.write("EndProject\n");
441 }, checkLines(firstLine, secondLine, thirdLine));
442 }
443
444 @Test
445 public void addLicenseToVS2010ExpressSolution() throws IOException {
446 String filename = "tmp.sln";
447 final String firstLine = "Microsoft Visual Studio Solution File, " + "Format Version 11.00";
448 final String secondLine = "# Visual C# Express 2010";
449 final String thirdLine = "#" + FIRST_LICENSE_LINE;
450
451 commonTestTemplate(filename, writer -> {
452 writer.write(firstLine + "\n");
453 writer.write(secondLine + "\n");
454 writer.write(
455 "Project(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Lucene.Net\", \"..\\..\\..\\src\\core\\Lucene.Net.csproj\", \"{5D4AD9BE-1FFB-41AB-9943-25737971BF57}\"\n");
456 writer.write("EndProject\n");
457 writer.write(
458 "Project(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Contrib.Highlighter\", \"..\\..\\..\\src\\contrib\\Highlighter\\Contrib.Highlighter.csproj\", \"{901D5415-383C-4AA6-A256-879558841BEA}\"\n");
459 writer.write("EndProject\n");
460 writer.write("Global\n");
461 writer.write("GlobalSection(SolutionConfigurationPlatforms) = preSolution\n");
462 writer.write("Debug|Any CPU = Debug|Any CPU\n");
463 writer.write("Release|Any CPU = Release|Any CPU\n");
464 writer.write("EndGlobalSection\n");
465 writer.write("GlobalSection(ProjectConfigurationPlatforms) = postSolution\n");
466 writer.write("{5D4AD9BE-1FFB-41AB-9943-25737971BF57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n");
467 writer.write("{5D4AD9BE-1FFB-41AB-9943-25737971BF57}.Debug|Any CPU.Build.0 = Debug|Any CPU\n");
468 writer.write("{5D4AD9BE-1FFB-41AB-9943-25737971BF57}.Release|Any CPU.ActiveCfg = Release|Any CPU\n");
469 writer.write("{5D4AD9BE-1FFB-41AB-9943-25737971BF57}.Release|Any CPU.Build.0 = Release|Any CPU\n");
470 writer.write("{901D5415-383C-4AA6-A256-879558841BEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n");
471 writer.write("{901D5415-383C-4AA6-A256-879558841BEA}.Debug|Any CPU.Build.0 = Debug|Any CPU\n");
472 writer.write("{901D5415-383C-4AA6-A256-879558841BEA}.Release|Any CPU.ActiveCfg = Release|Any CPU\n");
473 writer.write("{901D5415-383C-4AA6-A256-879558841BEA}.Release|Any CPU.Build.0 = Release|Any CPU\n");
474 writer.write("EndGlobalSection\n");
475 writer.write("GlobalSection(SolutionProperties) = preSolution\n");
476 writer.write("HideSolutionNode = FALSE\n");
477 writer.write("EndGlobalSection\n");
478 writer.write("EndGlobal \n");
479 }, checkLines(firstLine, secondLine, thirdLine));
480 }
481
482 @Test
483 public void addLicenseToVS2010SolutionWithBlankLine() throws IOException {
484 String filename = "tmp.sln";
485 final String firstLine = "";
486 final String secondLine = "Microsoft Visual Studio Solution File, " + "Format Version 11.00";
487 final String thirdLine = "# Visual C# Express 2010";
488 final String forthLine = "#" + FIRST_LICENSE_LINE;
489
490 commonTestTemplate(filename, writer -> {
491 writer.write(firstLine + "\n");
492 writer.write(secondLine + "\n");
493 writer.write(thirdLine + "\n");
494 writer.write(
495 "Project(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Lucene.Net\", \"..\\..\\..\\src\\core\\Lucene.Net.csproj\", \"{5D4AD9BE-1FFB-41AB-9943-25737971BF57}\"\n");
496 writer.write("EndProject\n");
497 writer.write(
498 "Project(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Contrib.Highlighter\", \"..\\..\\..\\src\\contrib\\Highlighter\\Contrib.Highlighter.csproj\", \"{901D5415-383C-4AA6-A256-879558841BEA}\"\n");
499 writer.write("EndProject\n");
500 writer.write("Global\n");
501 writer.write("GlobalSection(SolutionConfigurationPlatforms) = preSolution\n");
502 writer.write("Debug|Any CPU = Debug|Any CPU\n");
503 writer.write("Release|Any CPU = Release|Any CPU\n");
504 writer.write("EndGlobalSection\n");
505 writer.write("GlobalSection(ProjectConfigurationPlatforms) = postSolution\n");
506 writer.write("{5D4AD9BE-1FFB-41AB-9943-25737971BF57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n");
507 writer.write("{5D4AD9BE-1FFB-41AB-9943-25737971BF57}.Debug|Any CPU.Build.0 = Debug|Any CPU\n");
508 writer.write("{5D4AD9BE-1FFB-41AB-9943-25737971BF57}.Release|Any CPU.ActiveCfg = Release|Any CPU\n");
509 writer.write("{5D4AD9BE-1FFB-41AB-9943-25737971BF57}.Release|Any CPU.Build.0 = Release|Any CPU\n");
510 writer.write("{901D5415-383C-4AA6-A256-879558841BEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n");
511 writer.write("{901D5415-383C-4AA6-A256-879558841BEA}.Debug|Any CPU.Build.0 = Debug|Any CPU\n");
512 writer.write("{901D5415-383C-4AA6-A256-879558841BEA}.Release|Any CPU.ActiveCfg = Release|Any CPU\n");
513 writer.write("{901D5415-383C-4AA6-A256-879558841BEA}.Release|Any CPU.Build.0 = Release|Any CPU\n");
514 writer.write("EndGlobalSection\n");
515 writer.write("GlobalSection(SolutionProperties) = preSolution\n");
516 writer.write("HideSolutionNode = FALSE\n");
517 writer.write("EndGlobalSection\n");
518 writer.write("EndGlobal \n");
519 }, checkLines(firstLine, secondLine, thirdLine, forthLine));
520 }
521
522 @Test
523 public void addLicenseMarkdown() throws IOException {
524 String filename = "tmp.md";
525
526 commonTestTemplate(filename, writer -> {
527 writer.write("## This is the first header\n");
528 writer.write(" * this is a list entry\n");
529 writer.write(" * this is another list entry\n");
530 writer.write(" <!-- this is a comment line -->");
531 writer.write("## This is the second header\n");
532 }, r -> {
533 String line = r.readLine();
534 assertEquals("<!--", line, "First line is incorrect");
535 line = r.readLine();
536 });
537 }
538
539 @Test
540 public void testOverwrite() throws IOException {
541 String filename = "tmp.php";
542 final String firstLine = "<?php";
543
544 FileCreator phpCreator = (writer) -> {
545 writer.write(firstLine + "\n");
546 writer.write("echo 'Hello World'\n");
547 writer.write("?>\n");
548 };
549
550 String name = getTemporaryFileWithName(filename);
551 try {
552 createTestFile(name, phpCreator);
553
554 ApacheV2LicenseAppender appender = new ApacheV2LicenseAppender();
555 appender.setOverwrite(true);
556 appender.append(new File(name));
557
558 assertFalse(new File(name + ".new").exists());
559 assertTrue(new File(name).exists());
560
561 try (FileInputStream inputStream = new FileInputStream(name)) {
562 String everything = IOUtils.toString(inputStream, Charset.defaultCharset());
563 assertTrue(everything.contains("Licensed to the Apache Software Foundation "));
564 }
565 } finally {
566 new File(name + ".new").delete();
567 FileUtils.delete(new File(name));
568 }
569 }
570
571 @Test
572 public void testExecutePermsPreserved() throws IOException {
573 String filename = "tmp.php";
574 final String firstLine = "<?php";
575
576 FileCreator phpCreator = (writer) -> {
577 writer.write(firstLine + "\n");
578 writer.write("echo 'Hello World'\n");
579 writer.write("?>\n");
580 };
581
582 String name = getTemporaryFileWithName(filename);
583 try {
584 createTestFile(name, phpCreator);
585 assertTrue(new File(name).setExecutable(true), "Unable to set executable flag");
586
587 ApacheV2LicenseAppender appender = new ApacheV2LicenseAppender();
588 appender.setOverwrite(true);
589 appender.append(new File(name));
590
591 assertFalse(new File(name + ".new").exists());
592 assertTrue(new File(name).exists());
593
594 try (FileInputStream inputStream = new FileInputStream(name)) {
595 String everything = IOUtils.toString(inputStream, Charset.defaultCharset());
596 assertTrue(everything.contains("Licensed to the Apache Software Foundation "));
597 }
598 assertTrue(new File(name).canExecute());
599 } finally {
600 new File(name + ".new").delete();
601 FileUtils.delete(new File(name));
602 }
603 }
604 }