1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17package libcore.java.lang.invoke; 18 19import junit.framework.TestCase; 20 21import java.lang.invoke.MethodType; 22import java.util.Arrays; 23import java.util.List; 24 25public class MethodTypeTest extends TestCase { 26 private static final Class<?>[] LARGE_PARAMETER_ARRAY; 27 28 static { 29 LARGE_PARAMETER_ARRAY = new Class<?>[254]; 30 for (int i = 0; i < 254; ++i) { 31 LARGE_PARAMETER_ARRAY[i] = Object.class; 32 } 33 } 34 35 public void test_methodType_basicTestsReturnTypeAndParameterClassArray() { 36 MethodType mt = MethodType.methodType(int.class, 37 new Class<?>[] { String.class, long.class}); 38 39 assertEquals(int.class, mt.returnType()); 40 assertParameterTypes(mt, String.class, long.class); 41 42 try { 43 MethodType.methodType(null, new Class<?>[] { String.class }); 44 fail(); 45 } catch (NullPointerException expected) { 46 } 47 48 try { 49 MethodType.methodType(int.class, (Class<?>[]) null); 50 fail(); 51 } catch (NullPointerException expected) { 52 } 53 54 try { 55 MethodType.methodType(int.class, new Class<?>[] {void.class}); 56 fail(); 57 } catch (IllegalArgumentException expected) { 58 } 59 } 60 61 public void test_methodType_basicTestsReturnTypeAndParameterClassList() { 62 MethodType mt = MethodType.methodType(int.class, Arrays.asList(String.class, long.class)); 63 64 assertEquals(int.class, mt.returnType()); 65 assertParameterTypes(mt, String.class, long.class); 66 67 try { 68 MethodType.methodType(null, Arrays.asList(String.class)); 69 fail(); 70 } catch (NullPointerException expected) { 71 } 72 73 try { 74 MethodType.methodType(int.class, (List<Class<?>>) null); 75 fail(); 76 } catch (NullPointerException expected) { 77 } 78 79 try { 80 MethodType.methodType(int.class, Arrays.asList(void.class)); 81 fail(); 82 } catch (IllegalArgumentException expected) { 83 } 84 } 85 86 public void test_methodType_basicTestsReturnTypeAndVarargsParameters() { 87 MethodType mt = MethodType.methodType(int.class, String.class, long.class); 88 89 assertEquals(int.class, mt.returnType()); 90 assertParameterTypes(mt, String.class, long.class); 91 92 try { 93 MethodType.methodType(null, String.class); 94 fail(); 95 } catch (NullPointerException expected) { 96 } 97 98 try { 99 MethodType.methodType(int.class, String.class, null); 100 fail(); 101 } catch (NullPointerException expected) { 102 } 103 104 try { 105 MethodType.methodType(int.class, void.class, String.class); 106 fail(); 107 } catch (IllegalArgumentException expected) { 108 } 109 } 110 111 public void test_methodType_basicTestsReturnTypeOnly() { 112 MethodType mt = MethodType.methodType(int.class); 113 114 assertEquals(int.class, mt.returnType()); 115 assertEquals(0, mt.parameterCount()); 116 117 try { 118 MethodType.methodType(null); 119 fail(); 120 } catch (NullPointerException expected) { 121 } 122 } 123 124 public void test_methodType_basicTestsReturnTypeAndSingleParameter() { 125 MethodType mt = MethodType.methodType(int.class, long.class); 126 127 assertEquals(int.class, mt.returnType()); 128 assertParameterTypes(mt, long.class); 129 130 try { 131 MethodType.methodType(null); 132 fail(); 133 } catch (NullPointerException expected) { 134 } 135 136 try { 137 MethodType.methodType(null, String.class); 138 fail(); 139 } catch (NullPointerException expected) { 140 } 141 142 try { 143 MethodType.methodType(int.class, (Class<?>) null); 144 fail(); 145 } catch (NullPointerException expected) { 146 } 147 148 try { 149 MethodType.methodType(int.class, void.class); 150 fail(); 151 } catch (IllegalArgumentException expected) { 152 } 153 } 154 155 public void test_methodType_basicTestsReturnTypeAndMethodTypeParameters() { 156 MethodType mt = MethodType.methodType(int.class, long.class, String.class); 157 assertEquals(int.class, mt.returnType()); 158 159 MethodType mt2 = MethodType.methodType(long.class, mt); 160 161 assertEquals(long.class, mt2.returnType()); 162 assertEquals(long.class, mt2.parameterType(0)); 163 assertEquals(String.class, mt2.parameterType(1)); 164 165 try { 166 MethodType.methodType(int.class, (MethodType) null); 167 fail(); 168 } catch (NullPointerException expected) { 169 } 170 } 171 172 public void testGenericMethodType() { 173 MethodType mt = MethodType.genericMethodType(0); 174 assertEquals(0, mt.parameterCount()); 175 assertEquals(Object.class, mt.returnType()); 176 177 mt = MethodType.genericMethodType(3); 178 assertEquals(Object.class, mt.returnType()); 179 180 assertEquals(3, mt.parameterCount()); 181 assertParameterTypes(mt, Object.class, Object.class, Object.class); 182 183 try { 184 MethodType.genericMethodType(-1); 185 fail(); 186 } catch (IllegalArgumentException expected) { 187 } 188 189 try { 190 MethodType.genericMethodType(256); 191 fail(); 192 } catch (IllegalArgumentException expected) { 193 } 194 } 195 196 public void testGenericMethodTypeWithTrailingArray() { 197 MethodType mt = MethodType.genericMethodType(3, false /* finalArray */); 198 assertEquals(Object.class, mt.returnType()); 199 assertParameterTypes(mt, Object.class, Object.class, Object.class); 200 201 mt = MethodType.genericMethodType(0, true /* finalArray */); 202 assertEquals(Object.class, mt.returnType()); 203 assertParameterTypes(mt, Object[].class); 204 205 mt = MethodType.genericMethodType(2, true /* finalArray */); 206 assertEquals(Object.class, mt.returnType()); 207 assertParameterTypes(mt, Object.class, Object.class, Object[].class); 208 209 try { 210 MethodType.genericMethodType(-1, true); 211 fail(); 212 } catch (IllegalArgumentException expected) { 213 } 214 215 try { 216 MethodType.genericMethodType(255, true); 217 fail(); 218 } catch (IllegalArgumentException expected) { 219 } 220 } 221 222 public void testChangeParameterType() { 223 // int method(String, Object, List); 224 MethodType mt = MethodType.methodType(int.class, String.class, Object.class, List.class); 225 assertEquals(Object.class, mt.parameterType(1)); 226 227 MethodType changed = mt.changeParameterType(1, String.class); 228 assertEquals(String.class, changed.parameterType(1)); 229 230 // Assert that the return types and the other parameter types haven't changed. 231 assertEquals(mt.parameterCount(), changed.parameterCount()); 232 assertEquals(mt.returnType(), changed.returnType()); 233 assertEquals(mt.parameterType(0), changed.parameterType(0)); 234 assertEquals(mt.parameterType(2), changed.parameterType(2)); 235 236 try { 237 mt.changeParameterType(-1, String.class); 238 fail(); 239 } catch (ArrayIndexOutOfBoundsException expected) { 240 } 241 242 try { 243 mt.changeParameterType(3, String.class); 244 fail(); 245 } catch (ArrayIndexOutOfBoundsException expected) { 246 } 247 248 try { 249 mt.changeParameterType(1, void.class); 250 fail(); 251 } catch (IllegalArgumentException expected) { 252 } 253 254 try { 255 mt.changeParameterType(1, null); 256 fail(); 257 } catch (NullPointerException expected) { 258 } 259 } 260 261 public void testInsertParameterTypes_varargs() { 262 MethodType mt = MethodType.methodType(int.class, String.class, Object.class); 263 264 MethodType insert0 = mt.insertParameterTypes(0, Integer.class, Long.class); 265 assertEquals(int.class, insert0.returnType()); 266 assertParameterTypes(insert0, Integer.class, Long.class, String.class, Object.class); 267 268 MethodType insert1 = mt.insertParameterTypes(1, Integer.class, Long.class); 269 assertParameterTypes(insert1, String.class, Integer.class, Long.class, Object.class); 270 271 MethodType insert2 = mt.insertParameterTypes(2, Integer.class, Long.class); 272 assertParameterTypes(insert2, String.class, Object.class, Integer.class, Long.class); 273 274 try { 275 mt.insertParameterTypes(1, LARGE_PARAMETER_ARRAY); 276 fail(); 277 } catch (IllegalArgumentException expected) { 278 } 279 280 try { 281 mt.insertParameterTypes(1, void.class); 282 fail(); 283 } catch (IllegalArgumentException expected) { 284 } 285 286 try { 287 mt.insertParameterTypes(1, (Class<?>) null); 288 fail(); 289 } catch (NullPointerException expected) { 290 } 291 292 try { 293 mt.insertParameterTypes(-1, String.class); 294 fail(); 295 } catch (IndexOutOfBoundsException expected) { 296 } 297 298 try { 299 mt.insertParameterTypes(3, String.class); 300 fail(); 301 } catch (IndexOutOfBoundsException expected) { 302 } 303 } 304 305 public void testInsertParameterTypes_list() { 306 MethodType mt = MethodType.methodType(int.class, String.class, Object.class); 307 308 MethodType insert0 = mt.insertParameterTypes(0, Arrays.asList(Integer.class, Long.class)); 309 assertEquals(int.class, insert0.returnType()); 310 assertParameterTypes(insert0, Integer.class, Long.class, String.class, Object.class); 311 312 MethodType insert1 = mt.insertParameterTypes(1, Arrays.asList(Integer.class, Long.class)); 313 assertParameterTypes(insert1, String.class, Integer.class, Long.class, Object.class); 314 315 MethodType insert2 = mt.insertParameterTypes(2, Arrays.asList(Integer.class, Long.class)); 316 assertParameterTypes(insert2, String.class, Object.class, Integer.class, Long.class); 317 318 try { 319 mt.insertParameterTypes(1, Arrays.asList(LARGE_PARAMETER_ARRAY)); 320 fail(); 321 } catch (IllegalArgumentException expected) { 322 } 323 324 try { 325 mt.insertParameterTypes(1, Arrays.asList(void.class)); 326 fail(); 327 } catch (IllegalArgumentException expected) { 328 } 329 330 try { 331 mt.insertParameterTypes(1, (List<Class<?>>) null); 332 fail(); 333 } catch (NullPointerException expected) { 334 } 335 336 try { 337 mt.insertParameterTypes(1, Arrays.asList(null)); 338 fail(); 339 } catch (NullPointerException expected) { 340 } 341 342 try { 343 mt.insertParameterTypes(-1, Arrays.asList(String.class)); 344 fail(); 345 } catch (IndexOutOfBoundsException expected) { 346 } 347 348 try { 349 mt.insertParameterTypes(3, Arrays.asList(String.class)); 350 fail(); 351 } catch (IndexOutOfBoundsException expected) { 352 } 353 } 354 355 public void testAppendParameterTypes_varargs() { 356 MethodType mt = MethodType.methodType(int.class, String.class, String.class); 357 358 MethodType appended = mt.appendParameterTypes(List.class, Integer.class); 359 assertEquals(int.class, appended.returnType()); 360 assertParameterTypes(appended, String.class, String.class, List.class, Integer.class); 361 362 try { 363 mt.appendParameterTypes(LARGE_PARAMETER_ARRAY); 364 fail(); 365 } catch (IllegalArgumentException expected) { 366 } 367 368 try { 369 mt.appendParameterTypes(void.class); 370 fail(); 371 } catch (IllegalArgumentException expected) { 372 } 373 374 try { 375 mt.appendParameterTypes((Class<?>) null); 376 fail(); 377 } catch (NullPointerException expected) { 378 } 379 } 380 381 public void testAppendParameterTypes_list() { 382 MethodType mt = MethodType.methodType(int.class, String.class, String.class); 383 384 MethodType appended = mt.appendParameterTypes(Arrays.asList(List.class, Integer.class)); 385 assertEquals(int.class, appended.returnType()); 386 assertParameterTypes(appended, String.class, String.class, List.class, Integer.class); 387 388 try { 389 mt.appendParameterTypes(Arrays.asList(LARGE_PARAMETER_ARRAY)); 390 fail(); 391 } catch (IllegalArgumentException expected) { 392 } 393 394 try { 395 mt.appendParameterTypes(Arrays.asList(void.class)); 396 fail(); 397 } catch (IllegalArgumentException expected) { 398 } 399 400 try { 401 mt.appendParameterTypes((List<Class<?>>) null); 402 fail(); 403 } catch (NullPointerException expected) { 404 } 405 406 try { 407 mt.appendParameterTypes(Arrays.asList(null)); 408 fail(); 409 } catch (NullPointerException expected) { 410 } 411 } 412 413 public void testDropParameterTypes() { 414 MethodType mt = MethodType.methodType(int.class, String.class, List.class, Object.class); 415 416 MethodType dropNone = mt.dropParameterTypes(0, 0); 417 assertEquals(int.class, dropNone.returnType()); 418 assertParameterTypes(dropNone, String.class, List.class, Object.class); 419 420 MethodType dropFirst = mt.dropParameterTypes(0, 1); 421 assertEquals(int.class, dropFirst.returnType()); 422 assertParameterTypes(dropFirst, List.class, Object.class); 423 424 MethodType dropAll = mt.dropParameterTypes(0, 3); 425 assertEquals(0, dropAll.parameterCount()); 426 assertEquals(int.class, dropAll.returnType()); 427 428 try { 429 mt.dropParameterTypes(-1, 1); 430 fail(); 431 } catch (IndexOutOfBoundsException expected) { 432 } 433 434 try { 435 mt.dropParameterTypes(1, 4); 436 fail(); 437 } catch (IndexOutOfBoundsException expected) { 438 } 439 440 try { 441 mt.dropParameterTypes(2, 1); 442 fail(); 443 } catch (IndexOutOfBoundsException expected) { 444 } 445 } 446 447 public void testChangeReturnType() { 448 MethodType mt = MethodType.methodType(int.class, String.class); 449 450 MethodType changed = mt.changeReturnType(long.class); 451 assertEquals(long.class, changed.returnType()); 452 assertParameterTypes(changed, String.class); 453 454 try { 455 mt.changeReturnType(null); 456 fail(); 457 } catch (NullPointerException expected) { 458 } 459 } 460 461 public void testHasPrimitives() { 462 MethodType mt = MethodType.methodType(Integer.class, Object.class, String.class); 463 assertFalse(mt.hasPrimitives()); 464 465 mt = MethodType.methodType(int.class, Object.class); 466 assertTrue(mt.hasPrimitives()); 467 468 mt = MethodType.methodType(Integer.class, long.class); 469 assertTrue(mt.hasPrimitives()); 470 471 mt = MethodType.methodType(Integer.class, int[].class); 472 assertFalse(mt.hasPrimitives()); 473 474 mt = MethodType.methodType(void.class); 475 assertTrue(mt.hasPrimitives()); 476 } 477 478 public void testHasWrappers() { 479 MethodType mt = MethodType.methodType(Integer.class); 480 assertTrue(mt.hasWrappers()); 481 482 mt = MethodType.methodType(String.class, Integer.class); 483 assertTrue(mt.hasWrappers()); 484 485 mt = MethodType.methodType(int.class, long.class); 486 assertFalse(mt.hasWrappers()); 487 } 488 489 public void testErase() { 490 // String mt(int, String, Object) should be erased to Object mt(int, Object, Object); 491 MethodType mt = MethodType.methodType(String.class, int.class, String.class, Object.class); 492 493 MethodType erased = mt.erase(); 494 assertEquals(Object.class, erased.returnType()); 495 assertParameterTypes(erased, int.class, Object.class, Object.class); 496 497 // Void returns must be left alone. 498 mt = MethodType.methodType(void.class, int.class); 499 erased = mt.erase(); 500 assertEquals(mt, erased); 501 } 502 503 public void testGeneric() { 504 // String mt(int, String, Object) should be generified to Object mt(Object, Object, Object). 505 // In other words, it must be equal to genericMethodType(3 /* parameterCount */); 506 MethodType mt = MethodType.methodType(String.class, int.class, String.class, Object.class); 507 508 MethodType generic = mt.generic(); 509 510 assertEquals(generic, MethodType.genericMethodType(mt.parameterCount())); 511 assertEquals(generic, mt.wrap().erase()); 512 513 assertEquals(Object.class, generic.returnType()); 514 assertParameterTypes(generic, Object.class, Object.class, Object.class); 515 516 // Primitive return types must also become Object. 517 generic = MethodType.methodType(int.class).generic(); 518 assertEquals(Object.class, generic.returnType()); 519 520 // void returns get converted to object returns (the same as wrap). 521 generic = MethodType.methodType(void.class).generic(); 522 assertEquals(Object.class, generic.returnType()); 523 } 524 525 public void testWrap() { 526 // int mt(String, int, long, float, double, short, char, byte) should be wrapped to 527 // Integer mt(String, Integer, Long, Float, Double, Short, Character, Byte); 528 MethodType mt = MethodType.methodType(int.class, String.class, int.class, long.class, 529 float.class, double.class, short.class, char.class, byte.class); 530 531 MethodType wrapped = mt.wrap(); 532 assertFalse(wrapped.hasPrimitives()); 533 assertTrue(wrapped.hasWrappers()); 534 535 assertEquals(Integer.class, wrapped.returnType()); 536 assertParameterTypes(wrapped, String.class, Integer.class, Long.class, Float.class, 537 Double.class, Short.class, Character.class, Byte.class); 538 539 // (semi) special case - void return types get wrapped to Void. 540 wrapped = MethodType.methodType(void.class, int.class).wrap(); 541 assertEquals(Void.class, wrapped.returnType()); 542 } 543 544 public void testUnwrap() { 545 // Integer mt(String, Integer, Long, Float, Double, Short, Character, Byte); 546 // should be unwrapped to : 547 // int mt(String, int, long, float, double, short, char, byte). 548 MethodType mt = MethodType.methodType(Integer.class, String.class, Integer.class, 549 Long.class, Float.class, Double.class, Short.class, Character.class, Byte.class); 550 551 MethodType unwrapped = mt.unwrap(); 552 assertTrue(unwrapped.hasPrimitives()); 553 assertFalse(unwrapped.hasWrappers()); 554 555 assertEquals(int.class, unwrapped.returnType()); 556 assertParameterTypes(unwrapped, String.class, int.class, long.class, float.class, 557 double.class, short.class, char.class, byte.class); 558 559 // (semi) special case - void return types get wrapped to Void. 560 unwrapped = MethodType.methodType(Void.class, int.class).unwrap(); 561 assertEquals(void.class, unwrapped.returnType()); 562 } 563 564 public void testParameterListAndArray() { 565 MethodType mt = MethodType.methodType(String.class, int.class, String.class, Object.class); 566 567 List<Class<?>> paramsList = mt.parameterList(); 568 Class<?>[] paramsArray = mt.parameterArray(); 569 570 assertEquals(3, mt.parameterCount()); 571 572 for (int i = 0; i < 3; ++i) { 573 Class<?> param = mt.parameterType(i); 574 assertEquals(param, paramsList.get(i)); 575 assertEquals(param, paramsArray[i]); 576 } 577 578 mt = MethodType.methodType(int.class); 579 assertEquals(0, mt.parameterCount()); 580 581 paramsList = mt.parameterList(); 582 paramsArray = mt.parameterArray(); 583 584 assertEquals(0, paramsList.size()); 585 assertEquals(0, paramsArray.length); 586 } 587 588 public void testEquals() { 589 MethodType mt = MethodType.methodType(int.class, String.class); 590 MethodType mt2 = MethodType.methodType(int.class, String.class); 591 592 assertEquals(mt, mt2); 593 assertEquals(mt, mt); 594 595 assertFalse(mt.equals(null)); 596 assertFalse(mt.equals(MethodType.methodType(Integer.class, String.class))); 597 } 598 599 public void testHashCode() { 600 MethodType mt = MethodType.methodType(int.class, String.class, Object.class); 601 int hashCode = mt.hashCode(); 602 603 // The hash code should change if we change the return type or any of the parameters, 604 // or if we add or remove parameters from the list. 605 assertFalse(hashCode == mt.changeReturnType(long.class).hashCode()); 606 assertFalse(hashCode == mt.changeParameterType(0, Object.class).hashCode()); 607 assertFalse(hashCode == mt.appendParameterTypes(List.class).hashCode()); 608 assertFalse(hashCode == mt.dropParameterTypes(0, 1).hashCode()); 609 } 610 611 public void testToString() { 612 assertEquals("(String,Object)int", 613 MethodType.methodType(int.class, String.class, Object.class).toString()); 614 assertEquals("()int", MethodType.methodType(int.class).toString()); 615 assertEquals("()void", MethodType.methodType(void.class).toString()); 616 assertEquals("()int[]", MethodType.methodType(int[].class).toString()); 617 } 618 619 public void testFromMethodDescriptorString() { 620 assertEquals( 621 MethodType.methodType(int.class, String.class, Object.class), 622 MethodType.fromMethodDescriptorString("(Ljava/lang/String;Ljava/lang/Object;)I", null)); 623 624 assertEquals(MethodType.fromMethodDescriptorString("()I", null), 625 MethodType.methodType(int.class)); 626 assertEquals(MethodType.fromMethodDescriptorString("()[I", null), 627 MethodType.methodType(int[].class)); 628 assertEquals(MethodType.fromMethodDescriptorString("([I)V", null), 629 MethodType.methodType(void.class, int[].class)); 630 631 try { 632 MethodType.fromMethodDescriptorString(null, null); 633 fail(); 634 } catch (NullPointerException expected) { 635 } 636 637 try { 638 MethodType.fromMethodDescriptorString("(a/b/c)I", null); 639 fail(); 640 } catch (IllegalArgumentException expected) { 641 } 642 643 try { 644 MethodType.fromMethodDescriptorString("(A)I", null); 645 fail(); 646 } catch (IllegalArgumentException expected) { 647 } 648 649 try { 650 MethodType.fromMethodDescriptorString("(Ljava/lang/String)I", null); 651 fail(); 652 } catch (IllegalArgumentException expected) { 653 } 654 655 try { 656 MethodType.fromMethodDescriptorString("(Ljava/lang/String;)", null); 657 fail(); 658 } catch (IllegalArgumentException expected) { 659 } 660 661 try { 662 MethodType.fromMethodDescriptorString("(Ljava/lang/NonExistentString;)I", null); 663 fail(); 664 } catch (TypeNotPresentException expected) { 665 } 666 } 667 668 public void testToMethodDescriptorString() { 669 assertEquals("(Ljava/lang/String;Ljava/lang/Object;)I", MethodType.methodType( 670 int.class, String.class, Object.class).toMethodDescriptorString()); 671 672 assertEquals("()I", MethodType.methodType(int.class).toMethodDescriptorString()); 673 assertEquals("()[I", MethodType.methodType(int[].class).toMethodDescriptorString()); 674 675 assertEquals("([I)V", MethodType.methodType(void.class, int[].class) 676 .toMethodDescriptorString()); 677 } 678 679 private static void assertParameterTypes(MethodType type, Class<?>... params) { 680 assertEquals(params.length, type.parameterCount()); 681 682 List<Class<?>> paramsList = type.parameterList(); 683 for (int i = 0; i < params.length; ++i) { 684 assertEquals(params[i], type.parameterType(i)); 685 assertEquals(params[i], paramsList.get(i)); 686 } 687 688 assertTrue(Arrays.equals(params, type.parameterArray())); 689 } 690} 691