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