8038186: [TESTBUG] improvements of test j.l.i.MethodHandles
Reviewed-by: iveresov, twisti, vlivanov
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/MethodHandles/CatchExceptionTest.java Sat Mar 29 12:29:21 2014 +0400
@@ -0,0 +1,542 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.lang.invoke.MethodHandles;
+
+import com.oracle.testlibrary.jsr292.Helper;
+import jdk.testlibrary.Asserts;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.Array;
+import java.util.*;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+/* @test
+ * @library /lib/testlibrary/jsr292 /lib/testlibrary/
+ * @compile CatchExceptionTest.java
+ * @run main/othervm -esa test.java.lang.invoke.MethodHandles.CatchExceptionTest
+ */
+public class CatchExceptionTest {
+ private static final List<Class<?>> ARGS_CLASSES;
+ protected static final int MAX_ARITY = Helper.MAX_ARITY - 1;
+ static {
+ Class<?> classes[] = {
+ Object.class,
+ long.class,
+ int.class,
+ byte.class,
+ Integer[].class,
+ double[].class,
+ String.class,
+ };
+ List<Class<?>> list = new ArrayList<>(MAX_ARITY);
+ for (int i = 0; i < MAX_ARITY; ++i) {
+ list.add(classes[Helper.RNG.nextInt(classes.length)]);
+ }
+ ARGS_CLASSES = Collections.unmodifiableList(list);
+ }
+
+ private final TestCase testCase;
+ private final int nargs;
+ private final int argsCount;
+ private final MethodHandle catcher;
+ private int dropped;
+ private MethodHandle thrower;
+
+
+ public CatchExceptionTest(TestCase testCase, final boolean isVararg, final int argsCount,
+ final int catchDrops) {
+ this.testCase = testCase;
+ this.dropped = catchDrops;
+ if (Helper.IS_VERBOSE) {
+ System.out.printf("CatchException::CatchException(%s, isVararg=%b " +
+ "argsCount=%d catchDrops=%d)%n",
+ testCase, isVararg, argsCount, catchDrops
+ );
+ }
+ MethodHandle thrower = testCase.thrower;
+ int throwerLen = thrower.type().parameterCount();
+ List<Class<?>> classes;
+ int extra = Math.max(0, argsCount - throwerLen);
+ classes = getThrowerParams(isVararg, extra);
+ this.argsCount = throwerLen + classes.size();
+ thrower = Helper.addTrailingArgs(thrower, this.argsCount, classes);
+ if (isVararg && argsCount > throwerLen) {
+ MethodType mt = thrower.type();
+ Class<?> lastParam = mt.parameterType(mt.parameterCount() - 1);
+ thrower = thrower.asVarargsCollector(lastParam);
+ }
+ this.thrower = thrower;
+ this.dropped = Math.min(this.argsCount, catchDrops);
+ catcher = testCase.getCatcher(getCatcherParams());
+ nargs = Math.max(2, this.argsCount);
+ }
+
+ public static void main(String[] args) throws Throwable {
+ for (CatchExceptionTest test : TestFactory.MANDATORY_TEST_CASES) {
+ test.runTest();
+ }
+ TestFactory factory = new TestFactory();
+ CatchExceptionTest test;
+ while ((test = factory.nextTest()) != null ) {
+ test.runTest();
+ }
+ }
+
+ private List<Class<?>> getThrowerParams(boolean isVararg, int argsCount) {
+ boolean unmodifiable = true;
+ List<Class<?>> classes;
+ classes = ARGS_CLASSES.subList(0,
+ Math.min(argsCount, (MAX_ARITY / 2) - 1));
+ int extra = 0;
+ if (argsCount >= MAX_ARITY / 2) {
+ classes = new ArrayList<>(classes);
+ unmodifiable = false;
+ extra = (int) classes.stream().filter(Helper::isDoubleCost).count();
+ int i = classes.size();
+ while (classes.size() + extra < argsCount) {
+ Class<?> aClass = ARGS_CLASSES.get(i);
+ if (Helper.isDoubleCost(aClass)) {
+ ++extra;
+ if (classes.size() + extra >= argsCount) {
+ break;
+ }
+ }
+ classes.add(aClass);
+ }
+ }
+ if (isVararg && classes.size() > 0) {
+ if (unmodifiable) {
+ classes = new ArrayList<>(classes);
+ }
+ int last = classes.size() - 1;
+ Class<?> aClass = classes.get(classes.size() - 1);
+ aClass = Array.newInstance(aClass, 2).getClass();
+ classes.set(last, aClass);
+ }
+ return classes;
+ }
+
+
+ private List<Class<?>> getCatcherParams() {
+ int catchArgc = 1 + this.argsCount - dropped;
+ List<Class<?>> result = new ArrayList<>(
+ thrower.type().parameterList().subList(0, catchArgc - 1));
+ // prepend throwable
+ result.add(0, testCase.throwableClass);
+ return result;
+ }
+
+ private void runTest() {
+ Helper.clear();
+
+ Object[] args = Helper.randomArgs(
+ argsCount, thrower.type().parameterArray());
+ Object arg0 = Helper.MISSING_ARG;
+ Object arg1 = testCase.thrown;
+ if (argsCount > 0) {
+ arg0 = args[0];
+ }
+ if (argsCount > 1) {
+ args[1] = arg1;
+ }
+ Asserts.assertEQ(nargs, thrower.type().parameterCount());
+ if (argsCount < nargs) {
+ Object[] appendArgs = {arg0, arg1};
+ appendArgs = Arrays.copyOfRange(appendArgs, argsCount, nargs);
+ thrower = MethodHandles.insertArguments(
+ thrower, argsCount, appendArgs);
+ }
+ Asserts.assertEQ(argsCount, thrower.type().parameterCount());
+
+ MethodHandle target = MethodHandles.catchException(
+ testCase.filter(thrower), testCase.throwableClass,
+ testCase.filter(catcher));
+
+ Asserts.assertEQ(thrower.type(), target.type());
+ Asserts.assertEQ(argsCount, target.type().parameterCount());
+
+ Object returned;
+ try {
+ returned = target.invokeWithArguments(args);
+ } catch (Throwable ex) {
+ testCase.assertCatch(ex);
+ returned = ex;
+ }
+
+ testCase.assertReturn(returned, arg0, arg1, dropped, args);
+ }
+}
+
+class TestFactory {
+ public static final List<CatchExceptionTest> MANDATORY_TEST_CASES = new ArrayList<>();
+
+ private static final int MIN_TESTED_ARITY = 10;
+
+ static {
+ for (int[] args : new int[][]{
+ {0, 0},
+ {MIN_TESTED_ARITY, 0},
+ {MIN_TESTED_ARITY, MIN_TESTED_ARITY},
+ {CatchExceptionTest.MAX_ARITY, 0},
+ {CatchExceptionTest.MAX_ARITY, CatchExceptionTest.MAX_ARITY},
+ }) {
+ MANDATORY_TEST_CASES.addAll(createTests(args[0], args[1]));
+ }
+ }
+
+ private int count;
+ private int args;
+ private int dropArgs;
+ private int currentMaxDrops;
+ private int maxArgs;
+ private int maxDrops;
+ private int constructor;
+ private int constructorSize;
+ private boolean isVararg;
+
+ public TestFactory() {
+ if (Helper.IS_THOROUGH) {
+ maxArgs = maxDrops = CatchExceptionTest.MAX_ARITY;
+ } else {
+ maxArgs = MIN_TESTED_ARITY
+ + Helper.RNG.nextInt(CatchExceptionTest.MAX_ARITY
+ - MIN_TESTED_ARITY)
+ + 1;
+ maxDrops = MIN_TESTED_ARITY
+ + Helper.RNG.nextInt(maxArgs - MIN_TESTED_ARITY)
+ + 1;
+ args = 1;
+ }
+
+ if (Helper.IS_VERBOSE) {
+ System.out.printf("maxArgs = %d%nmaxDrops = %d%n",
+ maxArgs, maxDrops);
+ }
+ constructorSize = TestCase.CONSTRUCTORS.size();
+ }
+
+ private static List<CatchExceptionTest> createTests(int argsCount,
+ int catchDrops) {
+ if (catchDrops > argsCount || argsCount < 0 || catchDrops < 0) {
+ throw new IllegalArgumentException("argsCount = " + argsCount
+ + ", catchDrops = " + catchDrops
+ );
+ }
+ List<CatchExceptionTest> result = new ArrayList<>(
+ TestCase.CONSTRUCTORS.size());
+ for (Supplier<TestCase> constructor : TestCase.CONSTRUCTORS) {
+ result.add(new CatchExceptionTest(constructor.get(),
+ /* isVararg = */ true,
+ argsCount,
+ catchDrops));
+ result.add(new CatchExceptionTest(constructor.get(),
+ /* isVararg = */ false,
+ argsCount,
+ catchDrops));
+ }
+ return result;
+ }
+
+ /**
+ * @return next test from test matrix:
+ * {varArgs, noVarArgs} x TestCase.rtypes x TestCase.THROWABLES x {1, .., maxArgs } x {1, .., maxDrops}
+ */
+ public CatchExceptionTest nextTest() {
+ if (constructor < constructorSize) {
+ return createTest();
+ }
+ constructor = 0;
+ count++;
+ if (!Helper.IS_THOROUGH && count > Helper.TEST_LIMIT) {
+ System.out.println("test limit is exceeded");
+ return null;
+ }
+ if (dropArgs <= currentMaxDrops) {
+ if (dropArgs == 1) {
+ if (Helper.IS_THOROUGH || Helper.RNG.nextBoolean()) {
+ ++dropArgs;
+ return createTest();
+ } else if (Helper.IS_VERBOSE) {
+ System.out.printf(
+ "argsCount=%d : \"drop\" scenarios are skipped%n",
+ args);
+ }
+ } else {
+ ++dropArgs;
+ return createTest();
+ }
+ }
+
+ if (args <= maxArgs) {
+ dropArgs = 1;
+ currentMaxDrops = Math.min(args, maxDrops);
+ ++args;
+ return createTest();
+ }
+ return null;
+ }
+
+ private CatchExceptionTest createTest() {
+ if (!Helper.IS_THOROUGH) {
+ return new CatchExceptionTest(
+ TestCase.CONSTRUCTORS.get(constructor++).get(),
+ Helper.RNG.nextBoolean(), args, dropArgs);
+ } else {
+ if (isVararg) {
+ isVararg = false;
+ return new CatchExceptionTest(
+ TestCase.CONSTRUCTORS.get(constructor++).get(),
+ isVararg, args, dropArgs);
+ } else {
+ isVararg = true;
+ return new CatchExceptionTest(
+ TestCase.CONSTRUCTORS.get(constructor).get(),
+ isVararg, args, dropArgs);
+ }
+ }
+ }
+}
+
+class TestCase<T> {
+ private static enum ThrowMode {
+ NOTHING,
+ CAUGHT,
+ UNCAUGHT,
+ ADAPTER
+ }
+
+ @SuppressWarnings("unchecked")
+ public static final List<Supplier<TestCase>> CONSTRUCTORS;
+ private static final MethodHandle FAKE_IDENTITY;
+ private static final MethodHandle THROW_OR_RETURN;
+ private static final MethodHandle CATCHER;
+
+ static {
+ try {
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+ THROW_OR_RETURN = lookup.findStatic(
+ TestCase.class,
+ "throwOrReturn",
+ MethodType.methodType(Object.class, Object.class,
+ Throwable.class)
+ );
+ CATCHER = lookup.findStatic(
+ TestCase.class,
+ "catcher",
+ MethodType.methodType(Object.class, Object.class));
+ FAKE_IDENTITY = lookup.findVirtual(
+ TestCase.class, "fakeIdentity",
+ MethodType.methodType(Object.class, Object.class));
+
+ } catch (NoSuchMethodException | IllegalAccessException e) {
+ throw new Error(e);
+ }
+ PartialConstructor[] constructors = {
+ create(Object.class, Object.class::cast),
+ create(String.class, Objects::toString),
+ create(int[].class, x -> new int[]{Objects.hashCode(x)}),
+ create(long.class,
+ x -> Objects.hashCode(x) & (-1L >>> 32)),
+ create(void.class, TestCase::noop)};
+ Throwable[] throwables = {
+ new ClassCastException("testing"),
+ new java.io.IOException("testing"),
+ new LinkageError("testing")};
+ List<Supplier<TestCase>> list = new ArrayList<>(constructors.length *
+ throwables.length * ThrowMode.values().length);
+ //noinspection unchecked
+ for (PartialConstructor f : constructors) {
+ for (ThrowMode mode : ThrowMode.values()) {
+ for (Throwable t : throwables) {
+ list.add(f.apply(mode, t));
+ }
+ }
+ }
+ CONSTRUCTORS = Collections.unmodifiableList(list);
+ }
+
+ public final Class<T> rtype;
+ public final ThrowMode throwMode;
+ public final Throwable thrown;
+ public final Class<? extends Throwable> throwableClass;
+ /**
+ * MH which takes 2 args (Object,Throwable), 1st is the return value,
+ * 2nd is the exception which will be thrown, if it's supposed in current
+ * {@link #throwMode}.
+ */
+ public final MethodHandle thrower;
+ private final Function<Object, T> cast;
+ protected MethodHandle filter;
+ private int fakeIdentityCount;
+
+ private TestCase(Class<T> rtype, Function<Object, T> cast,
+ ThrowMode throwMode, Throwable thrown)
+ throws NoSuchMethodException, IllegalAccessException {
+ this.cast = cast;
+ filter = MethodHandles.lookup().findVirtual(
+ Function.class,
+ "apply",
+ MethodType.methodType(Object.class, Object.class))
+ .bindTo(cast);
+ this.rtype = rtype;
+ this.throwMode = throwMode;
+ this.throwableClass = thrown.getClass();
+ switch (throwMode) {
+ case NOTHING:
+ this.thrown = null;
+ break;
+ case ADAPTER:
+ case UNCAUGHT:
+ this.thrown = new Error("do not catch this");
+ break;
+ default:
+ this.thrown = thrown;
+ }
+
+ MethodHandle throwOrReturn = THROW_OR_RETURN;
+ if (throwMode == ThrowMode.ADAPTER) {
+ MethodHandle fakeIdentity = FAKE_IDENTITY.bindTo(this);
+ for (int i = 0; i < 10; ++i) {
+ throwOrReturn = MethodHandles.filterReturnValue(
+ throwOrReturn, fakeIdentity);
+ }
+ }
+ thrower = throwOrReturn.asType(MethodType.genericMethodType(2));
+ }
+
+ private static Void noop(Object x) {
+ return null;
+ }
+
+ private static <T2> PartialConstructor create(
+ Class<T2> rtype, Function<Object, T2> cast) {
+ return (t, u) -> () -> {
+ try {
+ return new TestCase<>(rtype, cast, t, u);
+ } catch (NoSuchMethodException | IllegalAccessException e) {
+ throw new Error(e);
+ }
+ };
+ }
+
+ private static <T extends Throwable>
+ Object throwOrReturn(Object normal, T exception) throws T {
+ if (exception != null) {
+ Helper.called("throwOrReturn/throw", normal, exception);
+ throw exception;
+ }
+ Helper.called("throwOrReturn/normal", normal, exception);
+ return normal;
+ }
+
+ private static <T extends Throwable>
+ Object catcher(Object o) {
+ Helper.called("catcher", o);
+ return o;
+ }
+
+ public MethodHandle filter(MethodHandle target) {
+ return MethodHandles.filterReturnValue(target, filter);
+ }
+
+ public MethodHandle getCatcher(List<Class<?>> classes) {
+ return MethodHandles.filterReturnValue(Helper.AS_LIST.asType(
+ MethodType.methodType(Object.class, classes)),
+ CATCHER
+ );
+ }
+
+ @Override
+ public String toString() {
+ return "TestCase{" +
+ "rtype=" + rtype +
+ ", throwMode=" + throwMode +
+ ", throwableClass=" + throwableClass +
+ '}';
+ }
+
+ public String callName() {
+ return "throwOrReturn/" +
+ (throwMode == ThrowMode.NOTHING
+ ? "normal"
+ : "throw");
+ }
+
+ public void assertReturn(Object returned, Object arg0, Object arg1,
+ int catchDrops, Object... args) {
+ int lag = 0;
+ if (throwMode == ThrowMode.CAUGHT) {
+ lag = 1;
+ }
+ Helper.assertCalled(lag, callName(), arg0, arg1);
+
+ if (throwMode == ThrowMode.NOTHING) {
+ assertEQ(cast.apply(arg0), returned);
+ } else if (throwMode == ThrowMode.CAUGHT) {
+ List<Object> catchArgs = new ArrayList<>(Arrays.asList(args));
+ // catcher receives an initial subsequence of target arguments:
+ catchArgs.subList(args.length - catchDrops, args.length).clear();
+ // catcher also receives the exception, prepended:
+ catchArgs.add(0, thrown);
+ Helper.assertCalled("catcher", catchArgs);
+ assertEQ(cast.apply(catchArgs), returned);
+ }
+ Asserts.assertEQ(0, fakeIdentityCount);
+ }
+
+ private void assertEQ(T t, Object returned) {
+ if (rtype.isArray()) {
+ Asserts.assertEQ(t.getClass(), returned.getClass());
+ int n = Array.getLength(t);
+ Asserts.assertEQ(n, Array.getLength(returned));
+ for (int i = 0; i < n; ++i) {
+ Asserts.assertEQ(Array.get(t, i), Array.get(returned, i));
+ }
+ } else {
+ Asserts.assertEQ(t, returned);
+ }
+ }
+
+ private Object fakeIdentity(Object x) {
+ System.out.println("should throw through this!");
+ ++fakeIdentityCount;
+ return x;
+ }
+
+ public void assertCatch(Throwable ex) {
+ try {
+ Asserts.assertSame(thrown, ex,
+ "must get the out-of-band exception");
+ } catch (Throwable t) {
+ ex.printStackTrace();
+ }
+ }
+
+ public interface PartialConstructor
+ extends BiFunction<ThrowMode, Throwable, Supplier<TestCase>> {
+ }
+}
--- a/jdk/test/java/lang/invoke/MethodHandlesTest.java Fri Mar 28 18:03:40 2014 +0100
+++ b/jdk/test/java/lang/invoke/MethodHandlesTest.java Sat Mar 29 12:29:21 2014 +0400
@@ -2406,108 +2406,6 @@
}
@Test
- public void testCatchException() throws Throwable {
- if (CAN_SKIP_WORKING) return;
- startTest("catchException");
- for (int nargs = 0; nargs < 40; nargs++) {
- if (CAN_TEST_LIGHTLY && nargs > 11) break;
- for (int throwMode = 0; throwMode < THROW_MODE_LIMIT; throwMode++) {
- testCatchException(int.class, new ClassCastException("testing"), throwMode, nargs);
- if (CAN_TEST_LIGHTLY && nargs > 3) continue;
- testCatchException(void.class, new java.io.IOException("testing"), throwMode, nargs);
- testCatchException(String.class, new LinkageError("testing"), throwMode, nargs);
- }
- }
- }
-
- static final int THROW_NOTHING = 0, THROW_CAUGHT = 1, THROW_UNCAUGHT = 2, THROW_THROUGH_ADAPTER = 3, THROW_MODE_LIMIT = 4;
-
- void testCatchException(Class<?> returnType, Throwable thrown, int throwMode, int nargs) throws Throwable {
- testCatchException(returnType, thrown, throwMode, nargs, 0);
- if (nargs <= 5 || nargs % 10 == 3) {
- for (int catchDrops = 1; catchDrops <= nargs; catchDrops++)
- testCatchException(returnType, thrown, throwMode, nargs, catchDrops);
- }
- }
-
- private static <T extends Throwable>
- Object throwOrReturn(Object normal, T exception) throws T {
- if (exception != null) {
- called("throwOrReturn/throw", normal, exception);
- throw exception;
- }
- called("throwOrReturn/normal", normal, exception);
- return normal;
- }
- private int fakeIdentityCount;
- private Object fakeIdentity(Object x) {
- System.out.println("should throw through this!");
- fakeIdentityCount++;
- return x;
- }
-
- void testCatchException(Class<?> returnType, Throwable thrown, int throwMode, int nargs, int catchDrops) throws Throwable {
- countTest();
- if (verbosity >= 3)
- System.out.println("catchException rt="+returnType+" throw="+throwMode+" nargs="+nargs+" drops="+catchDrops);
- Class<? extends Throwable> exType = thrown.getClass();
- if (throwMode > THROW_CAUGHT) thrown = new UnsupportedOperationException("do not catch this");
- MethodHandle throwOrReturn
- = PRIVATE.findStatic(MethodHandlesTest.class, "throwOrReturn",
- MethodType.methodType(Object.class, Object.class, Throwable.class));
- if (throwMode == THROW_THROUGH_ADAPTER) {
- MethodHandle fakeIdentity
- = PRIVATE.findVirtual(MethodHandlesTest.class, "fakeIdentity",
- MethodType.methodType(Object.class, Object.class)).bindTo(this);
- for (int i = 0; i < 10; i++)
- throwOrReturn = MethodHandles.filterReturnValue(throwOrReturn, fakeIdentity);
- }
- int nargs1 = Math.max(2, nargs);
- MethodHandle thrower = throwOrReturn.asType(MethodType.genericMethodType(2));
- thrower = addTrailingArgs(thrower, nargs, Object.class);
- int catchArgc = 1 + nargs - catchDrops;
- MethodHandle catcher = varargsList(catchArgc).asType(MethodType.genericMethodType(catchArgc));
- Object[] args = randomArgs(nargs, Object.class);
- Object arg0 = MISSING_ARG;
- Object arg1 = (throwMode == THROW_NOTHING) ? (Throwable) null : thrown;
- if (nargs > 0) arg0 = args[0];
- if (nargs > 1) args[1] = arg1;
- assertEquals(nargs1, thrower.type().parameterCount());
- if (nargs < nargs1) {
- Object[] appendArgs = { arg0, arg1 };
- appendArgs = Arrays.copyOfRange(appendArgs, nargs, nargs1);
- thrower = MethodHandles.insertArguments(thrower, nargs, appendArgs);
- }
- assertEquals(nargs, thrower.type().parameterCount());
- MethodHandle target = MethodHandles.catchException(thrower, exType, catcher);
- assertEquals(thrower.type(), target.type());
- assertEquals(nargs, target.type().parameterCount());
- //System.out.println("catching with "+target+" : "+throwOrReturn);
- Object returned;
- try {
- returned = target.invokeWithArguments(args);
- } catch (Throwable ex) {
- assertSame("must get the out-of-band exception", thrown, ex);
- if (throwMode <= THROW_CAUGHT)
- assertEquals(THROW_UNCAUGHT, throwMode);
- returned = ex;
- }
- assertCalled("throwOrReturn/"+(throwMode == THROW_NOTHING ? "normal" : "throw"), arg0, arg1);
- //System.out.println("return from "+target+" : "+returned);
- if (throwMode == THROW_NOTHING) {
- assertSame(arg0, returned);
- } else if (throwMode == THROW_CAUGHT) {
- List<Object> catchArgs = new ArrayList<>(Arrays.asList(args));
- // catcher receives an initial subsequence of target arguments:
- catchArgs.subList(nargs - catchDrops, nargs).clear();
- // catcher also receives the exception, prepended:
- catchArgs.add(0, thrown);
- assertEquals(catchArgs, returned);
- }
- assertEquals(0, fakeIdentityCount);
- }
-
- @Test
public void testThrowException() throws Throwable {
if (CAN_SKIP_WORKING) return;
startTest("throwException");
--- a/jdk/test/lib/testlibrary/jdk/testlibrary/Asserts.java Fri Mar 28 18:03:40 2014 +0100
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/Asserts.java Sat Mar 29 12:29:21 2014 +0400
@@ -207,6 +207,34 @@
}
/**
+ * Calls {@link #assertSame(java.lang.Object, java.lang.Object, java.lang.String)} with a default message.
+ *
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @see #assertSame(Object, Object, String)
+ */
+ public static void assertSame(Object lhs, Object rhs) {
+ assertSame(lhs, rhs, null);
+ }
+
+ /**
+ * Asserts that {@code lhs} is the same as {@code rhs}.
+ *
+ * @param lhs The left hand side of the comparison.
+ * @param rhs The right hand side of the comparison.
+ * @param msg A description of the assumption; {@code null} for a default message.
+ * @throws RuntimeException if the assertion is not true.
+ */
+ public static void assertSame(Object lhs, Object rhs, String msg) {
+ if (lhs != rhs) {
+ msg = Objects.toString(msg, "assertSame")
+ + ": expected " + Objects.toString(lhs)
+ + " to equal " + Objects.toString(rhs);
+ fail(msg);
+ }
+ }
+
+ /**
* Shorthand for {@link #assertGreaterThanOrEqual(Comparable, Comparable)}.
*
* @param <T> a type
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/lib/testlibrary/jsr292/com/oracle/testlibrary/jsr292/Helper.java Sat Mar 29 12:29:21 2014 +0400
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.testlibrary.jsr292;
+
+import jdk.testlibrary.Asserts;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.Array;
+import java.util.*;
+
+public class Helper {
+ /** Flag for verbose output, true if {@code -Dverbose} specified */
+ public static final boolean IS_VERBOSE
+ = System.getProperty("verbose") != null;
+ /**
+ * Flag for thorough testing -- all test will be executed,
+ * true if {@code -Dthorough} specified. */
+ public static final boolean IS_THOROUGH
+ = System.getProperty("thorough") != null;
+ /** Random number generator w/ initial seed equal to {@code -Dseed} */
+ public static final Random RNG;
+
+ static {
+ String str = System.getProperty("seed");
+ long seed = str != null ? Long.parseLong(str) : new Random().nextLong();
+ RNG = new Random(seed);
+ System.out.printf("-Dseed=%d%n", seed);
+ }
+
+ public static final long TEST_LIMIT;
+ static {
+ String str = System.getProperty("testLimit");
+ TEST_LIMIT = str != null ? Long.parseUnsignedLong(str) : 2_000L;
+ System.out.printf("-DtestLimit=%d%n", TEST_LIMIT);
+ }
+
+ public static final int MAX_ARITY = 254;
+ public static final String MISSING_ARG = "missingArg";
+ public static final String MISSING_ARG_2 = "missingArg#2";
+
+ private static final int
+ // first int value
+ ONE_MILLION = (1000 * 1000),
+ // scale factor to reach upper 32 bits
+ TEN_BILLION = (10 * 1000 * 1000 * 1000),
+ // <<1 makes space for sign bit;
+ INITIAL_ARG_VAL = ONE_MILLION << 1;
+
+ public static final MethodHandle AS_LIST;
+
+ static {
+ try {
+ AS_LIST = MethodHandles.lookup().findStatic(
+ Arrays.class, "asList",
+ MethodType.methodType(List.class, Object[].class));
+ } catch (NoSuchMethodException | IllegalAccessException ex) {
+ throw new Error(ex);
+ }
+ }
+
+ public static boolean isDoubleCost(Class<?> aClass) {
+ return aClass == double.class || aClass == long.class;
+ }
+
+ private static List<List<Object>> calledLog = new ArrayList<>();
+ private static long nextArgVal;
+
+ public static void assertCalled(String name, Object... args) {
+ assertCalled(0, name, args);
+ }
+
+ public static void assertCalled(int lag, String name, Object... args) {
+ Object expected = logEntry(name, args);
+ Object actual = getCalled(lag);
+ Asserts.assertEQ(expected, actual, "method call w/ lag = " + lag);
+ }
+
+ public static Object called(String name, Object... args) {
+ List<Object> entry = logEntry(name, args);
+ calledLog.add(entry);
+ return entry;
+ }
+
+ private static List<Object> logEntry(String name, Object... args) {
+ return Arrays.asList(name, Arrays.asList(args));
+ }
+
+ public static void clear() {
+ calledLog.clear();
+ }
+
+ public static List<Object> getCalled(int lag) {
+ int size = calledLog.size();
+ return size <= lag ? null : calledLog.get(size - lag - 1);
+ }
+
+ public static MethodHandle addTrailingArgs(MethodHandle target, int nargs,
+ List<Class<?>> classes) {
+ int targetLen = target.type().parameterCount();
+ int extra = (nargs - targetLen);
+ if (extra <= 0) {
+ return target;
+ }
+ List<Class<?>> fakeArgs = new ArrayList<>(extra);
+ for (int i = 0; i < extra; ++i) {
+ fakeArgs.add(classes.get(i % classes.size()));
+ }
+ return MethodHandles.dropArguments(target, targetLen, fakeArgs);
+ }
+
+ public static MethodHandle varargsList(int arity) {
+ return AS_LIST.asCollector(Object[].class, arity);
+ }
+
+ private static long nextArg(boolean moreBits) {
+ long val = nextArgVal++;
+ long sign = -(val & 1); // alternate signs
+ val >>= 1;
+ if (moreBits)
+ // Guarantee some bits in the high word.
+ // In any case keep the decimal representation simple-looking,
+ // with lots of zeroes, so as not to make the printed decimal
+ // strings unnecessarily noisy.
+ {
+ val += (val % ONE_MILLION) * TEN_BILLION;
+ }
+ return val ^ sign;
+ }
+
+ private static int nextArg() {
+ // Produce a 32-bit result something like ONE_MILLION+(smallint).
+ // Example: 1_000_042.
+ return (int) nextArg(false);
+ }
+
+ private static long nextArg(Class<?> kind) {
+ if (kind == long.class || kind == Long.class ||
+ kind == double.class || kind == Double.class)
+ // produce a 64-bit result something like
+ // ((TEN_BILLION+1) * (ONE_MILLION+(smallint)))
+ // Example: 10_000_420_001_000_042.
+ {
+ return nextArg(true);
+ }
+ return (long) nextArg();
+ }
+
+ private static Object randomArg(Class<?> param) {
+ Object wrap = castToWrapperOrNull(nextArg(param), param);
+ if (wrap != null) {
+ return wrap;
+ }
+
+ if (param.isInterface()) {
+ for (Class<?> c : param.getClasses()) {
+ if (param.isAssignableFrom(c) && !c.isInterface()) {
+ param = c;
+ break;
+ }
+ }
+ }
+ if (param.isArray()) {
+ Class<?> ctype = param.getComponentType();
+ Object arg = Array.newInstance(ctype, 2);
+ Array.set(arg, 0, randomArg(ctype));
+ return arg;
+ }
+ if (param.isInterface() && param.isAssignableFrom(List.class)) {
+ return Arrays.asList("#" + nextArg());
+ }
+ if (param.isInterface() || param.isAssignableFrom(String.class)) {
+ return "#" + nextArg();
+ }
+
+ try {
+ return param.newInstance();
+ } catch (InstantiationException | IllegalAccessException ex) {
+ }
+ return null; // random class not Object, String, Integer, etc.
+ }
+
+ public static Object[] randomArgs(Class<?>... params) {
+ Object[] args = new Object[params.length];
+ for (int i = 0; i < args.length; i++) {
+ args[i] = randomArg(params[i]);
+ }
+ return args;
+ }
+
+ public static Object[] randomArgs(int nargs, Class<?> param) {
+ Object[] args = new Object[nargs];
+ for (int i = 0; i < args.length; i++) {
+ args[i] = randomArg(param);
+ }
+ return args;
+ }
+
+ public static Object[] randomArgs(int nargs, Class<?>... params) {
+ Object[] args = new Object[nargs];
+ for (int i = 0; i < args.length; i++) {
+ Class<?> param = params[i % params.length];
+ args[i] = randomArg(param);
+ }
+ return args;
+ }
+
+ public static Object[] randomArgs(List<Class<?>> params) {
+ return randomArgs(params.toArray(new Class<?>[params.size()]));
+ }
+
+ private static Object castToWrapper(Object value, Class<?> dst) {
+ Object wrap = null;
+ if (value instanceof Number) {
+ wrap = castToWrapperOrNull(((Number) value).longValue(), dst);
+ }
+ if (value instanceof Character) {
+ wrap = castToWrapperOrNull((char) (Character) value, dst);
+ }
+ if (wrap != null) {
+ return wrap;
+ }
+ return dst.cast(value);
+ }
+
+ @SuppressWarnings("cast")
+ // primitive cast to (long) is part of the pattern
+ private static Object castToWrapperOrNull(long value, Class<?> dst) {
+ if (dst == int.class || dst == Integer.class) {
+ return (int) (value);
+ }
+ if (dst == long.class || dst == Long.class) {
+ return (long) (value);
+ }
+ if (dst == char.class || dst == Character.class) {
+ return (char) (value);
+ }
+ if (dst == short.class || dst == Short.class) {
+ return (short) (value);
+ }
+ if (dst == float.class || dst == Float.class) {
+ return (float) (value);
+ }
+ if (dst == double.class || dst == Double.class) {
+ return (double) (value);
+ }
+ if (dst == byte.class || dst == Byte.class) {
+ return (byte) (value);
+ }
+ if (dst == boolean.class || dst == boolean.class) {
+ return ((value % 29) & 1) == 0;
+ }
+ return null;
+ }
+}