1 /* 2 * Copyright (c) 2015, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 import static jdk.dynalink.StandardNamespace.ELEMENT; 27 import static jdk.dynalink.StandardNamespace.METHOD; 28 import static jdk.dynalink.StandardNamespace.PROPERTY; 29 import static jdk.dynalink.StandardOperation.CALL; 30 import static jdk.dynalink.StandardOperation.GET; 31 import static jdk.dynalink.StandardOperation.NEW; 32 import static jdk.dynalink.StandardOperation.REMOVE; 33 import static jdk.dynalink.StandardOperation.SET; 34 35 import java.lang.invoke.CallSite; 36 import java.lang.invoke.MethodHandle; 37 import java.lang.invoke.MethodHandles; 38 import java.lang.invoke.MethodType; 39 import java.security.AccessControlException; 40 import java.util.ArrayList; 41 import java.util.Date; 42 import java.util.HashMap; 43 import java.util.List; 44 import java.util.Map; 45 import jdk.dynalink.CallSiteDescriptor; 46 import jdk.dynalink.DynamicLinker; 47 import jdk.dynalink.DynamicLinkerFactory; 48 import jdk.dynalink.NamedOperation; 49 import jdk.dynalink.NoSuchDynamicMethodException; 50 import jdk.dynalink.Operation; 51 import jdk.dynalink.beans.BeansLinker; 52 import jdk.dynalink.beans.StaticClass; 53 import jdk.dynalink.support.SimpleRelinkableCallSite; 54 import org.testng.Assert; 55 import org.testng.annotations.AfterTest; 56 import org.testng.annotations.BeforeTest; 57 import org.testng.annotations.DataProvider; 58 import org.testng.annotations.Test; 59 60 /** 61 * @test 62 * @run testng/othervm/java.security.policy=untrusted.security.policy BeanLinkerTest 63 */ 64 public class BeanLinkerTest { 65 66 private DynamicLinker linker; 67 private static final MethodHandles.Lookup MY_LOOKUP = MethodHandles.lookup(); 68 69 @SuppressWarnings("unused") 70 @DataProvider 71 private static Object[][] flags() { 72 return new Object[][]{ 73 {Boolean.FALSE}, 74 {Boolean.TRUE} 75 }; 76 } 77 78 // helpers to create callsite objects 79 private CallSite createCallSite(final boolean publicLookup, final Operation op, final MethodType mt) { 80 return linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor( 81 publicLookup ? MethodHandles.publicLookup() : MY_LOOKUP, op, mt))); 82 } 83 84 private CallSite createCallSite(final boolean publicLookup, final Operation op, final Object name, final MethodType mt) { 85 return createCallSite(publicLookup, op.named(name), mt); 86 } 87 88 private CallSite createGetMethodCallSite(final boolean publicLookup, final String name) { 89 return createCallSite(publicLookup, GET_METHOD, name, MethodType.methodType(Object.class, Object.class)); 90 } 91 92 private static final MethodHandle throwArrayIndexOutOfBounds = findThrower("throwArrayIndexOutOfBounds"); 93 private static final MethodHandle throwIndexOutOfBounds = findThrower("throwIndexOutOfBounds"); 94 95 private static final Operation GET_PROPERTY = GET.withNamespace(PROPERTY); 96 private static final Operation GET_ELEMENT = GET.withNamespace(ELEMENT); 97 private static final Operation GET_METHOD = GET.withNamespace(METHOD); 98 private static final Operation SET_ELEMENT = SET.withNamespace(ELEMENT); 99 private static final Operation REMOVE_ELEMENT = REMOVE.withNamespace(ELEMENT); 100 101 private static MethodHandle findThrower(final String name) { 102 try { 103 return MethodHandles.lookup().findStatic(BeanLinkerTest.class, name, 104 MethodType.methodType(Object.class, Object.class, Object.class)); 105 } catch (NoSuchMethodException | IllegalAccessException e) { 106 Assert.fail("Unexpected exception", e); 107 return null; 108 } 109 } 110 111 private static Object throwArrayIndexOutOfBounds(final Object receiver, final Object index) { 112 throw new ArrayIndexOutOfBoundsException(String.valueOf(index)); 113 } 114 115 private static Object throwIndexOutOfBounds(final Object receiver, final Object index) { 116 throw new IndexOutOfBoundsException(String.valueOf(index)); 117 } 118 119 @BeforeTest 120 public void initLinker() { 121 final DynamicLinkerFactory factory = new DynamicLinkerFactory(); 122 factory.setFallbackLinkers(new BeansLinker((req, services) -> { 123 // This is a MissingMemberHandlerFactory that creates a missing 124 // member handler for element getters and setters that throw an 125 // ArrayIndexOutOfBoundsException when applied to an array and an 126 // IndexOutOfBoundsException when applied to a list. 127 128 final CallSiteDescriptor desc = req.getCallSiteDescriptor(); 129 final Operation op = desc.getOperation(); 130 final Operation baseOp = NamedOperation.getBaseOperation(op); 131 if (baseOp != GET_ELEMENT && baseOp != SET_ELEMENT && baseOp != REMOVE_ELEMENT) { 132 // We only handle GET_ELEMENT, SET_ELEMENT and REMOVE_ELEMENT. 133 return null; 134 } 135 136 final Object receiver = req.getReceiver(); 137 Assert.assertNotNull(receiver); 138 139 final Class<?> clazz = receiver.getClass(); 140 final MethodHandle throwerHandle; 141 if (clazz.isArray()) { 142 throwerHandle = throwArrayIndexOutOfBounds; 143 } else if (List.class.isAssignableFrom(clazz)) { 144 throwerHandle = throwIndexOutOfBounds; 145 } else if (Map.class.isAssignableFrom(clazz)) { 146 return null; 147 } else { 148 Assert.fail("Unexpected receiver type " + clazz.getName()); 149 return null; 150 } 151 152 final Object name = NamedOperation.getName(op); 153 final MethodHandle nameBoundHandle; 154 if (name == null) { 155 nameBoundHandle = throwerHandle; 156 } else { 157 // If the operation is for a fixed index, bind it 158 nameBoundHandle = MethodHandles.insertArguments(throwerHandle, 1, name); 159 } 160 161 final MethodType callSiteType = desc.getMethodType(); 162 final MethodHandle arityMatchedHandle; 163 if (baseOp == SET_ELEMENT) { 164 // Drop "value" parameter for a setter 165 final int handleArity = nameBoundHandle.type().parameterCount(); 166 arityMatchedHandle = MethodHandles.dropArguments(nameBoundHandle, 167 handleArity, callSiteType.parameterType(handleArity)); 168 } else { 169 arityMatchedHandle = nameBoundHandle; 170 } 171 172 return arityMatchedHandle.asType(callSiteType); 173 })); 174 this.linker = factory.createLinker(); 175 } 176 177 @AfterTest 178 public void afterTest() { 179 this.linker = null; 180 } 181 182 @Test(dataProvider = "flags") 183 public void getPropertyTest(final boolean publicLookup) throws Throwable { 184 final MethodType mt = MethodType.methodType(Object.class, Object.class, String.class); 185 final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, mt); 186 Assert.assertEquals(cs.getTarget().invoke(new Object(), "class"), Object.class); 187 Assert.assertEquals(cs.getTarget().invoke(new Date(), "class"), Date.class); 188 } 189 190 @Test(dataProvider = "flags") 191 public void getPropertyNegativeTest(final boolean publicLookup) throws Throwable { 192 final MethodType mt = MethodType.methodType(Object.class, Object.class, String.class); 193 final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, mt); 194 Assert.assertNull(cs.getTarget().invoke(new Object(), "DOES_NOT_EXIST")); 195 } 196 197 @Test(dataProvider = "flags") 198 public void getPropertyTest2(final boolean publicLookup) throws Throwable { 199 final MethodType mt = MethodType.methodType(Object.class, Object.class); 200 final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, "class", mt); 201 Assert.assertEquals(cs.getTarget().invoke(new Object()), Object.class); 202 Assert.assertEquals(cs.getTarget().invoke(new Date()), Date.class); 203 } 204 205 @Test(dataProvider = "flags") 206 public void getPropertyNegativeTest2(final boolean publicLookup) throws Throwable { 207 final MethodType mt = MethodType.methodType(Object.class, Object.class); 208 final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, "DOES_NOT_EXIST", mt); 209 210 try { 211 cs.getTarget().invoke(new Object()); 212 throw new RuntimeException("Expected NoSuchDynamicMethodException"); 213 } catch (final Throwable th) { 214 Assert.assertTrue(th instanceof NoSuchDynamicMethodException); 215 } 216 } 217 218 @Test(dataProvider = "flags") 219 public void getLengthPropertyTest(final boolean publicLookup) throws Throwable { 220 final MethodType mt = MethodType.methodType(int.class, Object.class, String.class); 221 final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, mt); 222 223 Assert.assertEquals((int) cs.getTarget().invoke(new int[10], "length"), 10); 224 Assert.assertEquals((int) cs.getTarget().invoke(new String[33], "length"), 33); 225 } 226 227 @Test(dataProvider = "flags") 228 public void getElementTest(final boolean publicLookup) throws Throwable { 229 final MethodType mt = MethodType.methodType(int.class, Object.class, int.class); 230 final CallSite cs = createCallSite(publicLookup, GET_ELEMENT, mt); 231 232 final int[] arr = {23, 42}; 233 Assert.assertEquals((int) cs.getTarget().invoke(arr, 0), 23); 234 Assert.assertEquals((int) cs.getTarget().invoke(arr, 1), 42); 235 try { 236 final int x = (int) cs.getTarget().invoke(arr, -1); 237 throw new RuntimeException("expected ArrayIndexOutOfBoundsException"); 238 } catch (final ArrayIndexOutOfBoundsException ex) { 239 } 240 241 try { 242 final int x = (int) cs.getTarget().invoke(arr, arr.length); 243 throw new RuntimeException("expected ArrayIndexOutOfBoundsException"); 244 } catch (final ArrayIndexOutOfBoundsException ex) { 245 } 246 247 final List<Integer> list = new ArrayList<>(); 248 list.add(23); 249 list.add(430); 250 list.add(-4354); 251 Assert.assertEquals((int) cs.getTarget().invoke(list, 0), (int) list.get(0)); 252 Assert.assertEquals((int) cs.getTarget().invoke(list, 1), (int) list.get(1)); 253 Assert.assertEquals((int) cs.getTarget().invoke(list, 2), (int) list.get(2)); 254 try { 255 cs.getTarget().invoke(list, -1); 256 throw new RuntimeException("expected IndexOutOfBoundsException"); 257 } catch (final IndexOutOfBoundsException ex) { 258 } 259 260 try { 261 cs.getTarget().invoke(list, list.size()); 262 throw new RuntimeException("expected IndexOutOfBoundsException"); 263 } catch (final IndexOutOfBoundsException ex) { 264 } 265 } 266 267 private Object invokeWithFixedKey(boolean publicLookup, Operation op, Object name, MethodType mt, Object... args) throws Throwable { 268 return createCallSite(publicLookup, op.named(name), mt).getTarget().invokeWithArguments(args); 269 } 270 271 @Test(dataProvider = "flags") 272 public void getElementWithFixedKeyTest(final boolean publicLookup) throws Throwable { 273 final MethodType mt = MethodType.methodType(int.class, Object.class); 274 275 final int[] arr = {23, 42}; 276 Assert.assertEquals((int) invokeWithFixedKey(publicLookup, GET_ELEMENT, 0, mt, arr), 23); 277 Assert.assertEquals((int) invokeWithFixedKey(publicLookup, GET_ELEMENT, 1, mt, arr), 42); 278 try { 279 invokeWithFixedKey(publicLookup, GET_ELEMENT, -1, mt, arr); 280 throw new RuntimeException("expected ArrayIndexOutOfBoundsException"); 281 } catch (final ArrayIndexOutOfBoundsException ex) { 282 } 283 284 try { 285 invokeWithFixedKey(publicLookup, GET_ELEMENT, arr.length, mt, arr); 286 throw new RuntimeException("expected ArrayIndexOutOfBoundsException"); 287 } catch (final ArrayIndexOutOfBoundsException ex) { 288 } 289 290 final List<Integer> list = new ArrayList<>(); 291 list.add(23); 292 list.add(430); 293 list.add(-4354); 294 for (int i = 0; i < 3; ++i) { 295 Assert.assertEquals((int) invokeWithFixedKey(publicLookup, GET_ELEMENT, i, mt, list), (int) list.get(i)); 296 } 297 try { 298 invokeWithFixedKey(publicLookup, GET_ELEMENT, -1, mt, list); 299 throw new RuntimeException("expected IndexOutOfBoundsException"); 300 } catch (final IndexOutOfBoundsException ex) { 301 } 302 303 try { 304 invokeWithFixedKey(publicLookup, GET_ELEMENT, list.size(), mt, list); 305 throw new RuntimeException("expected IndexOutOfBoundsException"); 306 } catch (final IndexOutOfBoundsException ex) { 307 } 308 } 309 310 @Test(dataProvider = "flags") 311 public void setElementTest(final boolean publicLookup) throws Throwable { 312 final MethodType mt = MethodType.methodType(void.class, Object.class, int.class, int.class); 313 final CallSite cs = createCallSite(publicLookup, SET_ELEMENT, mt); 314 315 final int[] arr = {23, 42}; 316 cs.getTarget().invoke(arr, 0, 0); 317 Assert.assertEquals(arr[0], 0); 318 cs.getTarget().invoke(arr, 1, -5); 319 Assert.assertEquals(arr[1], -5); 320 321 try { 322 cs.getTarget().invoke(arr, -1, 12); 323 throw new RuntimeException("expected ArrayIndexOutOfBoundsException"); 324 } catch (final ArrayIndexOutOfBoundsException ex) { 325 } 326 327 try { 328 cs.getTarget().invoke(arr, arr.length, 20); 329 throw new RuntimeException("expected ArrayIndexOutOfBoundsException"); 330 } catch (final ArrayIndexOutOfBoundsException ex) { 331 } 332 333 final List<Integer> list = new ArrayList<>(); 334 list.add(23); 335 list.add(430); 336 list.add(-4354); 337 338 cs.getTarget().invoke(list, 0, -list.get(0)); 339 Assert.assertEquals((int) list.get(0), -23); 340 cs.getTarget().invoke(list, 1, -430); 341 Assert.assertEquals((int) list.get(1), -430); 342 cs.getTarget().invoke(list, 2, 4354); 343 Assert.assertEquals((int) list.get(2), 4354); 344 try { 345 cs.getTarget().invoke(list, -1, 343); 346 throw new RuntimeException("expected IndexOutOfBoundsException"); 347 } catch (final IndexOutOfBoundsException ex) { 348 } 349 350 try { 351 cs.getTarget().invoke(list, list.size(), 43543); 352 throw new RuntimeException("expected IndexOutOfBoundsException"); 353 } catch (final IndexOutOfBoundsException ex) { 354 } 355 } 356 357 @Test(dataProvider = "flags") 358 public void setElementWithFixedKeyTest(final boolean publicLookup) throws Throwable { 359 final MethodType mt = MethodType.methodType(void.class, Object.class, int.class); 360 361 final int[] arr = {23, 42}; 362 invokeWithFixedKey(publicLookup, SET_ELEMENT, 0, mt, arr, 0); 363 Assert.assertEquals(arr[0], 0); 364 invokeWithFixedKey(publicLookup, SET_ELEMENT, 1, mt, arr, -5); 365 Assert.assertEquals(arr[1], -5); 366 367 try { 368 invokeWithFixedKey(publicLookup, SET_ELEMENT, -1, mt, arr, 12); 369 throw new RuntimeException("expected ArrayIndexOutOfBoundsException"); 370 } catch (final ArrayIndexOutOfBoundsException ex) { 371 } 372 373 try { 374 invokeWithFixedKey(publicLookup, SET_ELEMENT, arr.length, mt, arr, 20); 375 throw new RuntimeException("expected ArrayIndexOutOfBoundsException"); 376 } catch (final ArrayIndexOutOfBoundsException ex) { 377 } 378 379 final List<Integer> list = new ArrayList<>(); 380 list.add(23); 381 list.add(430); 382 list.add(-4354); 383 384 invokeWithFixedKey(publicLookup, SET_ELEMENT, 0, mt, list, -list.get(0)); 385 Assert.assertEquals((int) list.get(0), -23); 386 invokeWithFixedKey(publicLookup, SET_ELEMENT, 1, mt, list, -430); 387 Assert.assertEquals((int) list.get(1), -430); 388 invokeWithFixedKey(publicLookup, SET_ELEMENT, 2, mt, list, 4354); 389 Assert.assertEquals((int) list.get(2), 4354); 390 try { 391 invokeWithFixedKey(publicLookup, SET_ELEMENT, -1, mt, list, 343); 392 throw new RuntimeException("expected IndexOutOfBoundsException"); 393 } catch (final IndexOutOfBoundsException ex) { 394 } 395 396 try { 397 invokeWithFixedKey(publicLookup, SET_ELEMENT, list.size(), mt, list, 43543); 398 throw new RuntimeException("expected IndexOutOfBoundsException"); 399 } catch (final IndexOutOfBoundsException ex) { 400 } 401 } 402 403 @Test(dataProvider = "flags") 404 public void newObjectTest(final boolean publicLookup) { 405 final MethodType mt = MethodType.methodType(Object.class, Object.class); 406 final CallSite cs = createCallSite(publicLookup, NEW, mt); 407 408 Object obj = null; 409 try { 410 obj = cs.getTarget().invoke(StaticClass.forClass(Date.class)); 411 } catch (final Throwable th) { 412 throw new RuntimeException(th); 413 } 414 415 Assert.assertTrue(obj instanceof Date); 416 } 417 418 @Test(dataProvider = "flags") 419 public void staticPropertyTest(final boolean publicLookup) { 420 final MethodType mt = MethodType.methodType(Object.class, Class.class); 421 final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, "static", mt); 422 423 Object obj = null; 424 try { 425 obj = cs.getTarget().invoke(Object.class); 426 } catch (final Throwable th) { 427 throw new RuntimeException(th); 428 } 429 430 Assert.assertTrue(obj instanceof StaticClass); 431 Assert.assertEquals(((StaticClass) obj).getRepresentedClass(), Object.class); 432 433 try { 434 obj = cs.getTarget().invoke(Date.class); 435 } catch (final Throwable th) { 436 throw new RuntimeException(th); 437 } 438 439 Assert.assertTrue(obj instanceof StaticClass); 440 Assert.assertEquals(((StaticClass) obj).getRepresentedClass(), Date.class); 441 442 try { 443 obj = cs.getTarget().invoke(Object[].class); 444 } catch (final Throwable th) { 445 throw new RuntimeException(th); 446 } 447 448 Assert.assertTrue(obj instanceof StaticClass); 449 Assert.assertEquals(((StaticClass) obj).getRepresentedClass(), Object[].class); 450 } 451 452 @Test(dataProvider = "flags") 453 public void instanceMethodCallTest(final boolean publicLookup) { 454 final CallSite cs = createGetMethodCallSite(publicLookup, "getClass"); 455 final MethodType mt2 = MethodType.methodType(Class.class, Object.class, Object.class); 456 final CallSite cs2 = createCallSite(publicLookup, CALL, mt2); 457 458 Object method = null; 459 try { 460 method = cs.getTarget().invoke(new Date()); 461 } catch (final Throwable th) { 462 throw new RuntimeException(th); 463 } 464 465 Assert.assertNotNull(method); 466 Assert.assertTrue(BeansLinker.isDynamicMethod(method)); 467 Class clz = null; 468 try { 469 clz = (Class) cs2.getTarget().invoke(method, new Date()); 470 } catch (final Throwable th) { 471 throw new RuntimeException(th); 472 } 473 474 Assert.assertEquals(clz, Date.class); 475 } 476 477 @Test(dataProvider = "flags") 478 public void staticMethodCallTest(final boolean publicLookup) { 479 final CallSite cs = createGetMethodCallSite(publicLookup, "getProperty"); 480 final MethodType mt2 = MethodType.methodType(String.class, Object.class, Object.class, String.class); 481 final CallSite cs2 = createCallSite(publicLookup, CALL, mt2); 482 483 Object method = null; 484 try { 485 method = cs.getTarget().invoke(StaticClass.forClass(System.class)); 486 } catch (final Throwable th) { 487 throw new RuntimeException(th); 488 } 489 490 Assert.assertNotNull(method); 491 Assert.assertTrue(BeansLinker.isDynamicMethod(method)); 492 493 String str = null; 494 try { 495 str = (String) cs2.getTarget().invoke(method, null, "os.name"); 496 } catch (final Throwable th) { 497 throw new RuntimeException(th); 498 } 499 Assert.assertEquals(str, System.getProperty("os.name")); 500 } 501 502 // try calling System.getenv and expect security exception 503 @Test(dataProvider = "flags") 504 public void systemGetenvTest(final boolean publicLookup) { 505 final CallSite cs1 = createGetMethodCallSite(publicLookup, "getenv"); 506 final CallSite cs2 = createCallSite(publicLookup, CALL, MethodType.methodType(Object.class, Object.class, Object.class)); 507 508 try { 509 final Object method = cs1.getTarget().invoke(StaticClass.forClass(System.class)); 510 cs2.getTarget().invoke(method, StaticClass.forClass(System.class)); 511 throw new RuntimeException("should not reach here in any case!"); 512 } catch (final Throwable th) { 513 Assert.assertTrue(th instanceof SecurityException); 514 } 515 } 516 517 // try getting a specific sensitive System property and expect security exception 518 @Test(dataProvider = "flags") 519 public void systemGetPropertyTest(final boolean publicLookup) { 520 final CallSite cs1 = createGetMethodCallSite(publicLookup, "getProperty"); 521 final CallSite cs2 = createCallSite(publicLookup, CALL, MethodType.methodType(String.class, Object.class, Object.class, String.class)); 522 523 try { 524 final Object method = cs1.getTarget().invoke(StaticClass.forClass(System.class)); 525 cs2.getTarget().invoke(method, StaticClass.forClass(System.class), "java.home"); 526 throw new RuntimeException("should not reach here in any case!"); 527 } catch (final Throwable th) { 528 Assert.assertTrue(th instanceof SecurityException); 529 } 530 } 531 532 // check a @CallerSensitive API and expect appropriate access check exception 533 @Test(dataProvider = "flags") 534 public void systemLoadLibraryTest(final boolean publicLookup) { 535 final CallSite cs1 = createGetMethodCallSite(publicLookup, "loadLibrary"); 536 final CallSite cs2 = createCallSite(publicLookup, CALL, MethodType.methodType(void.class, Object.class, Object.class, String.class)); 537 538 try { 539 final Object method = cs1.getTarget().invoke(StaticClass.forClass(System.class)); 540 cs2.getTarget().invoke(method, StaticClass.forClass(System.class), "foo"); 541 throw new RuntimeException("should not reach here in any case!"); 542 } catch (final Throwable th) { 543 if (publicLookup) { 544 Assert.assertTrue(th instanceof IllegalAccessError); 545 } else { 546 Assert.assertTrue(th instanceof AccessControlException, "Expected AccessControlException, got " + th.getClass().getName()); 547 } 548 } 549 } 550 551 @Test(dataProvider = "flags") 552 public void removeElementFromListTest(final boolean publicLookup) throws Throwable { 553 final MethodType mt = MethodType.methodType(void.class, Object.class, int.class); 554 final CallSite cs = createCallSite(publicLookup, REMOVE_ELEMENT, mt); 555 556 final List<Integer> list = new ArrayList<>(List.of(23, 430, -4354)); 557 558 cs.getTarget().invoke(list, 1); 559 Assert.assertEquals(list, List.of(23, -4354)); 560 cs.getTarget().invoke(list, 1); 561 Assert.assertEquals(list, List.of(23)); 562 cs.getTarget().invoke(list, 0); 563 Assert.assertEquals(list, List.of()); 564 try { 565 cs.getTarget().invoke(list, -1); 566 throw new RuntimeException("expected IndexOutOfBoundsException"); 567 } catch (final IndexOutOfBoundsException ex) { 568 } 569 570 try { 571 cs.getTarget().invoke(list, list.size()); 572 throw new RuntimeException("expected IndexOutOfBoundsException"); 573 } catch (final IndexOutOfBoundsException ex) { 574 } 575 } 576 577 @Test(dataProvider = "flags") 578 public void removeElementFromListWithFixedKeyTest(final boolean publicLookup) throws Throwable { 579 final MethodType mt = MethodType.methodType(void.class, Object.class); 580 581 final List<Integer> list = new ArrayList<>(List.of(23, 430, -4354)); 582 583 createCallSite(publicLookup, REMOVE_ELEMENT.named(1), mt).getTarget().invoke(list); 584 Assert.assertEquals(list, List.of(23, -4354)); 585 createCallSite(publicLookup, REMOVE_ELEMENT.named(1), mt).getTarget().invoke(list); 586 Assert.assertEquals(list, List.of(23)); 587 createCallSite(publicLookup, REMOVE_ELEMENT.named(0), mt).getTarget().invoke(list); 588 Assert.assertEquals(list, List.of()); 589 try { 590 createCallSite(publicLookup, REMOVE_ELEMENT.named(-1), mt).getTarget().invoke(list); 591 throw new RuntimeException("expected IndexOutOfBoundsException"); 592 } catch (final IndexOutOfBoundsException ex) { 593 } 594 595 try { 596 createCallSite(publicLookup, REMOVE_ELEMENT.named(list.size()), mt).getTarget().invoke(list); 597 throw new RuntimeException("expected IndexOutOfBoundsException"); 598 } catch (final IndexOutOfBoundsException ex) { 599 } 600 } 601 602 @Test(dataProvider = "flags") 603 public void removeElementFromMapTest(final boolean publicLookup) throws Throwable { 604 final MethodType mt = MethodType.methodType(void.class, Object.class, Object.class); 605 final CallSite cs = createCallSite(publicLookup, REMOVE_ELEMENT, mt); 606 607 final Map<String, String> map = new HashMap<>(Map.of("k1", "v1", "k2", "v2", "k3", "v3")); 608 609 cs.getTarget().invoke(map, "k2"); 610 Assert.assertEquals(map, Map.of("k1", "v1", "k3", "v3")); 611 cs.getTarget().invoke(map, "k4"); 612 Assert.assertEquals(map, Map.of("k1", "v1", "k3", "v3")); 613 cs.getTarget().invoke(map, "k1"); 614 Assert.assertEquals(map, Map.of("k3", "v3")); 615 } 616 617 618 @Test(dataProvider = "flags") 619 public void removeElementFromMapWithFixedKeyTest(final boolean publicLookup) throws Throwable { 620 final MethodType mt = MethodType.methodType(void.class, Object.class); 621 622 final Map<String, String> map = new HashMap<>(Map.of("k1", "v1", "k2", "v2", "k3", "v3")); 623 624 createCallSite(publicLookup, REMOVE_ELEMENT.named("k2"), mt).getTarget().invoke(map); 625 Assert.assertEquals(map, Map.of("k1", "v1", "k3", "v3")); 626 createCallSite(publicLookup, REMOVE_ELEMENT.named("k4"), mt).getTarget().invoke(map); 627 Assert.assertEquals(map, Map.of("k1", "v1", "k3", "v3")); 628 createCallSite(publicLookup, REMOVE_ELEMENT.named("k1"), mt).getTarget().invoke(map); 629 Assert.assertEquals(map, Map.of("k3", "v3")); 630 } 631 }