1 /* 2 * Copyright (c) 2013, 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 25 package org.graalvm.compiler.test; 26 27 import static org.graalvm.compiler.debug.DebugContext.DEFAULT_LOG_STREAM; 28 import static org.graalvm.compiler.debug.DebugContext.NO_DESCRIPTION; 29 30 import java.io.PrintStream; 31 import java.io.PrintWriter; 32 import java.lang.reflect.Field; 33 import java.lang.reflect.Method; 34 import java.util.ArrayList; 35 import java.util.Arrays; 36 import java.util.Collection; 37 import java.util.Collections; 38 import java.util.List; 39 import java.util.concurrent.TimeUnit; 40 41 import org.graalvm.compiler.debug.DebugContext; 42 import org.graalvm.compiler.debug.DebugDumpHandler; 43 import org.graalvm.compiler.debug.DebugHandlersFactory; 44 import org.graalvm.compiler.debug.GlobalMetrics; 45 import org.graalvm.compiler.options.OptionValues; 46 import org.graalvm.compiler.serviceprovider.GraalServices; 47 import org.junit.After; 48 import org.junit.Assert; 49 import org.junit.AssumptionViolatedException; 50 import org.junit.internal.ComparisonCriteria; 51 import org.junit.internal.ExactComparisonCriteria; 52 import org.junit.rules.DisableOnDebug; 53 import org.junit.rules.TestRule; 54 import org.junit.rules.Timeout; 55 56 import jdk.vm.ci.meta.ResolvedJavaMethod; 57 import sun.misc.Unsafe; 58 59 /** 60 * Base class that contains common utility methods and classes useful in unit tests. 61 */ 62 public class GraalTest { 63 64 public static final Unsafe UNSAFE; 65 static { 66 try { 67 Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); 68 theUnsafe.setAccessible(true); 69 UNSAFE = (Unsafe) theUnsafe.get(Unsafe.class); 70 } catch (Exception e) { 71 throw new RuntimeException("exception while trying to get Unsafe", e); 72 } 73 } 74 75 public static final boolean Java8OrEarlier = GraalServices.Java8OrEarlier; 76 public static final boolean Java11OrEarlier = GraalServices.Java11OrEarlier; 77 78 protected Method getMethod(String methodName) { 79 return getMethod(getClass(), methodName); 80 } 81 82 protected Method getMethod(Class<?> clazz, String methodName) { 83 Method found = null; 84 for (Method m : clazz.getMethods()) { 85 if (m.getName().equals(methodName)) { 86 Assert.assertNull(found); 87 found = m; 88 } 89 } 90 if (found == null) { 91 /* Now look for non-public methods (but this does not look in superclasses). */ 92 for (Method m : clazz.getDeclaredMethods()) { 93 if (m.getName().equals(methodName)) { 94 Assert.assertNull(found); 95 found = m; 96 } 97 } 98 } 99 if (found != null) { 100 return found; 101 } else { 102 throw new RuntimeException("method not found: " + methodName); 103 } 104 } 105 106 protected Method getMethod(Class<?> clazz, String methodName, Class<?>... parameterTypes) { 107 try { 108 return clazz.getMethod(methodName, parameterTypes); 109 } catch (NoSuchMethodException | SecurityException e) { 110 throw new RuntimeException("method not found: " + methodName + "" + Arrays.toString(parameterTypes)); 111 } 112 } 113 114 /** 115 * Compares two given objects for {@linkplain Assert#assertEquals(Object, Object) equality}. 116 * Does a deep copy equality comparison if {@code expected} is an array. 117 */ 118 protected void assertDeepEquals(Object expected, Object actual) { 119 assertDeepEquals(null, expected, actual); 120 } 121 122 /** 123 * Compares two given objects for {@linkplain Assert#assertEquals(Object, Object) equality}. 124 * Does a deep copy equality comparison if {@code expected} is an array. 125 * 126 * @param message the identifying message for the {@link AssertionError} 127 */ 128 protected void assertDeepEquals(String message, Object expected, Object actual) { 129 if (ulpsDelta() > 0) { 130 assertDeepEquals(message, expected, actual, ulpsDelta()); 131 } else { 132 assertDeepEquals(message, expected, actual, equalFloatsOrDoublesDelta()); 133 } 134 } 135 136 /** 137 * Compares two given values for equality, doing a recursive test if both values are arrays of 138 * the same type. 139 * 140 * @param message the identifying message for the {@link AssertionError} 141 * @param delta the maximum delta between two doubles or floats for which both numbers are still 142 * considered equal. 143 */ 144 protected void assertDeepEquals(String message, Object expected, Object actual, double delta) { 145 if (expected != null && actual != null) { 146 Class<?> expectedClass = expected.getClass(); 147 Class<?> actualClass = actual.getClass(); 148 if (expectedClass.isArray()) { 149 Assert.assertEquals(message, expectedClass, actual.getClass()); 150 if (expected instanceof int[]) { 151 Assert.assertArrayEquals(message, (int[]) expected, (int[]) actual); 152 } else if (expected instanceof byte[]) { 153 Assert.assertArrayEquals(message, (byte[]) expected, (byte[]) actual); 154 } else if (expected instanceof char[]) { 155 Assert.assertArrayEquals(message, (char[]) expected, (char[]) actual); 156 } else if (expected instanceof short[]) { 157 Assert.assertArrayEquals(message, (short[]) expected, (short[]) actual); 158 } else if (expected instanceof float[]) { 159 Assert.assertArrayEquals(message, (float[]) expected, (float[]) actual, (float) delta); 160 } else if (expected instanceof long[]) { 161 Assert.assertArrayEquals(message, (long[]) expected, (long[]) actual); 162 } else if (expected instanceof double[]) { 163 Assert.assertArrayEquals(message, (double[]) expected, (double[]) actual, delta); 164 } else if (expected instanceof boolean[]) { 165 new ExactComparisonCriteria().arrayEquals(message, expected, actual); 166 } else if (expected instanceof Object[]) { 167 new ComparisonCriteria() { 168 @Override 169 protected void assertElementsEqual(Object e, Object a) { 170 assertDeepEquals(message, e, a, delta); 171 } 172 }.arrayEquals(message, expected, actual); 173 } else { 174 Assert.fail((message == null ? "" : message) + "non-array value encountered: " + expected); 175 } 176 } else if (expectedClass.equals(double.class) && actualClass.equals(double.class)) { 177 Assert.assertEquals((double) expected, (double) actual, delta); 178 } else if (expectedClass.equals(float.class) && actualClass.equals(float.class)) { 179 Assert.assertEquals((float) expected, (float) actual, delta); 180 } else { 181 Assert.assertEquals(message, expected, actual); 182 } 183 } else { 184 Assert.assertEquals(message, expected, actual); 185 } 186 } 187 188 /** 189 * Compares two given values for equality, doing a recursive test if both values are arrays of 190 * the same type. Uses {@linkplain StrictMath#ulp(float) ULP}s for comparison of floats. 191 * 192 * @param message the identifying message for the {@link AssertionError} 193 * @param ulpsDelta the maximum allowed ulps difference between two doubles or floats for which 194 * both numbers are still considered equal. 195 */ 196 protected void assertDeepEquals(String message, Object expected, Object actual, int ulpsDelta) { 197 ComparisonCriteria doubleUlpsDeltaCriteria = new ComparisonCriteria() { 198 @Override 199 protected void assertElementsEqual(Object e, Object a) { 200 assertTrue(message, e instanceof Double && a instanceof Double); 201 // determine acceptable error based on whether it is a normal number or a NaN/Inf 202 double de = (Double) e; 203 double epsilon = (!Double.isNaN(de) && Double.isFinite(de) ? ulpsDelta * Math.ulp(de) : 0); 204 Assert.assertEquals(message, (Double) e, (Double) a, epsilon); 205 } 206 }; 207 208 ComparisonCriteria floatUlpsDeltaCriteria = new ComparisonCriteria() { 209 @Override 210 protected void assertElementsEqual(Object e, Object a) { 211 assertTrue(message, e instanceof Float && a instanceof Float); 212 // determine acceptable error based on whether it is a normal number or a NaN/Inf 213 float fe = (Float) e; 214 float epsilon = (!Float.isNaN(fe) && Float.isFinite(fe) ? ulpsDelta * Math.ulp(fe) : 0); 215 Assert.assertEquals(message, (Float) e, (Float) a, epsilon); 216 } 217 }; 218 219 if (expected != null && actual != null) { 220 Class<?> expectedClass = expected.getClass(); 221 Class<?> actualClass = actual.getClass(); 222 if (expectedClass.isArray()) { 223 Assert.assertEquals(message, expectedClass, actualClass); 224 if (expected instanceof double[] || expected instanceof Object[]) { 225 doubleUlpsDeltaCriteria.arrayEquals(message, expected, actual); 226 return; 227 } else if (expected instanceof float[] || expected instanceof Object[]) { 228 floatUlpsDeltaCriteria.arrayEquals(message, expected, actual); 229 return; 230 } 231 } else if (expectedClass.equals(double.class) && actualClass.equals(double.class)) { 232 doubleUlpsDeltaCriteria.arrayEquals(message, expected, actual); 233 return; 234 } else if (expectedClass.equals(float.class) && actualClass.equals(float.class)) { 235 floatUlpsDeltaCriteria.arrayEquals(message, expected, actual); 236 return; 237 } 238 } 239 // anything else just use the non-ulps version 240 assertDeepEquals(message, expected, actual, equalFloatsOrDoublesDelta()); 241 } 242 243 /** @see <a href="https://bugs.openjdk.java.net/browse/JDK-8076557">JDK-8076557</a> */ 244 protected static void assumeManagementLibraryIsLoadable() { 245 try { 246 /* Trigger loading of the management library using the bootstrap class loader. */ 247 GraalServices.getCurrentThreadAllocatedBytes(); 248 } catch (UnsatisfiedLinkError | NoClassDefFoundError | UnsupportedOperationException e) { 249 throw new AssumptionViolatedException("Management interface is unavailable: " + e); 250 } 251 } 252 253 /** 254 * Gets the value used by {@link #assertDeepEquals(Object, Object)} and 255 * {@link #assertDeepEquals(String, Object, Object)} for the maximum delta between two doubles 256 * or floats for which both numbers are still considered equal. 257 */ 258 protected double equalFloatsOrDoublesDelta() { 259 return 0.0D; 260 } 261 262 // unless overridden ulpsDelta is not used 263 protected int ulpsDelta() { 264 return 0; 265 } 266 267 @SuppressWarnings("serial") 268 public static class MultiCauseAssertionError extends AssertionError { 269 270 private Throwable[] causes; 271 272 public MultiCauseAssertionError(String message, Throwable... causes) { 273 super(message); 274 this.causes = causes; 275 } 276 277 @Override 278 public void printStackTrace(PrintStream out) { 279 super.printStackTrace(out); 280 int num = 0; 281 for (Throwable cause : causes) { 282 if (cause != null) { 283 out.print("cause " + (num++)); 284 cause.printStackTrace(out); 285 } 286 } 287 } 288 289 @Override 290 public void printStackTrace(PrintWriter out) { 291 super.printStackTrace(out); 292 int num = 0; 293 for (Throwable cause : causes) { 294 if (cause != null) { 295 out.print("cause " + (num++) + ": "); 296 cause.printStackTrace(out); 297 } 298 } 299 } 300 } 301 302 /* 303 * Overrides to the normal JUnit {@link Assert} routines that provide varargs style formatting 304 * and produce an exception stack trace with the assertion frames trimmed out. 305 */ 306 307 /** 308 * Fails a test with the given message. 309 * 310 * @param message the identifying message for the {@link AssertionError} (<code>null</code> 311 * okay) 312 * @see AssertionError 313 */ 314 public static void fail(String message, Object... objects) { 315 AssertionError e; 316 if (message == null) { 317 e = new AssertionError(); 318 } else { 319 e = new AssertionError(String.format(message, objects)); 320 } 321 // Trim the assert frames from the stack trace 322 StackTraceElement[] trace = e.getStackTrace(); 323 int start = 1; // Skip this frame 324 String thisClassName = GraalTest.class.getName(); 325 while (start < trace.length && trace[start].getClassName().equals(thisClassName) && (trace[start].getMethodName().equals("assertTrue") || trace[start].getMethodName().equals("assertFalse"))) { 326 start++; 327 } 328 e.setStackTrace(Arrays.copyOfRange(trace, start, trace.length)); 329 throw e; 330 } 331 332 /** 333 * Asserts that a condition is true. If it isn't it throws an {@link AssertionError} with the 334 * given message. 335 * 336 * @param message the identifying message for the {@link AssertionError} (<code>null</code> 337 * okay) 338 * @param condition condition to be checked 339 */ 340 public static void assertTrue(String message, boolean condition) { 341 assertTrue(condition, message); 342 } 343 344 /** 345 * Asserts that a condition is true. If it isn't it throws an {@link AssertionError} without a 346 * message. 347 * 348 * @param condition condition to be checked 349 */ 350 public static void assertTrue(boolean condition) { 351 assertTrue(condition, null); 352 } 353 354 /** 355 * Asserts that a condition is false. If it isn't it throws an {@link AssertionError} with the 356 * given message. 357 * 358 * @param message the identifying message for the {@link AssertionError} (<code>null</code> 359 * okay) 360 * @param condition condition to be checked 361 */ 362 public static void assertFalse(String message, boolean condition) { 363 assertTrue(!condition, message); 364 } 365 366 /** 367 * Asserts that a condition is false. If it isn't it throws an {@link AssertionError} without a 368 * message. 369 * 370 * @param condition condition to be checked 371 */ 372 public static void assertFalse(boolean condition) { 373 assertTrue(!condition, null); 374 } 375 376 /** 377 * Asserts that a condition is true. If it isn't it throws an {@link AssertionError} with the 378 * given message. 379 * 380 * @param condition condition to be checked 381 * @param message the identifying message for the {@link AssertionError} 382 * @param objects arguments to the format string 383 */ 384 public static void assertTrue(boolean condition, String message, Object... objects) { 385 if (!condition) { 386 fail(message, objects); 387 } 388 } 389 390 /** 391 * Asserts that a condition is false. If it isn't it throws an {@link AssertionError} with the 392 * given message produced by {@link String#format}. 393 * 394 * @param condition condition to be checked 395 * @param message the identifying message for the {@link AssertionError} 396 * @param objects arguments to the format string 397 */ 398 public static void assertFalse(boolean condition, String message, Object... objects) { 399 assertTrue(!condition, message, objects); 400 } 401 402 /** 403 * Gets the {@link DebugHandlersFactory}s available for a {@link DebugContext}. 404 */ 405 protected Collection<DebugHandlersFactory> getDebugHandlersFactories() { 406 return Collections.emptyList(); 407 } 408 409 /** 410 * Gets a {@link DebugContext} object corresponding to {@code options}, creating a new one if 411 * none currently exists. Debug contexts created by this method will have their 412 * {@link DebugDumpHandler}s closed in {@link #afterTest()}. 413 */ 414 protected DebugContext getDebugContext(OptionValues options) { 415 return getDebugContext(options, null, null); 416 } 417 418 /** 419 * Gets a {@link DebugContext} object corresponding to {@code options}, creating a new one if 420 * none currently exists. Debug contexts created by this method will have their 421 * {@link DebugDumpHandler}s closed in {@link #afterTest()}. 422 * 423 * @param options currently active options 424 * @param id identification of the compilation or {@code null} 425 * @param method method to use for a proper description of the context or {@code null} 426 * @return configured context for compilation 427 */ 428 protected DebugContext getDebugContext(OptionValues options, String id, ResolvedJavaMethod method) { 429 List<DebugContext> cached = cachedDebugs.get(); 430 if (cached == null) { 431 cached = new ArrayList<>(); 432 cachedDebugs.set(cached); 433 } 434 for (DebugContext debug : cached) { 435 if (debug.getOptions() == options) { 436 return debug; 437 } 438 } 439 final DebugContext.Description descr; 440 if (method == null) { 441 descr = NO_DESCRIPTION; 442 } else { 443 descr = new DebugContext.Description(method, id == null ? method.getName() : id); 444 } 445 DebugContext debug = DebugContext.create(options, descr, globalMetrics, DEFAULT_LOG_STREAM, getDebugHandlersFactories()); 446 cached.add(debug); 447 return debug; 448 } 449 450 private static final GlobalMetrics globalMetrics = new GlobalMetrics(); 451 452 static { 453 Runtime.getRuntime().addShutdownHook(new Thread("GlobalMetricsPrinter") { 454 @Override 455 public void run() { 456 globalMetrics.print(new OptionValues(OptionValues.newOptionMap())); 457 } 458 }); 459 } 460 private final ThreadLocal<List<DebugContext>> cachedDebugs = new ThreadLocal<>(); 461 462 @After 463 public void afterTest() { 464 List<DebugContext> cached = cachedDebugs.get(); 465 if (cached != null) { 466 for (DebugContext debug : cached) { 467 debug.close(); 468 debug.closeDumpHandlers(true); 469 } 470 } 471 } 472 473 private static final double TIMEOUT_SCALING_FACTOR = Double.parseDouble(System.getProperty("graaltest.timeout.factor", "1.0")); 474 475 /** 476 * Creates a {@link TestRule} that applies a given timeout. 477 * 478 * A test harness can scale {@code length} with a factor specified by the 479 * {@code graaltest.timeout.factor} system property. 480 */ 481 public static TestRule createTimeout(long length, TimeUnit timeUnit) { 482 Timeout timeout = new Timeout((long) (length * TIMEOUT_SCALING_FACTOR), timeUnit); 483 try { 484 return new DisableOnDebug(timeout); 485 } catch (LinkageError ex) { 486 return timeout; 487 } 488 } 489 490 /** 491 * @see #createTimeout 492 */ 493 public static TestRule createTimeoutSeconds(int seconds) { 494 return createTimeout(seconds, TimeUnit.SECONDS); 495 } 496 497 /** 498 * @see #createTimeout 499 */ 500 public static TestRule createTimeoutMillis(long milliseconds) { 501 return createTimeout(milliseconds, TimeUnit.MILLISECONDS); 502 } 503 }