View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.collections4.list;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertFalse;
21  import static org.junit.jupiter.api.Assertions.assertThrows;
22  import static org.junit.jupiter.api.Assertions.assertTrue;
23  
24  import java.io.IOException;
25  import java.io.Serializable;
26  import java.lang.reflect.InvocationTargetException;
27  import java.lang.reflect.Method;
28  import java.util.AbstractCollection;
29  import java.util.ArrayList;
30  import java.util.Arrays;
31  import java.util.Collection;
32  import java.util.Collections;
33  import java.util.ConcurrentModificationException;
34  import java.util.Iterator;
35  import java.util.List;
36  import java.util.ListIterator;
37  import java.util.NoSuchElementException;
38  
39  import org.apache.commons.collections4.BulkTest;
40  import org.apache.commons.collections4.collection.AbstractCollectionTest;
41  import org.apache.commons.collections4.iterators.AbstractListIteratorTest;
42  import org.apache.commons.lang3.StringUtils;
43  import org.junit.jupiter.api.Test;
44  
45  /**
46   * Abstract test class for {@link java.util.List} methods and contracts.
47   * <p>
48   * To use, simply extend this class, and implement
49   * the {@link #makeObject} method.
50   * <p>
51   * If your {@link List} fails one of these tests by design,
52   * you may still use this base set of cases.  Simply override the
53   * test case (method) your {@link List} fails or override one of the
54   * protected methods from AbstractCollectionTest.
55   */
56  public abstract class AbstractListTest<E> extends AbstractCollectionTest<E> {
57  
58      public static class BulkTestSubList<E> extends AbstractListTest<E> {
59  
60          private final AbstractListTest<E> outer;
61  
62          public BulkTestSubList(final AbstractListTest<E> outer) {
63              super(StringUtils.EMPTY);
64              this.outer = outer;
65          }
66  
67          @Override
68          @SuppressWarnings("unchecked")
69          public E[] getFullElements() {
70              final List<E> l = Arrays.asList(outer.getFullElements());
71              return (E[]) l.subList(3, l.size() - 3).toArray();
72          }
73  
74          @Override
75          public E[] getOtherElements() {
76              return outer.getOtherElements();
77          }
78  
79          @Override
80          public boolean isAddSupported() {
81              return outer.isAddSupported();
82          }
83  
84          @Override
85          public boolean isRemoveSupported() {
86              return outer.isRemoveSupported();
87          }
88  
89          @Override
90          public boolean isSetSupported() {
91              return outer.isSetSupported();
92          }
93  
94          @Override
95          public boolean isTestSerialization() {
96              return false;
97          }
98  
99          @Override
100         public List<E> makeFullCollection() {
101             final int size = getFullElements().length;
102             return outer.makeFullCollection().subList(3, size - 3);
103         }
104 
105         @Override
106         public List<E> makeObject() {
107             return outer.makeFullCollection().subList(4, 4);
108         }
109 
110         @Override
111         public void resetEmpty() {
112             outer.resetFull();
113             this.setCollection(outer.getCollection().subList(4, 4));
114             this.setConfirmed(outer.getConfirmed().subList(4, 4));
115         }
116 
117         @Override
118         public void resetFull() {
119             outer.resetFull();
120             final int size = outer.getConfirmed().size();
121             this.setCollection(outer.getCollection().subList(3, size - 3));
122             this.setConfirmed(outer.getConfirmed().subList(3, size - 3));
123         }
124 
125         @Override
126         public void verify() {
127             super.verify();
128             outer.verify();
129         }
130     }
131 
132     public class TestListIterator extends AbstractListIteratorTest<E> {
133         public TestListIterator() {
134             super("TestListIterator");
135         }
136 
137         @Override
138         public E addSetValue() {
139             return AbstractListTest.this.getOtherElements()[0];
140         }
141 
142         @Override
143         public ListIterator<E> makeEmptyIterator() {
144             resetEmpty();
145             return AbstractListTest.this.getCollection().listIterator();
146         }
147 
148         @Override
149         public ListIterator<E> makeObject() {
150             resetFull();
151             return AbstractListTest.this.getCollection().listIterator();
152         }
153 
154         @Override
155         public boolean supportsAdd() {
156             return AbstractListTest.this.isAddSupported();
157         }
158 
159         @Override
160         public boolean supportsRemove() {
161             return AbstractListTest.this.isRemoveSupported();
162         }
163 
164         @Override
165         public boolean supportsSet() {
166             return AbstractListTest.this.isSetSupported();
167         }
168     }
169 
170     /**
171      * JUnit constructor.
172      *
173      * @param testName  the test class name
174      */
175     public AbstractListTest(final String testName) {
176         super(testName);
177     }
178 
179     /**
180      *  Traverses to the beginning of the given iterator.
181      *
182      *  @param iter  the iterator to traverse
183      *  @param i     the starting index
184      */
185     private void backwardTest(final ListIterator<E> iter, int i) {
186         final List<E> list = getCollection();
187 
188         while (i > 0) {
189             assertTrue(iter.hasPrevious(),
190                 "Iterator should have previous, i:" + i);
191             assertEquals(i, iter.nextIndex(),
192                 "Iterator.nextIndex should work, i:" + i);
193             assertEquals(i - 1, iter.previousIndex(),
194                 "Iterator.previousIndex should work, i:" + i);
195             final E o = iter.previous();
196             assertEquals(list.get(i - 1), o,
197                 "Iterator returned correct element");
198             i--;
199         }
200 
201         assertFalse(iter.hasPrevious(), "Iterator shouldn't have previous");
202         final int nextIndex = iter.nextIndex();
203         assertEquals(0, nextIndex, "nextIndex should be 0");
204         final int prevIndex = iter.previousIndex();
205         assertEquals(-1, prevIndex, "previousIndex should be -1");
206 
207         assertThrows(NoSuchElementException.class, () -> iter.previous(),
208                 "Exhausted iterator should raise NoSuchElement");
209     }
210 
211     public BulkTest bulkTestListIterator() {
212         return new TestListIterator();
213     }
214 
215     /**
216      *  Returns a {@link BulkTest} for testing {@link List#subList(int,int)}.
217      *  The returned bulk test will run through every {@code TestList}
218      *  method, <i>including</i> another {@code bulkTestSubList}.
219      *  Sublists are tested until the size of the sublist is less than 10.
220      *  Each sublist is 6 elements smaller than its parent list.
221      *  (By default this means that two rounds of sublists will be tested).
222      *  The verify() method is overloaded to test that the original list is
223      *  modified when the sublist is.
224      */
225     public BulkTest bulkTestSubList() {
226         if (getFullElements().length - 6 < 10) {
227             return null;
228         }
229         return new BulkTestSubList<>(this);
230     }
231 
232     /**
233      * Invokes all the methods on the given sublist to make sure they raise
234      * a {@link java.util.ConcurrentModificationException ConcurrentModificationException}.
235      */
236     protected void failFastAll(final List<E> list) {
237         final Method[] methods = List.class.getMethods();
238         for (final Method method : methods) {
239             failFastMethod(list, method);
240         }
241     }
242 
243     /**
244      * Invokes the given method on the given sublist to make sure it raises
245      * a {@link java.util.ConcurrentModificationException ConcurrentModificationException}.
246      *
247      * Unless the method happens to be the equals() method, in which case
248      * the test is skipped. There seems to be a bug in
249      * java.util.AbstractList.subList(int,int).equals(Object) -- it never
250      * raises a ConcurrentModificationException.
251      *
252      * @param list the sublist to test
253      * @param m the method to invoke
254      */
255     protected void failFastMethod(final List<E> list, final Method m) {
256         if (m.getName().equals("equals")) {
257             return;
258         }
259 
260         final E element = getOtherElements()[0];
261         final Collection<E> c = Collections.singleton(element);
262 
263         final Class<?>[] types = m.getParameterTypes();
264         final Object[] params = new Object[types.length];
265         for (int i = 0; i < params.length; i++) {
266             if (types[i] == Integer.TYPE) {
267                 params[i] = Integer.valueOf(0);
268             } else if (types[i] == Collection.class) {
269                 params[i] = c;
270             } else if (types[i] == Object.class) {
271                 params[i] = element;
272             } else if (types[i] == Object[].class) {
273                 params[i] = new Object[0];
274             }
275         }
276 
277         final InvocationTargetException thrown = assertThrows(InvocationTargetException.class, () -> m.invoke(list, params),
278                 m.getName() + " should raise ConcurrentModification");
279         assertTrue(thrown.getTargetException() instanceof ConcurrentModificationException,
280                 m.getName() + " raised unexpected " + thrown.getTargetException());
281     }
282 
283     /**
284      *  Traverses to the end of the given iterator.
285      *
286      *  @param iter  the iterator to traverse
287      *  @param i     the starting index
288      */
289     private void forwardTest(final ListIterator<E> iter, int i) {
290         final List<E> list = getCollection();
291         final int max = getFullElements().length;
292 
293         while (i < max) {
294             assertTrue(iter.hasNext(), "Iterator should have next");
295             assertEquals(i, iter.nextIndex(),
296                 "Iterator.nextIndex should work");
297             assertEquals(i - 1, iter.previousIndex(),
298                 "Iterator.previousIndex should work");
299             final Object o = iter.next();
300             assertEquals(list.get(i), o, "Iterator returned correct element");
301             i++;
302         }
303 
304         assertFalse(iter.hasNext(), "Iterator shouldn't have next");
305         assertEquals(max, iter.nextIndex(), "nextIndex should be size");
306         assertEquals(max - 1, iter.previousIndex(), "previousIndex should be size - 1");
307 
308         assertThrows(NoSuchElementException.class, () -> iter.next(),
309                 "Exhausted iterator should raise NoSuchElement");
310     }
311 
312     /**
313      * Returns the {@link #collection} field cast to a {@link List}.
314      *
315      * @return the collection field as a List
316      */
317     @Override
318     public List<E> getCollection() {
319         return (List<E>) super.getCollection();
320     }
321 
322     /**
323      * Returns the {@link #confirmed} field cast to a {@link List}.
324      *
325      * @return the confirmed field as a List
326      */
327     @Override
328     public List<E> getConfirmed() {
329         return (List<E>) super.getConfirmed();
330     }
331 
332     /**
333      * List equals method is defined.
334      */
335     @Override
336     public boolean isEqualsCheckable() {
337         return true;
338     }
339 
340     /**
341      *  Returns true if the collections produced by
342      *  {@link #makeObject()} and {@link #makeFullCollection()}
343      *  support the <code>set operation.<p>
344      *  Default implementation returns true.  Override if your collection
345      *  class does not support set.
346      */
347     public boolean isSetSupported() {
348         return true;
349     }
350 
351     /**
352      * Returns an empty {@link ArrayList}.
353      */
354     @Override
355     public Collection<E> makeConfirmedCollection() {
356         final ArrayList<E> list = new ArrayList<>();
357         return list;
358     }
359 
360     /**
361      * Returns a full {@link ArrayList}.
362      */
363     @Override
364     public Collection<E> makeConfirmedFullCollection() {
365         return new ArrayList<>(Arrays.asList(getFullElements()));
366     }
367 
368     /**
369      * {@inheritDoc}
370      */
371     @Override
372     public List<E> makeFullCollection() {
373         // only works if list supports optional "addAll(Collection)"
374         final List<E> list = makeObject();
375         list.addAll(Arrays.asList(getFullElements()));
376         return list;
377     }
378 
379     /**
380      * Returns {@link #makeObject()}.
381      *
382      * @return an empty list to be used for testing
383      */
384     @Override
385     public abstract List<E> makeObject();
386 
387     /**
388      * Compare the current serialized form of the List
389      * against the canonical version in SCM.
390      */
391     @Test
392     @SuppressWarnings("unchecked")
393     public void testEmptyListCompatibility() throws IOException, ClassNotFoundException {
394         /*
395          * Create canonical objects with this code
396         List list = makeEmptyList();
397         if (!(list instanceof Serializable)) return;
398 
399         writeExternalFormToDisk((Serializable) list, getCanonicalEmptyCollectionName(list));
400         */
401 
402         // test to make sure the canonical form has been preserved
403         final List<E> list = makeObject();
404         if (list instanceof Serializable && !skipSerializedCanonicalTests()
405                 && isTestSerialization()) {
406             final List<E> list2 = (List<E>) readExternalFormFromDisk(getCanonicalEmptyCollectionName(list));
407             assertEquals(0, list2.size(), "List is empty");
408             assertEquals(list, list2);
409         }
410     }
411 
412     @Test
413     @SuppressWarnings("unchecked")
414     public void testEmptyListSerialization() throws IOException, ClassNotFoundException {
415         final List<E> list = makeObject();
416         if (!(list instanceof Serializable && isTestSerialization())) {
417             return;
418         }
419 
420         final byte[] object = writeExternalFormToBytes((Serializable) list);
421         final List<E> list2 = (List<E>) readExternalFormFromBytes(object);
422 
423         assertEquals(0, list.size(), "Both lists are empty");
424         assertEquals(0, list2.size(), "Both lists are empty");
425     }
426 
427     /**
428      * Compare the current serialized form of the List
429      * against the canonical version in SCM.
430      */
431     @Test
432     @SuppressWarnings("unchecked")
433     public void testFullListCompatibility() throws IOException, ClassNotFoundException {
434         /*
435          * Create canonical objects with this code
436         List list = makeFullList();
437         if (!(list instanceof Serializable)) return;
438 
439         writeExternalFormToDisk((Serializable) list, getCanonicalFullCollectionName(list));
440         */
441 
442         // test to make sure the canonical form has been preserved
443         final List<E> list = makeFullCollection();
444         if (list instanceof Serializable && !skipSerializedCanonicalTests() && isTestSerialization()) {
445             final List<E> list2 = (List<E>) readExternalFormFromDisk(getCanonicalFullCollectionName(list));
446             if (list2.size() == 4) {
447                 // old serialized tests
448                 return;
449             }
450             assertEquals(list.size(), list2.size(), "List is the right size");
451             assertEquals(list, list2);
452         }
453     }
454 
455     @Test
456     @SuppressWarnings("unchecked")
457     public void testFullListSerialization() throws IOException, ClassNotFoundException {
458         final List<E> list = makeFullCollection();
459         final int size = getFullElements().length;
460         if (!(list instanceof Serializable && isTestSerialization())) {
461             return;
462         }
463 
464         final byte[] object = writeExternalFormToBytes((Serializable) list);
465         final List<E> list2 = (List<E>) readExternalFormFromBytes(object);
466 
467         assertEquals(size, list.size(), "Both lists are same size");
468         assertEquals(size, list2.size(), "Both lists are same size");
469     }
470 
471     /**
472      *  Tests {@link List#add(int,Object)}.
473      */
474     @Test
475     public void testListAddByIndex() {
476         if (!isAddSupported()) {
477             return;
478         }
479 
480         final E element = getOtherElements()[0];
481         final int max = getFullElements().length;
482 
483         for (int i = 0; i <= max; i++) {
484             resetFull();
485             getCollection().add(i, element);
486             getConfirmed().add(i, element);
487             verify();
488         }
489     }
490 
491     /**
492      *  Tests bounds checking for {@link List#add(int, Object)} on an
493      *  empty list.
494      */
495     @Test
496     public void testListAddByIndexBoundsChecking() {
497         if (!isAddSupported()) {
498             return;
499         }
500 
501         final E element = getOtherElements()[0];
502 
503         final List<E> finalList0 = makeObject();
504         assertThrows(IndexOutOfBoundsException.class, () -> finalList0.add(Integer.MIN_VALUE, element),
505                 "List.add should throw IndexOutOfBoundsException [Integer.MIN_VALUE]");
506 
507         final List<E> finalList1 = makeObject();
508         assertThrows(IndexOutOfBoundsException.class, () -> finalList1.add(-1, element),
509                 "List.add should throw IndexOutOfBoundsException [-1]");
510 
511         final List<E> finalList2 = makeObject();
512         assertThrows(IndexOutOfBoundsException.class, () -> finalList2.add(1, element),
513                 "List.add should throw IndexOutOfBoundsException [1]");
514 
515         final List<E> finalList3 = makeObject();
516         assertThrows(IndexOutOfBoundsException.class, () -> finalList3.add(Integer.MAX_VALUE, element),
517                 "List.add should throw IndexOutOfBoundsException [Integer.MAX_VALUE]");
518     }
519 
520     /**
521      *  Tests bounds checking for {@link List#add(int, Object)} on a
522      *  full list.
523      */
524     @Test
525     public void testListAddByIndexBoundsChecking2() {
526         if (!isAddSupported()) {
527             return;
528         }
529 
530         final E element = getOtherElements()[0];
531 
532         final List<E> finalList0 = makeFullCollection();
533         assertThrows(IndexOutOfBoundsException.class, () -> finalList0.add(Integer.MIN_VALUE, element),
534                 "List.add should throw IndexOutOfBoundsException [Integer.MIN_VALUE]");
535 
536         final List<E> finalList1 = makeFullCollection();
537         assertThrows(IndexOutOfBoundsException.class, () -> finalList1.add(-1, element),
538                 "List.add should throw IndexOutOfBoundsException [-1]");
539 
540         final List<E> finalList2 = makeFullCollection();
541         assertThrows(IndexOutOfBoundsException.class, () -> finalList2.add(finalList2.size() + 1, element),
542                 "List.add should throw IndexOutOfBoundsException [size + 1]");
543 
544         final List<E> finalList3 = makeFullCollection();
545         assertThrows(IndexOutOfBoundsException.class, () -> finalList3.add(Integer.MAX_VALUE, element),
546                 "List.add should throw IndexOutOfBoundsException [Integer.MAX_VALUE]");
547     }
548 
549     /**
550      *  Tests {@link List#equals(Object)}.
551      */
552     @Test
553     public void testListEquals() {
554         resetEmpty();
555         List<E> list = getCollection();
556         assertTrue(list.equals(getConfirmed()), "Empty lists should be equal");
557         verify();
558         assertTrue(list.equals(list), "Empty list should equal self");
559         verify();
560 
561         List<E> list2 = Arrays.asList(getFullElements());
562         assertFalse(list.equals(list2), "Empty list shouldn't equal full");
563         verify();
564 
565         list2 = Arrays.asList(getOtherElements());
566         assertFalse(list.equals(list2), "Empty list shouldn't equal other");
567         verify();
568 
569         resetFull();
570         list = getCollection();
571         assertTrue(list.equals(getConfirmed()), "Full lists should be equal");
572         verify();
573         assertTrue(list.equals(list), "Full list should equal self");
574         verify();
575 
576         list2 = makeObject();
577         assertFalse(list.equals(list2), "Full list shouldn't equal empty");
578         verify();
579 
580         list2 = Arrays.asList(getOtherElements());
581         assertFalse(list.equals(list2), "Full list shouldn't equal other");
582         verify();
583 
584         list2 = Arrays.asList(getFullElements());
585         if (list2.size() < 2 && isAddSupported()) {
586             // main list is only size 1, so let's add other elements to get a better list
587             list.addAll(Arrays.asList(getOtherElements()));
588             getConfirmed().addAll(Arrays.asList(getOtherElements()));
589             list2 = new ArrayList<>(list2);
590             list2.addAll(Arrays.asList(getOtherElements()));
591         }
592         if (list2.size() > 1) {
593             Collections.reverse(list2);
594             assertFalse(list.equals(list2), "Full list shouldn't equal full list with same elements but different order");
595             verify();
596         }
597 
598         resetFull();
599         list = getCollection();
600         assertFalse(list.isEmpty(), "List shouldn't equal String");
601         verify();
602 
603         final List<E> listForC = Arrays.asList(getFullElements());
604         final Collection<E> c = new AbstractCollection<E>() {
605             @Override
606             public Iterator<E> iterator() {
607                 return listForC.iterator();
608             }
609 
610             @Override
611             public int size() {
612                 return listForC.size();
613             }
614         };
615 
616         assertFalse(list.equals(c), "List shouldn't equal nonlist with same elements in same order");
617         verify();
618     }
619 
620     /**
621      *  Tests {@link List#get(int)}.
622      */
623     @Test
624     public void testListGetByIndex() {
625         resetFull();
626         final List<E> list = getCollection();
627         final E[] elements = getFullElements();
628         for (int i = 0; i < elements.length; i++) {
629             assertEquals(elements[i], list.get(i), "List should contain correct elements");
630             verify();
631         }
632     }
633 
634     /**
635      *  Tests bounds checking for {@link List#get(int)} on an
636      *  empty list.
637      */
638     @Test
639     public void testListGetByIndexBoundsChecking() {
640         final List<E> list = makeObject();
641 
642         assertThrows(IndexOutOfBoundsException.class, () -> list.get(Integer.MIN_VALUE),
643                 "List.get should throw IndexOutOfBoundsException [Integer.MIN_VALUE]");
644 
645         assertThrows(IndexOutOfBoundsException.class, () -> list.get(-1),
646                 "List.get should throw IndexOutOfBoundsException [-1]");
647 
648         assertThrows(IndexOutOfBoundsException.class, () -> list.get(0),
649                 "List.get should throw IndexOutOfBoundsException [0]");
650 
651         assertThrows(IndexOutOfBoundsException.class, () -> list.get(1),
652                 "List.get should throw IndexOutOfBoundsException [1]");
653 
654         assertThrows(IndexOutOfBoundsException.class, () -> list.get(Integer.MAX_VALUE),
655                 "List.get should throw IndexOutOfBoundsException [Integer.MAX_VALUE]");
656     }
657 
658     /**
659      *  Tests bounds checking for {@link List#get(int)} on a
660      *  full list.
661      */
662     @Test
663     public void testListGetByIndexBoundsChecking2() {
664         final List<E> list = makeFullCollection();
665 
666         assertThrows(IndexOutOfBoundsException.class, () -> list.get(Integer.MIN_VALUE),
667                 "List.get should throw IndexOutOfBoundsException [Integer.MIN_VALUE]");
668 
669         assertThrows(IndexOutOfBoundsException.class, () -> list.get(-1),
670                 "List.get should throw IndexOutOfBoundsException [-1]");
671 
672         assertThrows(IndexOutOfBoundsException.class, () -> list.get(getFullElements().length),
673                 "List.get should throw IndexOutOfBoundsException [size]");
674 
675         assertThrows(IndexOutOfBoundsException.class, () -> list.get(Integer.MAX_VALUE),
676                 "List.get should throw IndexOutOfBoundsException [Integer.MAX_VALUE]");
677     }
678 
679     /**
680      *  Tests {@link List#hashCode()}.
681      */
682     @Test
683     public void testListHashCode() {
684         resetEmpty();
685         int hash1 = getCollection().hashCode();
686         int hash2 = getConfirmed().hashCode();
687         assertEquals(hash1, hash2, "Empty lists should have equal hashCodes");
688         verify();
689 
690         resetFull();
691         hash1 = getCollection().hashCode();
692         hash2 = getConfirmed().hashCode();
693         assertEquals(hash1, hash2, "Full lists should have equal hashCodes");
694         verify();
695     }
696 
697     /**
698      *  Tests {@link List#indexOf}.
699      */
700     @Test
701     public void testListIndexOf() {
702         resetFull();
703         final List<E> list1 = getCollection();
704         final List<E> list2 = getConfirmed();
705 
706         for (final E element : list2) {
707             assertEquals(list1.indexOf(element),
708                     list2.indexOf(element), "indexOf should return correct result");
709             verify();
710         }
711 
712         final E[] other = getOtherElements();
713         for (final E element : other) {
714             assertEquals(-1, list1.indexOf(element),
715                     "indexOf should return -1 for nonexistent element");
716             verify();
717         }
718     }
719 
720     /**
721      *  Tests the {@link ListIterator#add(Object)} method of the list
722      *  iterator.
723      */
724     @Test
725     public void testListIteratorAdd() {
726         if (!isAddSupported()) {
727             return;
728         }
729 
730         resetEmpty();
731         final List<E> list1 = getCollection();
732         final List<E> list2 = getConfirmed();
733 
734         final E[] elements = getFullElements();
735         ListIterator<E> iter1 = list1.listIterator();
736         ListIterator<E> iter2 = list2.listIterator();
737 
738         for (final E element : elements) {
739             iter1.add(element);
740             iter2.add(element);
741             verify();
742         }
743 
744         resetFull();
745         iter1 = getCollection().listIterator();
746         iter2 = getConfirmed().listIterator();
747         for (final E element : elements) {
748             iter1.next();
749             iter2.next();
750             iter1.add(element);
751             iter2.add(element);
752             verify();
753         }
754     }
755 
756     /**
757      *  Tests the {@link ListIterator#set(Object)} method of the list
758      *  iterator.
759      */
760     @Test
761     public void testListIteratorSet() {
762         if (!isSetSupported()) {
763             return;
764         }
765 
766         final E[] elements = getFullElements();
767 
768         resetFull();
769         final ListIterator<E> iter1 = getCollection().listIterator();
770         final ListIterator<E> iter2 = getConfirmed().listIterator();
771         for (final E element : elements) {
772             iter1.next();
773             iter2.next();
774             iter1.set(element);
775             iter2.set(element);
776             verify();
777         }
778     }
779 
780     /**
781      *  Tests {@link List#lastIndexOf}.
782      */
783     @Test
784     public void testListLastIndexOf() {
785         resetFull();
786         final List<E> list1 = getCollection();
787         final List<E> list2 = getConfirmed();
788 
789         for (final E element : list2) {
790             assertEquals(list1.lastIndexOf(element), list2.lastIndexOf(element),
791                     "lastIndexOf should return correct result");
792             verify();
793         }
794 
795         final E[] other = getOtherElements();
796         for (final E element : other) {
797             assertEquals(-1, list1.lastIndexOf(element),
798                     "lastIndexOf should return -1 for nonexistent " + "element");
799             verify();
800         }
801     }
802 
803     /**
804      *  Tests the read-only bits of {@link List#listIterator()}.
805      */
806     @Test
807     public void testListListIterator() {
808         resetFull();
809         forwardTest(getCollection().listIterator(), 0);
810         backwardTest(getCollection().listIterator(), 0);
811     }
812 
813     /**
814      *  Tests the read-only bits of {@link List#listIterator(int)}.
815      */
816     @Test
817     public void testListListIteratorByIndex() {
818         resetFull();
819         try {
820             getCollection().listIterator(-1);
821         } catch (final IndexOutOfBoundsException ex) {}
822         resetFull();
823         try {
824             getCollection().listIterator(getCollection().size() + 1);
825         } catch (final IndexOutOfBoundsException ex) {}
826         resetFull();
827         for (int i = 0; i <= getConfirmed().size(); i++) {
828             forwardTest(getCollection().listIterator(i), i);
829             backwardTest(getCollection().listIterator(i), i);
830         }
831         resetFull();
832         for (int i = 0; i <= getConfirmed().size(); i++) {
833             backwardTest(getCollection().listIterator(i), i);
834         }
835     }
836 
837     /**
838      * Tests remove on list iterator is correct.
839      */
840     @Test
841     public void testListListIteratorNextRemoveNext() {
842         if (!isRemoveSupported()) {
843             return;
844         }
845         resetFull();
846         if (getCollection().size() < 4) {
847             return;
848         }
849         final ListIterator<E> it = getCollection().listIterator();
850         final E zero = it.next();
851         final E one = it.next();
852         final E two = it.next();
853         assertEquals(zero, getCollection().get(0));
854         assertEquals(one, getCollection().get(1));
855         assertEquals(two, getCollection().get(2));
856         final E three = getCollection().get(3);
857 
858         it.remove(); // removed element at index 2 (two)
859         assertEquals(zero, getCollection().get(0));
860         assertEquals(one, getCollection().get(1));
861         final E three2 = it.next();  // do next after remove
862         assertEquals(three, three2);
863         assertEquals(getCollection().size() > 3, it.hasNext());
864         assertTrue(it.hasPrevious());
865     }
866 
867     /**
868      * Tests remove on list iterator is correct.
869      */
870     @Test
871     public void testListListIteratorNextRemovePrevious() {
872         if (!isRemoveSupported()) {
873             return;
874         }
875         resetFull();
876         if (getCollection().size() < 4) {
877             return;
878         }
879         final ListIterator<E> it = getCollection().listIterator();
880         final E zero = it.next();
881         final E one = it.next();
882         final E two = it.next();
883         assertEquals(zero, getCollection().get(0));
884         assertEquals(one, getCollection().get(1));
885         assertEquals(two, getCollection().get(2));
886 
887         it.remove(); // removed element at index 2 (two)
888         assertEquals(zero, getCollection().get(0));
889         assertEquals(one, getCollection().get(1));
890         final E one2 = it.previous();  // do previous after remove
891         assertEquals(one, one2);
892         assertTrue(it.hasNext());
893         assertTrue(it.hasPrevious());
894     }
895 
896     /**
897      * Tests remove on list iterator is correct.
898      */
899     @Test
900     public void testListListIteratorPreviousRemoveNext() {
901         if (!isRemoveSupported()) {
902             return;
903         }
904         resetFull();
905         if (getCollection().size() < 4) {
906             return;
907         }
908         final ListIterator<E> it = getCollection().listIterator();
909         final E zero = it.next();
910         final E one = it.next();
911         final E two = it.next();
912         final E two2 = it.previous();
913         final E one2 = it.previous();
914         assertEquals(one, one2);
915         assertEquals(two, two2);
916         assertEquals(zero, getCollection().get(0));
917         assertEquals(one, getCollection().get(1));
918         assertEquals(two, getCollection().get(2));
919 
920         it.remove(); // removed element at index 1 (one)
921         assertEquals(zero, getCollection().get(0));
922         assertEquals(two, getCollection().get(1));
923         final E two3 = it.next();  // do next after remove
924         assertEquals(two, two3);
925         assertEquals(getCollection().size() > 2, it.hasNext());
926         assertTrue(it.hasPrevious());
927     }
928 
929     /**
930      * Tests remove on list iterator is correct.
931      */
932     @Test
933     public void testListListIteratorPreviousRemovePrevious() {
934         if (!isRemoveSupported()) {
935             return;
936         }
937         resetFull();
938         if (getCollection().size() < 4) {
939             return;
940         }
941         final ListIterator<E> it = getCollection().listIterator();
942         final E zero = it.next();
943         final E one = it.next();
944         final E two = it.next();
945         final E two2 = it.previous();
946         final E one2 = it.previous();
947         assertEquals(one, one2);
948         assertEquals(two, two2);
949         assertEquals(zero, getCollection().get(0));
950         assertEquals(one, getCollection().get(1));
951         assertEquals(two, getCollection().get(2));
952 
953         it.remove(); // removed element at index 1 (one)
954         assertEquals(zero, getCollection().get(0));
955         assertEquals(two, getCollection().get(1));
956         final E zero3 = it.previous();  // do previous after remove
957         assertEquals(zero, zero3);
958         assertFalse(it.hasPrevious());
959         assertEquals(getCollection().size() > 2, it.hasNext());
960     }
961 
962     /**
963      *  Tests {@link List#remove(int)}.
964      */
965     @Test
966     public void testListRemoveByIndex() {
967         if (!isRemoveSupported()) {
968             return;
969         }
970 
971         final int max = getFullElements().length;
972         for (int i = 0; i < max; i++) {
973             resetFull();
974             final E o1 = getCollection().remove(i);
975             final E o2 = getConfirmed().remove(i);
976             assertEquals(o1, o2, "remove should return correct element");
977             verify();
978         }
979     }
980 
981     /**
982      *  Tests bounds checking for {@link List#remove(int)} on an
983      *  empty list.
984      */
985     @Test
986     public void testListRemoveByIndexBoundsChecking() {
987         if (!isRemoveSupported()) {
988             return;
989         }
990 
991         final List<E> list = makeObject();
992 
993         assertThrows(IndexOutOfBoundsException.class, () -> list.remove(Integer.MIN_VALUE),
994                 "List.remove should throw IndexOutOfBoundsException [Integer.MIN_VALUE]");
995 
996         assertThrows(IndexOutOfBoundsException.class, () -> list.remove(-1),
997                 "List.remove should throw IndexOutOfBoundsException [-1]");
998 
999         assertThrows(IndexOutOfBoundsException.class, () -> list.remove(0),
1000                 "List.remove should throw IndexOutOfBoundsException [0]");
1001 
1002         assertThrows(IndexOutOfBoundsException.class, () -> list.remove(1),
1003                 "List.remove should throw IndexOutOfBoundsException [1]");
1004 
1005         assertThrows(IndexOutOfBoundsException.class, () -> list.remove(Integer.MAX_VALUE),
1006                 "List.remove should throw IndexOutOfBoundsException [Integer.MAX_VALUE]");
1007     }
1008 
1009     /**
1010      *  Tests bounds checking for {@link List#remove(int)} on a
1011      *  full list.
1012      */
1013     @Test
1014     public void testListRemoveByIndexBoundsChecking2() {
1015         if (!isRemoveSupported()) {
1016             return;
1017         }
1018 
1019         final List<E> list = makeFullCollection();
1020 
1021         assertThrows(IndexOutOfBoundsException.class, () -> list.remove(Integer.MIN_VALUE),
1022                 "List.remove should throw IndexOutOfBoundsException [Integer.MIN_VALUE]");
1023 
1024         assertThrows(IndexOutOfBoundsException.class, () -> list.remove(-1),
1025                 "List.remove should throw IndexOutOfBoundsException [-1]");
1026 
1027         assertThrows(IndexOutOfBoundsException.class, () -> list.remove(getFullElements().length),
1028                 "List.remove should throw IndexOutOfBoundsException [size]");
1029 
1030         assertThrows(IndexOutOfBoundsException.class, () -> list.remove(Integer.MAX_VALUE),
1031                 "List.remove should throw IndexOutOfBoundsException [Integer.MAX_VALUE]");
1032     }
1033 
1034     /**
1035      *  Test {@link List#set(int,Object)}.
1036      */
1037     @Test
1038     public void testListSetByIndex() {
1039         if (!isSetSupported()) {
1040             return;
1041         }
1042 
1043         resetFull();
1044         final E[] elements = getFullElements();
1045         final E[] other = getOtherElements();
1046 
1047         for (int i = 0; i < elements.length; i++) {
1048             final E n = other[i % other.length];
1049             final E v = getCollection().set(i, n);
1050             assertEquals(elements[i], v, "Set should return correct element");
1051             getConfirmed().set(i, n);
1052             verify();
1053         }
1054     }
1055 
1056     /**
1057      *  Tests bounds checking for {@link List#set(int,Object)} on an
1058      *  empty list.
1059      */
1060     @Test
1061     public void testListSetByIndexBoundsChecking() {
1062         if (!isSetSupported()) {
1063             return;
1064         }
1065 
1066         final List<E> list = makeObject();
1067         final E element = getOtherElements()[0];
1068 
1069         assertThrows(IndexOutOfBoundsException.class, () -> list.set(Integer.MIN_VALUE, element),
1070                 "List.set should throw IndexOutOfBoundsException [Integer.MIN_VALUE]");
1071 
1072         assertThrows(IndexOutOfBoundsException.class, () -> list.set(-1, element),
1073                 "List.set should throw IndexOutOfBoundsException [-1]");
1074 
1075         assertThrows(IndexOutOfBoundsException.class, () -> list.set(0, element),
1076                 "List.set should throw IndexOutOfBoundsException [0]");
1077 
1078         assertThrows(IndexOutOfBoundsException.class, () -> list.set(1, element),
1079                 "List.set should throw IndexOutOfBoundsException [1]");
1080 
1081         assertThrows(IndexOutOfBoundsException.class, () -> list.set(Integer.MAX_VALUE, element),
1082                 "List.set should throw IndexOutOfBoundsException [Integer.MAX_VALUE]");
1083     }
1084 
1085     /**
1086      *  Tests bounds checking for {@link List#set(int,Object)} on a
1087      *  full list.
1088      */
1089     @Test
1090     public void testListSetByIndexBoundsChecking2() {
1091         if (!isSetSupported()) {
1092             return;
1093         }
1094 
1095         final List<E> list = makeFullCollection();
1096         final E element = getOtherElements()[0];
1097 
1098         assertThrows(IndexOutOfBoundsException.class, () -> list.set(Integer.MIN_VALUE, element),
1099                 "List.set should throw IndexOutOfBoundsException [Integer.MIN_VALUE]");
1100 
1101         assertThrows(IndexOutOfBoundsException.class, () -> list.set(-1, element),
1102                 "List.set should throw IndexOutOfBoundsException [-1]");
1103 
1104         assertThrows(IndexOutOfBoundsException.class, () -> list.set(getFullElements().length, element),
1105                 "List.set should throw IndexOutOfBoundsException [size]");
1106 
1107         assertThrows(IndexOutOfBoundsException.class, () -> list.set(Integer.MAX_VALUE, element),
1108                 "List.set should throw IndexOutOfBoundsException [Integer.MAX_VALUE]");
1109     }
1110 
1111     /**
1112      * Tests that a sublist raises a {@link java.util.ConcurrentModificationException ConcurrentModificationException}
1113      * if elements are added to the original list.
1114      */
1115     @Test
1116     public void testListSubListFailFastOnAdd() {
1117         if (!isFailFastSupported()) {
1118             return;
1119         }
1120         if (!isAddSupported()) {
1121             return;
1122         }
1123 
1124         resetFull();
1125         final int size = getCollection().size();
1126         List<E> sub = getCollection().subList(1, size);
1127         getCollection().add(getOtherElements()[0]);
1128         failFastAll(sub);
1129 
1130         resetFull();
1131         sub = getCollection().subList(1, size);
1132         getCollection().add(0, getOtherElements()[0]);
1133         failFastAll(sub);
1134 
1135         resetFull();
1136         sub = getCollection().subList(1, size);
1137         getCollection().addAll(Arrays.asList(getOtherElements()));
1138         failFastAll(sub);
1139 
1140         resetFull();
1141         sub = getCollection().subList(1, size);
1142         getCollection().addAll(0, Arrays.asList(getOtherElements()));
1143         failFastAll(sub);
1144     }
1145 
1146     /**
1147      * Tests that a sublist raises a {@link java.util.ConcurrentModificationException ConcurrentModificationException}
1148      * if elements are removed from the original list.
1149      */
1150     @Test
1151     public void testListSubListFailFastOnRemove() {
1152         if (!isFailFastSupported()) {
1153             return;
1154         }
1155         if (!isRemoveSupported()) {
1156             return;
1157         }
1158 
1159         resetFull();
1160         final int size = getCollection().size();
1161         List<E> sub = getCollection().subList(1, size);
1162         getCollection().remove(0);
1163         failFastAll(sub);
1164 
1165         resetFull();
1166         sub = getCollection().subList(1, size);
1167         getCollection().remove(getFullElements()[2]);
1168         failFastAll(sub);
1169 
1170         resetFull();
1171         sub = getCollection().subList(1, size);
1172         getCollection().removeAll(Arrays.asList(getFullElements()));
1173         failFastAll(sub);
1174 
1175         resetFull();
1176         sub = getCollection().subList(1, size);
1177         getCollection().retainAll(Arrays.asList(getOtherElements()));
1178         failFastAll(sub);
1179 
1180         resetFull();
1181         sub = getCollection().subList(1, size);
1182         getCollection().clear();
1183         failFastAll(sub);
1184     }
1185 
1186     /**
1187      *  If {@link #isSetSupported()} returns false, tests that set operation
1188      *  raises <Code>UnsupportedOperationException.
1189      */
1190     @Test
1191     public void testUnsupportedSet() {
1192         if (isSetSupported()) {
1193             return;
1194         }
1195 
1196         resetFull();
1197         assertThrows(UnsupportedOperationException.class, () -> getCollection().set(0, getFullElements()[0]),
1198                 "Empty collection should not support set.");
1199         // make sure things didn't change even if the expected exception was
1200         // thrown.
1201         verify();
1202     }
1203 
1204     /**
1205      *  Verifies that the test list implementation matches the confirmed list
1206      *  implementation.
1207      */
1208     @Override
1209     @SuppressWarnings("unchecked")
1210     public void verify() {
1211         super.verify();
1212 
1213         final List<E> list1 = getCollection();
1214         final List<E> list2 = getConfirmed();
1215 
1216         assertEquals(list1, list2, "List should equal confirmed");
1217         assertEquals(list2, list1, "Confirmed should equal list");
1218 
1219         assertEquals(list1.hashCode(), list2.hashCode(), "Hash codes should be equal");
1220 
1221         int i = 0;
1222         final Iterator<E> iterator1 = list1.iterator();
1223         final E[] array = (E[]) list1.toArray();
1224         for (Object o2 : list2) {
1225             assertTrue(iterator1.hasNext(), "List iterator should have next");
1226             final Object o1 = iterator1.next();
1227             assertEquals(o1, o2, "Iterator elements should be equal");
1228             o2 = list1.get(i);
1229             assertEquals(o1, o2, "get should return correct element");
1230             o2 = array[i];
1231             assertEquals(o1, o2, "toArray should have correct element");
1232             i++;
1233         }
1234     }
1235 
1236 }