1 /*
   2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.
   7  *
   8  * This code is distributed in the hope that it will be useful, but WITHOUT
   9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  11  * version 2 for more details (a copy is included in the LICENSE file that
  12  * accompanied this code).
  13  *
  14  * You should have received a copy of the GNU General Public License version
  15  * 2 along with this work; if not, write to the Free Software Foundation,
  16  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  17  *
  18  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  19  * or visit www.oracle.com if you need additional information or have any
  20  * questions.
  21  */
  22 
  23 /*
  24  * This file is available under and governed by the GNU General Public
  25  * License version 2 only, as published by the Free Software Foundation.
  26  * However, the following notice accompanied the original version of this
  27  * file:
  28  *
  29  * Written by Doug Lea with assistance from members of JCP JSR-166
  30  * Expert Group and released to the public domain, as explained at
  31  * http://creativecommons.org/publicdomain/zero/1.0/
  32  * Other contributors include Andrew Wright, Jeffrey Hayes,
  33  * Pat Fisher, Mike Judd.
  34  */
  35 
  36 import java.util.ArrayList;
  37 import java.util.Arrays;
  38 import java.util.Collection;
  39 import java.util.Collections;
  40 import java.util.Iterator;
  41 import java.util.List;
  42 import java.util.ListIterator;
  43 import java.util.NoSuchElementException;
  44 import java.util.concurrent.CopyOnWriteArrayList;
  45 import java.util.concurrent.ThreadLocalRandom;
  46 
  47 import junit.framework.Test;
  48 
  49 public class CopyOnWriteArrayListTest extends JSR166TestCase {
  50 
  51     public static void main(String[] args) {
  52         main(suite(), args);
  53     }
  54 
  55     public static Test suite() {
  56         class Implementation implements CollectionImplementation {
  57             public Class<?> klazz() { return CopyOnWriteArrayList.class; }
  58             public List emptyCollection() { return new CopyOnWriteArrayList(); }
  59             public Object makeElement(int i) { return i; }
  60             public boolean isConcurrent() { return true; }
  61             public boolean permitsNulls() { return true; }
  62         }
  63         class SubListImplementation extends Implementation {
  64             public List emptyCollection() {
  65                 List list = super.emptyCollection();
  66                 ThreadLocalRandom rnd = ThreadLocalRandom.current();
  67                 if (rnd.nextBoolean())
  68                     list.add(makeElement(rnd.nextInt()));
  69                 int i = rnd.nextInt(list.size() + 1);
  70                 return list.subList(i, i);
  71             }
  72         }
  73         return newTestSuite(
  74                 CopyOnWriteArrayListTest.class,
  75                 CollectionTest.testSuite(new Implementation()),
  76                 CollectionTest.testSuite(new SubListImplementation()));
  77     }
  78 
  79     static CopyOnWriteArrayList<Integer> populatedList(int n) {
  80         CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<>();
  81         assertTrue(list.isEmpty());
  82         for (int i = 0; i < n; i++)
  83             list.add(i);
  84         assertEquals(n <= 0, list.isEmpty());
  85         assertEquals(n, list.size());
  86         return list;
  87     }
  88 
  89     static CopyOnWriteArrayList<Integer> populatedList(Integer[] elements) {
  90         CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<>();
  91         assertTrue(list.isEmpty());
  92         for (Integer element : elements)
  93             list.add(element);
  94         assertFalse(list.isEmpty());
  95         assertEquals(elements.length, list.size());
  96         return list;
  97     }
  98 
  99     /**
 100      * a new list is empty
 101      */
 102     public void testConstructor() {
 103         List list = new CopyOnWriteArrayList();
 104         assertTrue(list.isEmpty());
 105     }
 106 
 107     /**
 108      * new list contains all elements of initializing array
 109      */
 110     public void testConstructor2() {
 111         Integer[] elts = new Integer[SIZE];
 112         for (int i = 0; i < SIZE - 1; ++i)
 113             elts[i] = i;
 114         List list = new CopyOnWriteArrayList(elts);
 115         for (int i = 0; i < SIZE; ++i)
 116             assertEquals(elts[i], list.get(i));
 117     }
 118 
 119     /**
 120      * new list contains all elements of initializing collection
 121      */
 122     public void testConstructor3() {
 123         Integer[] elts = new Integer[SIZE];
 124         for (int i = 0; i < SIZE - 1; ++i)
 125             elts[i] = i;
 126         List list = new CopyOnWriteArrayList(Arrays.asList(elts));
 127         for (int i = 0; i < SIZE; ++i)
 128             assertEquals(elts[i], list.get(i));
 129     }
 130 
 131     /**
 132      * addAll adds each element from the given collection, including duplicates
 133      */
 134     public void testAddAll() {
 135         List list = populatedList(3);
 136         assertTrue(list.addAll(Arrays.asList(three, four, five)));
 137         assertEquals(6, list.size());
 138         assertTrue(list.addAll(Arrays.asList(three, four, five)));
 139         assertEquals(9, list.size());
 140     }
 141 
 142     /**
 143      * addAllAbsent adds each element from the given collection that did not
 144      * already exist in the List
 145      */
 146     public void testAddAllAbsent() {
 147         CopyOnWriteArrayList list = populatedList(3);
 148         // "one" is duplicate and will not be added
 149         assertEquals(2, list.addAllAbsent(Arrays.asList(three, four, one)));
 150         assertEquals(5, list.size());
 151         assertEquals(0, list.addAllAbsent(Arrays.asList(three, four, one)));
 152         assertEquals(5, list.size());
 153     }
 154 
 155     /**
 156      * addIfAbsent will not add the element if it already exists in the list
 157      */
 158     public void testAddIfAbsent() {
 159         CopyOnWriteArrayList list = populatedList(SIZE);
 160         list.addIfAbsent(one);
 161         assertEquals(SIZE, list.size());
 162     }
 163 
 164     /**
 165      * addIfAbsent adds the element when it does not exist in the list
 166      */
 167     public void testAddIfAbsent2() {
 168         CopyOnWriteArrayList list = populatedList(SIZE);
 169         list.addIfAbsent(three);
 170         assertTrue(list.contains(three));
 171     }
 172 
 173     /**
 174      * clear removes all elements from the list
 175      */
 176     public void testClear() {
 177         List list = populatedList(SIZE);
 178         list.clear();
 179         assertEquals(0, list.size());
 180     }
 181 
 182     /**
 183      * Cloned list is equal
 184      */
 185     public void testClone() {
 186         CopyOnWriteArrayList l1 = populatedList(SIZE);
 187         CopyOnWriteArrayList l2 = (CopyOnWriteArrayList)(l1.clone());
 188         assertEquals(l1, l2);
 189         l1.clear();
 190         assertFalse(l1.equals(l2));
 191     }
 192 
 193     /**
 194      * contains is true for added elements
 195      */
 196     public void testContains() {
 197         List list = populatedList(3);
 198         assertTrue(list.contains(one));
 199         assertFalse(list.contains(five));
 200     }
 201 
 202     /**
 203      * adding at an index places it in the indicated index
 204      */
 205     public void testAddIndex() {
 206         List list = populatedList(3);
 207         list.add(0, m1);
 208         assertEquals(4, list.size());
 209         assertEquals(m1, list.get(0));
 210         assertEquals(zero, list.get(1));
 211 
 212         list.add(2, m2);
 213         assertEquals(5, list.size());
 214         assertEquals(m2, list.get(2));
 215         assertEquals(two, list.get(4));
 216     }
 217 
 218     /**
 219      * lists with same elements are equal and have same hashCode
 220      */
 221     public void testEquals() {
 222         List a = populatedList(3);
 223         List b = populatedList(3);
 224         assertTrue(a.equals(b));
 225         assertTrue(b.equals(a));
 226         assertTrue(a.containsAll(b));
 227         assertTrue(b.containsAll(a));
 228         assertEquals(a.hashCode(), b.hashCode());
 229         a.add(m1);
 230         assertFalse(a.equals(b));
 231         assertFalse(b.equals(a));
 232         assertTrue(a.containsAll(b));
 233         assertFalse(b.containsAll(a));
 234         b.add(m1);
 235         assertTrue(a.equals(b));
 236         assertTrue(b.equals(a));
 237         assertTrue(a.containsAll(b));
 238         assertTrue(b.containsAll(a));
 239         assertEquals(a.hashCode(), b.hashCode());
 240 
 241         assertFalse(a.equals(null));
 242     }
 243 
 244     /**
 245      * containsAll returns true for collections with subset of elements
 246      */
 247     public void testContainsAll() {
 248         List list = populatedList(3);
 249         assertTrue(list.containsAll(Arrays.asList()));
 250         assertTrue(list.containsAll(Arrays.asList(one)));
 251         assertTrue(list.containsAll(Arrays.asList(one, two)));
 252         assertFalse(list.containsAll(Arrays.asList(one, two, six)));
 253         assertFalse(list.containsAll(Arrays.asList(six)));
 254 
 255         try {
 256             list.containsAll(null);
 257             shouldThrow();
 258         } catch (NullPointerException success) {}
 259     }
 260 
 261     /**
 262      * get returns the value at the given index
 263      */
 264     public void testGet() {
 265         List list = populatedList(3);
 266         assertEquals(0, list.get(0));
 267     }
 268 
 269     /**
 270      * indexOf(Object) returns the index of the first occurrence of the
 271      * specified element in this list, or -1 if this list does not
 272      * contain the element
 273      */
 274     public void testIndexOf() {
 275         List list = populatedList(3);
 276         assertEquals(-1, list.indexOf(-42));
 277         int size = list.size();
 278         for (int i = 0; i < size; i++) {
 279             assertEquals(i, list.indexOf(i));
 280             assertEquals(i, list.subList(0, size).indexOf(i));
 281             assertEquals(i, list.subList(0, i + 1).indexOf(i));
 282             assertEquals(-1, list.subList(0, i).indexOf(i));
 283             assertEquals(0, list.subList(i, size).indexOf(i));
 284             assertEquals(-1, list.subList(i + 1, size).indexOf(i));
 285         }
 286 
 287         list.add(1);
 288         assertEquals(1, list.indexOf(1));
 289         assertEquals(1, list.subList(0, size + 1).indexOf(1));
 290         assertEquals(0, list.subList(1, size + 1).indexOf(1));
 291         assertEquals(size - 2, list.subList(2, size + 1).indexOf(1));
 292         assertEquals(0, list.subList(size, size + 1).indexOf(1));
 293         assertEquals(-1, list.subList(size + 1, size + 1).indexOf(1));
 294     }
 295 
 296     /**
 297      * indexOf(E, int) returns the index of the first occurrence of the
 298      * specified element in this list, searching forwards from index,
 299      * or returns -1 if the element is not found
 300      */
 301     public void testIndexOf2() {
 302         CopyOnWriteArrayList list = populatedList(3);
 303         int size = list.size();
 304         assertEquals(-1, list.indexOf(-42, 0));
 305 
 306         // we might expect IOOBE, but spec says otherwise
 307         assertEquals(-1, list.indexOf(0, size));
 308         assertEquals(-1, list.indexOf(0, Integer.MAX_VALUE));
 309 
 310         assertThrows(
 311             IndexOutOfBoundsException.class,
 312             () -> list.indexOf(0, -1),
 313             () -> list.indexOf(0, Integer.MIN_VALUE));
 314 
 315         for (int i = 0; i < size; i++) {
 316             assertEquals(i, list.indexOf(i, 0));
 317             assertEquals(i, list.indexOf(i, i));
 318             assertEquals(-1, list.indexOf(i, i + 1));
 319         }
 320 
 321         list.add(1);
 322         assertEquals(1, list.indexOf(1, 0));
 323         assertEquals(1, list.indexOf(1, 1));
 324         assertEquals(size, list.indexOf(1, 2));
 325         assertEquals(size, list.indexOf(1, size));
 326     }
 327 
 328     /**
 329      * isEmpty returns true when empty, else false
 330      */
 331     public void testIsEmpty() {
 332         List empty = new CopyOnWriteArrayList();
 333         assertTrue(empty.isEmpty());
 334         assertTrue(empty.subList(0, 0).isEmpty());
 335 
 336         List full = populatedList(SIZE);
 337         assertFalse(full.isEmpty());
 338         assertTrue(full.subList(0, 0).isEmpty());
 339         assertTrue(full.subList(SIZE, SIZE).isEmpty());
 340     }
 341 
 342     /**
 343      * iterator() returns an iterator containing the elements of the
 344      * list in insertion order
 345      */
 346     public void testIterator() {
 347         Collection empty = new CopyOnWriteArrayList();
 348         assertFalse(empty.iterator().hasNext());
 349         try {
 350             empty.iterator().next();
 351             shouldThrow();
 352         } catch (NoSuchElementException success) {}
 353 
 354         Integer[] elements = new Integer[SIZE];
 355         for (int i = 0; i < SIZE; i++)
 356             elements[i] = i;
 357         shuffle(elements);
 358         Collection<Integer> full = populatedList(elements);
 359 
 360         Iterator it = full.iterator();
 361         for (int j = 0; j < SIZE; j++) {
 362             assertTrue(it.hasNext());
 363             assertEquals(elements[j], it.next());
 364         }
 365         assertIteratorExhausted(it);
 366     }
 367 
 368     /**
 369      * iterator of empty collection has no elements
 370      */
 371     public void testEmptyIterator() {
 372         Collection c = new CopyOnWriteArrayList();
 373         assertIteratorExhausted(c.iterator());
 374     }
 375 
 376     /**
 377      * iterator.remove throws UnsupportedOperationException
 378      */
 379     public void testIteratorRemove() {
 380         CopyOnWriteArrayList list = populatedList(SIZE);
 381         Iterator it = list.iterator();
 382         it.next();
 383         try {
 384             it.remove();
 385             shouldThrow();
 386         } catch (UnsupportedOperationException success) {}
 387     }
 388 
 389     /**
 390      * toString contains toString of elements
 391      */
 392     public void testToString() {
 393         assertEquals("[]", new CopyOnWriteArrayList().toString());
 394         List list = populatedList(3);
 395         String s = list.toString();
 396         for (int i = 0; i < 3; ++i)
 397             assertTrue(s.contains(String.valueOf(i)));
 398         assertEquals(new ArrayList(list).toString(),
 399                      list.toString());
 400     }
 401 
 402     /**
 403      * lastIndexOf(Object) returns the index of the last occurrence of
 404      * the specified element in this list, or -1 if this list does not
 405      * contain the element
 406      */
 407     public void testLastIndexOf1() {
 408         List list = populatedList(3);
 409         assertEquals(-1, list.lastIndexOf(-42));
 410         int size = list.size();
 411         for (int i = 0; i < size; i++) {
 412             assertEquals(i, list.lastIndexOf(i));
 413             assertEquals(i, list.subList(0, size).lastIndexOf(i));
 414             assertEquals(i, list.subList(0, i + 1).lastIndexOf(i));
 415             assertEquals(-1, list.subList(0, i).lastIndexOf(i));
 416             assertEquals(0, list.subList(i, size).lastIndexOf(i));
 417             assertEquals(-1, list.subList(i + 1, size).lastIndexOf(i));
 418         }
 419 
 420         list.add(1);
 421         assertEquals(size, list.lastIndexOf(1));
 422         assertEquals(size, list.subList(0, size + 1).lastIndexOf(1));
 423         assertEquals(1, list.subList(0, size).lastIndexOf(1));
 424         assertEquals(0, list.subList(1, 2).lastIndexOf(1));
 425         assertEquals(-1, list.subList(0, 1).indexOf(1));
 426     }
 427 
 428     /**
 429      * lastIndexOf(E, int) returns the index of the last occurrence of the
 430      * specified element in this list, searching backwards from index, or
 431      * returns -1 if the element is not found
 432      */
 433     public void testLastIndexOf2() {
 434         CopyOnWriteArrayList list = populatedList(3);
 435 
 436         // we might expect IOOBE, but spec says otherwise
 437         assertEquals(-1, list.lastIndexOf(0, -1));
 438 
 439         int size = list.size();
 440         assertThrows(
 441             IndexOutOfBoundsException.class,
 442             () -> list.lastIndexOf(0, size),
 443             () -> list.lastIndexOf(0, Integer.MAX_VALUE));
 444 
 445         for (int i = 0; i < size; i++) {
 446             assertEquals(i, list.lastIndexOf(i, i));
 447             assertEquals(list.indexOf(i), list.lastIndexOf(i, i));
 448             if (i > 0)
 449                 assertEquals(-1, list.lastIndexOf(i, i - 1));
 450         }
 451         list.add(one);
 452         list.add(three);
 453         assertEquals(1, list.lastIndexOf(one, 1));
 454         assertEquals(1, list.lastIndexOf(one, 2));
 455         assertEquals(3, list.lastIndexOf(one, 3));
 456         assertEquals(3, list.lastIndexOf(one, 4));
 457         assertEquals(-1, list.lastIndexOf(three, 3));
 458     }
 459 
 460     /**
 461      * listIterator traverses all elements
 462      */
 463     public void testListIterator1() {
 464         List list = populatedList(SIZE);
 465         ListIterator i = list.listIterator();
 466         int j;
 467         for (j = 0; i.hasNext(); j++)
 468             assertEquals(j, i.next());
 469         assertEquals(SIZE, j);
 470     }
 471 
 472     /**
 473      * listIterator only returns those elements after the given index
 474      */
 475     public void testListIterator2() {
 476         List list = populatedList(3);
 477         ListIterator i = list.listIterator(1);
 478         int j;
 479         for (j = 0; i.hasNext(); j++)
 480             assertEquals(j + 1, i.next());
 481         assertEquals(2, j);
 482     }
 483 
 484     /**
 485      * remove(int) removes and returns the object at the given index
 486      */
 487     public void testRemove_int() {
 488         int SIZE = 3;
 489         for (int i = 0; i < SIZE; i++) {
 490             List list = populatedList(SIZE);
 491             assertEquals(i, list.remove(i));
 492             assertEquals(SIZE - 1, list.size());
 493             assertFalse(list.contains(new Integer(i)));
 494         }
 495     }
 496 
 497     /**
 498      * remove(Object) removes the object if found and returns true
 499      */
 500     public void testRemove_Object() {
 501         int SIZE = 3;
 502         for (int i = 0; i < SIZE; i++) {
 503             List list = populatedList(SIZE);
 504             assertFalse(list.remove(new Integer(-42)));
 505             assertTrue(list.remove(new Integer(i)));
 506             assertEquals(SIZE - 1, list.size());
 507             assertFalse(list.contains(new Integer(i)));
 508         }
 509         CopyOnWriteArrayList x = new CopyOnWriteArrayList(Arrays.asList(4, 5, 6));
 510         assertTrue(x.remove(new Integer(6)));
 511         assertEquals(x, Arrays.asList(4, 5));
 512         assertTrue(x.remove(new Integer(4)));
 513         assertEquals(x, Arrays.asList(5));
 514         assertTrue(x.remove(new Integer(5)));
 515         assertEquals(x, Arrays.asList());
 516         assertFalse(x.remove(new Integer(5)));
 517     }
 518 
 519     /**
 520      * removeAll removes all elements from the given collection
 521      */
 522     public void testRemoveAll() {
 523         List list = populatedList(3);
 524         assertTrue(list.removeAll(Arrays.asList(one, two)));
 525         assertEquals(1, list.size());
 526         assertFalse(list.removeAll(Arrays.asList(one, two)));
 527         assertEquals(1, list.size());
 528     }
 529 
 530     /**
 531      * set changes the element at the given index
 532      */
 533     public void testSet() {
 534         List list = populatedList(3);
 535         assertEquals(2, list.set(2, four));
 536         assertEquals(4, list.get(2));
 537     }
 538 
 539     /**
 540      * size returns the number of elements
 541      */
 542     public void testSize() {
 543         List empty = new CopyOnWriteArrayList();
 544         assertEquals(0, empty.size());
 545         assertEquals(0, empty.subList(0, 0).size());
 546 
 547         List full = populatedList(SIZE);
 548         assertEquals(SIZE, full.size());
 549         assertEquals(0, full.subList(0, 0).size());
 550         assertEquals(0, full.subList(SIZE, SIZE).size());
 551     }
 552 
 553     /**
 554      * toArray() returns an Object array containing all elements from
 555      * the list in insertion order
 556      */
 557     public void testToArray() {
 558         Object[] a = new CopyOnWriteArrayList().toArray();
 559         assertTrue(Arrays.equals(new Object[0], a));
 560         assertSame(Object[].class, a.getClass());
 561 
 562         Integer[] elements = new Integer[SIZE];
 563         for (int i = 0; i < SIZE; i++)
 564             elements[i] = i;
 565         shuffle(elements);
 566         Collection<Integer> full = populatedList(elements);
 567 
 568         assertTrue(Arrays.equals(elements, full.toArray()));
 569         assertSame(Object[].class, full.toArray().getClass());
 570     }
 571 
 572     /**
 573      * toArray(Integer array) returns an Integer array containing all
 574      * elements from the list in insertion order
 575      */
 576     public void testToArray2() {
 577         Collection empty = new CopyOnWriteArrayList();
 578         Integer[] a;
 579 
 580         a = new Integer[0];
 581         assertSame(a, empty.toArray(a));
 582 
 583         a = new Integer[SIZE / 2];
 584         Arrays.fill(a, 42);
 585         assertSame(a, empty.toArray(a));
 586         assertNull(a[0]);
 587         for (int i = 1; i < a.length; i++)
 588             assertEquals(42, (int) a[i]);
 589 
 590         Integer[] elements = new Integer[SIZE];
 591         for (int i = 0; i < SIZE; i++)
 592             elements[i] = i;
 593         shuffle(elements);
 594         Collection<Integer> full = populatedList(elements);
 595 
 596         Arrays.fill(a, 42);
 597         assertTrue(Arrays.equals(elements, full.toArray(a)));
 598         for (int i = 0; i < a.length; i++)
 599             assertEquals(42, (int) a[i]);
 600         assertSame(Integer[].class, full.toArray(a).getClass());
 601 
 602         a = new Integer[SIZE];
 603         Arrays.fill(a, 42);
 604         assertSame(a, full.toArray(a));
 605         assertTrue(Arrays.equals(elements, a));
 606 
 607         a = new Integer[2 * SIZE];
 608         Arrays.fill(a, 42);
 609         assertSame(a, full.toArray(a));
 610         assertTrue(Arrays.equals(elements, Arrays.copyOf(a, SIZE)));
 611         assertNull(a[SIZE]);
 612         for (int i = SIZE + 1; i < a.length; i++)
 613             assertEquals(42, (int) a[i]);
 614     }
 615 
 616     /**
 617      * sublists contains elements at indexes offset from their base
 618      */
 619     public void testSubList() {
 620         List a = populatedList(10);
 621         assertTrue(a.subList(1,1).isEmpty());
 622         for (int j = 0; j < 9; ++j) {
 623             for (int i = j ; i < 10; ++i) {
 624                 List b = a.subList(j,i);
 625                 for (int k = j; k < i; ++k) {
 626                     assertEquals(new Integer(k), b.get(k-j));
 627                 }
 628             }
 629         }
 630 
 631         List s = a.subList(2, 5);
 632         assertEquals(3, s.size());
 633         s.set(2, m1);
 634         assertEquals(a.get(4), m1);
 635         s.clear();
 636         assertEquals(7, a.size());
 637 
 638         assertThrows(
 639             IndexOutOfBoundsException.class,
 640             () -> s.get(0),
 641             () -> s.set(0, 42));
 642     }
 643 
 644     // Exception tests
 645 
 646     /**
 647      * toArray throws an ArrayStoreException when the given array
 648      * can not store the objects inside the list
 649      */
 650     public void testToArray_ArrayStoreException() {
 651         List list = new CopyOnWriteArrayList();
 652         // Integers are not auto-converted to Longs
 653         list.add(86);
 654         list.add(99);
 655         assertThrows(
 656             ArrayStoreException.class,
 657             () -> list.toArray(new Long[0]),
 658             () -> list.toArray(new Long[5]));
 659     }
 660 
 661     void testIndexOutOfBoundsException(List list) {
 662         int size = list.size();
 663         assertThrows(
 664             IndexOutOfBoundsException.class,
 665             () -> list.get(-1),
 666             () -> list.get(size),
 667             () -> list.set(-1, "qwerty"),
 668             () -> list.set(size, "qwerty"),
 669             () -> list.add(-1, "qwerty"),
 670             () -> list.add(size + 1, "qwerty"),
 671             () -> list.remove(-1),
 672             () -> list.remove(size),
 673             () -> list.addAll(-1, Collections.emptyList()),
 674             () -> list.addAll(size + 1, Collections.emptyList()),
 675             () -> list.listIterator(-1),
 676             () -> list.listIterator(size + 1),
 677             () -> list.subList(-1, size),
 678             () -> list.subList(0, size + 1));
 679 
 680         // Conversely, operations that must not throw
 681         list.addAll(0, Collections.emptyList());
 682         list.addAll(size, Collections.emptyList());
 683         list.add(0, "qwerty");
 684         list.add(list.size(), "qwerty");
 685         list.get(0);
 686         list.get(list.size() - 1);
 687         list.set(0, "azerty");
 688         list.set(list.size() - 1, "azerty");
 689         list.listIterator(0);
 690         list.listIterator(list.size());
 691         list.subList(0, list.size());
 692         list.remove(list.size() - 1);
 693     }
 694 
 695     /**
 696      * IndexOutOfBoundsException is thrown when specified
 697      */
 698     public void testIndexOutOfBoundsException() {
 699         ThreadLocalRandom rnd = ThreadLocalRandom.current();
 700         List x = populatedList(rnd.nextInt(5));
 701         testIndexOutOfBoundsException(x);
 702 
 703         int start = rnd.nextInt(x.size() + 1);
 704         int end = rnd.nextInt(start, x.size() + 1);
 705         assertThrows(
 706             IndexOutOfBoundsException.class,
 707             () -> x.subList(start, start - 1));
 708         List subList = x.subList(start, end);
 709         testIndexOutOfBoundsException(x);
 710     }
 711 
 712     /**
 713      * a deserialized/reserialized list equals original
 714      */
 715     public void testSerialization() throws Exception {
 716         List x = populatedList(SIZE);
 717         List y = serialClone(x);
 718 
 719         assertNotSame(x, y);
 720         assertEquals(x.size(), y.size());
 721         assertEquals(x.toString(), y.toString());
 722         assertTrue(Arrays.equals(x.toArray(), y.toArray()));
 723         assertEquals(x, y);
 724         assertEquals(y, x);
 725         while (!x.isEmpty()) {
 726             assertFalse(y.isEmpty());
 727             assertEquals(x.remove(0), y.remove(0));
 728         }
 729         assertTrue(y.isEmpty());
 730     }
 731 
 732 }