1 /* 2 * Copyright (c) 2019, 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.foreign.annotations.NativeAddressof; 25 import java.foreign.annotations.NativeGetter; 26 import java.foreign.annotations.NativeHeader; 27 import java.foreign.annotations.NativeLocation; 28 import java.foreign.annotations.NativeSetter; 29 import java.foreign.annotations.NativeStruct; 30 import java.foreign.memory.Pointer; 31 import java.io.File; 32 import java.io.IOException; 33 import java.lang.reflect.Method; 34 import java.lang.reflect.Modifier; 35 import java.nio.file.Files; 36 import java.nio.file.Path; 37 import java.nio.file.Paths; 38 import java.util.Arrays; 39 import java.util.ArrayList; 40 import java.util.spi.ToolProvider; 41 import org.testng.annotations.Test; 42 import static org.testng.Assert.assertTrue; 43 44 /* 45 * @test 46 * @bug 8221154 8221228 8221336 8221419 8221443 8222274 8222288 47 * @summary jextract should generate java source files 48 * @library .. 49 * @run testng SrcGenTest 50 */ 51 public class SrcGenTest extends JextractToolRunner { 52 private static final ToolProvider JEXTRACT = ToolProvider.findFirst("jextract") 53 .orElseThrow(() -> 54 new RuntimeException("jextract tool not found") 55 ); 56 57 private static final ToolProvider JAVAC = ToolProvider.findFirst("javac") 58 .orElseThrow(() -> 59 new RuntimeException("javac tool not found") 60 ); 61 62 @Test 63 public void test() throws IOException { 64 Path inputDir = Paths.get(System.getProperty("test.src", ".")); 65 Path outputDir = Paths.get(System.getProperty("test.classes", ".")); 66 inputDir = inputDir.toAbsolutePath(); 67 outputDir = outputDir.toAbsolutePath(); 68 String pkgName = "test8221154"; 69 Path jarPath = outputDir.resolve(pkgName + ".jar"); 70 71 // run jextract with --src-dump-dir option 72 ArrayList<String> jextrOpts = new ArrayList<>(); 73 jextrOpts.add("-C-nostdinc"); 74 jextrOpts.add("-I"); 75 jextrOpts.add(inputDir.toString()); 76 jextrOpts.add("-o"); 77 jextrOpts.add(jarPath.toString()); 78 jextrOpts.add("--src-dump-dir"); 79 jextrOpts.add(outputDir.toString()); 80 jextrOpts.add("-t"); 81 jextrOpts.add(pkgName); 82 jextrOpts.add("-l"); 83 jextrOpts.add("srcgentest"); 84 jextrOpts.add(inputDir + File.separator + "srcgentest.h"); 85 86 int result = JEXTRACT.run(System.out, System.err, jextrOpts.toArray(String[]::new)); 87 if (result != 0) { 88 throw new RuntimeException(JEXTRACT.name() + " returns non-zero value"); 89 } 90 91 // delete .jar file generated by jextract 92 Files.delete(jarPath); 93 94 Path pkgDir = outputDir.resolve(pkgName); 95 96 String srcgentestIfaceName = headerInterfaceName("srcgentest.h"); 97 String srcgentestForwarderName = staticForwarderName("srcgentest.h"); 98 String dupnameIfaceName = headerInterfaceName("dupname.h"); 99 String dupnameDupnameNotName = structInterfaceName("dupname.h", "dupnameNot"); 100 String dupnameForwarderName = staticForwarderName("dupname.h"); 101 String srcgentestPointName = structInterfaceName("srcgentest.h", "Point"); 102 String srcgentestColorName = enumInterfaceName("srcgentest.h", "Color"); 103 String srcgentestForwarderEnumName = enumForwarderInterfaceName("srcgentest.h", "Color"); 104 105 // compile jextract generated java sources 106 ArrayList<String> javacOpts = new ArrayList<>(); 107 javacOpts.add("-d"); 108 javacOpts.add(outputDir.toString()); 109 javacOpts.add(outputDir.resolve("clang_support").resolve("stdbool_h.java").toString()); 110 javacOpts.add(pkgDir.resolve(srcgentestIfaceName + ".java").toString()); 111 javacOpts.add(pkgDir.resolve(srcgentestForwarderName + ".java").toString()); 112 javacOpts.add(pkgDir.resolve("sub").resolve(dupnameIfaceName + ".java").toString()); 113 javacOpts.add(pkgDir.resolve("sub").resolve(dupnameForwarderName + ".java").toString()); 114 result = JAVAC.run(System.out, System.err, javacOpts.toArray(String[]::new)); 115 if (result != 0) { 116 throw new RuntimeException(JAVAC.name() + " returns non-zero value"); 117 } 118 119 // sanity checks for .class file existence 120 assertTrue(Files.isRegularFile(outputDir.resolve("clang_support").resolve("stdbool_h.class"))); 121 assertTrue(Files.isRegularFile(pkgDir.resolve(srcgentestIfaceName + ".class"))); 122 assertTrue(Files.isRegularFile(pkgDir.resolve(srcgentestPointName + ".class"))); 123 assertTrue(Files.isRegularFile(pkgDir.resolve(srcgentestColorName + ".class"))); 124 assertTrue(Files.isRegularFile(pkgDir.resolve(srcgentestForwarderName + ".class"))); 125 assertTrue(Files.isRegularFile(pkgDir.resolve(srcgentestForwarderEnumName + ".class"))); 126 assertTrue(Files.isRegularFile(pkgDir.resolve("sub").resolve(dupnameForwarderName + ".class"))); 127 assertTrue(Files.isRegularFile(pkgDir.resolve("sub").resolve(dupnameIfaceName + ".class"))); 128 assertTrue(Files.isRegularFile(pkgDir.resolve("sub").resolve(dupnameDupnameNotName + ".class"))); 129 130 checkClasses(outputDir, pkgName); 131 } 132 133 private void checkClasses(Path outputDir, String pkgName) { 134 Loader loader = classLoader(outputDir); 135 checkSubdirClass(loader, pkgName); 136 checkHeaderClass(loader, pkgName); 137 checkForwarderClass(loader, pkgName); 138 } 139 140 private void checkSubdirClass(Loader loader, String pkgName) { 141 Class<?> dupname = loader.loadClass(pkgName + ".sub." + headerInterfaceName("dupname.h")); 142 assertTrue(dupname != null); 143 } 144 145 private void checkHeaderClass(Loader loader, String pkgName) { 146 Class<?> headerCls = loader.loadClass(pkgName + "." + headerInterfaceName("srcgentest.h")); 147 assertTrue(headerCls != null); 148 assertTrue(headerCls.getAnnotation(NativeHeader.class) != null); 149 150 // global 'num' getter, pointer getter 151 Method numGetter = findGlobalVariableGet(headerCls, "num"); 152 assertTrue(numGetter != null); 153 assertTrue(numGetter.getAnnotation(NativeGetter.class) != null); 154 assertTrue(numGetter.getAnnotation(NativeLocation.class) != null); 155 156 Method numPtrGetter = findGlobalVariablePointerGet(headerCls, "num"); 157 assertTrue(numPtrGetter != null); 158 assertTrue(numPtrGetter.getAnnotation(NativeAddressof.class) != null); 159 160 // global 'num' setter 161 Method numSetter = findGlobalVariableSet(headerCls, "num", int.class); 162 assertTrue(numSetter != null); 163 assertTrue(numSetter.getAnnotation(NativeSetter.class) != null); 164 165 // check "x_coord" method 166 Method xCoordMethod = findFirstMethod(headerCls, "x_coord"); 167 assertTrue(xCoordMethod.getReturnType() == int.class); 168 Class<?>[] xCoordParamTypes = xCoordMethod.getParameterTypes(); 169 assertTrue(xCoordParamTypes.length == 1); 170 assertTrue(xCoordParamTypes[0] == Pointer.class); 171 assertTrue(xCoordMethod.getAnnotation(NativeLocation.class) != null); 172 assertTrue(!Modifier.isStatic(xCoordMethod.getModifiers())); 173 174 // check "y_coord" method 175 Method yCoordMethod = findFirstMethod(headerCls, "y_coord"); 176 assertTrue(yCoordMethod.getReturnType() == int.class); 177 Class<?>[] yCoordParamTypes = yCoordMethod.getParameterTypes(); 178 assertTrue(yCoordParamTypes.length == 1); 179 assertTrue(yCoordParamTypes[0] == Pointer.class); 180 assertTrue(yCoordMethod.getAnnotation(NativeLocation.class) != null); 181 assertTrue(!Modifier.isStatic(yCoordMethod.getModifiers())); 182 183 // check "sum" method 184 Method sumMethod = findFirstMethod(headerCls, "sum"); 185 assertTrue(sumMethod.getReturnType() == int.class); 186 Class<?>[] sumParamTypes = sumMethod.getParameterTypes(); 187 assertTrue(sumParamTypes.length == 2); 188 assertTrue(sumParamTypes[0] == int.class); 189 assertTrue(sumParamTypes[1] == Object[].class); 190 assertTrue(sumMethod.getAnnotation(NativeLocation.class) != null); 191 assertTrue(!Modifier.isStatic(sumMethod.getModifiers())); 192 193 // struct Point 194 Class<?> pointCls = Arrays.stream(headerCls.getClasses()) 195 .filter(c -> c.getSimpleName().equals("Point")).findFirst().get(); 196 assertTrue(Modifier.isInterface(pointCls.getModifiers())); 197 assertTrue(pointCls.getAnnotation(NativeStruct.class) != null); 198 assertTrue(pointCls.getAnnotation(NativeLocation.class) != null); 199 200 // Point extends Struct 201 Class<?> pointSuper = pointCls.getInterfaces()[0]; 202 assertTrue(pointSuper.getName().equals("java.foreign.memory.Struct")); 203 204 // x, y getters, pointer getters 205 Method xGetter = findStructFieldGet(pointCls, "x"); 206 assertTrue(xGetter != null); 207 assertTrue(xGetter.getAnnotation(NativeGetter.class) != null); 208 assertTrue(xGetter.getAnnotation(NativeLocation.class) != null); 209 210 Method yGetter = findStructFieldGet(pointCls, "y"); 211 assertTrue(yGetter != null); 212 assertTrue(yGetter.getAnnotation(NativeGetter.class) != null); 213 assertTrue(yGetter.getAnnotation(NativeLocation.class) != null); 214 215 Method xPtrGetter = findStructFieldPointerGet(pointCls, "x"); 216 assertTrue(xPtrGetter != null); 217 assertTrue(xPtrGetter.getAnnotation(NativeAddressof.class) != null); 218 219 Method yPtrGetter = findStructFieldPointerGet(pointCls, "y"); 220 assertTrue(yPtrGetter != null); 221 assertTrue(yPtrGetter.getAnnotation(NativeAddressof.class) != null); 222 223 // x, y setters 224 Method xSetter = findStructFieldSet(pointCls, "x", int.class); 225 assertTrue(xSetter != null); 226 assertTrue(xSetter.getAnnotation(NativeSetter.class) != null); 227 228 Method ySetter = findStructFieldSet(pointCls, "y", int.class); 229 assertTrue(ySetter != null); 230 assertTrue(ySetter.getAnnotation(NativeSetter.class) != null); 231 } 232 233 private void checkForwarderClass(Loader loader, String pkgName) { 234 Class<?> forwarderCls = loader.loadClass(pkgName + "." + staticForwarderName("srcgentest.h")); 235 assertTrue(forwarderCls != null); 236 237 // check "sum" method 238 Method sumMethod = findFirstMethod(forwarderCls, "sum"); 239 assertTrue(sumMethod.getReturnType() == int.class); 240 Class<?>[] sumParamTypes = sumMethod.getParameterTypes(); 241 assertTrue(sumParamTypes.length == 2); 242 assertTrue(sumParamTypes[0] == int.class); 243 assertTrue(sumParamTypes[1] == Object[].class); 244 assertTrue(Modifier.isStatic(sumMethod.getModifiers())); 245 246 // check "x_coord" method 247 Method xCoordMethod = findFirstMethod(forwarderCls, "x_coord"); 248 assertTrue(xCoordMethod.getReturnType() == int.class); 249 Class<?>[] xCoordParamTypes = xCoordMethod.getParameterTypes(); 250 assertTrue(xCoordParamTypes.length == 1); 251 assertTrue(xCoordParamTypes[0] == Pointer.class); 252 assertTrue(Modifier.isStatic(xCoordMethod.getModifiers())); 253 254 // check "y_coord" method 255 Method yCoordMethod = findFirstMethod(forwarderCls, "y_coord"); 256 assertTrue(yCoordMethod.getReturnType() == int.class); 257 Class<?>[] yCoordParamTypes = yCoordMethod.getParameterTypes(); 258 assertTrue(yCoordParamTypes.length == 1); 259 assertTrue(yCoordParamTypes[0] == Pointer.class); 260 assertTrue(Modifier.isStatic(xCoordMethod.getModifiers())); 261 262 // global variable "num" getter 263 Method numGet = findGlobalVariableGet(forwarderCls, "num"); 264 assertTrue(numGet != null); 265 266 // anonymous enum fields 267 assertTrue(findField(forwarderCls, "R") != null); 268 assertTrue(findField(forwarderCls, "G") != null); 269 assertTrue(findField(forwarderCls, "B") != null); 270 271 // enum interface class 272 Class<?> colorCls = Arrays.stream(forwarderCls.getClasses()) 273 .filter(c -> c.getSimpleName().equals("Color")).findFirst().get(); 274 assertTrue(Modifier.isInterface(colorCls.getModifiers())); 275 checkIntField(colorCls, "RED", 0); 276 checkIntField(colorCls, "GREEN", 1); 277 checkIntField(colorCls, "BLUE", 2); 278 } 279 }