1 /* 2 * Copyright (c) 2018, 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 24 import java.lang.invoke.MethodType; 25 import java.lang.constant.ClassDesc; 26 import java.lang.constant.MethodTypeDesc; 27 import java.util.Arrays; 28 import java.util.List; 29 import java.util.stream.IntStream; 30 import java.util.stream.Stream; 31 32 import org.testng.annotations.Test; 33 34 import static java.lang.constant.ConstantDescs.CD_int; 35 import static java.lang.constant.ConstantDescs.CD_void; 36 import static java.util.stream.Collectors.joining; 37 import static java.util.stream.Collectors.toList; 38 import static org.testng.Assert.assertEquals; 39 import static org.testng.Assert.fail; 40 41 /** 42 * @test 43 * @compile MethodTypeDescTest.java 44 * @run testng MethodTypeDescTest 45 * @summary unit tests for java.lang.constant.MethodTypeDesc 46 */ 47 @Test 48 public class MethodTypeDescTest extends SymbolicDescTest { 49 50 private void testMethodTypeDesc(MethodTypeDesc r) throws ReflectiveOperationException { 51 testSymbolicDesc(r); 52 53 // Tests accessors (rType, pType, pCount, pList, pArray, descriptorString), 54 // factories (ofDescriptor, of), equals 55 assertEquals(r, MethodTypeDesc.ofDescriptor(r.descriptorString())); 56 assertEquals(r, MethodTypeDesc.of(r.returnType(), r.parameterArray())); 57 assertEquals(r, MethodTypeDesc.of(r.returnType(), r.parameterList().toArray(new ClassDesc[0]))); 58 assertEquals(r, MethodTypeDesc.of(r.returnType(), r.parameterList().stream().toArray(ClassDesc[]::new))); 59 assertEquals(r, MethodTypeDesc.of(r.returnType(), IntStream.range(0, r.parameterCount()) 60 .mapToObj(r::parameterType) 61 .toArray(ClassDesc[]::new))); 62 } 63 64 private void testMethodTypeDesc(MethodTypeDesc r, MethodType mt) throws ReflectiveOperationException { 65 testMethodTypeDesc(r); 66 67 assertEquals(r.resolveConstantDesc(LOOKUP), mt); 68 assertEquals(mt.describeConstable().get(), r); 69 70 assertEquals(r.descriptorString(), mt.toMethodDescriptorString()); 71 assertEquals(r.parameterCount(), mt.parameterCount()); 72 assertEquals(r.parameterList(), mt.parameterList().stream().map(SymbolicDescTest::classToDesc).collect(toList())); 73 assertEquals(r.parameterArray(), Stream.of(mt.parameterArray()).map(SymbolicDescTest::classToDesc).toArray(ClassDesc[]::new)); 74 for (int i=0; i<r.parameterCount(); i++) 75 assertEquals(r.parameterType(i), classToDesc(mt.parameterType(i))); 76 assertEquals(r.returnType(), classToDesc(mt.returnType())); 77 } 78 79 private void assertMethodType(ClassDesc returnType, 80 ClassDesc... paramTypes) throws ReflectiveOperationException { 81 String descriptor = Stream.of(paramTypes).map(ClassDesc::descriptorString).collect(joining("", "(", ")")) 82 + returnType.descriptorString(); 83 MethodTypeDesc mtDesc = MethodTypeDesc.of(returnType, paramTypes); 84 85 // MTDesc accessors 86 assertEquals(descriptor, mtDesc.descriptorString()); 87 assertEquals(returnType, mtDesc.returnType()); 88 assertEquals(paramTypes, mtDesc.parameterArray()); 89 assertEquals(Arrays.asList(paramTypes), mtDesc.parameterList()); 90 assertEquals(paramTypes.length, mtDesc.parameterCount()); 91 for (int i=0; i<paramTypes.length; i++) 92 assertEquals(paramTypes[i], mtDesc.parameterType(i)); 93 94 // Consistency between MT and MTDesc 95 MethodType mt = MethodType.fromMethodDescriptorString(descriptor, null); 96 testMethodTypeDesc(mtDesc, mt); 97 98 // changeReturnType 99 for (String r : returnDescs) { 100 ClassDesc rc = ClassDesc.ofDescriptor(r); 101 MethodTypeDesc newDesc = mtDesc.changeReturnType(rc); 102 assertEquals(newDesc, MethodTypeDesc.of(rc, paramTypes)); 103 testMethodTypeDesc(newDesc, mt.changeReturnType((Class<?>)rc.resolveConstantDesc(LOOKUP))); 104 } 105 106 // changeParamType 107 for (int i=0; i<paramTypes.length; i++) { 108 for (String p : paramDescs) { 109 ClassDesc pc = ClassDesc.ofDescriptor(p); 110 ClassDesc[] ps = paramTypes.clone(); 111 ps[i] = pc; 112 MethodTypeDesc newDesc = mtDesc.changeParameterType(i, pc); 113 assertEquals(newDesc, MethodTypeDesc.of(returnType, ps)); 114 testMethodTypeDesc(newDesc, mt.changeParameterType(i, (Class<?>)pc.resolveConstantDesc(LOOKUP))); 115 } 116 } 117 118 // dropParamType 119 for (int i=0; i<paramTypes.length; i++) { 120 int k = i; 121 ClassDesc[] ps = IntStream.range(0, paramTypes.length) 122 .filter(j -> j != k) 123 .mapToObj(j -> paramTypes[j]) 124 .toArray(ClassDesc[]::new); 125 MethodTypeDesc newDesc = mtDesc.dropParameterTypes(i, i + 1); 126 assertEquals(newDesc, MethodTypeDesc.of(returnType, ps)); 127 testMethodTypeDesc(newDesc, mt.dropParameterTypes(i, i+1)); 128 } 129 130 badDropParametersTypes(CD_void, paramDescs); 131 132 // addParam 133 for (int i=0; i <= paramTypes.length; i++) { 134 for (ClassDesc p : paramTypes) { 135 int k = i; 136 ClassDesc[] ps = IntStream.range(0, paramTypes.length + 1) 137 .mapToObj(j -> (j < k) ? paramTypes[j] : (j == k) ? p : paramTypes[j-1]) 138 .toArray(ClassDesc[]::new); 139 MethodTypeDesc newDesc = mtDesc.insertParameterTypes(i, p); 140 assertEquals(newDesc, MethodTypeDesc.of(returnType, ps)); 141 testMethodTypeDesc(newDesc, mt.insertParameterTypes(i, (Class<?>)p.resolveConstantDesc(LOOKUP))); 142 } 143 } 144 145 badInsertParametersTypes(CD_void, paramDescs); 146 } 147 148 private void badInsertParametersTypes(ClassDesc returnType, String... paramDescTypes) { 149 ClassDesc[] paramTypes = 150 IntStream.rangeClosed(0, paramDescTypes.length - 1) 151 .mapToObj(i -> ClassDesc.ofDescriptor(paramDescTypes[i])).toArray(ClassDesc[]::new); 152 MethodTypeDesc mtDesc = MethodTypeDesc.of(returnType, paramTypes); 153 try { 154 MethodTypeDesc newDesc = mtDesc.insertParameterTypes(-1, paramTypes); 155 fail("pos < 0 should have failed"); 156 } catch (IndexOutOfBoundsException ex) { 157 // good 158 } 159 160 try { 161 MethodTypeDesc newDesc = mtDesc.insertParameterTypes(paramTypes.length + 1, paramTypes); 162 fail("pos > current arguments length should have failed"); 163 } catch (IndexOutOfBoundsException ex) { 164 // good 165 } 166 } 167 168 private void badDropParametersTypes(ClassDesc returnType, String... paramDescTypes) { 169 ClassDesc[] paramTypes = 170 IntStream.rangeClosed(0, paramDescTypes.length - 1) 171 .mapToObj(i -> ClassDesc.ofDescriptor(paramDescTypes[i])).toArray(ClassDesc[]::new); 172 MethodTypeDesc mtDesc = MethodTypeDesc.of(returnType, paramTypes); 173 try { 174 MethodTypeDesc newDesc = mtDesc.dropParameterTypes(-1, 0); 175 fail("start index < 0 should have failed"); 176 } catch (IndexOutOfBoundsException ex) { 177 // good 178 } 179 180 try { 181 MethodTypeDesc newDesc = mtDesc.dropParameterTypes(paramTypes.length, 0); 182 fail("start index = arguments.length should have failed"); 183 } catch (IndexOutOfBoundsException ex) { 184 // good 185 } 186 187 try { 188 MethodTypeDesc newDesc = mtDesc.dropParameterTypes(paramTypes.length + 1, 0); 189 fail("start index > arguments.length should have failed"); 190 } catch (IndexOutOfBoundsException ex) { 191 // good 192 } 193 194 try { 195 MethodTypeDesc newDesc = mtDesc.dropParameterTypes(0, paramTypes.length + 1); 196 fail("end index > arguments.length should have failed"); 197 } catch (IndexOutOfBoundsException ex) { 198 // good 199 } 200 201 try { 202 MethodTypeDesc newDesc = mtDesc.dropParameterTypes(1, 0); 203 fail("start index > end index should have failed"); 204 } catch (IllegalArgumentException ex) { 205 // good 206 } 207 } 208 209 public void testMethodTypeDesc() throws ReflectiveOperationException { 210 for (String r : returnDescs) { 211 assertMethodType(ClassDesc.ofDescriptor(r)); 212 for (String p1 : paramDescs) { 213 assertMethodType(ClassDesc.ofDescriptor(r), ClassDesc.ofDescriptor(p1)); 214 for (String p2 : paramDescs) { 215 assertMethodType(ClassDesc.ofDescriptor(r), ClassDesc.ofDescriptor(p1), ClassDesc.ofDescriptor(p2)); 216 } 217 } 218 } 219 } 220 221 public void testBadMethodTypeRefs() { 222 List<String> badDescriptors = List.of("()II", "()I;", "(I;)", "(I)", "()L", "(V)V", 223 "(java.lang.String)V", "()[]", "(Ljava/lang/String)V", 224 "(Ljava.lang.String;)V", "(java/lang/String)V"); 225 226 for (String d : badDescriptors) { 227 try { 228 MethodTypeDesc r = MethodTypeDesc.ofDescriptor(d); 229 fail(d); 230 } 231 catch (IllegalArgumentException e) { 232 // good 233 } 234 } 235 236 // try with void arguments, this will stress another code path in particular 237 // ConstantMethodTypeDesc::init 238 try { 239 MethodTypeDesc r = MethodTypeDesc.of(CD_int, CD_void); 240 fail("can't reach here"); 241 } 242 catch (IllegalArgumentException e) { 243 // good 244 } 245 } 246 }