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