diff -r 97bec6ab1227 -r b14d9583ce92 test/tools/javac/nativeHeaders/NativeHeaderTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/nativeHeaders/NativeHeaderTest.java Tue Mar 13 15:43:40 2012 -0700 @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 7150368 + * @summary javac should include basic ability to generate native headers + */ + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; + +import com.sun.source.util.JavacTask; +import com.sun.tools.javac.api.JavacTool; + +public class NativeHeaderTest { + public static void main(String... args) throws Exception { + new NativeHeaderTest().run(); + } + + /** How to invoke javac. */ + enum RunKind { + /** Use the command line entry point. */ + CMD, + /** Use the JavaCompiler API. */ + API + }; + + /** Which classes for which to generate headers. */ + enum GenKind { + /** Just classes with native methods or the marker annotation. */ + SIMPLE, + /** All appropriate classes within the top level class. */ + FULL + }; + + // ---------- Test cases, invoked reflectively via run. ---------- + + @Test + void simpleTest(RunKind rk, GenKind gk) throws Exception { + List files = new ArrayList(); + files.add(createFile("p/C.java", + "class C { native void m(); }")); + + Set expect = createSet("C.h"); + + test(rk, gk, files, expect); + } + + @Test + void nestedClassTest(RunKind rk, GenKind gk) throws Exception { + List files = new ArrayList(); + files.add(createFile("p/C.java", + "class C { static class Inner { native void m(); } }")); + + Set expect = createSet("C_Inner.h"); + if (gk == GenKind.FULL) expect.add("C.h"); + + test(rk, gk, files, expect); + } + + @Test + void localClassTest(RunKind rk, GenKind gk) throws Exception { + List files = new ArrayList(); + files.add(createFile("p/C.java", + "class C { native void m(); void m2() { class Local { } } }")); + + Set expect = createSet("C.h"); + + test(rk, gk, files, expect); + } + + @Test + void syntheticClassTest(RunKind rk, GenKind gk) throws Exception { + List files = new ArrayList(); + files.add(createFile("p/C.java", + "class C {\n" + + " private C() { }\n" + + " class Inner extends C { native void m(); }\n" + + "}")); + + Set expect = createSet("C_Inner.h"); + if (gk == GenKind.FULL) expect.add("C.h"); + + test(rk, gk, files, expect); + + // double check the synthetic class was generated + checkEqual("generatedClasses", + createSet("C.class", "C$1.class", "C$Inner.class"), + createSet(classesDir.list())); + } + + @Test + void annoTest(RunKind rk, GenKind gk) throws Exception { + List files = new ArrayList(); + files.add(createFile("p/C.java", + "@javax.tools.annotation.GenerateNativeHeader class C { }")); + + Set expect = createSet("C.h"); + + test(rk, gk, files, expect); + } + + @Test + void annoNestedClassTest(RunKind rk, GenKind gk) throws Exception { + List files = new ArrayList(); + files.add(createFile("p/C.java", + "class C { @javax.tools.annotation.GenerateNativeHeader class Inner { } }")); + + Set expect = createSet("C_Inner.h"); + if (gk == GenKind.FULL) expect.add("C.h"); + + test(rk, gk, files, expect); + } + + /** + * The worker method for each test case. + * Compile the files and verify that exactly the expected set of header files + * is generated. + */ + void test(RunKind rk, GenKind gk, List files, Set expect) throws Exception { + List args = new ArrayList(); + if (gk == GenKind.FULL) + args.add("-XDjavah:full"); + + switch (rk) { + case CMD: + args.add("-d"); + args.add(classesDir.getPath()); + args.add("-h"); + args.add(headersDir.getPath()); + for (File f: files) + args.add(f.getPath()); + int rc = com.sun.tools.javac.Main.compile(args.toArray(new String[args.size()])); + if (rc != 0) + throw new Exception("compilation failed, rc=" + rc); + break; + + case API: + fm.setLocation(StandardLocation.SOURCE_PATH, Arrays.asList(srcDir)); + fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(classesDir)); + fm.setLocation(StandardLocation.NATIVE_HEADER_OUTPUT, Arrays.asList(headersDir)); + JavacTask task = javac.getTask(null, fm, null, args, null, + fm.getJavaFileObjectsFromFiles(files)); + if (!task.call()) + throw new Exception("compilation failed"); + break; + } + + Set found = createSet(headersDir.list()); + checkEqual("header files", expect, found); + } + + /** Marker annotation for test cases. */ + @Retention(RetentionPolicy.RUNTIME) + @interface Test { } + + /** Combo test to run all test cases in all modes. */ + void run() throws Exception { + javac = JavacTool.create(); + fm = javac.getStandardFileManager(null, null, null); + + for (RunKind rk: RunKind.values()) { + for (GenKind gk: GenKind.values()) { + for (Method m: getClass().getDeclaredMethods()) { + Annotation a = m.getAnnotation(Test.class); + if (a != null) { + init(rk, gk, m.getName()); + try { + m.invoke(this, new Object[] { rk, gk }); + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + throw (cause instanceof Exception) ? ((Exception) cause) : e; + } + System.err.println(); + } + } + } + } + System.err.println(testCount + " tests" + ((errorCount == 0) ? "" : ", " + errorCount + " errors")); + if (errorCount > 0) + throw new Exception(errorCount + " errors found"); + } + + /** + * Init directories for a test case. + */ + void init(RunKind rk, GenKind gk, String name) throws IOException { + System.err.println("Test " + rk + " " + gk + " " + name); + testCount++; + + testDir = new File(rk.toString().toLowerCase() + "_" + gk.toString().toLowerCase() + "-" + name); + srcDir = new File(testDir, "src"); + srcDir.mkdirs(); + classesDir = new File(testDir, "classes"); + classesDir.mkdirs(); + headersDir = new File(testDir, "headers"); + headersDir.mkdirs(); + } + + /** Create a source file with given body text. */ + File createFile(String path, final String body) throws IOException { + File f = new File(srcDir, path); + f.getParentFile().mkdirs(); + try (FileWriter out = new FileWriter(f)) { + out.write(body); + } + return f; + } + + /** Convenience method to create a set of items. */ + Set createSet(T... items) { + return new HashSet(Arrays.asList(items)); + } + + /** Convenience method to check two values are equal, and report an error if not. */ + void checkEqual(String label, T expect, T found) { + if ((found == null) ? (expect == null) : found.equals(expect)) + return; + System.err.println("Error: mismatch"); + System.err.println(" expected: " + expect); + System.err.println(" found: " + found); + errorCount++; + } + + // Shared across API test cases + JavacTool javac; + StandardJavaFileManager fm; + + // Directories set up by init + File testDir; + File srcDir; + File classesDir; + File headersDir; + + // Statistics + int testCount; + int errorCount; +} +