001/*
002 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.test;
024
025import java.io.*;
026import java.lang.reflect.*;
027import java.util.*;
028
029import org.junit.*;
030import org.junit.internal.*;
031
032/**
033 * Base class that contains common utility methods and classes useful in unit tests.
034 */
035public class GraalTest {
036
037    protected Method getMethod(String methodName) {
038        return getMethod(getClass(), methodName);
039    }
040
041    protected Method getMethod(Class<?> clazz, String methodName) {
042        Method found = null;
043        for (Method m : clazz.getMethods()) {
044            if (m.getName().equals(methodName)) {
045                Assert.assertNull(found);
046                found = m;
047            }
048        }
049        if (found == null) {
050            /* Now look for non-public methods (but this does not look in superclasses). */
051            for (Method m : clazz.getDeclaredMethods()) {
052                if (m.getName().equals(methodName)) {
053                    Assert.assertNull(found);
054                    found = m;
055                }
056            }
057        }
058        if (found != null) {
059            return found;
060        } else {
061            throw new RuntimeException("method not found: " + methodName);
062        }
063    }
064
065    protected Method getMethod(Class<?> clazz, String methodName, Class<?>[] parameterTypes) {
066        try {
067            return clazz.getMethod(methodName, parameterTypes);
068        } catch (NoSuchMethodException | SecurityException e) {
069            throw new RuntimeException("method not found: " + methodName + "" + Arrays.toString(parameterTypes));
070        }
071    }
072
073    /**
074     * Compares two given objects for {@linkplain Assert#assertEquals(Object, Object) equality}.
075     * Does a deep copy equality comparison if {@code expected} is an array.
076     */
077    protected void assertDeepEquals(Object expected, Object actual) {
078        assertDeepEquals(null, expected, actual);
079    }
080
081    /**
082     * Compares two given objects for {@linkplain Assert#assertEquals(Object, Object) equality}.
083     * Does a deep copy equality comparison if {@code expected} is an array.
084     *
085     * @param message the identifying message for the {@link AssertionError}
086     */
087    protected void assertDeepEquals(String message, Object expected, Object actual) {
088        if (ulpsDelta() > 0) {
089            assertDeepEquals(message, expected, actual, ulpsDelta());
090        } else {
091            assertDeepEquals(message, expected, actual, equalFloatsOrDoublesDelta());
092        }
093    }
094
095    /**
096     * Compares two given values for equality, doing a recursive test if both values are arrays of
097     * the same type.
098     *
099     * @param message the identifying message for the {@link AssertionError}
100     * @param delta the maximum delta between two doubles or floats for which both numbers are still
101     *            considered equal.
102     */
103    protected void assertDeepEquals(String message, Object expected, Object actual, double delta) {
104        if (expected != null && actual != null) {
105            Class<?> expectedClass = expected.getClass();
106            Class<?> actualClass = actual.getClass();
107            if (expectedClass.isArray()) {
108                Assert.assertTrue(message, expected != null);
109                Assert.assertTrue(message, actual != null);
110                Assert.assertEquals(message, expectedClass, actual.getClass());
111                if (expected instanceof int[]) {
112                    Assert.assertArrayEquals(message, (int[]) expected, (int[]) actual);
113                } else if (expected instanceof byte[]) {
114                    Assert.assertArrayEquals(message, (byte[]) expected, (byte[]) actual);
115                } else if (expected instanceof char[]) {
116                    Assert.assertArrayEquals(message, (char[]) expected, (char[]) actual);
117                } else if (expected instanceof short[]) {
118                    Assert.assertArrayEquals(message, (short[]) expected, (short[]) actual);
119                } else if (expected instanceof float[]) {
120                    Assert.assertArrayEquals(message, (float[]) expected, (float[]) actual, (float) delta);
121                } else if (expected instanceof long[]) {
122                    Assert.assertArrayEquals(message, (long[]) expected, (long[]) actual);
123                } else if (expected instanceof double[]) {
124                    Assert.assertArrayEquals(message, (double[]) expected, (double[]) actual, delta);
125                } else if (expected instanceof boolean[]) {
126                    new ExactComparisonCriteria().arrayEquals(message, expected, actual);
127                } else if (expected instanceof Object[]) {
128                    new ComparisonCriteria() {
129                        @Override
130                        protected void assertElementsEqual(Object e, Object a) {
131                            assertDeepEquals(message, e, a, delta);
132                        }
133                    }.arrayEquals(message, expected, actual);
134                } else {
135                    Assert.fail((message == null ? "" : message) + "non-array value encountered: " + expected);
136                }
137            } else if (expectedClass.equals(double.class) && actualClass.equals(double.class)) {
138                Assert.assertEquals((double) expected, (double) actual, delta);
139            } else if (expectedClass.equals(float.class) && actualClass.equals(float.class)) {
140                Assert.assertEquals((float) expected, (float) actual, delta);
141            } else {
142                Assert.assertEquals(message, expected, actual);
143            }
144        } else {
145            Assert.assertEquals(message, expected, actual);
146        }
147    }
148
149    /**
150     * Compares two given values for equality, doing a recursive test if both values are arrays of
151     * the same type. Uses {@linkplain StrictMath#ulp(float) ULP}s for comparison of floats.
152     *
153     * @param message the identifying message for the {@link AssertionError}
154     * @param ulpsDelta the maximum allowed ulps difference between two doubles or floats for which
155     *            both numbers are still considered equal.
156     */
157    protected void assertDeepEquals(String message, Object expected, Object actual, int ulpsDelta) {
158        ComparisonCriteria doubleUlpsDeltaCriteria = new ComparisonCriteria() {
159            @Override
160            protected void assertElementsEqual(Object e, Object a) {
161                assertTrue(message, e instanceof Double && a instanceof Double);
162                // determine acceptable error based on whether it is a normal number or a NaN/Inf
163                double de = (Double) e;
164                double epsilon = (!Double.isNaN(de) && Double.isFinite(de) ? ulpsDelta * Math.ulp(de) : 0);
165                Assert.assertEquals(message, (Double) e, (Double) a, epsilon);
166            }
167        };
168
169        ComparisonCriteria floatUlpsDeltaCriteria = new ComparisonCriteria() {
170            @Override
171            protected void assertElementsEqual(Object e, Object a) {
172                assertTrue(message, e instanceof Float && a instanceof Float);
173                // determine acceptable error based on whether it is a normal number or a NaN/Inf
174                float fe = (Float) e;
175                float epsilon = (!Float.isNaN(fe) && Float.isFinite(fe) ? ulpsDelta * Math.ulp(fe) : 0);
176                Assert.assertEquals(message, (Float) e, (Float) a, epsilon);
177            }
178        };
179
180        if (expected != null && actual != null) {
181            Class<?> expectedClass = expected.getClass();
182            Class<?> actualClass = actual.getClass();
183            if (expectedClass.isArray()) {
184                Assert.assertEquals(message, expectedClass, actualClass);
185                if (expected instanceof double[] || expected instanceof Object[]) {
186                    doubleUlpsDeltaCriteria.arrayEquals(message, expected, actual);
187                    return;
188                } else if (expected instanceof float[] || expected instanceof Object[]) {
189                    floatUlpsDeltaCriteria.arrayEquals(message, expected, actual);
190                    return;
191                }
192            } else if (expectedClass.equals(double.class) && actualClass.equals(double.class)) {
193                doubleUlpsDeltaCriteria.arrayEquals(message, expected, actual);
194                return;
195            } else if (expectedClass.equals(float.class) && actualClass.equals(float.class)) {
196                floatUlpsDeltaCriteria.arrayEquals(message, expected, actual);
197                return;
198            }
199        }
200        // anything else just use the non-ulps version
201        assertDeepEquals(message, expected, actual, equalFloatsOrDoublesDelta());
202    }
203
204    /**
205     * Gets the value used by {@link #assertDeepEquals(Object, Object)} and
206     * {@link #assertDeepEquals(String, Object, Object)} for the maximum delta between two doubles
207     * or floats for which both numbers are still considered equal.
208     */
209    protected double equalFloatsOrDoublesDelta() {
210        return 0.0D;
211    }
212
213    // unless overridden ulpsDelta is not used
214    protected int ulpsDelta() {
215        return 0;
216    }
217
218    @SuppressWarnings("serial")
219    public static class MultiCauseAssertionError extends AssertionError {
220
221        private Throwable[] causes;
222
223        public MultiCauseAssertionError(String message, Throwable... causes) {
224            super(message);
225            this.causes = causes;
226        }
227
228        @Override
229        public void printStackTrace(PrintStream out) {
230            super.printStackTrace(out);
231            int num = 0;
232            for (Throwable cause : causes) {
233                if (cause != null) {
234                    out.print("cause " + (num++));
235                    cause.printStackTrace(out);
236                }
237            }
238        }
239
240        @Override
241        public void printStackTrace(PrintWriter out) {
242            super.printStackTrace(out);
243            int num = 0;
244            for (Throwable cause : causes) {
245                if (cause != null) {
246                    out.print("cause " + (num++) + ": ");
247                    cause.printStackTrace(out);
248                }
249            }
250        }
251    }
252
253    /*
254     * Overrides to the normal JUnit {@link Assert} routines that provide varargs style formatting
255     * and produce an exception stack trace with the assertion frames trimmed out.
256     */
257
258    /**
259     * Fails a test with the given message.
260     *
261     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
262     *            okay)
263     * @see AssertionError
264     */
265    public static void fail(String message, Object... objects) {
266        AssertionError e;
267        if (message == null) {
268            e = new AssertionError();
269        } else {
270            e = new AssertionError(String.format(message, objects));
271        }
272        // Trim the assert frames from the stack trace
273        StackTraceElement[] trace = e.getStackTrace();
274        int start = 1; // Skip this frame
275        String thisClassName = GraalTest.class.getName();
276        while (start < trace.length && trace[start].getClassName().equals(thisClassName) && (trace[start].getMethodName().equals("assertTrue") || trace[start].getMethodName().equals("assertFalse"))) {
277            start++;
278        }
279        e.setStackTrace(Arrays.copyOfRange(trace, start, trace.length));
280        throw e;
281    }
282
283    /**
284     * Asserts that a condition is true. If it isn't it throws an {@link AssertionError} with the
285     * given message.
286     *
287     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
288     *            okay)
289     * @param condition condition to be checked
290     */
291    public static void assertTrue(String message, boolean condition) {
292        assertTrue(condition, message);
293    }
294
295    /**
296     * Asserts that a condition is true. If it isn't it throws an {@link AssertionError} without a
297     * message.
298     *
299     * @param condition condition to be checked
300     */
301    public static void assertTrue(boolean condition) {
302        assertTrue(condition, null);
303    }
304
305    /**
306     * Asserts that a condition is false. If it isn't it throws an {@link AssertionError} with the
307     * given message.
308     *
309     * @param message the identifying message for the {@link AssertionError} (<code>null</code>
310     *            okay)
311     * @param condition condition to be checked
312     */
313    public static void assertFalse(String message, boolean condition) {
314        assertTrue(!condition, message);
315    }
316
317    /**
318     * Asserts that a condition is false. If it isn't it throws an {@link AssertionError} without a
319     * message.
320     *
321     * @param condition condition to be checked
322     */
323    public static void assertFalse(boolean condition) {
324        assertTrue(!condition, null);
325    }
326
327    /**
328     * Asserts that a condition is true. If it isn't it throws an {@link AssertionError} with the
329     * given message.
330     *
331     * @param condition condition to be checked
332     * @param message the identifying message for the {@link AssertionError}
333     * @param objects arguments to the format string
334     */
335    public static void assertTrue(boolean condition, String message, Object... objects) {
336        if (!condition) {
337            fail(message, objects);
338        }
339    }
340
341    /**
342     * Asserts that a condition is false. If it isn't it throws an {@link AssertionError} with the
343     * given message produced by {@link String#format}.
344     *
345     * @param condition condition to be checked
346     * @param message the identifying message for the {@link AssertionError}
347     * @param objects arguments to the format string
348     */
349    public static void assertFalse(boolean condition, String message, Object... objects) {
350        assertTrue(!condition, message, objects);
351    }
352
353}