1 /* 2 * Copyright (c) 2018, 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.IOException; 25 import java.io.PrintWriter; 26 import java.io.StringWriter; 27 import java.lang.reflect.Field; 28 import java.lang.reflect.Method; 29 import java.net.URL; 30 import java.net.URLClassLoader; 31 import java.nio.file.FileVisitResult; 32 import java.nio.file.Files; 33 import java.nio.file.Path; 34 import java.nio.file.Paths; 35 import java.nio.file.SimpleFileVisitor; 36 import java.nio.file.attribute.BasicFileAttributes; 37 import java.util.Objects; 38 import java.util.spi.ToolProvider; 39 40 import static org.testng.Assert.assertEquals; 41 import static org.testng.Assert.assertNotEquals; 42 import static org.testng.Assert.assertNotNull; 43 import static org.testng.Assert.assertTrue; 44 import static org.testng.Assert.fail; 45 46 public class JextractToolRunner { 47 // utilities to avoid hard-coding generated class, interface names everywhere 48 public static String headerInterfaceName(String filename) { 49 int ext = filename.lastIndexOf('.'); 50 return ext != -1 ? filename.substring(0, ext) : filename; 51 } 52 53 public static String staticForwarderName(String filename) { 54 return headerInterfaceName(filename) + "_h"; 55 } 56 57 // struct, enum and callback interfaces are nested types of header interface 58 public static String structInterfaceName(String headerFileName, String structName) { 59 return headerInterfaceName(headerFileName) + "$" + structName; 60 } 61 62 public static String enumInterfaceName(String headerFileName, String enumName) { 63 return headerInterfaceName(headerFileName) + "$" + enumName; 64 } 65 66 public static String callbackInterfaceName(String headerFileName, String fiName) { 67 return headerInterfaceName(headerFileName) + "$" + fiName; 68 } 69 70 public static String enumForwarderInterfaceName(String headerFileName, String enumName) { 71 return staticForwarderName(headerFileName) + "$" + enumName; 72 } 73 74 private static final ToolProvider JEXTRACT_TOOL = ToolProvider.findFirst("jextract") 75 .orElseThrow(() -> 76 new RuntimeException("jextract tool not found") 77 ); 78 79 private final Path inputDir; 80 private final Path outputDir; 81 82 protected JextractToolRunner() { 83 this(null, null); 84 } 85 86 protected JextractToolRunner(Path input, Path output) { 87 inputDir = (input != null) ? input : 88 Paths.get(System.getProperty("test.src", ".")); 89 outputDir = (output != null) ? output : 90 Paths.get(System.getProperty("test.classes", ".")); 91 } 92 93 protected Path getInputFilePath(String fileName) { 94 return inputDir.resolve(fileName).toAbsolutePath(); 95 } 96 97 protected Path getOutputFilePath(String fileName) { 98 return outputDir.resolve(fileName).toAbsolutePath(); 99 } 100 101 protected static class JextractResult { 102 private int exitCode; 103 private String output; 104 105 JextractResult(int exitCode, String output) { 106 this.exitCode = exitCode; 107 this.output = output; 108 } 109 110 protected JextractResult checkSuccess() { 111 assertEquals(exitCode, 0, "Sucess excepted, failed: " + exitCode); 112 return this; 113 } 114 115 protected JextractResult checkFailure() { 116 assertNotEquals(exitCode, 0, "Failure excepted, succeeded!"); 117 return this; 118 } 119 120 protected JextractResult checkContainsOutput(String expected) { 121 Objects.requireNonNull(expected); 122 assertTrue(output.contains(expected), "Output does not contain string: " + expected); 123 return this; 124 } 125 126 protected JextractResult checkMatchesOutput(String regex) { 127 Objects.requireNonNull(regex); 128 assertTrue(output.trim().matches(regex), "Output does not match regex: " + regex); 129 return this; 130 } 131 } 132 133 protected static JextractResult run(String... options) { 134 StringWriter writer = new StringWriter(); 135 PrintWriter pw = new PrintWriter(writer); 136 String[] args = new String[options.length + 1]; 137 System.arraycopy(options, 0, args, 1, options.length); 138 args[0] = "-C-nostdinc"; 139 int result = JEXTRACT_TOOL.run(pw, pw, options); 140 String output = writer.toString(); 141 System.err.println(output); 142 return new JextractResult(result, output); 143 } 144 145 protected static void deleteFile(Path path) { 146 try { 147 Files.deleteIfExists(path); 148 } catch (IOException ioExp) { 149 throw new RuntimeException(ioExp); 150 } 151 } 152 153 protected static void deleteDir(Path path) { 154 try { 155 Files.walkFileTree(path, new SimpleFileVisitor<>() { 156 @Override 157 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { 158 deleteFile(file); 159 return FileVisitResult.CONTINUE; 160 } 161 162 @Override 163 public FileVisitResult postVisitDirectory(Path dir, IOException exc) { 164 deleteFile(dir); 165 return FileVisitResult.CONTINUE; 166 } 167 }); 168 } catch (IOException ioExp) { 169 throw new RuntimeException(ioExp); 170 } 171 } 172 173 protected static Loader classLoader(Path... paths) { 174 try { 175 URL[] urls = new URL[paths.length]; 176 for (int i = 0; i < paths.length; i++) { 177 urls[i] = paths[i].toUri().toURL(); 178 } 179 URLClassLoader ucl = new URLClassLoader(urls, null); 180 return new Loader(ucl); 181 } catch (RuntimeException re) { 182 throw re; 183 } catch (Exception e) { 184 throw new RuntimeException(e); 185 } 186 } 187 188 protected static Field findField(Class<?> cls, String name) { 189 try { 190 return cls.getField(name); 191 } catch (Exception e) { 192 System.err.println(e); 193 return null; 194 } 195 } 196 197 protected static Method findMethod(Class<?> cls, String name, Class<?>... argTypes) { 198 try { 199 return cls.getMethod(name, argTypes); 200 } catch (Exception e) { 201 System.err.println(e); 202 return null; 203 } 204 } 205 206 protected static Method findStructFieldGet(Class<?> cls, String name) { 207 return findMethod(cls, name + "$get"); 208 } 209 210 protected static Method findStructFieldSet(Class<?> cls, String name, Class<?> type) { 211 return findMethod(cls, name + "$set", type); 212 } 213 214 protected static Method findStructFieldPointerGet(Class<?> cls, String name) { 215 return findMethod(cls, name + "$ptr"); 216 } 217 218 protected static Method findGlobalVariableGet(Class<?> cls, String name) { 219 return findMethod(cls, name + "$get"); 220 } 221 222 protected static Method findGlobalVariableSet(Class<?> cls, String name, Class<?> type) { 223 return findMethod(cls, name + "$set", type); 224 } 225 226 protected static Method findGlobalVariablePointerGet(Class<?> cls, String name) { 227 return findMethod(cls, name + "$ptr"); 228 } 229 230 protected static Method findEnumConstGet(Class<?> cls, String name) { 231 return findMethod(cls, name); 232 } 233 234 protected static Method findFirstMethod(Class<?> cls, String name) { 235 try { 236 for (Method m : cls.getMethods()) { 237 if (name.equals(m.getName())) { 238 return m; 239 } 240 } 241 return null; 242 } catch (Exception e) { 243 System.err.println(e); 244 return null; 245 } 246 } 247 248 protected Field checkIntField(Class<?> cls, String name, int value) { 249 Field field = findField(cls, name); 250 assertNotNull(field); 251 assertEquals(field.getType(), int.class); 252 try { 253 assertEquals((int)field.get(null), value); 254 } catch (Exception exp) { 255 System.err.println(exp); 256 assertTrue(false, "should not reach here"); 257 } 258 return field; 259 } 260 261 protected Class<?> findClass(Class<?>[] clz, String name) { 262 for (Class<?> cls: clz) { 263 if (cls.getSimpleName().equals(name)) { 264 return cls; 265 } 266 } 267 return null; 268 } 269 270 protected Method checkMethod(Class<?> cls, String name, Class<?> returnType, Class<?>... args) { 271 try { 272 Method m = cls.getDeclaredMethod(name, args); 273 assertTrue(m.getReturnType() == returnType); 274 return m; 275 } catch (NoSuchMethodException nsme) { 276 fail("Expect method " + name); 277 } 278 return null; 279 } 280 281 protected static class Loader implements AutoCloseable { 282 283 private final URLClassLoader loader; 284 285 public Loader(URLClassLoader loader) { 286 this.loader = loader; 287 } 288 289 public Class<?> loadClass(String className) { 290 try { 291 return Class.forName(className, false, loader); 292 } catch (ClassNotFoundException e) { 293 // return null so caller can check if class loading 294 // was successful with assertNotNull/assertNull 295 return null; 296 } 297 } 298 299 @Override 300 public void close() { 301 try { 302 loader.close(); 303 } catch (IOException e) { 304 throw new RuntimeException(e); 305 } 306 } 307 } 308 }