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