1 /*
2  * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 package test.java.util.SequencedCollection;
25 
26 import java.io.*;
27 import java.util.*;
28 import java.util.concurrent.CopyOnWriteArrayList;
29 import org.testng.annotations.DataProvider;
30 import org.testng.annotations.Test;
31 
32 import static org.testng.Assert.assertEquals;
33 import static org.testng.Assert.assertSame;
34 import static org.testng.Assert.assertThrows;
35 import static org.testng.Assert.assertTrue;
36 
37 /*
38  * @test
39  * @bug     8266571
40  * @summary Basic tests for SequencedCollection
41  * @modules java.base/java.util:open
42  * @build   SimpleDeque SimpleList SimpleSortedSet
43  * @run     testng Basic
44  */
45 
46 // TODO test that remove(obj) with duplicates removes the right element
47 
48 public class Basic {
49 
50     // ========== Data Providers ==========
51 
52     static final List<String> ORIGINAL = List.of("a", "b", "c", "d", "e", "f", "g");
53 
cklist(List<String> contents)54     static List<String> cklist(List<String> contents) {
55         return Collections.checkedList(contents, String.class);
56     }
57 
cknav(NavigableSet<String> set)58     static NavigableSet<String> cknav(NavigableSet<String> set) {
59         return Collections.checkedNavigableSet(set, String.class);
60     }
61 
cksorted(SortedSet<String> set)62     static SortedSet<String> cksorted(SortedSet<String> set) {
63         return Collections.checkedSortedSet(set, String.class);
64     }
65 
setFromMap(List<String> contents)66     static SequencedSet<String> setFromMap(List<String> contents) {
67         var lhm = new LinkedHashMap<String, Boolean>();
68         var ss = Collections.newSequencedSetFromMap(lhm);
69         ss.addAll(contents);
70         return ss;
71     }
72 
ucoll(SequencedCollection<String> coll)73     static SequencedCollection<String> ucoll(SequencedCollection<String> coll) {
74         return Collections.unmodifiableSequencedCollection(coll);
75     }
76 
ulist(List<String> list)77     static SequencedCollection<String> ulist(List<String> list) {
78         return Collections.unmodifiableList(list);
79     }
80 
unav(NavigableSet<String> set)81     static NavigableSet<String> unav(NavigableSet<String> set) {
82         return Collections.unmodifiableNavigableSet(set);
83     }
84 
uset(SequencedSet<String> set)85     static SequencedSet<String> uset(SequencedSet<String> set) {
86         return Collections.unmodifiableSequencedSet(set);
87     }
88 
usorted(SortedSet<String> set)89     static SortedSet<String> usorted(SortedSet<String> set) {
90         return Collections.unmodifiableSortedSet(set);
91     }
92 
copyReversed(List<T> list)93     static <T> List<T> copyReversed(List<T> list) {
94         var r = new ArrayList<T>(list);
95         Collections.reverse(r);
96         return r;
97     }
98 
99     @DataProvider(name="all")
all()100     public Iterator<Object[]> all() {
101         var result = new ArrayList<Object[]>();
102         populated().forEachRemaining(result::add);
103         empties().forEachRemaining(result::add);
104         return result.iterator();
105     }
106 
107     @DataProvider(name="populated")
populated()108     public Iterator<Object[]> populated() {
109         return Arrays.asList(
110             new Object[] { "ArrayDeque", new ArrayDeque<>(ORIGINAL), ORIGINAL },
111             new Object[] { "ArrayList", new ArrayList<>(ORIGINAL), ORIGINAL },
112             new Object[] { "AsList", Arrays.asList(ORIGINAL.toArray()), ORIGINAL },
113             new Object[] { "COWAL", new CopyOnWriteArrayList<>(ORIGINAL), ORIGINAL },
114             new Object[] { "LinkedHashSet", new LinkedHashSet<>(ORIGINAL), ORIGINAL },
115             new Object[] { "LinkedList", new LinkedList<>(ORIGINAL), ORIGINAL },
116             new Object[] { "ListOf", ORIGINAL, ORIGINAL },
117             new Object[] { "SetFromMap", setFromMap(ORIGINAL), ORIGINAL },
118             new Object[] { "SimpleDeque", new SimpleDeque<>(ORIGINAL), ORIGINAL },
119             new Object[] { "SimpleList", new SimpleList<>(ORIGINAL), ORIGINAL },
120             new Object[] { "SimpleSortedSet", new SimpleSortedSet<>(ORIGINAL), ORIGINAL },
121             new Object[] { "TreeSet", new TreeSet<>(ORIGINAL), ORIGINAL },
122             new Object[] { "UnmodColl", ucoll(new ArrayList<>(ORIGINAL)), ORIGINAL },
123             new Object[] { "UnmodSet", uset(new LinkedHashSet<>(ORIGINAL)), ORIGINAL }
124         ).iterator();
125     }
126 
127     @DataProvider(name="empties")
empties()128     public Iterator<Object[]> empties() {
129         return Arrays.asList(
130             new Object[] { "ArrayDeque", new ArrayDeque<>(), List.of() },
131             new Object[] { "ArrayList", new ArrayList<>(), List.of() },
132             new Object[] { "AsList", Arrays.asList(new String[0]), List.of() },
133             new Object[] { "COWAL", new CopyOnWriteArrayList<>(), List.of() },
134             new Object[] { "EmptyList", Collections.emptyList(), List.of() },
135             new Object[] { "EmptyNavigableSet", Collections.emptyNavigableSet(), List.of() },
136             new Object[] { "EmptySortedSet", Collections.emptySortedSet(), List.of() },
137             new Object[] { "LinkedHashSet", new LinkedHashSet<>(), List.of() },
138             new Object[] { "LinkedList", new LinkedList<>(), List.of() },
139             new Object[] { "ListOf", List.of(), List.of() },
140             new Object[] { "SetFromMap", setFromMap(List.of()), List.of() },
141             new Object[] { "SimpleDeque", new SimpleDeque<>(), List.of() },
142             new Object[] { "SimpleList", new SimpleList<>(), List.of() },
143             new Object[] { "SimpleSortedSet", new SimpleSortedSet<>(), List.of() },
144             new Object[] { "TreeSet", new TreeSet<>(), List.of() },
145             new Object[] { "UnmodColl", ucoll(new ArrayList<>()), List.of() },
146             new Object[] { "UnmodSet", uset(new LinkedHashSet<>()), List.of() }
147         ).iterator();
148     }
149 
150     @DataProvider(name="adds")
adds()151     public Iterator<Object[]> adds() {
152         return Arrays.asList(
153             new Object[] { "ArrayDeque", new ArrayDeque<>(ORIGINAL), ORIGINAL },
154             new Object[] { "ArrayList", new ArrayList<>(ORIGINAL), ORIGINAL },
155             new Object[] { "COWAL", new CopyOnWriteArrayList<>(ORIGINAL), ORIGINAL },
156             new Object[] { "LinkedHashSet", new LinkedHashSet<>(ORIGINAL), ORIGINAL },
157             new Object[] { "LinkedList", new LinkedList<>(ORIGINAL), ORIGINAL },
158             new Object[] { "SetFromMap", setFromMap(ORIGINAL), ORIGINAL },
159             new Object[] { "SimpleDeque", new SimpleDeque<>(ORIGINAL), ORIGINAL },
160             new Object[] { "SimpleList", new SimpleList<>(ORIGINAL), ORIGINAL }
161         ).iterator();
162     }
163 
164     @DataProvider(name="unpositionedAdd")
unpositionedAdd()165     public Iterator<Object[]> unpositionedAdd() {
166         return Arrays.<Object[]>asList(
167             new Object[] { "LinkedHashSet", new LinkedHashSet<>(ORIGINAL), ORIGINAL }
168         ).iterator();
169     }
170 
171     @DataProvider(name="removes")
removes()172     public Iterator<Object[]> removes() {
173         return Arrays.asList(
174             new Object[] { "ArrayDeque", new ArrayDeque<>(ORIGINAL), ORIGINAL },
175             new Object[] { "ArrayList", new ArrayList<>(ORIGINAL), ORIGINAL },
176             new Object[] { "COWAL", new CopyOnWriteArrayList<>(ORIGINAL), ORIGINAL },
177             new Object[] { "LinkedHashSet", new LinkedHashSet<>(ORIGINAL), ORIGINAL },
178             new Object[] { "LinkedList", new LinkedList<>(ORIGINAL), ORIGINAL },
179             new Object[] { "SetFromMap", setFromMap(ORIGINAL), ORIGINAL },
180             new Object[] { "SimpleDeque", new SimpleDeque<>(ORIGINAL), ORIGINAL },
181             new Object[] { "SimpleList", new SimpleList<>(ORIGINAL), ORIGINAL },
182             new Object[] { "SimpleSortedSet", new SimpleSortedSet<>(ORIGINAL), ORIGINAL },
183             new Object[] { "TreeSet", new TreeSet<>(ORIGINAL), ORIGINAL }
184         ).iterator();
185     }
186 
187     @DataProvider(name="emptyRemoves")
emptyRemoves()188     public Iterator<Object[]> emptyRemoves() {
189         return Arrays.asList(
190             new Object[] { "ArrayDeque", new ArrayDeque<>(), List.of() },
191             new Object[] { "ArrayList", new ArrayList<>(), List.of() },
192             new Object[] { "COWAL", new CopyOnWriteArrayList<>(), List.of() },
193             new Object[] { "LinkedHashSet", new LinkedHashSet<>(), List.of() },
194             new Object[] { "LinkedList", new LinkedList<>(), List.of() },
195             new Object[] { "SetFromMap", setFromMap(List.of()), List.of() },
196             new Object[] { "SimpleDeque", new SimpleDeque<>(), List.of() },
197             new Object[] { "SimpleList", new SimpleList<>(), List.of() },
198             new Object[] { "SimpleSortedSet", new SimpleSortedSet<>(), List.of() },
199             new Object[] { "TreeSet", new TreeSet<>(), List.of() }
200         ).iterator();
201     }
202 
203     @DataProvider(name="serializable")
serializable()204     public Iterator<Object[]> serializable() {
205         return Arrays.asList(
206             new Object[] { "ArrayDeque", new ArrayDeque<>(ORIGINAL), ORIGINAL },
207             new Object[] { "ArrayList", new ArrayList<>(ORIGINAL), ORIGINAL },
208             new Object[] { "AsList", Arrays.asList(ORIGINAL.toArray()), ORIGINAL },
209             new Object[] { "COWAL", new CopyOnWriteArrayList<>(ORIGINAL), ORIGINAL },
210             new Object[] { "LinkedHashSet", new LinkedHashSet<>(ORIGINAL), ORIGINAL },
211             new Object[] { "LinkedList", new LinkedList<>(ORIGINAL), ORIGINAL },
212             new Object[] { "ListOf", ORIGINAL, ORIGINAL },
213             new Object[] { "SetFromMap", setFromMap(ORIGINAL), ORIGINAL },
214             new Object[] { "TreeSet", new TreeSet<>(ORIGINAL), ORIGINAL },
215             new Object[] { "UnmodColl", ucoll(new ArrayList<>(ORIGINAL)), ORIGINAL },
216             new Object[] { "UnmodSet", uset(new LinkedHashSet<>(ORIGINAL)), ORIGINAL }
217         ).iterator();
218     }
219 
220     @DataProvider(name="notSerializable")
notSerializable()221     public Iterator<Object[]> notSerializable() {
222         return Arrays.asList(
223             new Object[] { "ArrayDeque", new ArrayDeque<>(ORIGINAL).reversed() },
224             new Object[] { "ArrayList", new ArrayList<>(ORIGINAL).reversed() },
225             new Object[] { "AsList", Arrays.asList(ORIGINAL.toArray()).reversed() },
226             new Object[] { "COWAL", new CopyOnWriteArrayList<>(ORIGINAL).reversed() },
227             new Object[] { "LinkedHashSet", new LinkedHashSet<>(ORIGINAL).reversed() },
228             new Object[] { "LinkedList", new LinkedList<>(ORIGINAL).reversed() },
229             new Object[] { "ListOf", ORIGINAL.reversed() },
230             new Object[] { "SetFromMap", setFromMap(ORIGINAL).reversed() },
231             new Object[] { "UnmodColl", ucoll(new ArrayList<>(ORIGINAL)).reversed() },
232             new Object[] { "UnmodSet", uset(new LinkedHashSet<>(ORIGINAL)).reversed() }
233         ).iterator();
234     }
235 
236     @DataProvider(name="doubleReverse")
doubleReverse()237     public Iterator<Object[]> doubleReverse() {
238         return Arrays.asList(
239             new Object[] { "ArrayDeque", new ArrayDeque<>(ORIGINAL) },
240             new Object[] { "ArrayList", new ArrayList<>(ORIGINAL) },
241             new Object[] { "AsList", Arrays.asList(ORIGINAL.toArray()) },
242             new Object[] { "COWAL", new CopyOnWriteArrayList<>(ORIGINAL) },
243             new Object[] { "LinkedHashSet", new LinkedHashSet<>(ORIGINAL) },
244             new Object[] { "LinkedList", new LinkedList<>(ORIGINAL) },
245             new Object[] { "ListOf", ORIGINAL },
246             new Object[] { "SimpleDeque", new SimpleDeque<>(ORIGINAL) },
247             new Object[] { "SimpleList", new SimpleList<>(ORIGINAL) },
248             new Object[] { "SimpleSortedSet", new SimpleSortedSet<>(ORIGINAL) }
249         ).iterator();
250     }
251 
252     @DataProvider(name="unmodifiable")
unmodifiable()253     public Iterator<Object[]> unmodifiable() {
254         return Arrays.asList(
255             new Object[] { "ListOf", ORIGINAL, ORIGINAL },
256             new Object[] { "ListOfSub", ORIGINAL.subList(1, 3), ORIGINAL.subList(1, 3) },
257             new Object[] { "SingleList", Collections.singletonList("a"), List.of("a") },
258             new Object[] { "UnmodColl", ucoll(new ArrayList<>(ORIGINAL)), ORIGINAL },
259             new Object[] { "UnmodList", ulist(new ArrayList<>(ORIGINAL)), ORIGINAL },
260             new Object[] { "UnmodNav", unav(new TreeSet<>(ORIGINAL)), ORIGINAL },
261             new Object[] { "UnmodSet", uset(new LinkedHashSet<>(ORIGINAL)), ORIGINAL },
262             new Object[] { "UnmodSorted", usorted(new TreeSet<>(ORIGINAL)), ORIGINAL }
263         ).iterator();
264     }
265 
266     @DataProvider(name="checkedList")
checkedList()267     public Iterator<Object[]> checkedList() {
268         return Arrays.<Object[]>asList(
269             new Object[] { "ChkList", cklist(new ArrayList<>(ORIGINAL)), ORIGINAL }
270         ).iterator();
271     }
272 
273     @DataProvider(name="checkedNavSet")
checkedNavSet()274     public Iterator<Object[]> checkedNavSet() {
275         return Arrays.<Object[]>asList(
276             new Object[] { "ChkNav", cknav(new TreeSet<>(ORIGINAL)), ORIGINAL }
277         ).iterator();
278     }
279 
280     @DataProvider(name="checkedSortedSet")
checkedSortedSet()281     public Iterator<Object[]> checkedSortedSet() {
282         return Arrays.<Object[]>asList(
283             new Object[] { "ChkSorted", cksorted(new TreeSet<>(ORIGINAL)), ORIGINAL }
284         ).iterator();
285     }
286 
287     // mode bit tests for subList testing
288 
reverseList(int mode)289     boolean reverseList(int mode) { return (mode & 1) != 0; }
reverseSub(int mode)290     boolean reverseSub(int mode)  { return (mode & 2) != 0; }
isReversed(int mode)291     boolean isReversed(int mode) { return reverseList(mode) ^ reverseSub(mode); }
292 
applyMode(int mode, List<String> base)293     List<String> applyMode(int mode, List<String> base) {
294         var list = reverseList(mode) ? base.reversed() : base;
295         var sub = list.subList(2, 5);
296         return reverseSub(mode) ? sub.reversed() : sub;
297     }
298 
299     /**
300      * Generate cases for testing subLists. For each different List implementation, generate 4
301      * cases from the two bits of the testing mode int value:
302      *
303      *  (bit 1) if true, the List is reversed
304      *  (bit 2) if true, the subList is reversed
305      *
306      * @return the generated cases
307      */
308     @DataProvider(name="subListMods")
subListMods()309     public Iterator<Object[]> subListMods() {
310         var cases = new ArrayList<Object[]>();
311         for (int mode = 0; mode < 4; mode++) {
312             cases.addAll(Arrays.asList(
313                 new Object[] { "ArrayList", mode, new ArrayList<>(ORIGINAL), ORIGINAL },
314                 new Object[] { "COWAL", mode, new CopyOnWriteArrayList<>(ORIGINAL), ORIGINAL },
315                 new Object[] { "LinkedList", mode, new LinkedList<>(ORIGINAL), ORIGINAL },
316                 new Object[] { "SimpleList", mode, new SimpleList<>(ORIGINAL), ORIGINAL }
317             ));
318         }
319         return cases.iterator();
320     }
321 
322     @DataProvider(name="iteratorMods")
iteratorMods()323     public Iterator<Object[]> iteratorMods() {
324         var cases = new ArrayList<Object[]>();
325         for (boolean rev : List.of(false, true)) {
326             cases.addAll(Arrays.asList(
327                 new Object[] { "ArrayList", rev, new ArrayList<>(ORIGINAL), ORIGINAL },
328                 new Object[] { "LinkedList", rev, new LinkedList<>(ORIGINAL), ORIGINAL },
329                 new Object[] { "SimpleList", rev, new SimpleList<>(ORIGINAL), ORIGINAL }
330             ));
331         }
332         return cases.iterator();
333     }
334 
335     @DataProvider(name="subListIteratorMods")
subListIteratorMods()336     public Iterator<Object[]> subListIteratorMods() {
337         var cases = new ArrayList<Object[]>();
338         for (int mode = 0; mode < 4; mode++) {
339             cases.addAll(Arrays.asList(
340                 new Object[] { "ArrayList", mode, new ArrayList<>(ORIGINAL), ORIGINAL },
341                 new Object[] { "LinkedList", mode, new LinkedList<>(ORIGINAL), ORIGINAL },
342                 new Object[] { "SimpleList", mode, new SimpleList<>(ORIGINAL), ORIGINAL }
343             ));
344         }
345         return cases.iterator();
346     }
347 
348     // ========== Assertions ==========
349 
350     /**
351      * Basic checks over the contents of a SequencedCollection,
352      * compared to a reference List, in one direction.
353      *
354      * @param seq the SequencedCollection under test
355      * @param ref the reference List
356      */
checkContents1(SequencedCollection<String> seq, List<String> ref)357     public void checkContents1(SequencedCollection<String> seq, List<String> ref) {
358         var list1 = new ArrayList<String>();
359         for (var s : seq)
360             list1.add(s);
361         assertEquals(list1, ref);
362 
363         var list2 = new ArrayList<String>();
364         seq.forEach(list2::add);
365         assertEquals(list2, ref);
366 
367         var list3 = Arrays.asList(seq.toArray());
368         assertEquals(list3, ref);
369 
370         var list4 = Arrays.asList(seq.toArray(new String[0]));
371         assertEquals(list4, ref);
372 
373         var list5 = Arrays.asList(seq.toArray(String[]::new));
374         assertEquals(list5, ref);
375 
376         var list6 = seq.stream().toList();
377         assertEquals(list6, ref);
378 
379         var list7 = seq.parallelStream().toList();
380         assertEquals(list7, ref);
381 
382         assertEquals(seq.size(), ref.size());
383         assertEquals(seq.isEmpty(), ref.isEmpty());
384 
385         for (var s : ref) {
386             assertTrue(seq.contains(s));
387         }
388     }
389 
390     /**
391      * Check the contents of a SequencedCollection against a reference List,
392      * in both directions.
393      *
394      * @param seq the SequencedCollection under test
395      * @param ref the reference List
396      */
checkContents(SequencedCollection<String> seq, List<String> ref)397     public void checkContents(SequencedCollection<String> seq, List<String> ref) {
398         checkContents1(seq, ref);
399 
400         var rref = copyReversed(ref);
401         var rseq = seq.reversed();
402         checkContents1(rseq, rref);
403 
404         var rrseq = rseq.reversed();
405         checkContents1(rrseq, ref);
406     }
407 
408     /**
409      * Check that modification operations will throw UnsupportedOperationException,
410      * in one direction.
411      *
412      * @param seq the SequencedCollection under test
413      */
checkUnmodifiable1(SequencedCollection<String> seq)414     public void checkUnmodifiable1(SequencedCollection<String> seq) {
415         final var UOE = UnsupportedOperationException.class;
416 
417         assertThrows(UOE, () -> seq.add("x"));
418         assertThrows(UOE, () -> seq.clear());
419         assertThrows(UOE, () -> { var it = seq.iterator(); it.next(); it.remove(); });
420         assertThrows(UOE, () -> seq.removeIf(x -> true));
421 
422         assertThrows(UOE, () -> seq.addFirst("x"));
423         assertThrows(UOE, () -> seq.addLast("x"));
424         assertThrows(UOE, () -> seq.removeFirst());
425         assertThrows(UOE, () -> seq.removeLast());
426 
427 // TODO these ops should throw unconditionally, but they don't in some implementations
428      // assertThrows(UOE, () -> seq.addAll(List.of()));
429      // assertThrows(UOE, () -> seq.remove("x"));
430      // assertThrows(UOE, () -> seq.removeAll(List.of()));
431      // assertThrows(UOE, () -> seq.removeIf(x -> false));
432      // assertThrows(UOE, () -> seq.retainAll(seq));
433         assertThrows(UOE, () -> seq.addAll(seq));
434         assertThrows(UOE, () -> seq.remove(seq.iterator().next()));
435         assertThrows(UOE, () -> seq.removeAll(seq));
436         assertThrows(UOE, () -> seq.retainAll(List.of()));
437     }
438 
439     /**
440      * Check that modification operations will throw UnsupportedOperationException,
441      * in both directions.
442      *
443      * @param seq the SequencedCollection under test
444      */
checkUnmodifiable(SequencedCollection<String> seq)445     public void checkUnmodifiable(SequencedCollection<String> seq) {
446         checkUnmodifiable1(seq);
447         checkUnmodifiable1(seq.reversed());
448     }
449 
450     static final Class<? extends Throwable> CCE = ClassCastException.class;
451 
checkCheckedList(List<String> list)452     public void checkCheckedList(List<String> list) {
453         List<Object> objList = (List<Object>)(List)list;
454         assertThrows(CCE, () -> { objList.addFirst(new Object()); });
455         assertThrows(CCE, () -> { objList.addLast(new Object()); });
456         assertThrows(CCE, () -> { objList.reversed().addFirst(new Object()); });
457         assertThrows(CCE, () -> { objList.reversed().addLast(new Object()); });
458     }
459 
checkCheckedNavSet(NavigableSet<String> set)460     public void checkCheckedNavSet(NavigableSet<String> set) {
461         NavigableSet<Object> objSet = (NavigableSet<Object>)(NavigableSet)set;
462         assertThrows(CCE, () -> { objSet.add(new Object()); });
463         assertThrows(CCE, () -> { objSet.reversed().add(new Object()); });
464     }
465 
checkCheckedSortedSet(SortedSet<String> set)466     public void checkCheckedSortedSet(SortedSet<String> set) {
467         SortedSet<Object> objSet = (SortedSet<Object>)(SortedSet)set;
468         assertThrows(CCE, () -> { objSet.add(new Object()); });
469         assertThrows(CCE, () -> { objSet.reversed().add(new Object()); });
470     }
471 
472     // ========== Tests ==========
473 
474     @Test(dataProvider="all")
testFundamentals(String label, SequencedCollection<String> seq, List<String> ref)475     public void testFundamentals(String label, SequencedCollection<String> seq, List<String> ref) {
476         checkContents(seq, ref);
477     }
478 
479     @Test(dataProvider="populated")
testGetFirst(String label, SequencedCollection<String> seq, List<String> ref)480     public void testGetFirst(String label, SequencedCollection<String> seq, List<String> ref) {
481         assertEquals(seq.getFirst(), ref.get(0));
482         assertEquals(seq.reversed().getFirst(), ref.get(ref.size() - 1));
483         checkContents(seq, ref);
484     }
485 
486     @Test(dataProvider="populated")
testGetLast(String label, SequencedCollection<String> seq, List<String> ref)487     public void testGetLast(String label, SequencedCollection<String> seq, List<String> ref) {
488         assertEquals(seq.getLast(), ref.get(ref.size() - 1));
489         assertEquals(seq.reversed().getLast(), ref.get(0));
490         checkContents(seq, ref);
491     }
492 
493     @Test(dataProvider="empties")
testEmptyGetFirst(String label, SequencedCollection<String> seq, List<String> ref)494     public void testEmptyGetFirst(String label, SequencedCollection<String> seq, List<String> ref) {
495         assertThrows(NoSuchElementException.class, () -> seq.getFirst());
496         assertThrows(NoSuchElementException.class, () -> seq.reversed().getFirst());
497         checkContents(seq, ref);
498     }
499 
500     @Test(dataProvider="empties")
testEmptyGetLast(String label, SequencedCollection<String> seq, List<String> ref)501     public void testEmptyGetLast(String label, SequencedCollection<String> seq, List<String> ref) {
502         assertThrows(NoSuchElementException.class, () -> seq.getLast());
503         assertThrows(NoSuchElementException.class, () -> seq.reversed().getLast());
504         checkContents(seq, ref);
505     }
506 
507     @Test(dataProvider="adds")
testAddFirst(String label, SequencedCollection<String> seq, List<String> baseref)508     public void testAddFirst(String label, SequencedCollection<String> seq, List<String> baseref) {
509         var ref = new ArrayList<>(baseref);
510         ref.add(0, "x");
511         seq.addFirst("x");
512         checkContents(seq, ref);
513     }
514 
515     @Test(dataProvider="adds")
testAddFirstRev(String label, SequencedCollection<String> seq, List<String> baseref)516     public void testAddFirstRev(String label, SequencedCollection<String> seq, List<String> baseref) {
517         var ref = new ArrayList<>(baseref);
518         ref.add("x");
519         seq.reversed().addFirst("x");
520         checkContents(seq, ref);
521     }
522 
523     @Test(dataProvider="adds")
testAddLast(String label, SequencedCollection<String> seq, List<String> baseref)524     public void testAddLast(String label, SequencedCollection<String> seq, List<String> baseref) {
525         var ref = new ArrayList<>(baseref);
526         ref.add("x");
527         seq.addLast("x");
528         checkContents(seq, ref);
529     }
530 
531     @Test(dataProvider="adds")
testAddLastRev(String label, SequencedCollection<String> seq, List<String> baseref)532     public void testAddLastRev(String label, SequencedCollection<String> seq, List<String> baseref) {
533         var ref = new ArrayList<>(baseref);
534         ref.add(0, "x");
535         seq.reversed().addLast("x");
536         checkContents(seq, ref);
537     }
538 
539     @Test(dataProvider="unpositionedAdd")
testUnpositionedAdd(String label, SequencedCollection<String> seq, List<String> baseref)540     public void testUnpositionedAdd(String label, SequencedCollection<String> seq, List<String> baseref) {
541         var ref = new ArrayList<>(baseref);
542         ref.add("x");
543         seq.add("x");
544         checkContents(seq, ref);
545     }
546 
547     @Test(dataProvider="unpositionedAdd")
testUnpositionedAddRev(String label, SequencedCollection<String> seq, List<String> baseref)548     public void testUnpositionedAddRev(String label, SequencedCollection<String> seq, List<String> baseref) {
549         var ref = new ArrayList<>(baseref);
550         ref.add("x");
551         seq.reversed().add("x");
552         checkContents(seq, ref);
553     }
554 
555     @Test(dataProvider="removes")
testRemoveFirst(String label, SequencedCollection<String> seq, List<String> baseref)556     public void testRemoveFirst(String label, SequencedCollection<String> seq, List<String> baseref) {
557         var ref = new ArrayList<>(baseref);
558         var exp = ref.remove(0);
559         var act = seq.removeFirst();
560         assertEquals(act, exp);
561         checkContents(seq, ref);
562     }
563 
564     @Test(dataProvider="removes")
testRemoveFirstRev(String label, SequencedCollection<String> seq, List<String> baseref)565     public void testRemoveFirstRev(String label, SequencedCollection<String> seq, List<String> baseref) {
566         var ref = new ArrayList<>(baseref);
567         var exp = ref.remove(ref.size() - 1);
568         var act = seq.reversed().removeFirst();
569         assertEquals(act, exp);
570         checkContents(seq, ref);
571     }
572 
573     @Test(dataProvider="removes")
testRemoveLast(String label, SequencedCollection<String> seq, List<String> baseref)574     public void testRemoveLast(String label, SequencedCollection<String> seq, List<String> baseref) {
575         var ref = new ArrayList<>(baseref);
576         var exp = ref.remove(ref.size() - 1);
577         var act = seq.removeLast();
578         assertEquals(act, exp);
579         checkContents(seq, ref);
580     }
581 
582     @Test(dataProvider="removes")
testRemoveLastRev(String label, SequencedCollection<String> seq, List<String> baseref)583     public void testRemoveLastRev(String label, SequencedCollection<String> seq, List<String> baseref) {
584         var ref = new ArrayList<>(baseref);
585         var exp = ref.remove(0);
586         var act = seq.reversed().removeLast();
587         assertEquals(act, exp);
588         checkContents(seq, ref);
589     }
590 
591     @Test(dataProvider="emptyRemoves")
testEmptyRemoveFirst(String label, SequencedCollection<String> seq, List<String> baseref)592     public void testEmptyRemoveFirst(String label, SequencedCollection<String> seq, List<String> baseref) {
593         assertThrows(NoSuchElementException.class, () -> seq.removeFirst());
594         assertThrows(NoSuchElementException.class, () -> seq.reversed().removeFirst());
595         checkContents(seq, baseref);
596     }
597 
598     @Test(dataProvider="emptyRemoves")
testEmptyRemoveLast(String label, SequencedCollection<String> seq, List<String> baseref)599     public void testEmptyRemoveLast(String label, SequencedCollection<String> seq, List<String> baseref) {
600         assertThrows(NoSuchElementException.class, () -> seq.removeLast());
601         assertThrows(NoSuchElementException.class, () -> seq.reversed().removeLast());
602         checkContents(seq, baseref);
603     }
604 
605     @Test(dataProvider="serializable")
testSerializable(String label, SequencedCollection<String> seq, List<String> ref)606     public void testSerializable(String label, SequencedCollection<String> seq, List<String> ref)
607         throws ClassNotFoundException, IOException
608     {
609         var baos = new ByteArrayOutputStream();
610         try (var oos = new ObjectOutputStream(baos)) {
611             oos.writeObject(seq);
612         }
613 
614         try (var bais = new ByteArrayInputStream(baos.toByteArray());
615              var ois = new ObjectInputStream(bais)) {
616             var seq2 = (SequencedCollection<String>) ois.readObject();
617             checkContents(seq2, ref);
618         }
619     }
620 
621     @Test(dataProvider="notSerializable")
testNotSerializable(String label, SequencedCollection<String> seq)622     public void testNotSerializable(String label, SequencedCollection<String> seq)
623         throws ClassNotFoundException, IOException
624     {
625         var baos = new ByteArrayOutputStream();
626         try (var oos = new ObjectOutputStream(baos)) {
627             assertThrows(ObjectStreamException.class, () -> oos.writeObject(seq));
628         }
629     }
630 
631     @Test(dataProvider="doubleReverse")
testDoubleReverse(String label, SequencedCollection<String> seq)632     public void testDoubleReverse(String label, SequencedCollection<String> seq) {
633         var rrseq = seq.reversed().reversed();
634         assertSame(rrseq, seq);
635     }
636 
637     @Test(dataProvider="unmodifiable")
testUnmodifiable(String label, SequencedCollection<String> seq, List<String> ref)638     public void testUnmodifiable(String label, SequencedCollection<String> seq, List<String> ref) {
639         checkUnmodifiable(seq);
640         checkContents(seq, ref);
641     }
642 
643     @Test(dataProvider="checkedList")
testCheckedList(String label, List<String> list, List<String> ref)644     public void testCheckedList(String label, List<String> list, List<String> ref) {
645         checkCheckedList(list);
646         checkContents(list, ref);
647     }
648 
649     @Test(dataProvider="checkedNavSet")
testCheckedNavSet(String label, NavigableSet<String> set, List<String> ref)650     public void testCheckedNavSet(String label, NavigableSet<String> set, List<String> ref) {
651         checkCheckedNavSet(set);
652         checkContents(set, ref);
653     }
654 
655     @Test(dataProvider="checkedSortedSet")
testCheckedSortedSet(String label, SortedSet<String> set, List<String> ref)656     public void testCheckedSortedSet(String label, SortedSet<String> set, List<String> ref) {
657         checkCheckedSortedSet(set);
658         checkContents(set, ref);
659     }
660 
661     // Indexes for subList modification tests:
662     // 0  1  2  3  4  5  6
663     // a, b, c, d, e, f, g
664     //       c, d, e
665 
666     @Test(dataProvider="subListMods")
testSubListGet(String label, int mode, List<String> list, List<String> base)667     public void testSubListGet(String label, int mode, List<String> list, List<String> base) {
668         var sub = applyMode(mode, list);
669         assertEquals(sub.getFirst(), isReversed(mode) ? "e" : "c");
670         assertEquals(sub.getLast(),  isReversed(mode) ? "c" : "e");
671     }
672 
673     @Test(dataProvider="subListMods")
testSubListAddFirst(String label, int mode, List<String> list, List<String> base)674     public void testSubListAddFirst(String label, int mode, List<String> list, List<String> base) {
675         var refList = new ArrayList<>(base);
676         var sub = applyMode(mode, list);
677         var refSub = new ArrayList<>(sub);
678 
679         refList.add(isReversed(mode) ? 5 : 2, "x");
680         sub.addFirst("x");
681         refSub.add(0, "x");
682 
683         checkContents(sub, refSub);
684         checkContents(list, refList);
685     }
686 
687     @Test(dataProvider="subListMods")
testSubListAddLast(String label, int mode, List<String> list, List<String> base)688     public void testSubListAddLast(String label, int mode, List<String> list, List<String> base) {
689         var refList = new ArrayList<>(base);
690         var sub = applyMode(mode, list);
691         var refSub = new ArrayList<>(sub);
692 
693         refList.add(isReversed(mode) ? 2 : 5, "x");
694         sub.addLast("x");
695         refSub.add("x");
696 
697         checkContents(sub, refSub);
698         checkContents(list, refList);
699     }
700 
701     @Test(dataProvider="subListMods")
testSubListRemoveFirst(String label, int mode, List<String> list, List<String> base)702     public void testSubListRemoveFirst(String label, int mode, List<String> list, List<String> base) {
703         var refList = new ArrayList<>(base);
704         var sub = applyMode(mode, list);
705         var refSub = new ArrayList<>(sub);
706 
707         refList.remove(isReversed(mode) ? 4 : 2);
708         var act = sub.removeFirst();
709         var exp = refSub.remove(0);
710 
711         assertEquals(act, exp);
712         checkContents(sub, refSub);
713         checkContents(list, refList);
714     }
715 
716     @Test(dataProvider="subListMods")
testSubListRemoveLast(String label, int mode, List<String> list, List<String> base)717     public void testSubListRemoveLast(String label, int mode, List<String> list, List<String> base) {
718         var refList = new ArrayList<>(base);
719         var sub = applyMode(mode, list);
720         var refSub = new ArrayList<>(sub);
721 
722         refList.remove(isReversed(mode) ? 2 : 4);
723         var act = sub.removeLast();
724         var exp = refSub.remove(refSub.size() - 1);
725 
726         assertEquals(act, exp);
727         checkContents(sub, refSub);
728         checkContents(list, refList);
729     }
730 
731     @Test(dataProvider="subListMods")
testSubListAddAllFirst(String label, int mode, List<String> list, List<String> base)732     public void testSubListAddAllFirst(String label, int mode, List<String> list, List<String> base) {
733         var refList = new ArrayList<>(base);
734         var sub = applyMode(mode, list);
735         var refSub = new ArrayList<>(sub);
736 
737         if (isReversed(mode))
738             refList.addAll(5, List.of("y", "x"));
739         else
740             refList.addAll(2, List.of("x", "y"));
741         sub.addAll(0, List.of("x", "y"));
742         refSub.addAll(0, List.of("x", "y"));
743 
744         checkContents(sub, refSub);
745         checkContents(list, refList);
746     }
747 
748     @Test(dataProvider="subListMods")
testSubListAddAllLast(String label, int mode, List<String> list, List<String> base)749     public void testSubListAddAllLast(String label, int mode, List<String> list, List<String> base) {
750         var refList = new ArrayList<>(base);
751         var sub = applyMode(mode, list);
752         var refSub = new ArrayList<>(sub);
753 
754         if (isReversed(mode))
755             refList.addAll(2, List.of("y", "x"));
756         else
757             refList.addAll(5, List.of("x", "y"));
758         sub.addAll(List.of("x", "y"));
759         refSub.addAll(List.of("x", "y"));
760 
761         checkContents(sub, refSub);
762         checkContents(list, refList);
763     }
764 
765     @Test(dataProvider="iteratorMods")
testListIteratorAdd(String label, boolean rev, List<String> list, List<String> base)766     public void testListIteratorAdd(String label, boolean rev, List<String> list, List<String> base) {
767         var ref = new ArrayList<>(base);
768         var it = (rev ? list.reversed() : list).listIterator();
769 
770         ref.add(rev ? 5 : 2, "x");
771         it.next();
772         it.next();
773         it.add("x");
774 
775         assertEquals(it.next(), rev ? "e" : "c");
776         checkContents(list, ref);
777     }
778 
779     @Test(dataProvider="iteratorMods")
testListIteratorSet(String label, boolean rev, List<String> list, List<String> base)780     public void testListIteratorSet(String label, boolean rev, List<String> list, List<String> base) {
781         var ref = new ArrayList<>(base);
782         var it = (rev ? list.reversed() : list).listIterator();
783 
784         ref.set(rev ? 5 : 1, "x");
785         it.next();
786         it.next();
787         it.set("x");
788 
789         assertEquals(it.next(), rev ? "e" : "c");
790         checkContents(list, ref);
791     }
792 
793     @Test(dataProvider="iteratorMods")
testListIteratorRemove(String label, boolean rev, List<String> list, List<String> base)794     public void testListIteratorRemove(String label, boolean rev, List<String> list, List<String> base) {
795         var ref = new ArrayList<>(base);
796         var it = (rev ? list.reversed() : list).listIterator();
797 
798         ref.remove(rev ? 5 : 1);
799         it.next();
800         it.next();
801         it.remove();
802 
803         assertEquals(it.next(), rev ? "e" : "c");
804         checkContents(list, ref);
805     }
806 
807     // SubList ListIterator modification tests.
808 
809     @Test(dataProvider="subListIteratorMods")
testSubListIteratorAdd(String label, int mode, List<String> list, List<String> base)810     public void testSubListIteratorAdd(String label, int mode, List<String> list, List<String> base) {
811         var refList = new ArrayList<>(base);
812         var sub = applyMode(mode, list);
813         var refSub = new ArrayList<>(sub);
814 
815         var it = sub.listIterator();
816         it.next();
817         it.add("x");
818         refList.add(isReversed(mode) ? 4 : 3, "x");
819         refSub.add(1, "x");
820 
821         assertEquals(it.next(), "d");
822         checkContents(sub, refSub);
823         checkContents(list, refList);
824     }
825 
826     @Test(dataProvider="subListIteratorMods")
testSubListIteratorSet(String label, int mode, List<String> list, List<String> base)827     public void testSubListIteratorSet(String label, int mode, List<String> list, List<String> base) {
828         var refList = new ArrayList<>(base);
829         var sub = applyMode(mode, list);
830         var refSub = new ArrayList<>(sub);
831 
832         var it = sub.listIterator();
833         it.next();
834         it.set("x");
835         refList.set(isReversed(mode) ? 4 : 2, "x");
836         refSub.set(0, "x");
837 
838         assertEquals(it.next(), "d");
839         checkContents(sub, refSub);
840         checkContents(list, refList);
841     }
842 
843     @Test(dataProvider="subListIteratorMods")
testSubListIteratorRemove(String label, int mode, List<String> list, List<String> base)844     public void testSubListIteratorRemove(String label, int mode, List<String> list, List<String> base) {
845         var refList = new ArrayList<>(base);
846         var sub = applyMode(mode, list);
847         var refSub = new ArrayList<>(sub);
848 
849         var it = sub.listIterator();
850         it.next();
851         it.remove();
852         refList.remove(isReversed(mode) ? 4 : 2);
853         refSub.remove(0);
854 
855         assertEquals(it.next(), "d");
856         checkContents(sub, refSub);
857         checkContents(list, refList);
858     }
859 }
860