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