Mercurial > hg > shark
changeset 30:43bc68e00352
Import the other java.dyn unit tests
author | Gary Benson <gbenson@redhat.com> |
---|---|
date | Tue, 01 Mar 2011 17:09:50 +0000 |
parents | f5794124fd78 |
children | e394d06d764d |
files | Makefile test/java/dyn/ClassValueTest.java test/java/dyn/InvokeGenericTest.java test/java/dyn/JavaDocExamplesTest.java |
diffstat | 4 files changed, 837 insertions(+), 3 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile Tue Mar 01 14:33:05 2011 +0000 +++ b/Makefile Tue Mar 01 17:09:50 2011 +0000 @@ -25,16 +25,23 @@ diff -ru {~/work/icedtea6/ports/,}hotspot/src/$$i; \ done > patch.patch || true -test/java/dyn/MethodHandlesTest.class: test/java/dyn/MethodHandlesTest.java - $(JAVADIR)/bin/javac -cp $(JUNITJAR) $< +test/java/dyn/%.class: test/java/dyn/%.java + $(JAVADIR)/bin/javac -d . -cp $(JUNITJAR) $< -test: debugzero test/java/dyn/MethodHandlesTest.class +test: debugzero \ + test/java/dyn/ClassValueTest.class \ + test/java/dyn/InvokeGenericTest.class \ + test/java/dyn/JavaDocExamplesTest.class \ + test/java/dyn/MethodHandlesTest.class hotspot/build/linux/jdk-linux-zero/debug/bin/java \ -XX:+UnlockExperimentalVMOptions \ -XX:+EnableMethodHandles \ -XX:+EnableInvokeDynamic \ -Dtest.java.dyn.MethodHandlesTest.verbosity=0 \ -cp $(JUNITJAR):. org.junit.runner.JUnitCore \ + test.java.dyn.ClassValueTest \ + test.java.dyn.InvokeGenericTest \ + test.java.dyn.JavaDocExamplesTest \ test.java.dyn.MethodHandlesTest .PHONY: default $(TARGETS) build clean patch test
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/dyn/ClassValueTest.java Tue Mar 01 17:09:50 2011 +0000 @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2010, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +/* @test + * @summary tests for class-specific values + * @compile ClassValueTest.java + * @run junit/othervm test.java.dyn.ClassValueTest + */ + +/* + Manually: + $ $JAVA7X_HOME/bin/javac -d foo -cp $JUNIT4_JAR test/java/dyn/ClassValueTest.java + $ $JAVA7X_HOME/bin/java -cp foo:$JUNIT4_JAR org.junit.runner.JUnitCore test.java.dyn.ClassValueTest + Output: .testAdd => 1000 : Integer + */ + +package test.java.dyn; + +import java.util.*; + +import java.dyn.*; + +import org.junit.*; +import static org.junit.Assert.*; + +/** + * @author jrose + */ +public class ClassValueTest { + static String nameForCV1(Class<?> type) { + return "CV1:" + type.getName(); + } + static int countForCV1; + static final ClassValue<String> CV1 = new CV1(); + private static class CV1 extends ClassValue<String> { + protected String computeValue(Class<?> type) { + countForCV1++; + return nameForCV1(type); + } + } + + static final Class[] CLASSES = { + String.class, + Integer.class, + int.class, + boolean[].class, + char[][].class, + ClassValueTest.class + }; + + @Test + public void testGet() { + countForCV1 = 0; + for (Class c : CLASSES) { + assertEquals(nameForCV1(c), CV1.get(c)); + } + assertEquals(CLASSES.length, countForCV1); + for (Class c : CLASSES) { + assertEquals(nameForCV1(c), CV1.get(c)); + } + assertEquals(CLASSES.length, countForCV1); + } + + @Test + public void testRemove() { + for (Class c : CLASSES) { + CV1.get(c); + } + countForCV1 = 0; + int REMCOUNT = 3; + for (int i = 0; i < REMCOUNT; i++) { + CV1.remove(CLASSES[i]); + } + assertEquals(0, countForCV1); // no change + for (Class c : CLASSES) { + assertEquals(nameForCV1(c), CV1.get(c)); + } + assertEquals(REMCOUNT, countForCV1); + } + + static String nameForCVN(Class<?> type, int n) { + return "CV[" + n + "]" + type.getName(); + } + static int countForCVN; + static class CVN extends ClassValue<String> { + final int n; + CVN(int n) { this.n = n; } + protected String computeValue(Class<?> type) { + countForCVN++; + return nameForCVN(type, n); + } + }; + + @Test + public void testGetMany() { + int CVN_COUNT1 = 100, CVN_COUNT2 = 100; + CVN cvns[] = new CVN[CVN_COUNT1 * CVN_COUNT2]; + for (int n = 0; n < cvns.length; n++) { + cvns[n] = new CVN(n); + } + countForCVN = 0; + for (int pass = 0; pass <= 2; pass++) { + for (int i1 = 0; i1 < CVN_COUNT1; i1++) { + eachClass: + for (Class c : CLASSES) { + for (int i2 = 0; i2 < CVN_COUNT2; i2++) { + int n = i1*CVN_COUNT2 + i2; + assertEquals(0, countForCVN); + assertEquals(nameForCVN(c, n), cvns[n].get(c)); + cvns[n].get(c); //get it again + //System.out.println("getting "+n+":"+cvns[n].get(c)); + boolean doremove = (((i1 + i2) & 3) == 0); + switch (pass) { + case 0: + assertEquals(1, countForCVN); + break; + case 1: + // remove on middle pass + assertEquals(0, countForCVN); + if (doremove) { + //System.out.println("removing "+n+":"+cvns[n].get(c)); + cvns[n].remove(c); + assertEquals(0, countForCVN); + } + break; + case 2: + assertEquals(doremove ? 1 : 0, countForCVN); + break; + } + countForCVN = 0; + if (i1 > i2 && i1 < i2+5) continue eachClass; // leave diagonal gap + } + } + } + } + assertEquals(countForCVN, 0); + for (int n = 0; n < cvns.length; n++) { + for (Class c : CLASSES) { + assertEquals(nameForCVN(c, n), cvns[n].get(c)); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/dyn/InvokeGenericTest.java Tue Mar 01 17:09:50 2011 +0000 @@ -0,0 +1,484 @@ +/* + * Copyright (c) 2009, 2010, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +/* @test + * @summary unit tests for java.dyn.MethodHandle.invokeGeneric + * @compile -XDallowTransitionalJSR292=no -target 7 InvokeGenericTest.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.dyn.InvokeGenericTest + */ + +package test.java.dyn; + +import java.dyn.*; +import static java.dyn.MethodHandles.*; +import static java.dyn.MethodType.*; +import java.lang.reflect.*; +import java.util.*; +import org.junit.*; +import static org.junit.Assert.*; +import static org.junit.Assume.*; + + +/** + * + * @author jrose + */ +public class InvokeGenericTest { + // How much output? + static int verbosity = 0; + static { + String vstr = System.getProperty("test.java.dyn.InvokeGenericTest.verbosity"); + if (vstr != null) verbosity = Integer.parseInt(vstr); + } + + @Test + public void testFirst() throws Throwable { + verbosity += 9; try { + // left blank for debugging + } finally { printCounts(); verbosity -= 9; } + } + + public InvokeGenericTest() { + } + + @Before + public void checkImplementedPlatform() { + boolean platformOK = false; + Properties properties = System.getProperties(); + String vers = properties.getProperty("java.vm.version"); + String name = properties.getProperty("java.vm.name"); + String arch = properties.getProperty("os.arch"); + if ((arch.equals("amd64") || arch.equals("i386") || arch.equals("x86") || + arch.equals("sparc") || arch.equals("sparcv9")) && + (name.contains("Client") || name.contains("Server")) + ) { + platformOK = true; + } else { + System.err.println("Skipping tests for unsupported platform: "+Arrays.asList(vers, name, arch)); + } + assumeTrue(platformOK); + } + + String testName; + static int allPosTests, allNegTests; + int posTests, negTests; + @After + public void printCounts() { + if (verbosity >= 2 && (posTests | negTests) != 0) { + System.out.println(); + if (posTests != 0) System.out.println("=== "+testName+": "+posTests+" positive test cases run"); + if (negTests != 0) System.out.println("=== "+testName+": "+negTests+" negative test cases run"); + allPosTests += posTests; + allNegTests += negTests; + posTests = negTests = 0; + } + } + void countTest(boolean positive) { + if (positive) ++posTests; + else ++negTests; + } + void countTest() { countTest(true); } + void startTest(String name) { + if (testName != null) printCounts(); + if (verbosity >= 1) + System.out.println(name); + posTests = negTests = 0; + testName = name; + } + + @BeforeClass + public static void setUpClass() throws Exception { + calledLog.clear(); + calledLog.add(null); + nextArgVal = INITIAL_ARG_VAL; + } + + @AfterClass + public static void tearDownClass() throws Exception { + int posTests = allPosTests, negTests = allNegTests; + if (verbosity >= 2 && (posTests | negTests) != 0) { + System.out.println(); + if (posTests != 0) System.out.println("=== "+posTests+" total positive test cases"); + if (negTests != 0) System.out.println("=== "+negTests+" total negative test cases"); + } + } + + static List<Object> calledLog = new ArrayList<Object>(); + static Object logEntry(String name, Object... args) { + return Arrays.asList(name, Arrays.asList(args)); + } + static Object called(String name, Object... args) { + Object entry = logEntry(name, args); + calledLog.add(entry); + return entry; + } + static void assertCalled(String name, Object... args) { + Object expected = logEntry(name, args); + Object actual = calledLog.get(calledLog.size() - 1); + if (expected.equals(actual) && verbosity < 9) return; + System.out.println("assertCalled "+name+":"); + System.out.println("expected: "+expected); + System.out.println("actual: "+actual); + System.out.println("ex. types: "+getClasses(expected)); + System.out.println("act. types: "+getClasses(actual)); + assertEquals("previous method call", expected, actual); + } + static void printCalled(MethodHandle target, String name, Object... args) { + if (verbosity >= 3) + System.out.println("calling MH="+target+" to "+name+Arrays.toString(args)); + } + + 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); + } + + 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; + } + + static final int ONE_MILLION = (1000*1000), // first int value + TEN_BILLION = (10*1000*1000*1000), // scale factor to reach upper 32 bits + INITIAL_ARG_VAL = ONE_MILLION << 1; // <<1 makes space for sign bit; + static long nextArgVal; + 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; + } + static int nextArg() { + // Produce a 32-bit result something like ONE_MILLION+(smallint). + // Example: 1_000_042. + return (int) nextArg(false); + } + 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(); + } + + static Object randomArg(Class<?> param) { + Object wrap = castToWrapperOrNull(nextArg(param), param); + if (wrap != null) { + return wrap; + } +// import sun.dyn.util.Wrapper; +// Wrapper wrap = Wrapper.forBasicType(dst); +// if (wrap == Wrapper.OBJECT && Wrapper.isWrapperType(dst)) +// wrap = Wrapper.forWrapperType(dst); +// if (wrap != Wrapper.OBJECT) +// return wrap.wrap(nextArg++); + if (param.isInterface()) { + for (Class<?> c : param.getClasses()) { + if (param.isAssignableFrom(c) && !c.isInterface()) + { param = c; break; } + } + } + if (param.isInterface() || param.isAssignableFrom(String.class)) + return "#"+nextArg(); + else + try { + return param.newInstance(); + } catch (InstantiationException ex) { + } catch (IllegalAccessException ex) { + } + return null; // random class not Object, String, Integer, etc. + } + 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; + } + 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; + } + + static final Object ANON_OBJ = new Object(); + static Object zeroArg(Class<?> param) { + Object x = castToWrapperOrNull(0L, param); + if (x != null) return x; + if (param.isInterface() || param.isAssignableFrom(String.class)) return "\"\""; + if (param == Object.class) return ANON_OBJ; + if (param.getComponentType() != null) return Array.newInstance(param.getComponentType(), 0); + return null; + } + static Object[] zeroArgs(Class<?>... params) { + Object[] args = new Object[params.length]; + for (int i = 0; i < args.length; i++) + args[i] = zeroArg(params[i]); + return args; + } + static Object[] zeroArgs(List<Class<?>> params) { + return zeroArgs(params.toArray(new Class<?>[0])); + } + + static <T, E extends T> T[] array(Class<T[]> atype, E... a) { + return Arrays.copyOf(a, a.length, atype); + } + static <T> T[] cat(T[] a, T... b) { + int alen = a.length, blen = b.length; + if (blen == 0) return a; + T[] c = Arrays.copyOf(a, alen + blen); + System.arraycopy(b, 0, c, alen, blen); + return c; + } + static Integer[] boxAll(int... vx) { + Integer[] res = new Integer[vx.length]; + for (int i = 0; i < res.length; i++) { + res[i] = vx[i]; + } + return res; + } + static Object getClasses(Object x) { + if (x == null) return x; + if (x instanceof String) return x; // keep the name + if (x instanceof List) { + // recursively report classes of the list elements + Object[] xa = ((List)x).toArray(); + for (int i = 0; i < xa.length; i++) + xa[i] = getClasses(xa[i]); + return Arrays.asList(xa); + } + return x.getClass().getSimpleName(); + } + + static MethodHandle changeArgTypes(MethodHandle target, Class<?> argType) { + return changeArgTypes(target, 0, 999, argType); + } + static MethodHandle changeArgTypes(MethodHandle target, + int beg, int end, Class<?> argType) { + MethodType targetType = target.type(); + end = Math.min(end, targetType.parameterCount()); + ArrayList<Class<?>> argTypes = new ArrayList<Class<?>>(targetType.parameterList()); + Collections.fill(argTypes.subList(beg, end), argType); + MethodType ttype2 = MethodType.methodType(targetType.returnType(), argTypes); + return MethodHandles.convertArguments(target, ttype2); + } + + // This lookup is good for all members in and under InvokeGenericTest. + static final Lookup LOOKUP = MethodHandles.lookup(); + + Map<List<Class<?>>, MethodHandle> CALLABLES = new HashMap<List<Class<?>>, MethodHandle>(); + MethodHandle callable(List<Class<?>> params) { + MethodHandle mh = CALLABLES.get(params); + if (mh == null) { + mh = collectArguments(collector_MH, methodType(Object.class, params)); + CALLABLES.put(params, mh); + } + return mh; + } + MethodHandle callable(Class<?>... params) { + return callable(Arrays.asList(params)); + } + private static Object collector(Object... args) { + return Arrays.asList(args); + } + private static final MethodHandle collector_MH; + static { + try { + collector_MH + = LOOKUP.findStatic(LOOKUP.lookupClass(), + "collector", + methodType(Object.class, Object[].class)); + } catch (NoAccessException ex) { + throw new RuntimeException(ex); + } + } + + @Test + public void testSimple() throws Throwable { + startTest("testSimple"); + countTest(); + String[] args = { "one", "two" }; + MethodHandle mh = callable(Object.class, String.class); + Object res; List resl; + res = resl = (List) mh.invokeGeneric((String)args[0], (Object)args[1]); + //System.out.println(res); + assertEquals(Arrays.asList(args), res); + } + + @Test + public void testWrongArgumentCount() throws Throwable { + startTest("testWrongArgumentCount"); + for (int i = 0; i <= 10; i++) { + testWrongArgumentCount(Collections.<Class<?>>nCopies(i, Integer.class)); + if (i <= 4) { + testWrongArgumentCount(Collections.<Class<?>>nCopies(i, int.class)); + testWrongArgumentCount(Collections.<Class<?>>nCopies(i, long.class)); + } + } + } + public void testWrongArgumentCount(List<Class<?>> params) throws Throwable { + int max = params.size(); + for (int i = 0; i < max; i++) { + List<Class<?>> params2 = params.subList(0, i); + for (int k = 0; k <= 2; k++) { + if (k == 1) params = methodType(Object.class, params).generic().parameterList(); + if (k == 2) params2 = methodType(Object.class, params2).generic().parameterList(); + testWrongArgumentCount(params, params2); + testWrongArgumentCount(params2, params); + } + } + } + public void testWrongArgumentCount(List<Class<?>> expect, List<Class<?>> observe) throws Throwable { + countTest(false); + if (expect.equals(observe)) + assert(false); + MethodHandle target = callable(expect); + Object[] args = zeroArgs(observe); + Object junk; + try { + switch (args.length) { + case 0: + junk = target.invokeGeneric(); break; + case 1: + junk = target.invokeGeneric(args[0]); break; + case 2: + junk = target.invokeGeneric(args[0], args[1]); break; + case 3: + junk = target.invokeGeneric(args[0], args[1], args[2]); break; + case 4: + junk = target.invokeGeneric(args[0], args[1], args[2], args[3]); break; + default: + junk = target.invokeWithArguments(args); break; + } + } catch (WrongMethodTypeException ex) { + return; + } catch (Exception ex) { + throw new RuntimeException("wrong exception calling "+target+target.type()+" on "+Arrays.asList(args)+" : "+ex); + } + throw new RuntimeException("bad success calling "+target+target.type()+" on "+Arrays.asList(args)); + } + + /** Make a list of all combinations of the given types, with the given arities. + * A void return type is possible iff the first type is void.class. + */ + static List<MethodType> allMethodTypes(int minargc, int maxargc, Class<?>... types) { + ArrayList<MethodType> result = new ArrayList<MethodType>(); + if (types.length > 0) { + ArrayList<MethodType> argcTypes = new ArrayList<MethodType>(); + // build arity-zero types first + for (Class<?> rtype : types) { + argcTypes.add(MethodType.methodType(rtype)); + } + if (types[0] == void.class) + // void is not an argument type + types = Arrays.copyOfRange(types, 1, types.length); + for (int argc = 0; argc <= maxargc; argc++) { + if (argc >= minargc) + result.addAll(argcTypes); + if (argc >= maxargc) + break; + ArrayList<MethodType> prevTypes = argcTypes; + argcTypes = new ArrayList<MethodType>(); + for (MethodType prevType : prevTypes) { + for (Class<?> ptype : types) { + argcTypes.add(prevType.insertParameterTypes(argc, ptype)); + } + } + } + } + return Collections.unmodifiableList(result); + } + static List<MethodType> allMethodTypes(int argc, Class<?>... types) { + return allMethodTypes(argc, argc, types); + } + + interface RandomInterface { } + + MethodHandle toString_MH; + + @Test + public void testReferenceConversions() throws Throwable { + startTest("testReferenceConversions"); + toString_MH = LOOKUP. + findVirtual(Object.class, "toString", MethodType.methodType(String.class)); + String[] args = { "one", "two" }; + for (MethodType type : allMethodTypes(2, Object.class, String.class, RandomInterface.class)) { + testReferenceConversions(type, args); + } + } + public void testReferenceConversions(MethodType type, Object... args) throws Throwable { + countTest(); + if (verbosity > 3) System.out.println("target type: "+type); + MethodHandle mh = callable(type.parameterList()); + MethodHandle tsdrop = MethodHandles.dropArguments(toString_MH, 1, type.parameterList()); + mh = MethodHandles.foldArguments(tsdrop, mh); + mh = mh.asType(type); + Object res = mh.invokeGeneric((String)args[0], (Object)args[1]); + //System.out.println(res); + assertEquals(Arrays.asList(args).toString(), res); + } + + + @Test @Ignore("known failure pending 6939861") + public void testBoxConversions() throws Throwable { + startTest("testBoxConversions"); + countTest(); + Integer[] args = { 1, 2 }; + MethodHandle mh = callable(Object.class, int.class); + Object res; List resl; + res = resl = (List) mh.invokeGeneric((int)args[0], (Object)args[1]); + //System.out.println(res); + assertEquals(Arrays.asList(args), res); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/dyn/JavaDocExamplesTest.java Tue Mar 01 17:09:50 2011 +0000 @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2009, 2010, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +/* @test + * @summary example code used in javadoc for java.dyn API + * @compile -XDallowTransitionalJSR292=no JavaDocExamplesTest.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.dyn.JavaDocExamplesTest + */ + +/* +---- To run outside jtreg: +$ $JAVA7X_HOME/bin/javac -cp $JUNIT4_JAR -d /tmp/Classes \ + $DAVINCI/sources/jdk/test/java/dyn/JavaDocExamplesTest.java +$ $JAVA7X_HOME/bin/java -cp $JUNIT4_JAR:/tmp/Classes \ + -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles \ + -Dtest.java.dyn.JavaDocExamplesTest.verbosity=1 \ + test.java.dyn.JavaDocExamplesTest +---- +*/ + +package test.java.dyn; + +import java.dyn.*; +import static java.dyn.MethodHandles.*; +import static java.dyn.MethodType.*; + +import java.lang.reflect.*; +import java.util.*; + +import org.junit.*; +import static org.junit.Assert.*; +import static org.junit.Assume.*; + + +/** + * @author jrose + */ +public class JavaDocExamplesTest { + /** Wrapper for running the JUnit tests in this module. + * Put JUnit on the classpath! + */ + public static void main(String... ignore) { + org.junit.runner.JUnitCore.runClasses(JavaDocExamplesTest.class); + } + // How much output? + static int verbosity = Integer.getInteger("test.java.dyn.JavaDocExamplesTest.verbosity", 0); + +{} +static final private Lookup LOOKUP = lookup(); +// static final private MethodHandle CONCAT_1 = LOOKUP.findVirtual(String.class, +// "concat", methodType(String.class, String.class)); +// static final private MethodHandle HASHCODE_1 = LOOKUP.findVirtual(Object.class, +// "hashCode", methodType(int.class)); + +// form required if NoAccessException is intercepted: +static final private MethodHandle CONCAT_2, HASHCODE_2; +static { + try { + CONCAT_2 = LOOKUP.findVirtual(String.class, + "concat", methodType(String.class, String.class)); + HASHCODE_2 = LOOKUP.findVirtual(Object.class, + "hashCode", methodType(int.class)); + } catch (NoAccessException ex) { + throw new RuntimeException(ex); + } +} +{} + + @Test public void testFindVirtual() throws Throwable { +{} +MethodHandle CONCAT_3 = LOOKUP.findVirtual(String.class, + "concat", methodType(String.class, String.class)); +MethodHandle HASHCODE_3 = LOOKUP.findVirtual(Object.class, + "hashCode", methodType(int.class)); +//assertEquals("xy", (String) CONCAT_1.invokeExact("x", "y")); +assertEquals("xy", (String) CONCAT_2.invokeExact("x", "y")); +assertEquals("xy", (String) CONCAT_3.invokeExact("x", "y")); +//assertEquals("xy".hashCode(), (int) HASHCODE_1.invokeExact((Object)"xy")); +assertEquals("xy".hashCode(), (int) HASHCODE_2.invokeExact((Object)"xy")); +assertEquals("xy".hashCode(), (int) HASHCODE_3.invokeExact((Object)"xy")); +{} + } + @Test public void testDropArguments() throws Throwable { + {{ +{} /// JAVADOC +MethodHandle cat = lookup().findVirtual(String.class, + "concat", methodType(String.class, String.class)); +assertEquals("xy", (String) cat.invokeExact("x", "y")); +MethodHandle d0 = dropArguments(cat, 0, String.class); +assertEquals("yz", (String) d0.invokeExact("x", "y", "z")); +MethodHandle d1 = dropArguments(cat, 1, String.class); +assertEquals("xz", (String) d1.invokeExact("x", "y", "z")); +MethodHandle d2 = dropArguments(cat, 2, String.class); +assertEquals("xy", (String) d2.invokeExact("x", "y", "z")); +MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class); +assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z")); + }} + } + + @Test public void testFilterArguments() throws Throwable { + {{ +{} /// JAVADOC +MethodHandle cat = lookup().findVirtual(String.class, + "concat", methodType(String.class, String.class)); +MethodHandle upcase = lookup().findVirtual(String.class, + "toUpperCase", methodType(String.class)); +assertEquals("xy", (String) cat.invokeExact("x", "y")); +MethodHandle f0 = filterArguments(cat, 0, upcase); +assertEquals("Xy", (String) f0.invokeExact("x", "y")); // Xy +MethodHandle f1 = filterArguments(cat, 1, upcase); +assertEquals("xY", (String) f1.invokeExact("x", "y")); // xY +MethodHandle f2 = filterArguments(cat, 0, upcase, upcase); +assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY + }} + } + + static void assertEquals(Object exp, Object act) { + if (verbosity > 0) + System.out.println("result: "+act); + Assert.assertEquals(exp, act); + } + +static MethodHandle asList; + @Test public void testWithTypeHandler() throws Throwable { + {{ +{} /// JAVADOC +MethodHandle makeEmptyList = MethodHandles.constant(List.class, Arrays.asList()); +MethodHandle asList = lookup() + .findStatic(Arrays.class, "asList", methodType(List.class, Object[].class)); + +JavaDocExamplesTest.asList = asList; +/* +static MethodHandle collectingTypeHandler(MethodHandle base, MethodType newType) { + return asList.asCollector(Object[].class, newType.parameterCount()).asType(newType); +} +*/ + +MethodHandle collectingTypeHandler = lookup() + .findStatic(lookup().lookupClass(), "collectingTypeHandler", + methodType(MethodHandle.class, MethodHandle.class, MethodType.class)); +MethodHandle makeAnyList = makeEmptyList.withTypeHandler(collectingTypeHandler); + +assertEquals("[]", makeAnyList.invokeGeneric().toString()); +assertEquals("[1]", makeAnyList.invokeGeneric(1).toString()); +assertEquals("[two, too]", makeAnyList.invokeGeneric("two", "too").toString()); + }} + } + +static MethodHandle collectingTypeHandler(MethodHandle base, MethodType newType) { + //System.out.println("Converting "+asList+" to "+newType); + MethodHandle conv = asList.asCollector(Object[].class, newType.parameterCount()).asType(newType); + //System.out.println(" =>"+conv); + return conv; +} + +}