test/tools/sjavac/SJavac.java

changeset 1504
22e417cdddee
child 1516
8943b4213f59
equal deleted inserted replaced
1503:2d2b2be57c78 1504:22e417cdddee
1 /*
2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 /*
25 * @test
26 * @summary Test all aspects of sjavac.
27 *
28 * @bug 8004658
29 * @summary Add internal smart javac wrapper to solve JEP 139
30 *
31 * @run main SJavac
32 */
33
34 import java.util.*;
35 import java.io.*;
36 import java.net.*;
37 import java.nio.file.*;
38 import java.nio.file.attribute.*;
39 import java.nio.charset.*;
40
41 import com.sun.tools.sjavac.Main;
42
43 public
44 class SJavac {
45
46 public static void main(String... args) throws Exception {
47 URL url = SJavac.class.getClassLoader().getResource("com/sun/tools/sjavac/Main.class");
48 if (url == null) {
49 // No sjavac in the classpath.
50 System.out.println("pass by default");
51 return;
52 }
53
54 SJavac s = new SJavac();
55 s.test();
56 }
57
58 FileSystem defaultfs = FileSystems.getDefault();
59
60 // Where to put generated sources that will
61 // test aspects of sjavac, ie JTWork/scratch/gensrc
62 Path gensrc;
63 // More gensrc dirs are used to test merging of serveral source roots.
64 Path gensrc2;
65 Path gensrc3;
66
67 // Where to put compiled classes.
68 Path bin;
69 // Where to put c-header files.
70 Path headers;
71
72 // The sjavac compiler.
73 Main main = new Main();
74
75 // Remember the previous bin and headers state here.
76 Map<String,Long> previous_bin_state;
77 Map<String,Long> previous_headers_state;
78
79 public void test() throws Exception {
80 gensrc = defaultfs.getPath("gensrc");
81 gensrc2 = defaultfs.getPath("gensrc2");
82 gensrc3 = defaultfs.getPath("gensrc3");
83 bin = defaultfs.getPath("bin");
84 headers = defaultfs.getPath("headers");
85
86 Files.createDirectory(gensrc);
87 Files.createDirectory(gensrc2);
88 Files.createDirectory(gensrc3);
89 Files.createDirectory(bin);
90 Files.createDirectory(headers);
91
92 initialCompile();
93 incrementalCompileNoChanges();
94 incrementalCompileDroppingClasses();
95 incrementalCompileWithChange();
96 incrementalCompileDropAllNatives();
97 incrementalCompileAddNative();
98 incrementalCompileChangeNative();
99 compileWithOverrideSource();
100 compileWithInvisibleSources();
101 compileCircularSources();
102
103 delete(gensrc);
104 delete(gensrc2);
105 delete(gensrc3);
106 delete(bin);
107 }
108
109 void initialCompile() throws Exception {
110 System.out.println("\nInitial compile of gensrc.");
111 System.out.println("----------------------------");
112 populate(gensrc,
113 "alfa/AINT.java",
114 "package alfa; public interface AINT { void aint(); }",
115
116 "alfa/A.java",
117 "package alfa; public class A implements AINT { "+
118 "public final static int DEFINITION = 17; public void aint() { } }",
119
120 "alfa/AA.java",
121 "package alfa;"+
122 "// A package private class, not contributing to the public api.\n"+
123 "class AA {"+
124 " // A properly nested static inner class.\n"+
125 " static class AAA { }\n"+
126 " // A properly nested inner class.\n"+
127 " class AAAA { }\n"+
128 " Runnable foo() {\n"+
129 " // A proper anonymous class.\n"+
130 " return new Runnable() { public void run() { } };\n"+
131 " }\n"+
132 " AAA aaa;\n"+
133 " AAAA aaaa;\n"+
134 " AAAAA aaaaa;\n"+
135 "}\n"+
136 "class AAAAA {\n"+
137 " // A bad auxiliary class, but no one is referencing it\n"+
138 " // from outside of this source file, therefore it is ok.\n"+
139 "}\n",
140
141 "beta/BINT.java",
142 "package beta;public interface BINT { void foo(); }",
143
144 "beta/B.java",
145 "package beta; import alfa.A; public class B {"+
146 "private int b() { return A.DEFINITION; } native void foo(); }");
147
148 compile("gensrc", "-d", "bin", "-h", "headers", "-j", "1",
149 "--server:portfile=testserver,background=false", "--log=debug");
150 previous_bin_state = collectState(bin);
151 previous_headers_state = collectState(headers);
152 }
153
154 void incrementalCompileNoChanges() throws Exception {
155 System.out.println("\nTesting that no change in sources implies no change in binaries.");
156 System.out.println("------------------------------------------------------------------");
157 compile("gensrc", "-d", "bin", "-h", "headers", "-j", "1",
158 "--server:portfile=testserver,background=false", "--log=debug");
159 Map<String,Long> new_bin_state = collectState(bin);
160 verifyEqual(new_bin_state, previous_bin_state);
161 Map<String,Long> new_headers_state = collectState(headers);
162 verifyEqual(previous_headers_state, new_headers_state);
163 }
164
165 void incrementalCompileDroppingClasses() throws Exception {
166 System.out.println("\nTesting that deleting AA.java deletes all");
167 System.out.println("generated inner class as well as AA.class");
168 System.out.println("-----------------------------------------");
169 removeFrom(gensrc, "alfa/AA.java");
170 compile("gensrc", "-d", "bin", "-h", "headers", "-j", "1",
171 "--server:portfile=testserver,background=false", "--log=debug");
172 Map<String,Long> new_bin_state = collectState(bin);
173 verifyThatFilesHaveBeenRemoved(previous_bin_state, new_bin_state,
174 "bin/alfa/AA$1.class",
175 "bin/alfa/AA$AAAA.class",
176 "bin/alfa/AA$AAA.class",
177 "bin/alfa/AAAAA.class",
178 "bin/alfa/AA.class");
179
180 previous_bin_state = new_bin_state;
181 Map<String,Long> new_headers_state = collectState(headers);
182 verifyEqual(previous_headers_state, new_headers_state);
183 }
184
185 void incrementalCompileWithChange() throws Exception {
186 System.out.println("\nNow update the A.java file with a new timestamps and");
187 System.out.println("new final static definition. This should trigger a recompile,");
188 System.out.println("not only of alfa, but also beta.");
189 System.out.println("But check that the generated native header was not updated!");
190 System.out.println("Since we did not modify the native api of B.");
191 System.out.println("-------------------------------------------------------------");
192
193 populate(gensrc,"alfa/A.java",
194 "package alfa; public class A implements AINT { "+
195 "public final static int DEFINITION = 18; public void aint() { } private void foo() { } }");
196
197 compile("gensrc", "-d", "bin", "-h", "headers", "-j", "1",
198 "--server:portfile=testserver,background=false", "--log=debug");
199 Map<String,Long> new_bin_state = collectState(bin);
200
201 verifyNewerFiles(previous_bin_state, new_bin_state,
202 "bin/alfa/A.class",
203 "bin/alfa/AINT.class",
204 "bin/beta/B.class",
205 "bin/beta/BINT.class",
206 "bin/javac_state");
207 previous_bin_state = new_bin_state;
208
209 Map<String,Long> new_headers_state = collectState(headers);
210 verifyEqual(new_headers_state, previous_headers_state);
211 }
212
213 void incrementalCompileDropAllNatives() throws Exception {
214 System.out.println("\nNow update the B.java file with one less native method,");
215 System.out.println("ie it has no longer any methods!");
216 System.out.println("Verify that beta_B.h is removed!");
217 System.out.println("---------------------------------------------------------");
218
219 populate(gensrc,"beta/B.java",
220 "package beta; import alfa.A; public class B {"+
221 "private int b() { return A.DEFINITION; } }");
222
223 compile("gensrc", "-d", "bin", "-h", "headers", "-j", "1",
224 "--server:portfile=testserver,background=false", "--log=debug");
225 Map<String,Long> new_bin_state = collectState(bin);
226 verifyNewerFiles(previous_bin_state, new_bin_state,
227 "bin/beta/B.class",
228 "bin/beta/BINT.class",
229 "bin/javac_state");
230 previous_bin_state = new_bin_state;
231
232 Map<String,Long> new_headers_state = collectState(headers);
233 verifyThatFilesHaveBeenRemoved(previous_headers_state, new_headers_state,
234 "headers/beta_B.h");
235 previous_headers_state = new_headers_state;
236 }
237
238 void incrementalCompileAddNative() throws Exception {
239 System.out.println("\nNow update the B.java file with a final static annotated with @Native.");
240 System.out.println("Verify that beta_B.h is added again!");
241 System.out.println("------------------------------------------------------------------------");
242
243 populate(gensrc,"beta/B.java",
244 "package beta; import alfa.A; public class B {"+
245 "private int b() { return A.DEFINITION; } "+
246 "@java.lang.annotation.Native final static int alfa = 42; }");
247
248 compile("gensrc", "-d", "bin", "-h", "headers", "-j", "1",
249 "--server:portfile=testserver,background=false", "--log=debug");
250 Map<String,Long> new_bin_state = collectState(bin);
251 verifyNewerFiles(previous_bin_state, new_bin_state,
252 "bin/beta/B.class",
253 "bin/beta/BINT.class",
254 "bin/javac_state");
255 previous_bin_state = new_bin_state;
256
257 Map<String,Long> new_headers_state = collectState(headers);
258 verifyThatFilesHaveBeenAdded(previous_headers_state, new_headers_state,
259 "headers/beta_B.h");
260 previous_headers_state = new_headers_state;
261 }
262
263 void incrementalCompileChangeNative() throws Exception {
264 System.out.println("\nNow update the B.java file with a new value for the final static"+
265 " annotated with @Native.");
266 System.out.println("Verify that beta_B.h is rewritten again!");
267 System.out.println("-------------------------------------------------------------------");
268
269 populate(gensrc,"beta/B.java",
270 "package beta; import alfa.A; public class B {"+
271 "private int b() { return A.DEFINITION; } "+
272 "@java.lang.annotation.Native final static int alfa = 43; }");
273
274 compile("gensrc", "-d", "bin", "-h", "headers", "-j", "1",
275 "--server:portfile=testserver,background=false", "--log=debug");
276 Map<String,Long> new_bin_state = collectState(bin);
277 verifyNewerFiles(previous_bin_state, new_bin_state,
278 "bin/beta/B.class",
279 "bin/beta/BINT.class",
280 "bin/javac_state");
281 previous_bin_state = new_bin_state;
282
283 Map<String,Long> new_headers_state = collectState(headers);
284 verifyNewerFiles(previous_headers_state, new_headers_state,
285 "headers/beta_B.h");
286 previous_headers_state = new_headers_state;
287 }
288
289 void compileWithOverrideSource() throws Exception {
290 System.out.println("\nNow verify that we can override sources to be compiled.");
291 System.out.println("Compile gensrc and gensrc2. However do not compile broken beta.B in gensrc,");
292 System.out.println("only compile ok beta.B in gensrc2.");
293 System.out.println("---------------------------------------------------------------------------");
294
295 delete(gensrc);
296 delete(gensrc2);
297 delete(bin);
298 previous_bin_state = collectState(bin);
299
300 populate(gensrc,"alfa/A.java",
301 "package alfa; import beta.B; import gamma.C; public class A { B b; C c; }",
302 "beta/B.java",
303 "package beta; public class B { broken",
304 "gamma/C.java",
305 "package gamma; public class C { }");
306
307 populate(gensrc2,
308 "beta/B.java",
309 "package beta; public class B { }");
310
311 compile("-x", "beta", "gensrc", "gensrc2", "-d", "bin", "-h", "headers", "-j", "1",
312 "--server:portfile=testserver,background=false");
313 Map<String,Long> new_bin_state = collectState(bin);
314 verifyThatFilesHaveBeenAdded(previous_bin_state, new_bin_state,
315 "bin/alfa/A.class",
316 "bin/beta/B.class",
317 "bin/gamma/C.class",
318 "bin/javac_state");
319
320 System.out.println("----- Compile with exluded beta went well!");
321 delete(bin);
322 compileExpectFailure("gensrc", "gensrc2", "-d", "bin", "-h", "headers", "-j", "1",
323 "--server:portfile=testserver,background=false");
324
325 System.out.println("----- Compile without exluded beta failed, as expected! Good!");
326 delete(bin);
327 }
328
329 void compileWithInvisibleSources() throws Exception {
330 System.out.println("\nNow verify that we can make sources invisible to linking (sourcepath).");
331 System.out.println("Compile gensrc and link against gensrc2 and gensrc3, however");
332 System.out.println("gensrc2 contains broken code in beta.B, thus we must exclude that package");
333 System.out.println("fortunately gensrc3 contains a proper beta.B.");
334 System.out.println("------------------------------------------------------------------------");
335
336 // Start with a fresh gensrcs and bin.
337 delete(gensrc);
338 delete(gensrc2);
339 delete(gensrc3);
340 delete(bin);
341 previous_bin_state = collectState(bin);
342
343 populate(gensrc,"alfa/A.java",
344 "package alfa; import beta.B; import gamma.C; public class A { B b; C c; }");
345 populate(gensrc2,"beta/B.java",
346 "package beta; public class B { broken",
347 "gamma/C.java",
348 "package gamma; public class C { }");
349 populate(gensrc3, "beta/B.java",
350 "package beta; public class B { }");
351
352 compile("gensrc", "-x", "beta", "-sourcepath", "gensrc2",
353 "-sourcepath", "gensrc3", "-d", "bin", "-h", "headers", "-j", "1",
354 "--server:portfile=testserver,background=false");
355
356 System.out.println("The first compile went well!");
357 Map<String,Long> new_bin_state = collectState(bin);
358 verifyThatFilesHaveBeenAdded(previous_bin_state, new_bin_state,
359 "bin/alfa/A.class",
360 "bin/javac_state");
361
362 System.out.println("----- Compile with exluded beta went well!");
363 delete(bin);
364 compileExpectFailure("gensrc", "-sourcepath", "gensrc2", "-sourcepath", "gensrc3",
365 "-d", "bin", "-h", "headers", "-j", "1",
366 "--server:portfile=testserver,background=false");
367
368 System.out.println("----- Compile without exluded beta failed, as expected! Good!");
369 delete(bin);
370 }
371
372 void compileCircularSources() throws Exception {
373 System.out.println("\nNow verify that circular sources split on multiple cores can be compiled.");
374 System.out.println("---------------------------------------------------------------------------");
375
376 // Start with a fresh gensrcs and bin.
377 delete(gensrc);
378 delete(gensrc2);
379 delete(gensrc3);
380 delete(bin);
381 previous_bin_state = collectState(bin);
382
383 populate(gensrc,"alfa/A.java",
384 "package alfa; public class A { beta.B b; }",
385 "beta/B.java",
386 "package beta; public class B { gamma.C c; }",
387 "gamma/C.java",
388 "package gamma; public class C { alfa.A a; }");
389
390 compile("gensrc", "-d", "bin", "-h", "headers", "-j", "3",
391 "--server:portfile=testserver,background=false","--log=debug");
392 Map<String,Long> new_bin_state = collectState(bin);
393 verifyThatFilesHaveBeenAdded(previous_bin_state, new_bin_state,
394 "bin/alfa/A.class",
395 "bin/beta/B.class",
396 "bin/gamma/C.class",
397 "bin/javac_state");
398 delete(bin);
399 }
400
401 void removeFrom(Path dir, String... args) throws IOException {
402 for (String filename : args) {
403 Path p = dir.resolve(filename);
404 Files.delete(p);
405 }
406 }
407
408 void populate(Path src, String... args) throws IOException {
409 if (!Files.exists(src)) {
410 Files.createDirectory(src);
411 }
412 String[] a = args;
413 for (int i = 0; i<a.length; i+=2) {
414 String filename = a[i];
415 String content = a[i+1];
416 Path p = src.resolve(filename);
417 Files.createDirectories(p.getParent());
418 PrintWriter out = new PrintWriter(Files.newBufferedWriter(p,
419 Charset.defaultCharset()));
420 out.println(content);
421 out.close();
422 }
423 }
424
425 void delete(Path root) throws IOException {
426 if (!Files.exists(root)) return;
427 Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
428 @Override
429 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException
430 {
431 Files.delete(file);
432 return FileVisitResult.CONTINUE;
433 }
434
435 @Override
436 public FileVisitResult postVisitDirectory(Path dir, IOException e) throws IOException
437 {
438 if (e == null) {
439 if (!dir.equals(root)) Files.delete(dir);
440 return FileVisitResult.CONTINUE;
441 } else {
442 // directory iteration failed
443 throw e;
444 }
445 }
446 });
447 }
448
449 void compile(String... args) throws Exception {
450 int rc = main.go(args, System.out, System.err);
451 if (rc != 0) throw new Exception("Error during compile!");
452
453 // Wait a second, to get around the (temporary) problem with
454 // second resolution in the Java file api. But do not do this
455 // on windows where the timestamps work.
456 long in_a_sec = System.currentTimeMillis()+1000;
457 while (in_a_sec > System.currentTimeMillis()) {
458 try {
459 Thread.sleep(1000);
460 } catch (InterruptedException e) {
461 }
462 }
463 }
464
465 void compileExpectFailure(String... args) throws Exception {
466 int rc = main.go(args, System.out, System.err);
467 if (rc == 0) throw new Exception("Expected error during compile! Did not fail!");
468 }
469
470 Map<String,Long> collectState(Path dir) throws IOException
471 {
472 final Map<String,Long> files = new HashMap<>();
473 Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
474 @Override
475 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
476 throws IOException
477 {
478 files.put(file.toString(),new Long(Files.getLastModifiedTime(file).toMillis()));
479 return FileVisitResult.CONTINUE;
480 }
481 });
482 return files;
483 }
484
485 void verifyThatFilesHaveBeenRemoved(Map<String,Long> from,
486 Map<String,Long> to,
487 String... args) throws Exception {
488
489 Set<String> froms = from.keySet();
490 Set<String> tos = to.keySet();
491
492 if (froms.equals(tos)) {
493 throw new Exception("Expected new state to have fewer files than previous state!");
494 }
495
496 for (String t : tos) {
497 if (!froms.contains(t)) {
498 throw new Exception("Expected "+t+" to exist in previous state!");
499 }
500 }
501
502 for (String f : args) {
503 f = f.replace("/", File.separator);
504 if (!froms.contains(f)) {
505 throw new Exception("Expected "+f+" to exist in previous state!");
506 }
507 if (tos.contains(f)) {
508 throw new Exception("Expected "+f+" to have been removed from the new state!");
509 }
510 }
511
512 if (froms.size() - args.length != tos.size()) {
513 throw new Exception("There are more removed files than the expected list!");
514 }
515 }
516
517 void verifyThatFilesHaveBeenAdded(Map<String,Long> from,
518 Map<String,Long> to,
519 String... args) throws Exception {
520
521 Set<String> froms = from.keySet();
522 Set<String> tos = to.keySet();
523
524 if (froms.equals(tos)) {
525 throw new Exception("Expected new state to have more files than previous state!");
526 }
527
528 for (String t : froms) {
529 if (!tos.contains(t)) {
530 throw new Exception("Expected "+t+" to exist in new state!");
531 }
532 }
533
534 for (String f : args) {
535 f = f.replace("/", File.separator);
536 if (!tos.contains(f)) {
537 throw new Exception("Expected "+f+" to have been added to new state!");
538 }
539 if (froms.contains(f)) {
540 throw new Exception("Expected "+f+" to not exist in previous state!");
541 }
542 }
543
544 if (froms.size() + args.length != tos.size()) {
545 throw new Exception("There are more added files than the expected list!");
546 }
547 }
548
549 void verifyNewerFiles(Map<String,Long> from,
550 Map<String,Long> to,
551 String... args) throws Exception {
552 if (!from.keySet().equals(to.keySet())) {
553 throw new Exception("Expected the set of files to be identical!");
554 }
555 Set<String> files = new HashSet<String>();
556 for (String s : args) {
557 files.add(s.replace("/", File.separator));
558 }
559 for (String fn : from.keySet()) {
560 long f = from.get(fn);
561 long t = to.get(fn);
562 if (files.contains(fn)) {
563 if (t <= f) {
564 throw new Exception("Expected "+fn+" to have a more recent timestamp!");
565 }
566 } else {
567 if (t != f) {
568 throw new Exception("Expected "+fn+" to have the same timestamp!");
569 }
570 }
571 }
572 }
573
574 String print(Map<String,Long> m) {
575 StringBuilder b = new StringBuilder();
576 Set<String> keys = m.keySet();
577 for (String k : keys) {
578 b.append(k+" "+m.get(k)+"\n");
579 }
580 return b.toString();
581 }
582
583 void verifyEqual(Map<String,Long> from, Map<String,Long> to) throws Exception {
584 if (!from.equals(to)) {
585 System.out.println("FROM---"+print(from));
586 System.out.println("TO-----"+print(to));
587 throw new Exception("The dir should not differ! But it does!");
588 }
589 }
590 }

mercurial