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