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