Path: blob/master/test/jdk/java/lang/invoke/MethodHandles/TestTableSwitch.java
41152 views
/*1* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @run testng/othervm -Xverify:all TestTableSwitch26*/2728import org.testng.annotations.DataProvider;29import org.testng.annotations.Test;3031import javax.management.ObjectName;32import java.lang.invoke.MethodHandle;33import java.lang.invoke.MethodHandles;34import java.lang.invoke.MethodType;35import java.util.ArrayList;36import java.util.List;37import java.util.function.IntConsumer;38import java.util.function.IntFunction;3940import static org.testng.Assert.assertEquals;4142public class TestTableSwitch {4344static final MethodHandle MH_IntConsumer_accept;45static final MethodHandle MH_check;4647static {48try {49MethodHandles.Lookup lookup = MethodHandles.lookup();50MH_IntConsumer_accept = lookup.findVirtual(IntConsumer.class, "accept",51MethodType.methodType(void.class, int.class));52MH_check = lookup.findStatic(TestTableSwitch.class, "check",53MethodType.methodType(void.class, List.class, Object[].class));54} catch (ReflectiveOperationException e) {55throw new ExceptionInInitializerError(e);56}57}5859public static MethodHandle simpleTestCase(String value) {60return simpleTestCase(String.class, value);61}6263public static MethodHandle simpleTestCase(Class<?> type, Object value) {64return MethodHandles.dropArguments(MethodHandles.constant(type, value), 0, int.class);65}6667public static Object testValue(Class<?> type) {68if (type == String.class) {69return "X";70} else if (type == byte.class) {71return (byte) 42;72} else if (type == short.class) {73return (short) 84;74} else if (type == char.class) {75return 'Y';76} else if (type == int.class) {77return 168;78} else if (type == long.class) {79return 336L;80} else if (type == float.class) {81return 42F;82} else if (type == double.class) {83return 84D;84} else if (type == boolean.class) {85return true;86}87return null;88}8990static final Class<?>[] TEST_TYPES = {91Object.class,92String.class,93byte.class,94short.class,95char.class,96int.class,97long.class,98float.class,99double.class,100boolean.class101};102103public static Object[] testArguments(int caseNum, List<Object> testValues) {104Object[] args = new Object[testValues.size() + 1];105args[0] = caseNum;106int insertPos = 1;107for (Object testValue : testValues) {108args[insertPos++] = testValue;109}110return args;111}112113@DataProvider114public static Object[][] nonVoidCases() {115List<Object[]> tests = new ArrayList<>();116117for (Class<?> returnType : TEST_TYPES) {118for (int numCases = 1; numCases < 5; numCases++) {119tests.add(new Object[] { returnType, numCases, List.of() });120tests.add(new Object[] { returnType, numCases, List.of(TEST_TYPES) });121}122}123124return tests.toArray(Object[][]::new);125}126127private static void check(List<Object> testValues, Object[] collectedValues) {128assertEquals(collectedValues, testValues.toArray());129}130131@Test(dataProvider = "nonVoidCases")132public void testNonVoidHandles(Class<?> type, int numCases, List<Class<?>> additionalTypes) throws Throwable {133MethodHandle collector = MH_check;134List<Object> testArguments = new ArrayList<>();135collector = MethodHandles.insertArguments(collector, 0, testArguments);136collector = collector.asCollector(Object[].class, additionalTypes.size());137138Object defaultReturnValue = testValue(type);139MethodHandle defaultCase = simpleTestCase(type, defaultReturnValue);140defaultCase = MethodHandles.collectArguments(defaultCase, 1, collector);141Object[] returnValues = new Object[numCases];142MethodHandle[] cases = new MethodHandle[numCases];143for (int i = 0; i < cases.length; i++) {144Object returnValue = testValue(type);145returnValues[i] = returnValue;146MethodHandle theCase = simpleTestCase(type, returnValue);147theCase = MethodHandles.collectArguments(theCase, 1, collector);148cases[i] = theCase;149}150151MethodHandle mhSwitch = MethodHandles.tableSwitch(152defaultCase,153cases154);155156for (Class<?> additionalType : additionalTypes) {157testArguments.add(testValue(additionalType));158}159160assertEquals(mhSwitch.invokeWithArguments(testArguments(-1, testArguments)), defaultReturnValue);161162for (int i = 0; i < numCases; i++) {163assertEquals(mhSwitch.invokeWithArguments(testArguments(i, testArguments)), returnValues[i]);164}165166assertEquals(mhSwitch.invokeWithArguments(testArguments(numCases, testArguments)), defaultReturnValue);167}168169@Test170public void testVoidHandles() throws Throwable {171IntFunction<MethodHandle> makeTestCase = expectedIndex -> {172IntConsumer test = actualIndex -> assertEquals(actualIndex, expectedIndex);173return MH_IntConsumer_accept.bindTo(test);174};175176MethodHandle mhSwitch = MethodHandles.tableSwitch(177/* default: */ makeTestCase.apply(-1),178/* case 0: */ makeTestCase.apply(0),179/* case 1: */ makeTestCase.apply(1),180/* case 2: */ makeTestCase.apply(2)181);182183mhSwitch.invokeExact((int) -1);184mhSwitch.invokeExact((int) 0);185mhSwitch.invokeExact((int) 1);186mhSwitch.invokeExact((int) 2);187}188189@Test(expectedExceptions = NullPointerException.class)190public void testNullDefaultHandle() {191MethodHandles.tableSwitch(null, simpleTestCase("test"));192}193194@Test(expectedExceptions = NullPointerException.class)195public void testNullCases() {196MethodHandle[] cases = null;197MethodHandles.tableSwitch(simpleTestCase("default"), cases);198}199200@Test(expectedExceptions = NullPointerException.class)201public void testNullCase() {202MethodHandles.tableSwitch(simpleTestCase("default"), simpleTestCase("case"), null);203}204205@Test(expectedExceptions = IllegalArgumentException.class,206expectedExceptionsMessageRegExp = ".*Not enough cases.*")207public void testNotEnoughCases() {208MethodHandles.tableSwitch(simpleTestCase("default"));209}210211@Test(expectedExceptions = IllegalArgumentException.class,212expectedExceptionsMessageRegExp = ".*Case actions must have int as leading parameter.*")213public void testNotEnoughParameters() {214MethodHandle empty = MethodHandles.empty(MethodType.methodType(void.class));215MethodHandles.tableSwitch(empty, empty, empty);216}217218@Test(expectedExceptions = IllegalArgumentException.class,219expectedExceptionsMessageRegExp = ".*Case actions must have int as leading parameter.*")220public void testNoLeadingIntParameter() {221MethodHandle empty = MethodHandles.empty(MethodType.methodType(void.class, double.class));222MethodHandles.tableSwitch(empty, empty, empty);223}224225@Test(expectedExceptions = IllegalArgumentException.class,226expectedExceptionsMessageRegExp = ".*Case actions must have the same type.*")227public void testWrongCaseType() {228// doesn't return a String229MethodHandle wrongType = MethodHandles.empty(MethodType.methodType(void.class, int.class));230MethodHandles.tableSwitch(simpleTestCase("default"), simpleTestCase("case"), wrongType);231}232233}234235236