|
1 /* |
|
2 * Copyright (c) 2015, 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 import java.io.File; |
|
25 import java.io.InputStream; |
|
26 import java.io.Writer; |
|
27 import java.lang.annotation.Retention; |
|
28 import java.lang.annotation.RetentionPolicy; |
|
29 import java.lang.reflect.Method; |
|
30 import java.util.Arrays; |
|
31 import java.util.List; |
|
32 import com.sun.tools.javac.file.ZipFileIndexCache; |
|
33 import java.io.IOException; |
|
34 import java.nio.file.FileVisitResult; |
|
35 import java.nio.file.FileVisitor; |
|
36 import java.nio.file.Files; |
|
37 import java.nio.file.Path; |
|
38 import java.nio.file.Paths; |
|
39 import java.nio.file.attribute.BasicFileAttributes; |
|
40 import java.util.HashSet; |
|
41 import java.util.Set; |
|
42 import java.util.stream.Collectors; |
|
43 import java.util.stream.Stream; |
|
44 import symbolgenerator.CreateSymbols; |
|
45 import symbolgenerator.CreateSymbols.ClassDescription; |
|
46 import symbolgenerator.CreateSymbols.ClassList; |
|
47 import symbolgenerator.CreateSymbols.CtSymKind; |
|
48 import symbolgenerator.CreateSymbols.ExcludeIncludeList; |
|
49 import symbolgenerator.CreateSymbols.VersionDescription; |
|
50 |
|
51 public class CreateSymbolsTestImpl { |
|
52 |
|
53 static final String CREATE_SYMBOLS_NAME = "symbolgenerator.CreateSymbols"; |
|
54 |
|
55 public static void main(String... args) throws Exception { |
|
56 new CreateSymbolsTestImpl().doTest(); |
|
57 } |
|
58 |
|
59 void doTest() throws Exception { |
|
60 boolean testRun = false; |
|
61 for (Method m : CreateSymbolsTestImpl.class.getDeclaredMethods()) { |
|
62 if (!"testIncluded".equals(m.getName())) |
|
63 continue; |
|
64 if (m.isAnnotationPresent(Test.class)) { |
|
65 m.invoke(this); |
|
66 testRun = true; |
|
67 } |
|
68 } |
|
69 if (!testRun) { |
|
70 throw new IllegalStateException("No tests found."); |
|
71 } |
|
72 } |
|
73 |
|
74 @Test |
|
75 void testMethodRemoved() throws Exception { |
|
76 doTest("package t; public class T { public void m() { } }", |
|
77 "package t; public class T { }", |
|
78 "package t; public class Test { { T t = null; t.m(); } }", |
|
79 ToolBox.Expect.SUCCESS, |
|
80 ToolBox.Expect.FAIL); |
|
81 doTest("package t; public class T { public void b() { } public void m() { } public void a() { } }", |
|
82 "package t; public class T { public void b() { } public void a() { } }", |
|
83 "package t; public class Test { { T t = null; t.b(); t.a(); } }", |
|
84 ToolBox.Expect.SUCCESS, |
|
85 ToolBox.Expect.SUCCESS); |
|
86 //with additional attribute (need to properly skip the member): |
|
87 doTest("package t; public class T { public void m() throws IllegalStateException { } public void a() { } }", |
|
88 "package t; public class T { public void a() { } }", |
|
89 "package t; public class Test { { T t = null; t.a(); } }", |
|
90 ToolBox.Expect.SUCCESS, |
|
91 ToolBox.Expect.SUCCESS); |
|
92 } |
|
93 |
|
94 @Test |
|
95 void testMethodAdded() throws Exception { |
|
96 doTest("package t; public class T { }", |
|
97 "package t; public class T { public void m() { } }", |
|
98 "package t; public class Test { { T t = null; t.m(); } }", |
|
99 ToolBox.Expect.FAIL, |
|
100 ToolBox.Expect.SUCCESS); |
|
101 doTest("package t; public class T { public void b() { } public void a() { } }", |
|
102 "package t; public class T { public void b() { } public void m() { } public void a() { } }", |
|
103 "package t; public class Test { { T t = null; t.b(); t.a(); } }", |
|
104 ToolBox.Expect.SUCCESS, |
|
105 ToolBox.Expect.SUCCESS); |
|
106 } |
|
107 |
|
108 //verify fields added/modified/removed |
|
109 |
|
110 @Test |
|
111 void testClassAdded() throws Exception { |
|
112 doTest("class Dummy {}", |
|
113 "package t; public class T { }", |
|
114 "package t; public class Test { { T t = new T(); } }", |
|
115 ToolBox.Expect.FAIL, |
|
116 ToolBox.Expect.SUCCESS); |
|
117 } |
|
118 |
|
119 @Test |
|
120 void testClassModified() throws Exception { |
|
121 doTest("package t; public class T { public void m() { } }", |
|
122 "package t; public class T implements java.io.Serializable { public void m() { } }", |
|
123 "package t; public class Test { { java.io.Serializable t = new T(); } }", |
|
124 ToolBox.Expect.FAIL, |
|
125 ToolBox.Expect.SUCCESS); |
|
126 } |
|
127 |
|
128 @Test |
|
129 void testClassRemoved() throws Exception { |
|
130 doTest("package t; public class T { }", |
|
131 "class Dummy {}", |
|
132 "package t; public class Test { { T t = new T(); } }", |
|
133 ToolBox.Expect.SUCCESS, |
|
134 ToolBox.Expect.FAIL); |
|
135 } |
|
136 |
|
137 @Test |
|
138 void testInnerClassAttributes() throws Exception { |
|
139 doTest("package t; public class T { public static class Inner { } }", |
|
140 "package t; public class T { public static class Inner { } }", |
|
141 "package t; import t.T.Inner; public class Test { Inner i; }", |
|
142 ToolBox.Expect.SUCCESS, |
|
143 ToolBox.Expect.SUCCESS); |
|
144 } |
|
145 |
|
146 @Test |
|
147 void testConstantAdded() throws Exception { |
|
148 doTest("package t; public class T { }", |
|
149 "package t; public class T { public static final int A = 0; }", |
|
150 "package t; public class Test { void t(int i) { switch (i) { case T.A: break;} } }", |
|
151 ToolBox.Expect.FAIL, |
|
152 ToolBox.Expect.SUCCESS); |
|
153 } |
|
154 |
|
155 @Test |
|
156 void testAnnotationAttributeDefaultvalue() throws Exception { |
|
157 //TODO: this only verifies that there is *some* value, but we should also verify there is a specific value: |
|
158 doTest("package t; public @interface T { }", |
|
159 "package t;\n" + |
|
160 "public @interface T {\n" + |
|
161 " public boolean booleanValue() default true;\n" + |
|
162 " public byte byteValue() default 1;\n" + |
|
163 " public char charValue() default 2;\n" + |
|
164 " public short shortValue() default 3;\n" + |
|
165 " public int intValue() default 4;\n" + |
|
166 " public long longValue() default 5;\n" + |
|
167 " public float floatValue() default 6;\n" + |
|
168 " public double doubleValue() default 7;\n" + |
|
169 " public String stringValue() default \"8\";\n" + |
|
170 " public java.lang.annotation.RetentionPolicy enumValue() default java.lang.annotation.RetentionPolicy.RUNTIME;\n" + |
|
171 " public Class classValue() default Number.class;\n" + |
|
172 " public int[] arrayValue() default {1, 2};\n" + |
|
173 " public SuppressWarnings annotationValue() default @SuppressWarnings(\"cast\");\n" + |
|
174 "}\n", |
|
175 "package t; public @T class Test { }", |
|
176 ToolBox.Expect.SUCCESS, |
|
177 ToolBox.Expect.SUCCESS); |
|
178 } |
|
179 |
|
180 @Test |
|
181 void testConstantTest() throws Exception { |
|
182 //XXX: other constant types (String in particular) - see testStringConstant |
|
183 doPrintElementTest("package t; public class T { public static final int A = 1; }", |
|
184 "package t; public class T { public static final int A = 2; }", |
|
185 "t.T", |
|
186 "package t;\n\n" + |
|
187 "public class T {\n" + |
|
188 " public static final int A = 1;\n\n" + |
|
189 " public T();\n" + |
|
190 "}\n", |
|
191 "t.T", |
|
192 "package t;\n\n" + |
|
193 "public class T {\n" + |
|
194 " public static final int A = 2;\n\n" + |
|
195 " public T();\n" + |
|
196 "}\n"); |
|
197 doPrintElementTest("package t; public class T { public static final boolean A = false; }", |
|
198 "package t; public class T { public static final boolean A = true; }", |
|
199 "t.T", |
|
200 "package t;\n\n" + |
|
201 "public class T {\n" + |
|
202 " public static final boolean A = false;\n\n" + |
|
203 " public T();\n" + |
|
204 "}\n", |
|
205 "t.T", |
|
206 "package t;\n\n" + |
|
207 "public class T {\n" + |
|
208 " public static final boolean A = true;\n\n" + |
|
209 " public T();\n" + |
|
210 "}\n"); |
|
211 } |
|
212 |
|
213 @Test |
|
214 void testAnnotations() throws Exception { |
|
215 doPrintElementTest("package t;" + |
|
216 "import java.lang.annotation.*;" + |
|
217 "public @Visible @Invisible class T { }" + |
|
218 "@Retention(RetentionPolicy.RUNTIME) @interface Visible { }" + |
|
219 "@Retention(RetentionPolicy.CLASS) @interface Invisible { }", |
|
220 "package t;" + |
|
221 "import java.lang.annotation.*;" + |
|
222 "public @Visible @Invisible class T { }" + |
|
223 "@Retention(RetentionPolicy.RUNTIME) @interface Visible { }" + |
|
224 "@Retention(RetentionPolicy.CLASS) @interface Invisible { }", |
|
225 "t.T", |
|
226 "package t;\n\n" + |
|
227 "@t.Invisible\n" + |
|
228 "@t.Visible\n" + |
|
229 "public class T {\n\n" + |
|
230 " public T();\n" + |
|
231 "}\n", |
|
232 "t.Visible", |
|
233 "package t;\n\n" + |
|
234 "@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)\n" + |
|
235 "@interface Visible {\n" + |
|
236 "}\n"); |
|
237 doPrintElementTest("package t;" + |
|
238 "import java.lang.annotation.*;" + |
|
239 "import java.util.*;" + |
|
240 "public class T {" + |
|
241 " public void test(int h, @Invisible int i, @Visible List<String> j, int k) { }" + |
|
242 "}" + |
|
243 "@Retention(RetentionPolicy.RUNTIME) @interface Visible { }" + |
|
244 "@Retention(RetentionPolicy.CLASS) @interface Invisible { }", |
|
245 "package t;" + |
|
246 "import java.lang.annotation.*;" + |
|
247 "import java.util.*;" + |
|
248 "public class T {" + |
|
249 " public void test(int h, @Invisible int i, @Visible List<String> j, int k) { }" + |
|
250 "}" + |
|
251 "@Retention(RetentionPolicy.RUNTIME) @interface Visible { }" + |
|
252 "@Retention(RetentionPolicy.CLASS) @interface Invisible { }", |
|
253 "t.T", |
|
254 "package t;\n\n" + |
|
255 "public class T {\n\n" + |
|
256 " public T();\n\n" + |
|
257 " public void test(int arg0,\n" + |
|
258 " @t.Invisible int arg1,\n" + |
|
259 " @t.Visible java.util.List<java.lang.String> arg2,\n" + |
|
260 " int arg3);\n" + |
|
261 "}\n", |
|
262 "t.Visible", |
|
263 "package t;\n\n" + |
|
264 "@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)\n" + |
|
265 "@interface Visible {\n" + |
|
266 "}\n"); |
|
267 doPrintElementTest("package t;" + |
|
268 "import java.lang.annotation.*;" + |
|
269 "public class T {" + |
|
270 " public void test(@Ann(v=\"url\", dv=\"\\\"\\\"\") String str) { }" + |
|
271 "}" + |
|
272 "@Retention(RetentionPolicy.RUNTIME) @interface Ann {" + |
|
273 " public String v();" + |
|
274 " public String dv();" + |
|
275 "}", |
|
276 "package t;" + |
|
277 "public class T { }", |
|
278 "t.T", |
|
279 "package t;\n\n" + |
|
280 "public class T {\n\n" + |
|
281 " public T();\n\n" + |
|
282 " public void test(@t.Ann(dv=\"\\\"\\\"\", v=\"url\") java.lang.String arg0);\n" + |
|
283 "}\n", |
|
284 "t.T", |
|
285 "package t;\n\n" + |
|
286 "public class T {\n\n" + |
|
287 " public T();\n" + |
|
288 "}\n"); |
|
289 } |
|
290 |
|
291 @Test |
|
292 void testStringConstant() throws Exception { |
|
293 doTest("package t; public class T { public static final String C = \"\"; }", |
|
294 "package t; public class T { public static final String C = \"\"; }", |
|
295 "package t; public class Test { { System.err.println(T.C); } }", |
|
296 ToolBox.Expect.SUCCESS, |
|
297 ToolBox.Expect.SUCCESS); |
|
298 } |
|
299 |
|
300 @Test |
|
301 void testCopyProfileAnnotation() throws Exception { |
|
302 String oldProfileAnnotation = CreateSymbols.PROFILE_ANNOTATION; |
|
303 try { |
|
304 CreateSymbols.PROFILE_ANNOTATION = "Lt/Ann;"; |
|
305 doTestEquivalence("package t; public class T { public void t() {} } @interface Ann { }", |
|
306 "package t; public @Ann class T { public void t() {} } @interface Ann { }", |
|
307 "t.T"); |
|
308 } finally { |
|
309 CreateSymbols.PROFILE_ANNOTATION = oldProfileAnnotation; |
|
310 } |
|
311 } |
|
312 |
|
313 @Test |
|
314 void testParseAnnotation() throws Exception { |
|
315 CreateSymbols.parseAnnotations("@Lsun/Proprietary+Annotation;@Ljdk/Profile+Annotation;(value=I1)", new int[1]); |
|
316 CreateSymbols.parseAnnotations("@Ltest;(value={\"\"})", new int[1]); |
|
317 CreateSymbols.parseAnnotations("@Ljava/beans/ConstructorProperties;(value={\"path\"})", new int[1]); |
|
318 CreateSymbols.parseAnnotations("@Ljava/beans/ConstructorProperties;(value=I-2)", new int[1]); |
|
319 } |
|
320 |
|
321 @Test |
|
322 void testStringCharLiterals() throws Exception { |
|
323 doPrintElementTest("package t;" + |
|
324 "public class T {" + |
|
325 " public static final String STR = \"\\u0000\\u0001\\uffff\";" + |
|
326 " public static final String EMPTY = \"\";" + |
|
327 " public static final String AMP = \"&&<<>>''\";" + |
|
328 "}", |
|
329 "package t;" + |
|
330 " public class T {" + |
|
331 " public static final char c = '\\uffff';" + |
|
332 "}", |
|
333 "t.T", |
|
334 "package t;\n\n" + |
|
335 "public class T {\n" + |
|
336 " public static final java.lang.String STR = \"\\u0000\\u0001\\uffff\";\n" + |
|
337 " public static final java.lang.String EMPTY = \"\";\n" + |
|
338 " public static final java.lang.String AMP = \"&&<<>>'\\'\";\n\n" + |
|
339 " public T();\n" + |
|
340 "}\n", |
|
341 "t.T", |
|
342 "package t;\n\n" + |
|
343 "public class T {\n" + |
|
344 " public static final char c = '\\uffff';\n\n" + |
|
345 " public T();\n" + |
|
346 "}\n"); |
|
347 } |
|
348 |
|
349 @Test |
|
350 void testGenerification() throws Exception { |
|
351 doTest("package t; public class T { public class TT { public Object t() { return null; } } }", |
|
352 "package t; public class T<E> { public class TT { public E t() { return null; } } }", |
|
353 "package t; public class Test { { T.TT tt = null; tt.t(); } }", |
|
354 ToolBox.Expect.SUCCESS, |
|
355 ToolBox.Expect.SUCCESS); |
|
356 } |
|
357 |
|
358 int i = 0; |
|
359 |
|
360 void doTest(String code7, String code8, String testCode, ToolBox.Expect result7, ToolBox.Expect result8) throws Exception { |
|
361 ToolBox tb = new ToolBox(); |
|
362 Path classes = prepareVersionedCTSym(code7, code8); |
|
363 Path output = classes.getParent(); |
|
364 Path scratch = output.resolve("scratch"); |
|
365 |
|
366 Files.createDirectories(scratch); |
|
367 |
|
368 tb.new JavacTask() |
|
369 .sources(testCode) |
|
370 .options("-d", scratch.toAbsolutePath().toString(), "-classpath", computeClassPath(classes, "7"), "-XDuseOptimizedZip=false") |
|
371 .run(result7) |
|
372 .writeAll(); |
|
373 tb.new JavacTask() |
|
374 .sources(testCode) |
|
375 .options("-d", scratch.toAbsolutePath().toString(), "-classpath", computeClassPath(classes, "8"), "-XDuseOptimizedZip=false") |
|
376 .run(result8) |
|
377 .writeAll(); |
|
378 } |
|
379 |
|
380 private static String computeClassPath(Path classes, String version) throws IOException { |
|
381 try (Stream<Path> elements = Files.list(classes)) { |
|
382 return elements.map(el -> el.toAbsolutePath().toString()) |
|
383 .collect(Collectors.joining(File.pathSeparator)); |
|
384 } |
|
385 } |
|
386 |
|
387 void doPrintElementTest(String code7, String code8, String className7, String printed7, String className8, String printed8) throws Exception { |
|
388 ToolBox tb = new ToolBox(); |
|
389 Path classes = prepareVersionedCTSym(code7, code8); |
|
390 Path output = classes.getParent(); |
|
391 Path scratch = output.resolve("scratch"); |
|
392 |
|
393 Files.createDirectories(scratch); |
|
394 |
|
395 String out; |
|
396 out = tb.new JavacTask(ToolBox.Mode.CMDLINE) |
|
397 .options("-d", scratch.toAbsolutePath().toString(), "-classpath", computeClassPath(classes, "7"), "-XDuseOptimizedZip=false", "-Xprint", className7) |
|
398 .run(ToolBox.Expect.SUCCESS) |
|
399 .getOutput(ToolBox.OutputKind.STDOUT); |
|
400 if (!out.equals(printed7)) { |
|
401 throw new AssertionError("out=" + out + "; printed7=" + printed7); |
|
402 } |
|
403 out = tb.new JavacTask(ToolBox.Mode.CMDLINE) |
|
404 .options("-d", scratch.toAbsolutePath().toString(), "-classpath", computeClassPath(classes, "8"), "-XDuseOptimizedZip=false", "-Xprint", className8) |
|
405 .run(ToolBox.Expect.SUCCESS) |
|
406 .getOutput(ToolBox.OutputKind.STDOUT); |
|
407 if (!out.equals(printed8)) { |
|
408 throw new AssertionError("out=" + out + "; printed8=" + printed8); |
|
409 } |
|
410 } |
|
411 |
|
412 void doTestEquivalence(String code7, String code8, String testClass) throws Exception { |
|
413 Path classes = prepareVersionedCTSym(code7, code8); |
|
414 Path classfile = classes.resolve("78").resolve(testClass.replace('.', '/') + ".class"); |
|
415 |
|
416 if (!Files.isReadable(classfile)) { |
|
417 throw new AssertionError("Cannot find expected class."); |
|
418 } |
|
419 } |
|
420 |
|
421 @Test |
|
422 void testIncluded() throws Exception { |
|
423 doTestIncluded("package t;\n" + |
|
424 "public class Test extends PP1<PP2> implements PP3<PP4>, PP5<PP6> {\n" + |
|
425 " public PP7 m1(PP8 p) { return null;}\n" + |
|
426 " public PP9<PPA> m2(PPB<PPC> p) { return null;}\n" + |
|
427 " public PPD f1;\n" + |
|
428 " public PPE<PPF> f2;\n" + |
|
429 " public Test2 aux;\n" + |
|
430 "}\n" + |
|
431 "class Test2 extends PPG implements PPH, PPI {\n" + |
|
432 "}\n" + |
|
433 "class PP1<T> {}\n" + |
|
434 "class PP2 {}\n" + |
|
435 "interface PP3<T> {}\n" + |
|
436 "class PP4 {}\n" + |
|
437 "interface PP5<T> {}\n" + |
|
438 "class PP6 {}\n" + |
|
439 "class PP7 {}\n" + |
|
440 "class PP8 {}\n" + |
|
441 "class PP9<T> {}\n" + |
|
442 "class PPA {}\n" + |
|
443 "class PPB<T> {}\n" + |
|
444 "class PPC {}\n" + |
|
445 "class PPD {}\n" + |
|
446 "class PPE<T> {}\n" + |
|
447 "class PPF {}\n" + |
|
448 "class PPG {}\n" + |
|
449 "interface PPH {}\n" + |
|
450 "interface PPI {}\n", |
|
451 "t.Test", |
|
452 "t.Test2", |
|
453 "t.PP1", |
|
454 "t.PP2", |
|
455 "t.PP3", |
|
456 "t.PP4", |
|
457 "t.PP5", |
|
458 "t.PP6", |
|
459 "t.PP7", |
|
460 "t.PP8", |
|
461 "t.PP9", |
|
462 "t.PPA", |
|
463 "t.PPB", |
|
464 "t.PPC", |
|
465 "t.PPD", |
|
466 "t.PPE", |
|
467 "t.PPF", |
|
468 "t.PPG", |
|
469 "t.PPH", |
|
470 "t.PPI"); |
|
471 } |
|
472 |
|
473 void doTestIncluded(String code, String... includedClasses) throws Exception { |
|
474 boolean oldIncludeAll = includeAll; |
|
475 try { |
|
476 includeAll = false; |
|
477 Path classes = prepareVersionedCTSym(code, "package other; public class Other {}"); |
|
478 Path root = classes.resolve("7"); |
|
479 try (Stream<Path> classFiles = Files.walk(root)) { |
|
480 Set<String> names = classFiles.map(p -> root.relativize(p)) |
|
481 .map(p -> p.toString()) |
|
482 .map(n -> {System.err.println("n= " + n); return n;}) |
|
483 .filter(n -> n.endsWith(".class")) |
|
484 .map(n -> n.substring(0, n.lastIndexOf('.'))) |
|
485 .map(n -> n.replace(File.separator, ".")) |
|
486 .collect(Collectors.toSet()); |
|
487 |
|
488 if (!names.equals(new HashSet<>(Arrays.asList(includedClasses)))) |
|
489 throw new AssertionError("Expected classes not included: " + names); |
|
490 } |
|
491 } finally { |
|
492 includeAll = oldIncludeAll; |
|
493 } |
|
494 } |
|
495 |
|
496 Path prepareVersionedCTSym(String code7, String code8) throws Exception { |
|
497 String testClasses = System.getProperty("test.classes"); |
|
498 Path output = Paths.get(testClasses, "test-data" + i++); |
|
499 deleteRecursively(output); |
|
500 Files.createDirectories(output); |
|
501 Path ver7Jar = output.resolve("7.jar"); |
|
502 compileAndPack(output, ver7Jar, code7); |
|
503 Path ver8Jar = output.resolve("8.jar"); |
|
504 compileAndPack(output, ver8Jar, code8); |
|
505 |
|
506 ZipFileIndexCache.getSharedInstance().clearCache(); |
|
507 |
|
508 Path classes = output.resolve("classes"); |
|
509 |
|
510 Files.createDirectories(classes); |
|
511 |
|
512 Path ctSym = output.resolve("ct.sym"); |
|
513 |
|
514 deleteRecursively(ctSym); |
|
515 |
|
516 CreateSymbols.ALLOW_NON_EXISTING_CLASSES = true; |
|
517 CreateSymbols.EXTENSION = ".class"; |
|
518 |
|
519 testGenerate(ver7Jar, ver8Jar, ctSym, "8", classes.toAbsolutePath().toString()); |
|
520 |
|
521 return classes; |
|
522 } |
|
523 |
|
524 boolean includeAll = true; |
|
525 |
|
526 void testGenerate(Path jar7, Path jar8, Path descDest, String version, String classDest) throws IOException { |
|
527 deleteRecursively(descDest); |
|
528 |
|
529 List<VersionDescription> versions = |
|
530 Arrays.asList(new VersionDescription(jar7.toAbsolutePath().toString(), "7", null), |
|
531 new VersionDescription(jar8.toAbsolutePath().toString(), "8", "7")); |
|
532 |
|
533 ExcludeIncludeList acceptAll = new ExcludeIncludeList(null, null) { |
|
534 @Override public boolean accepts(String className) { |
|
535 return true; |
|
536 } |
|
537 }; |
|
538 new CreateSymbols() { |
|
539 @Override |
|
540 protected boolean includeEffectiveAccess(ClassList classes, ClassDescription clazz) { |
|
541 return includeAll ? true : super.includeEffectiveAccess(classes, clazz); |
|
542 } |
|
543 }.createBaseLine(versions, acceptAll, descDest, null); |
|
544 Path symbolsDesc = descDest.resolve("symbols"); |
|
545 try (Writer symbolsFile = Files.newBufferedWriter(symbolsDesc)) { |
|
546 symbolsFile.write("generate platforms 7:8"); |
|
547 symbolsFile.write(System.lineSeparator()); |
|
548 symbolsFile.write("platform version 7 files java.base-7.sym.txt"); |
|
549 symbolsFile.write(System.lineSeparator()); |
|
550 symbolsFile.write("platform version 8 base 7 files java.base-8.sym.txt"); |
|
551 symbolsFile.write(System.lineSeparator()); |
|
552 } |
|
553 new CreateSymbols().createSymbols(symbolsDesc.toAbsolutePath().toString(), classDest, CtSymKind.JOINED_VERSIONS); |
|
554 } |
|
555 |
|
556 void compileAndPack(Path output, Path outputFile, String... code) throws Exception { |
|
557 ToolBox tb = new ToolBox(); |
|
558 Path scratch = output.resolve("temp"); |
|
559 deleteRecursively(scratch); |
|
560 Files.createDirectories(scratch); |
|
561 System.err.println(Arrays.asList(code)); |
|
562 tb.new JavacTask().sources(code).options("-d", scratch.toAbsolutePath().toString()).run(ToolBox.Expect.SUCCESS); |
|
563 List<String> classFiles = collectClassFile(scratch); |
|
564 try (Writer out = Files.newBufferedWriter(outputFile)) { |
|
565 for (String classFile : classFiles) { |
|
566 try (InputStream in = Files.newInputStream(scratch.resolve(classFile))) { |
|
567 int read; |
|
568 |
|
569 while ((read = in.read()) != (-1)) { |
|
570 out.write(String.format("%02x", read)); |
|
571 } |
|
572 |
|
573 out.write("\n"); |
|
574 } |
|
575 } |
|
576 } |
|
577 } |
|
578 |
|
579 List<String> collectClassFile(Path root) throws IOException { |
|
580 try (Stream<Path> files = Files.walk(root)) { |
|
581 return files.filter(p -> Files.isRegularFile(p)) |
|
582 .filter(p -> p.getFileName().toString().endsWith(".class")) |
|
583 .map(p -> root.relativize(p).toString()) |
|
584 .collect(Collectors.toList()); |
|
585 } |
|
586 } |
|
587 |
|
588 void deleteRecursively(Path dir) throws IOException { |
|
589 Files.walkFileTree(dir, new FileVisitor<Path>() { |
|
590 @Override |
|
591 public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { |
|
592 return FileVisitResult.CONTINUE; |
|
593 } |
|
594 @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { |
|
595 Files.delete(file); |
|
596 return FileVisitResult.CONTINUE; |
|
597 } |
|
598 @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { |
|
599 return FileVisitResult.CONTINUE; |
|
600 } |
|
601 @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { |
|
602 Files.delete(dir); |
|
603 return FileVisitResult.CONTINUE; |
|
604 } |
|
605 }); |
|
606 } |
|
607 |
|
608 @Retention(RetentionPolicy.RUNTIME) |
|
609 @interface Test { |
|
610 } |
|
611 } |