1 /* 2 * Copyright (c) 2023, 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 package test.java.util.SequencedCollection; 25 26 import java.io.*; 27 import java.util.*; 28 29 import org.testng.annotations.DataProvider; 30 import org.testng.annotations.Test; 31 32 import static org.testng.Assert.assertEquals; 33 import static org.testng.Assert.assertNull; 34 import static org.testng.Assert.assertThrows; 35 import static org.testng.Assert.assertFalse; 36 import static org.testng.Assert.assertSame; 37 import static org.testng.Assert.assertTrue; 38 39 /* 40 * @test 41 * @bug 8266571 42 * @summary Basic tests for SequencedMap 43 * @modules java.base/java.util:open 44 * @build SimpleSortedMap 45 * @run testng BasicMap 46 */ 47 48 public class BasicMap { 49 50 // ========== Data Providers ========== 51 52 static final Class<? extends Throwable> CCE = ClassCastException.class; 53 static final Class<? extends Throwable> NSEE = NoSuchElementException.class; 54 static final Class<? extends Throwable> UOE = UnsupportedOperationException.class; 55 56 static final List<Map.Entry<String, Integer>> ORIGINAL = 57 List.of(Map.entry("a", 1), 58 Map.entry("b", 2), 59 Map.entry("c", 3), 60 Map.entry("d", 4), 61 Map.entry("e", 5)); 62 63 static <M extends SequencedMap<String, Integer>> load(M map, List<Map.Entry<String, Integer>> mappings)64 M load(M map, List<Map.Entry<String, Integer>> mappings) { 65 for (var e : mappings) 66 map.put(e.getKey(), e.getValue()); 67 return map; 68 } 69 cknav(NavigableMap<String, Integer> map)70 static NavigableMap<String, Integer> cknav(NavigableMap<String, Integer> map) { 71 return Collections.checkedNavigableMap(map, String.class, Integer.class); 72 } 73 cksorted(SortedMap<String, Integer> map)74 static SortedMap<String, Integer> cksorted(SortedMap<String, Integer> map) { 75 return Collections.checkedSortedMap(map, String.class, Integer.class); 76 } 77 umap(SequencedMap<String, Integer> map)78 static SequencedMap<String, Integer> umap(SequencedMap<String, Integer> map) { 79 return Collections.unmodifiableSequencedMap(map); 80 } 81 usorted(SortedMap<String, Integer> map)82 static SortedMap<String, Integer> usorted(SortedMap<String, Integer> map) { 83 return Collections.unmodifiableSortedMap(map); 84 } 85 unav(NavigableMap<String, Integer> map)86 static NavigableMap<String, Integer> unav(NavigableMap<String, Integer> map) { 87 return Collections.unmodifiableNavigableMap(map); 88 } 89 90 @DataProvider(name="all") all()91 public Iterator<Object[]> all() { 92 var result = new ArrayList<Object[]>(); 93 populated().forEachRemaining(result::add); 94 empties().forEachRemaining(result::add); 95 return result.iterator(); 96 } 97 98 @DataProvider(name="populated") populated()99 public Iterator<Object[]> populated() { 100 return Arrays.asList( 101 new Object[] { "LinkedHashMap", load(new LinkedHashMap<>(), ORIGINAL), ORIGINAL }, 102 new Object[] { "SimpleSortedMap", load(new SimpleSortedMap<>(), ORIGINAL), ORIGINAL }, 103 new Object[] { "TreeMap", load(new TreeMap<>(), ORIGINAL), ORIGINAL }, 104 new Object[] { "UnmodMap", umap(load(new LinkedHashMap<>(), ORIGINAL)), ORIGINAL } 105 ).iterator(); 106 } 107 108 @DataProvider(name="empties") empties()109 public Iterator<Object[]> empties() { 110 return Arrays.asList( 111 new Object[] { "EmptyNavigableMap", Collections.emptyNavigableMap(), List.of() }, 112 new Object[] { "EmptySortedMap", Collections.emptySortedMap(), List.of() }, 113 new Object[] { "LinkedHashMap", new LinkedHashMap<>(), List.of() }, 114 new Object[] { "SimpleSortedMap", new SimpleSortedMap<>(), List.of() }, 115 new Object[] { "TreeMap", new TreeMap<>(), List.of() }, 116 new Object[] { "UnmodMap", umap(new LinkedHashMap<>()), List.of() } 117 ).iterator(); 118 } 119 120 @DataProvider(name="polls") polls()121 public Iterator<Object[]> polls() { 122 return Arrays.asList( 123 new Object[] { "LinkedHashMap", load(new LinkedHashMap<>(), ORIGINAL), ORIGINAL }, 124 new Object[] { "SimpleSortedMap", load(new SimpleSortedMap<>(), ORIGINAL), ORIGINAL }, 125 new Object[] { "TreeMap", load(new TreeMap<>(), ORIGINAL), ORIGINAL } 126 ).iterator(); 127 } 128 129 @DataProvider(name="emptyPolls") emptyPolls()130 public Iterator<Object[]> emptyPolls() { 131 return Arrays.asList( 132 new Object[] { "LinkedHashMap", new LinkedHashMap<>(), List.of() }, 133 new Object[] { "SimpleSortedMap", new SimpleSortedMap<>(), List.of() }, 134 new Object[] { "TreeMap", new TreeMap<>(), List.of() } 135 ).iterator(); 136 } 137 138 @DataProvider(name="puts") puts()139 public Iterator<Object[]> puts() { 140 return Arrays.<Object[]>asList( 141 new Object[] { "LinkedHashMap", load(new LinkedHashMap<>(), ORIGINAL), ORIGINAL } 142 ).iterator(); 143 } 144 145 @DataProvider(name="putUnpositioned") putUnpositioned()146 public Iterator<Object[]> putUnpositioned() { 147 return Arrays.asList( 148 new Object[] { "LinkedHashMap", false, load(new LinkedHashMap<>(), ORIGINAL), ORIGINAL }, 149 new Object[] { "LinkedHashMap", true, load(new LinkedHashMap<>(), ORIGINAL), ORIGINAL } 150 ).iterator(); 151 } 152 153 @DataProvider(name="putThrows") putThrows()154 public Iterator<Object[]> putThrows() { 155 return Arrays.asList( 156 new Object[] { "SimpleSortedMap", load(new SimpleSortedMap<>(), ORIGINAL), ORIGINAL }, 157 new Object[] { "TreeMap", load(new TreeMap<>(), ORIGINAL), ORIGINAL } 158 ).iterator(); 159 } 160 161 @DataProvider(name="serializable") serializable()162 public Iterator<Object[]> serializable() { 163 return Arrays.asList( 164 new Object[] { "LinkedHashMap", load(new LinkedHashMap<>(), ORIGINAL), ORIGINAL }, 165 new Object[] { "TreeMap", load(new TreeMap<>(), ORIGINAL), ORIGINAL }, 166 new Object[] { "UnmodMap", umap(load(new LinkedHashMap<>(), ORIGINAL)), ORIGINAL } 167 ).iterator(); 168 } 169 170 @DataProvider(name="notSerializable") notSerializable()171 public Iterator<Object[]> notSerializable() { 172 return Arrays.asList( 173 new Object[] { "LinkedHashMap", load(new LinkedHashMap<>(), ORIGINAL).reversed() }, 174 new Object[] { "UnmodMap", umap(load(new LinkedHashMap<>(), ORIGINAL)).reversed() } 175 ).iterator(); 176 } 177 178 @DataProvider(name="doubleReverse") doubleReverse()179 public Iterator<Object[]> doubleReverse() { 180 return Arrays.<Object[]>asList( 181 new Object[] { "LinkedHashMap", load(new LinkedHashMap<>(), ORIGINAL) } 182 ).iterator(); 183 } 184 185 @DataProvider(name="unmodifiable") unmodifible()186 public Iterator<Object[]> unmodifible() { 187 return Arrays.<Object[]>asList( 188 new Object[] { "UnmodMap", umap(load(new LinkedHashMap<>(), ORIGINAL)), ORIGINAL }, 189 new Object[] { "UnmodNav", unav(load(new TreeMap<>(), ORIGINAL)), ORIGINAL }, 190 new Object[] { "UnmodSorted", usorted(load(new TreeMap<>(), ORIGINAL)), ORIGINAL } 191 ).iterator(); 192 } 193 194 @DataProvider(name="checked") checked()195 public Iterator<Object[]> checked() { 196 return Arrays.<Object[]>asList( 197 new Object[] { "ChkNav", cknav(load(new TreeMap<>(), ORIGINAL)), ORIGINAL }, 198 new Object[] { "ChkSorted", cksorted(load(new TreeMap<>(), ORIGINAL)), ORIGINAL } 199 ).iterator(); 200 } 201 202 // mode bit tests 203 reverseMap(int mode)204 boolean reverseMap(int mode) { return (mode & 1) != 0; } reverseView(int mode)205 boolean reverseView(int mode) { return (mode & 2) != 0; } callLast(int mode)206 boolean callLast(int mode) { return (mode & 4) != 0; } 207 refLast(int mode)208 boolean refLast(int mode) { return reverseMap(mode) ^ reverseView(mode) ^ callLast(mode); } 209 210 /** 211 * Generate cases for testing the removeFirst and removeLast methods of map views. For each 212 * different map implementation, generate 8 cases from the three bits of the testing mode 213 * int value: 214 * 215 * (bit 1) if true, the backing map is reversed 216 * (bit 2) if true, the view is reversed 217 * (bit 4) if true, the last element of the view is to be removed, otherwise the first 218 * 219 * The three bits XORed together (by refLast(), above) indicate (if true) the last 220 * or (if false) the first element of the reference entry list is to be removed. 221 * 222 * @return the generated cases 223 */ 224 @DataProvider(name="viewRemoves") viewRemoves()225 public Iterator<Object[]> viewRemoves() { 226 var cases = new ArrayList<Object[]>(); 227 for (int mode = 0; mode < 8; mode++) { 228 cases.addAll(Arrays.asList( 229 new Object[] { "LinkedHashMap", mode, load(new LinkedHashMap<>(), ORIGINAL), ORIGINAL }, 230 new Object[] { "SimpleSortedMap", mode, load(new SimpleSortedMap<>(), ORIGINAL), ORIGINAL }, 231 new Object[] { "TreeMap", mode, load(new TreeMap<>(), ORIGINAL), ORIGINAL } 232 )); 233 } 234 return cases.iterator(); 235 } 236 237 @DataProvider(name="emptyViewRemoves") emptyViewRemoves()238 public Iterator<Object[]> emptyViewRemoves() { 239 var cases = new ArrayList<Object[]>(); 240 for (int mode = 0; mode < 8; mode++) { 241 cases.addAll(Arrays.asList( 242 new Object[] { "LinkedHashMap", mode, new LinkedHashMap<>(), List.of() }, 243 new Object[] { "SimpleSortedMap", mode, new SimpleSortedMap<>(), List.of() }, 244 new Object[] { "TreeMap", mode, new TreeMap<>(), List.of() } 245 )); 246 } 247 return cases.iterator(); 248 } 249 250 @DataProvider(name="viewAddThrows") viewAddThrows()251 public Iterator<Object[]> viewAddThrows() { 252 var cases = new ArrayList<Object[]>(); 253 for (int mode = 0; mode < 8; mode++) { 254 cases.addAll(Arrays.asList( 255 new Object[] { "LinkedHashMap", mode, load(new LinkedHashMap<>(), ORIGINAL), ORIGINAL }, 256 new Object[] { "SimpleSortedMap", mode, load(new SimpleSortedMap<>(), ORIGINAL), ORIGINAL }, 257 new Object[] { "TreeMap", mode, load(new TreeMap<>(), ORIGINAL), ORIGINAL } 258 )); 259 } 260 return cases.iterator(); 261 } 262 263 @DataProvider(name="nullableEntries") nullableEntries()264 public Iterator<Object[]> nullableEntries() { 265 return Arrays.asList( 266 new Object[] { "firstEntry" }, 267 new Object[] { "lastEntry" }, 268 new Object[] { "pollFirstEntry" }, 269 new Object[] { "pollLastEntry" } 270 ).iterator(); 271 } 272 273 // ========== Assertions ========== 274 275 /** 276 * Basic checks over the contents of a SequencedMap, compared to a reference List of entries, 277 * in one direction. 278 * 279 * @param map the SequencedMap under test 280 * @param ref the reference list of entries 281 */ checkContents1(SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> ref)282 public void checkContents1(SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> ref) { 283 var list1 = new ArrayList<Map.Entry<String, Integer>>(); 284 map.forEach((k, v) -> list1.add(Map.entry(k, v))); 285 assertEquals(list1, ref); 286 287 assertEquals(map.size(), ref.size()); 288 assertEquals(map.isEmpty(), ref.isEmpty()); 289 290 for (var e : ref) { 291 assertTrue(map.containsKey(e.getKey())); 292 assertTrue(map.containsValue(e.getValue())); 293 assertEquals(map.get(e.getKey()), e.getValue()); 294 } 295 } 296 checkContents(SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> ref)297 public void checkContents(SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> ref) { 298 checkContents1(map, ref); 299 300 var rref = new ArrayList<>(ref); 301 Collections.reverse(rref); 302 var rmap = map.reversed(); 303 checkContents1(rmap, rref); 304 305 var rrmap = rmap.reversed(); 306 checkContents1(rrmap, ref); 307 } 308 309 /** 310 * Check the entrySet, keySet, or values view of a SequencedMap in one direction. The view 311 * collection is ordered even though the collection type is not sequenced. 312 * 313 * @param <T> the element type of the view 314 * @param mapView the actual map view 315 * @param expElements list of the expected elements 316 */ checkView1(Collection<T> mapView, List<T> expElements)317 public <T> void checkView1(Collection<T> mapView, List<T> expElements) { 318 var list1 = new ArrayList<T>(); 319 for (var k : mapView) 320 list1.add(k); 321 assertEquals(list1, expElements); 322 323 var list2 = new ArrayList<T>(); 324 mapView.forEach(list2::add); 325 assertEquals(list2, expElements); 326 327 var list3 = Arrays.asList(mapView.toArray()); 328 assertEquals(list3, expElements); 329 330 var list4 = Arrays.asList(mapView.toArray(new Object[0])); 331 assertEquals(list4, expElements); 332 333 var list5 = Arrays.asList(mapView.toArray(Object[]::new)); 334 assertEquals(list5, expElements); 335 336 var list6 = mapView.stream().toList(); 337 assertEquals(list6, expElements); 338 339 var list7 = mapView.parallelStream().toList(); 340 assertEquals(list7, expElements); 341 342 assertEquals(mapView.size(), expElements.size()); 343 assertEquals(mapView.isEmpty(), expElements.isEmpty()); 344 345 for (var k : expElements) { 346 assertTrue(mapView.contains(k)); 347 } 348 349 var it = mapView.iterator(); 350 if (expElements.isEmpty()) { 351 assertFalse(it.hasNext()); 352 } else { 353 assertTrue(it.hasNext()); 354 assertEquals(it.next(), expElements.get(0)); 355 } 356 } 357 358 /** 359 * Check the sequenced entrySet, keySet, or values view of a SequencedMap in one direction. 360 * 361 * @param <T> the element type of the view 362 * @param mapView the actual map view 363 * @param expElements list of the expected elements 364 */ checkSeqView1(SequencedCollection<T> mapView, List<T> expElements)365 public <T> void checkSeqView1(SequencedCollection<T> mapView, List<T> expElements) { 366 checkView1(mapView, expElements); 367 368 if (expElements.isEmpty()) { 369 assertThrows(NoSuchElementException.class, () -> mapView.getFirst()); 370 assertThrows(NoSuchElementException.class, () -> mapView.getLast()); 371 } else { 372 assertEquals(mapView.getFirst(), expElements.get(0)); 373 assertEquals(mapView.getLast(), expElements.get(expElements.size() - 1)); 374 } 375 } 376 377 /** 378 * Check the keySet and sequencedKeySet views of a map. It's possible to unify this with 379 * the corresponding checks for values and entrySet views, but doing this adds a bunch 380 * of generics and method references that tend to obscure more than they help. 381 * 382 * @param map the SequencedMap under test 383 * @param refEntries expected contents of the map 384 */ checkKeySet(SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> refEntries)385 public void checkKeySet(SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> refEntries) { 386 List<String> refKeys = refEntries.stream().map(Map.Entry::getKey).toList(); 387 List<String> rrefKeys = new ArrayList<>(refKeys); 388 Collections.reverse(rrefKeys); 389 SequencedMap<String, Integer> rmap = map.reversed(); 390 391 checkView1(map.keySet(), refKeys); 392 checkSeqView1(map.sequencedKeySet(), refKeys); 393 checkSeqView1(map.sequencedKeySet().reversed(), rrefKeys); 394 395 checkView1(rmap.keySet(), rrefKeys); 396 checkSeqView1(rmap.sequencedKeySet(), rrefKeys); 397 checkSeqView1(rmap.sequencedKeySet().reversed(), refKeys); 398 399 checkView1(rmap.reversed().keySet(), refKeys); 400 checkSeqView1(rmap.reversed().sequencedKeySet(), refKeys); 401 checkSeqView1(rmap.reversed().sequencedKeySet().reversed(), rrefKeys); 402 403 assertEquals(map.keySet().hashCode(), rmap.keySet().hashCode()); 404 assertEquals(map.keySet().hashCode(), map.sequencedKeySet().hashCode()); 405 assertEquals(rmap.keySet().hashCode(), rmap.sequencedKeySet().hashCode()); 406 407 // Don't use assertEquals(), as we really want to test the equals() methods. 408 assertTrue(map.keySet().equals(map.sequencedKeySet())); 409 assertTrue(map.sequencedKeySet().equals(map.keySet())); 410 assertTrue(rmap.keySet().equals(map.sequencedKeySet())); 411 assertTrue(rmap.sequencedKeySet().equals(map.keySet())); 412 assertTrue(map.keySet().equals(rmap.sequencedKeySet())); 413 assertTrue(map.sequencedKeySet().equals(rmap.keySet())); 414 assertTrue(rmap.keySet().equals(rmap.sequencedKeySet())); 415 assertTrue(rmap.sequencedKeySet().equals(rmap.keySet())); 416 } 417 418 /** 419 * Check the values and sequencedValues views of a map. 420 * 421 * @param map the SequencedMap under test 422 * @param refEntries expected contents of the map 423 */ checkValues(SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> refEntries)424 public void checkValues(SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> refEntries) { 425 List<Integer> refValues = refEntries.stream().map(Map.Entry::getValue).toList(); 426 List<Integer> rrefValues = new ArrayList<>(refValues); 427 Collections.reverse(rrefValues); 428 SequencedMap<String, Integer> rmap = map.reversed(); 429 430 checkView1(map.values(), refValues); 431 checkSeqView1(map.sequencedValues(), refValues); 432 checkSeqView1(map.sequencedValues().reversed(), rrefValues); 433 434 checkView1(rmap.values(), rrefValues); 435 checkSeqView1(rmap.sequencedValues(), rrefValues); 436 checkSeqView1(rmap.sequencedValues().reversed(), refValues); 437 438 checkView1(rmap.reversed().values(), refValues); 439 checkSeqView1(rmap.reversed().sequencedValues(), refValues); 440 checkSeqView1(rmap.reversed().sequencedValues().reversed(), rrefValues); 441 442 // No assertions over hashCode(), as Collection inherits Object.hashCode 443 // which is usually but not guaranteed to give unequal results. 444 445 // It's permissible for an implementation to return the same instance for values() 446 // as for sequencedValues(). Either they're the same instance, or they must be 447 // unequal, because distinct collections should always be unequal. 448 449 var v = map.values(); 450 var sv = map.sequencedValues(); 451 assertTrue((v == sv) || ! (v.equals(sv) || sv.equals(v))); 452 453 var rv = rmap.values(); 454 var rsv = rmap.sequencedValues(); 455 assertTrue((rv == rsv) || ! (rv.equals(rsv) || rsv.equals(rv))); 456 } 457 458 /** 459 * Check the entrySet and sequencedEntrySet views of a map. 460 * 461 * @param map the SequencedMap under test 462 * @param refEntries expected contents of the map 463 */ checkEntrySet(SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> refEntries)464 public void checkEntrySet(SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> refEntries) { 465 List<Map.Entry<String, Integer>> rref = new ArrayList<>(refEntries); 466 Collections.reverse(rref); 467 SequencedMap<String, Integer> rmap = map.reversed(); 468 469 checkView1(map.entrySet(), refEntries); 470 checkSeqView1(map.sequencedEntrySet(), refEntries); 471 checkSeqView1(map.sequencedEntrySet().reversed(), rref); 472 473 checkView1(rmap.entrySet(), rref); 474 checkSeqView1(rmap.sequencedEntrySet(), rref); 475 checkSeqView1(rmap.sequencedEntrySet().reversed(), refEntries); 476 477 checkView1(rmap.reversed().entrySet(), refEntries); 478 checkSeqView1(rmap.reversed().sequencedEntrySet(), refEntries); 479 checkSeqView1(rmap.reversed().sequencedEntrySet().reversed(), rref); 480 481 assertEquals(map.entrySet().hashCode(), rmap.entrySet().hashCode()); 482 assertEquals(map.entrySet().hashCode(), map.sequencedEntrySet().hashCode()); 483 assertEquals(map.sequencedEntrySet().hashCode(), map.entrySet().hashCode()); 484 485 assertTrue(map.entrySet().equals(map.sequencedEntrySet())); 486 assertTrue(map.sequencedEntrySet().equals(map.entrySet())); 487 assertTrue(rmap.entrySet().equals(map.sequencedEntrySet())); 488 assertTrue(rmap.sequencedEntrySet().equals(map.entrySet())); 489 assertTrue(map.entrySet().equals(rmap.sequencedEntrySet())); 490 assertTrue(map.sequencedEntrySet().equals(rmap.entrySet())); 491 assertTrue(rmap.entrySet().equals(rmap.sequencedEntrySet())); 492 assertTrue(rmap.sequencedEntrySet().equals(rmap.entrySet())); 493 } 494 495 /** 496 * Test attempted modifications to unmodifiable map views. The only mutating operation 497 * map views can support is removal. 498 * 499 * @param <T> element type of the map view 500 * @param view the map view 501 */ checkUnmodifiableView(Collection<T> view)502 public <T> void checkUnmodifiableView(Collection<T> view) { 503 assertThrows(UOE, () -> view.clear()); 504 assertThrows(UOE, () -> { var it = view.iterator(); it.next(); it.remove(); }); 505 assertThrows(UOE, () -> { var t = view.iterator().next(); view.remove(t); }); 506 507 // TODO these ops should throw unconditionally, but they don't in some implementations 508 // assertThrows(UOE, () -> view.removeAll(List.of())); 509 // assertThrows(UOE, () -> view.removeIf(x -> false)); 510 // assertThrows(UOE, () -> view.retainAll(view)); 511 assertThrows(UOE, () -> view.removeAll(view)); 512 assertThrows(UOE, () -> view.removeIf(x -> true)); 513 assertThrows(UOE, () -> view.retainAll(List.of())); 514 } 515 516 /** 517 * Test removal methods on unmodifiable sequenced map views. 518 * 519 * @param <T> element type of the map view 520 * @param view the map view 521 */ checkUnmodifiableSeqView(SequencedCollection<T> view)522 public <T> void checkUnmodifiableSeqView(SequencedCollection<T> view) { 523 checkUnmodifiableView(view); 524 assertThrows(UOE, () -> view.removeFirst()); 525 assertThrows(UOE, () -> view.removeLast()); 526 527 var rview = view.reversed(); 528 checkUnmodifiableView(rview); 529 assertThrows(UOE, () -> rview.removeFirst()); 530 assertThrows(UOE, () -> rview.removeLast()); 531 } 532 checkUnmodifiableEntry(SequencedMap<String, Integer> map)533 public void checkUnmodifiableEntry(SequencedMap<String, Integer> map) { 534 assertThrows(UOE, () -> { map.firstEntry().setValue(99); }); 535 assertThrows(UOE, () -> { map.lastEntry().setValue(99); }); 536 assertThrows(UOE, () -> { map.sequencedEntrySet().getFirst().setValue(99); }); 537 assertThrows(UOE, () -> { map.sequencedEntrySet().getLast().setValue(99); }); 538 assertThrows(UOE, () -> { map.sequencedEntrySet().reversed().getFirst().setValue(99); }); 539 assertThrows(UOE, () -> { map.sequencedEntrySet().reversed().getLast().setValue(99); }); 540 } 541 checkUnmodifiable1(SequencedMap<String, Integer> map)542 public void checkUnmodifiable1(SequencedMap<String, Integer> map) { 543 assertThrows(UOE, () -> map.putFirst("x", 99)); 544 assertThrows(UOE, () -> map.putLast("x", 99)); 545 assertThrows(UOE, () -> { map.pollFirstEntry(); }); 546 assertThrows(UOE, () -> { map.pollLastEntry(); }); 547 548 checkUnmodifiableEntry(map); 549 checkUnmodifiableView(map.keySet()); 550 checkUnmodifiableView(map.values()); 551 checkUnmodifiableView(map.entrySet()); 552 checkUnmodifiableSeqView(map.sequencedKeySet()); 553 checkUnmodifiableSeqView(map.sequencedValues()); 554 checkUnmodifiableSeqView(map.sequencedEntrySet()); 555 } 556 checkUnmodifiable(SequencedMap<String, Integer> map)557 public void checkUnmodifiable(SequencedMap<String, Integer> map) { 558 checkUnmodifiable1(map); 559 checkUnmodifiable1(map.reversed()); 560 } 561 562 // The putFirst/putLast operations aren't tested here, because the only instances of 563 // checked, sequenced maps are SortedMap and NavigableMap, which don't support them. checkChecked(SequencedMap<String, Integer> map)564 public void checkChecked(SequencedMap<String, Integer> map) { 565 SequencedMap<Object, Object> objMap = (SequencedMap<Object, Object>)(SequencedMap)map; 566 assertThrows(CCE, () -> { objMap.put(new Object(), 99); }); 567 assertThrows(CCE, () -> { objMap.put("x", new Object()); }); 568 assertThrows(CCE, () -> { objMap.sequencedEntrySet().getFirst().setValue(new Object()); }); 569 assertThrows(CCE, () -> { objMap.sequencedEntrySet().reversed().getFirst().setValue(new Object()); }); 570 assertThrows(CCE, () -> { objMap.reversed().put(new Object(), 99); }); 571 assertThrows(CCE, () -> { objMap.reversed().put("x", new Object()); }); 572 assertThrows(CCE, () -> { objMap.reversed().sequencedEntrySet().getFirst().setValue(new Object()); }); 573 assertThrows(CCE, () -> { objMap.reversed().sequencedEntrySet().reversed().getFirst().setValue(new Object()); }); 574 } 575 checkEntry(Map.Entry<String, Integer> entry, String key, Integer value)576 public void checkEntry(Map.Entry<String, Integer> entry, String key, Integer value) { 577 assertEquals(entry.getKey(), key); 578 assertEquals(entry.getValue(), value); 579 } 580 581 // ========== Tests ========== 582 583 @Test(dataProvider="all") testFundamentals(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> ref)584 public void testFundamentals(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> ref) { 585 checkContents(map, ref); 586 checkEntrySet(map, ref); 587 checkKeySet(map, ref); 588 checkValues(map, ref); 589 } 590 591 @Test(dataProvider="populated") testFirstEntry(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> ref)592 public void testFirstEntry(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> ref) { 593 assertEquals(map.firstEntry(), ref.get(0)); 594 assertEquals(map.reversed().firstEntry(), ref.get(ref.size() - 1)); 595 assertThrows(UOE, () -> { map.firstEntry().setValue(99); }); 596 assertThrows(UOE, () -> { map.reversed().firstEntry().setValue(99); }); 597 checkContents(map, ref); 598 } 599 600 @Test(dataProvider="populated") testLastEntry(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> ref)601 public void testLastEntry(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> ref) { 602 assertEquals(map.lastEntry(), ref.get(ref.size() - 1)); 603 assertEquals(map.reversed().lastEntry(), ref.get(0)); 604 assertThrows(UOE, () -> { map.lastEntry().setValue(99); }); 605 assertThrows(UOE, () -> { map.reversed().lastEntry().setValue(99); }); 606 checkContents(map, ref); 607 } 608 609 @Test(dataProvider="empties") testEmptyFirstEntry(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> ref)610 public void testEmptyFirstEntry(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> ref) { 611 assertNull(map.firstEntry()); 612 assertNull(map.reversed().firstEntry()); 613 checkContents(map, ref); 614 } 615 616 @Test(dataProvider="empties") testEmptyLastEntry(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> ref)617 public void testEmptyLastEntry(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> ref) { 618 assertNull(map.lastEntry()); 619 assertNull(map.reversed().lastEntry()); 620 checkContents(map, ref); 621 } 622 623 @Test(dataProvider="puts") testPutFirst(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref)624 public void testPutFirst(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref) { 625 var ref = new ArrayList<>(baseref); 626 ref.add(0, Map.entry("x", 99)); 627 map.putFirst("x", 99); 628 checkContents(map, ref); 629 } 630 631 @Test(dataProvider="puts") testPutFirstRev(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref)632 public void testPutFirstRev(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref) { 633 var ref = new ArrayList<>(baseref); 634 ref.add(Map.entry("x", 99)); 635 map.reversed().putFirst("x", 99); 636 checkContents(map, ref); 637 } 638 639 @Test(dataProvider="puts") testPutLast(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref)640 public void testPutLast(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref) { 641 var ref = new ArrayList<>(baseref); 642 ref.add(Map.entry("x", 99)); 643 map.putLast("x", 99); 644 checkContents(map, ref); 645 } 646 647 @Test(dataProvider="puts") testPutLastRev(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref)648 public void testPutLastRev(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref) { 649 var ref = new ArrayList<>(baseref); 650 ref.add(0, Map.entry("x", 99)); 651 map.reversed().putLast("x", 99); 652 checkContents(map, ref); 653 } 654 655 @Test(dataProvider="putUnpositioned") testUnposPut(String label, boolean rev, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref)656 public void testUnposPut(String label, boolean rev, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref) { 657 var ref = new ArrayList<>(baseref); 658 ref.add(Map.entry("x", 99)); 659 (rev ? map.reversed() : map).put("x", 99); 660 checkContents(map, ref); 661 } 662 663 @Test(dataProvider="putUnpositioned") testUnposPutAll(String label, boolean rev, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref)664 public void testUnposPutAll(String label, boolean rev, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref) { 665 var ref = new ArrayList<>(baseref); 666 ref.add(Map.entry("x", 99)); 667 (rev ? map.reversed() : map).putAll(Map.of("x", 99)); 668 checkContents(map, ref); 669 } 670 671 @Test(dataProvider="putUnpositioned") testUnposPutIfAbsent(String label, boolean rev, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref)672 public void testUnposPutIfAbsent(String label, boolean rev, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref) { 673 var ref = new ArrayList<>(baseref); 674 ref.add(Map.entry("x", 99)); 675 (rev ? map.reversed() : map).putIfAbsent("x", 99); 676 checkContents(map, ref); 677 } 678 679 @Test(dataProvider="putUnpositioned") testUnposCompute(String label, boolean rev, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref)680 public void testUnposCompute(String label, boolean rev, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref) { 681 var ref = new ArrayList<>(baseref); 682 ref.add(Map.entry("x", 99)); 683 (rev ? map.reversed() : map).compute("x", (k, v) -> 99); 684 checkContents(map, ref); 685 } 686 687 @Test(dataProvider="putUnpositioned") testUnposComputeIfAbsent(String label, boolean rev, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref)688 public void testUnposComputeIfAbsent(String label, boolean rev, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref) { 689 var ref = new ArrayList<>(baseref); 690 ref.add(Map.entry("x", 99)); 691 (rev ? map.reversed() : map).computeIfAbsent("x", k -> 99); 692 checkContents(map, ref); 693 } 694 695 @Test(dataProvider="putUnpositioned") testUnposMerge(String label, boolean rev, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref)696 public void testUnposMerge(String label, boolean rev, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref) { 697 var ref = new ArrayList<>(baseref); 698 ref.add(Map.entry("x", 99)); 699 (rev ? map.reversed() : map).merge("x", 99, /*unused*/ (k, v) -> -1); 700 checkContents(map, ref); 701 } 702 703 @Test(dataProvider="putThrows") testPutThrows(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref)704 public void testPutThrows(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref) { 705 assertThrows(UOE, () -> map.putFirst("x", 99)); 706 assertThrows(UOE, () -> map.putLast("x", 99)); 707 assertThrows(UOE, () -> map.reversed().putFirst("x", 99)); 708 assertThrows(UOE, () -> map.reversed().putLast("x", 99)); 709 checkContents(map, baseref); 710 } 711 712 @Test(dataProvider="polls") testPollFirst(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref)713 public void testPollFirst(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref) { 714 var ref = new ArrayList<>(baseref); 715 var act = map.pollFirstEntry(); 716 assertEquals(act, ref.remove(0)); 717 assertThrows(UOE, () -> { act.setValue(99); }); 718 checkContents(map, ref); 719 } 720 721 @Test(dataProvider="polls") testPollFirstRev(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref)722 public void testPollFirstRev(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref) { 723 var ref = new ArrayList<>(baseref); 724 var act = map.reversed().pollFirstEntry(); 725 assertEquals(act, ref.remove(ref.size() - 1)); 726 assertThrows(UOE, () -> { act.setValue(99); }); 727 checkContents(map, ref); 728 } 729 730 @Test(dataProvider="polls") testPollLast(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref)731 public void testPollLast(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref) { 732 var ref = new ArrayList<>(baseref); 733 var act = map.pollLastEntry(); 734 assertEquals(act, ref.remove(ref.size() - 1)); 735 assertThrows(UOE, () -> { act.setValue(99); }); 736 checkContents(map, ref); 737 } 738 739 @Test(dataProvider="polls") testPollLastRev(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref)740 public void testPollLastRev(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref) { 741 var ref = new ArrayList<>(baseref); 742 var act = map.reversed().pollLastEntry(); 743 assertEquals(act, ref.remove(0)); 744 assertThrows(UOE, () -> { act.setValue(99); }); 745 checkContents(map, ref); 746 } 747 748 @Test(dataProvider="emptyPolls") testEmptyPollFirst(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> ref)749 public void testEmptyPollFirst(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> ref) { 750 assertNull(map.pollFirstEntry()); 751 assertNull(map.reversed().pollFirstEntry()); 752 checkContents(map, ref); 753 } 754 755 @Test(dataProvider="emptyPolls") testEmptyPollLast(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> ref)756 public void testEmptyPollLast(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> ref) { 757 assertNull(map.pollLastEntry()); 758 assertNull(map.reversed().pollLastEntry()); 759 checkContents(map, ref); 760 } 761 762 @Test(dataProvider="serializable") testSerializable(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> ref)763 public void testSerializable(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> ref) 764 throws ClassNotFoundException, IOException 765 { 766 var baos = new ByteArrayOutputStream(); 767 try (var oos = new ObjectOutputStream(baos)) { 768 oos.writeObject(map); 769 } 770 771 try (var bais = new ByteArrayInputStream(baos.toByteArray()); 772 var ois = new ObjectInputStream(bais)) { 773 var map2 = (SequencedMap<String, Integer>) ois.readObject(); 774 checkContents(map2, ref); 775 } 776 } 777 778 @Test(dataProvider="notSerializable") testNotSerializable(String label, SequencedMap<String, Integer> map)779 public void testNotSerializable(String label, SequencedMap<String, Integer> map) 780 throws ClassNotFoundException, IOException 781 { 782 var baos = new ByteArrayOutputStream(); 783 try (var oos = new ObjectOutputStream(baos)) { 784 assertThrows(ObjectStreamException.class, () -> oos.writeObject(map)); 785 } 786 } 787 788 @Test(dataProvider="doubleReverse") testDoubleReverse(String label, SequencedMap<String, Integer> map)789 public void testDoubleReverse(String label, SequencedMap<String, Integer> map) { 790 var rrmap = map.reversed().reversed(); 791 assertSame(rrmap, map); 792 } 793 794 @Test(dataProvider="unmodifiable") testUnmodifiable(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> ref)795 public void testUnmodifiable(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> ref) { 796 checkUnmodifiable(map); 797 checkContents(map, ref); 798 } 799 800 @Test(dataProvider="checked") testChecked(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> ref)801 public void testChecked(String label, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> ref) { 802 checkChecked(map); 803 checkContents(map, ref); 804 } 805 806 /** 807 * Test that a removal from the sequenedKeySet view is properly reflected in the original 808 * backing map. The mode value indicates whether the backing map is reversed, whether the 809 * sequencedKeySet view is reversed, and whether the removeFirst or removeLast is called 810 * on the view. See the viewRemoves() dataProvider for details. 811 * 812 * @param label the implementation label 813 * @param mode reversed and first/last modes 814 * @param map the original map instance 815 * @param baseref reference contents of the original map 816 */ 817 @Test(dataProvider="viewRemoves") testKeySetRemoves(String label, int mode, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref)818 public void testKeySetRemoves(String label, 819 int mode, 820 SequencedMap<String, Integer> map, 821 List<Map.Entry<String, Integer>> baseref) { 822 var ref = new ArrayList<>(baseref); 823 var exp = (refLast(mode) ? ref.remove(ref.size() - 1) : ref.remove(0)).getKey(); 824 var tempmap = reverseMap(mode) ? map.reversed() : map; 825 var keySet = reverseView(mode) ? tempmap.sequencedKeySet().reversed() : tempmap.sequencedKeySet(); 826 var act = callLast(mode) ? keySet.removeLast() : keySet.removeFirst(); 827 assertEquals(act, exp); 828 checkContents(map, ref); 829 } 830 831 // As above, but for the sequencedValues view. 832 @Test(dataProvider="viewRemoves") testValuesRemoves(String label, int mode, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref)833 public void testValuesRemoves(String label, 834 int mode, 835 SequencedMap<String, Integer> map, 836 List<Map.Entry<String, Integer>> baseref) { 837 var ref = new ArrayList<>(baseref); 838 var exp = (refLast(mode) ? ref.remove(ref.size() - 1) : ref.remove(0)).getValue(); 839 var tempmap = reverseMap(mode) ? map.reversed() : map; 840 var values = reverseView(mode) ? tempmap.sequencedValues().reversed() : tempmap.sequencedValues(); 841 var act = callLast(mode) ? values.removeLast() : values.removeFirst(); 842 assertEquals(act, exp); 843 checkContents(map, ref); 844 } 845 846 // As above, but for the sequencedEntrySet view. 847 @Test(dataProvider="viewRemoves") testEntrySetRemoves(String label, int mode, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref)848 public void testEntrySetRemoves(String label, 849 int mode, 850 SequencedMap<String, Integer> map, 851 List<Map.Entry<String, Integer>> baseref) { 852 var ref = new ArrayList<>(baseref); 853 var exp = refLast(mode) ? ref.remove(ref.size() - 1) : ref.remove(0); 854 var tempmap = reverseMap(mode) ? map.reversed() : map; 855 var entrySet = reverseView(mode) ? tempmap.sequencedEntrySet().reversed() : tempmap.sequencedEntrySet(); 856 var act = callLast(mode) ? entrySet.removeLast() : entrySet.removeFirst(); 857 assertEquals(act, exp); 858 checkContents(map, ref); 859 } 860 861 // As above, but for the sequencedKeySet of an empty map. 862 @Test(dataProvider="emptyViewRemoves") testEmptyKeySetRemoves(String label, int mode, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref)863 public void testEmptyKeySetRemoves(String label, 864 int mode, 865 SequencedMap<String, Integer> map, 866 List<Map.Entry<String, Integer>> baseref) { 867 var tempmap = reverseMap(mode) ? map.reversed() : map; 868 var keySet = reverseView(mode) ? tempmap.sequencedKeySet().reversed() : tempmap.sequencedKeySet(); 869 if (callLast(mode)) 870 assertThrows(NSEE, () -> keySet.removeLast()); 871 else 872 assertThrows(NSEE, () -> keySet.removeFirst()); 873 checkContents(map, baseref); 874 875 } 876 877 // As above, but for the sequencedValues view. 878 @Test(dataProvider="emptyViewRemoves") testEmptyValuesRemoves(String label, int mode, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref)879 public void testEmptyValuesRemoves(String label, 880 int mode, 881 SequencedMap<String, Integer> map, 882 List<Map.Entry<String, Integer>> baseref) { 883 var tempmap = reverseMap(mode) ? map.reversed() : map; 884 var values = reverseView(mode) ? tempmap.sequencedValues().reversed() : tempmap.sequencedValues(); 885 if (callLast(mode)) 886 assertThrows(NSEE, () -> values.removeLast()); 887 else 888 assertThrows(NSEE, () -> values.removeFirst()); 889 checkContents(map, baseref); 890 } 891 892 // As above, but for the sequencedEntrySet view. 893 @Test(dataProvider="emptyViewRemoves") testEmptyEntrySetRemoves(String label, int mode, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref)894 public void testEmptyEntrySetRemoves(String label, 895 int mode, 896 SequencedMap<String, Integer> map, 897 List<Map.Entry<String, Integer>> baseref) { 898 var tempmap = reverseMap(mode) ? map.reversed() : map; 899 var entrySet = reverseView(mode) ? tempmap.sequencedEntrySet().reversed() : tempmap.sequencedEntrySet(); 900 if (callLast(mode)) 901 assertThrows(NSEE, () -> entrySet.removeLast()); 902 else 903 assertThrows(NSEE, () -> entrySet.removeFirst()); 904 checkContents(map, baseref); 905 } 906 907 // Test that addFirst/addLast on the sequencedKeySetView throw UnsupportedOperationException. 908 @Test(dataProvider="viewAddThrows") testKeySetAddThrows(String label, int mode, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref)909 public void testKeySetAddThrows(String label, 910 int mode, 911 SequencedMap<String, Integer> map, 912 List<Map.Entry<String, Integer>> baseref) { 913 var tempmap = reverseMap(mode) ? map.reversed() : map; 914 var keySet = reverseView(mode) ? tempmap.sequencedKeySet().reversed() : tempmap.sequencedKeySet(); 915 if (callLast(mode)) 916 assertThrows(UOE, () -> keySet.addLast("x")); 917 else 918 assertThrows(UOE, () -> keySet.addFirst("x")); 919 checkContents(map, baseref); 920 } 921 922 // As above, but for the sequencedValues view. 923 @Test(dataProvider="viewAddThrows") testValuesAddThrows(String label, int mode, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref)924 public void testValuesAddThrows(String label, 925 int mode, 926 SequencedMap<String, Integer> map, 927 List<Map.Entry<String, Integer>> baseref) { 928 var tempmap = reverseMap(mode) ? map.reversed() : map; 929 var values = reverseView(mode) ? tempmap.sequencedValues().reversed() : tempmap.sequencedValues(); 930 if (callLast(mode)) 931 assertThrows(UOE, () -> values.addLast(99)); 932 else 933 assertThrows(UOE, () -> values.addFirst(99)); 934 checkContents(map, baseref); 935 } 936 937 // As above, but for the sequencedEntrySet view. 938 @Test(dataProvider="viewAddThrows") testEntrySetAddThrows(String label, int mode, SequencedMap<String, Integer> map, List<Map.Entry<String, Integer>> baseref)939 public void testEntrySetAddThrows(String label, 940 int mode, 941 SequencedMap<String, Integer> map, 942 List<Map.Entry<String, Integer>> baseref) { 943 var tempmap = reverseMap(mode) ? map.reversed() : map; 944 var entrySet = reverseView(mode) ? tempmap.sequencedEntrySet().reversed() : tempmap.sequencedEntrySet(); 945 if (callLast(mode)) 946 assertThrows(UOE, () -> entrySet.addLast(Map.entry("x", 99))); 947 else 948 assertThrows(UOE, () -> entrySet.addFirst(Map.entry("x", 99))); 949 checkContents(map, baseref); 950 } 951 952 @Test(dataProvider="nullableEntries") testNullableKeyValue(String mode)953 public void testNullableKeyValue(String mode) { 954 // TODO this relies on LHM to inherit SequencedMap default 955 // methods which are actually being tested here. 956 SequencedMap<String, Integer> map = new LinkedHashMap<>(); 957 map.put(null, 1); 958 map.put("two", null); 959 960 switch (mode) { 961 case "firstEntry" -> checkEntry(map.firstEntry(), null, 1); 962 case "lastEntry" -> checkEntry(map.lastEntry(), "two", null); 963 case "pollFirstEntry" -> checkEntry(map.pollFirstEntry(), null, 1); 964 case "pollLastEntry" -> checkEntry(map.pollLastEntry(), "two", null); 965 default -> throw new AssertionError("illegal mode " + mode); 966 } 967 } 968 } 969