/* * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ import java.io.*; import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertSame; import static org.testng.Assert.assertThrows; import static org.testng.Assert.assertTrue; /* * @test * @bug 8266571 * @summary Basic tests for SequencedCollection * @modules java.base/java.util:open * @build SimpleDeque SimpleList SimpleSortedSet * @run testng Basic */ // TODO test that remove(obj) with duplicates removes the right element public class Basic { // ========== Data Providers ========== static final List ORIGINAL = List.of("a", "b", "c", "d", "e", "f", "g"); static List cklist(List contents) { return Collections.checkedList(contents, String.class); } static NavigableSet cknav(NavigableSet set) { return Collections.checkedNavigableSet(set, String.class); } static SortedSet cksorted(SortedSet set) { return Collections.checkedSortedSet(set, String.class); } static SequencedSet setFromMap(List contents) { var lhm = new LinkedHashMap(); var ss = Collections.newSequencedSetFromMap(lhm); ss.addAll(contents); return ss; } static SequencedCollection ucoll(SequencedCollection coll) { return Collections.unmodifiableSequencedCollection(coll); } static SequencedCollection ulist(List list) { return Collections.unmodifiableList(list); } static NavigableSet unav(NavigableSet set) { return Collections.unmodifiableNavigableSet(set); } static SequencedSet uset(SequencedSet set) { return Collections.unmodifiableSequencedSet(set); } static SortedSet usorted(SortedSet set) { return Collections.unmodifiableSortedSet(set); } static List copyReversed(List list) { var r = new ArrayList(list); Collections.reverse(r); return r; } @DataProvider(name="all") public Iterator all() { var result = new ArrayList(); populated().forEachRemaining(result::add); empties().forEachRemaining(result::add); return result.iterator(); } @DataProvider(name="populated") public Iterator populated() { return Arrays.asList( new Object[] { "ArrayDeque", new ArrayDeque<>(ORIGINAL), ORIGINAL }, new Object[] { "ArrayList", new ArrayList<>(ORIGINAL), ORIGINAL }, new Object[] { "AsList", Arrays.asList(ORIGINAL.toArray()), ORIGINAL }, new Object[] { "COWAL", new CopyOnWriteArrayList<>(ORIGINAL), ORIGINAL }, new Object[] { "LinkedHashSet", new LinkedHashSet<>(ORIGINAL), ORIGINAL }, new Object[] { "LinkedList", new LinkedList<>(ORIGINAL), ORIGINAL }, new Object[] { "ListOf", ORIGINAL, ORIGINAL }, new Object[] { "SetFromMap", setFromMap(ORIGINAL), ORIGINAL }, new Object[] { "SimpleDeque", new SimpleDeque<>(ORIGINAL), ORIGINAL }, new Object[] { "SimpleList", new SimpleList<>(ORIGINAL), ORIGINAL }, new Object[] { "SimpleSortedSet", new SimpleSortedSet<>(ORIGINAL), ORIGINAL }, new Object[] { "TreeSet", new TreeSet<>(ORIGINAL), ORIGINAL }, new Object[] { "UnmodColl", ucoll(new ArrayList<>(ORIGINAL)), ORIGINAL }, new Object[] { "UnmodSet", uset(new LinkedHashSet<>(ORIGINAL)), ORIGINAL } ).iterator(); } @DataProvider(name="empties") public Iterator empties() { return Arrays.asList( new Object[] { "ArrayDeque", new ArrayDeque<>(), List.of() }, new Object[] { "ArrayList", new ArrayList<>(), List.of() }, new Object[] { "AsList", Arrays.asList(new String[0]), List.of() }, new Object[] { "COWAL", new CopyOnWriteArrayList<>(), List.of() }, new Object[] { "EmptyList", Collections.emptyList(), List.of() }, new Object[] { "EmptyNavigableSet", Collections.emptyNavigableSet(), List.of() }, new Object[] { "EmptySortedSet", Collections.emptySortedSet(), List.of() }, new Object[] { "LinkedHashSet", new LinkedHashSet<>(), List.of() }, new Object[] { "LinkedList", new LinkedList<>(), List.of() }, new Object[] { "ListOf", List.of(), List.of() }, new Object[] { "SetFromMap", setFromMap(List.of()), List.of() }, new Object[] { "SimpleDeque", new SimpleDeque<>(), List.of() }, new Object[] { "SimpleList", new SimpleList<>(), List.of() }, new Object[] { "SimpleSortedSet", new SimpleSortedSet<>(), List.of() }, new Object[] { "TreeSet", new TreeSet<>(), List.of() }, new Object[] { "UnmodColl", ucoll(new ArrayList<>()), List.of() }, new Object[] { "UnmodSet", uset(new LinkedHashSet<>()), List.of() } ).iterator(); } @DataProvider(name="adds") public Iterator adds() { return Arrays.asList( new Object[] { "ArrayDeque", new ArrayDeque<>(ORIGINAL), ORIGINAL }, new Object[] { "ArrayList", new ArrayList<>(ORIGINAL), ORIGINAL }, new Object[] { "COWAL", new CopyOnWriteArrayList<>(ORIGINAL), ORIGINAL }, new Object[] { "LinkedHashSet", new LinkedHashSet<>(ORIGINAL), ORIGINAL }, new Object[] { "LinkedList", new LinkedList<>(ORIGINAL), ORIGINAL }, new Object[] { "SetFromMap", setFromMap(ORIGINAL), ORIGINAL }, new Object[] { "SimpleDeque", new SimpleDeque<>(ORIGINAL), ORIGINAL }, new Object[] { "SimpleList", new SimpleList<>(ORIGINAL), ORIGINAL } ).iterator(); } @DataProvider(name="unpositionedAdd") public Iterator unpositionedAdd() { return Arrays.asList( new Object[] { "LinkedHashSet", new LinkedHashSet<>(ORIGINAL), ORIGINAL } ).iterator(); } @DataProvider(name="removes") public Iterator removes() { return Arrays.asList( new Object[] { "ArrayDeque", new ArrayDeque<>(ORIGINAL), ORIGINAL }, new Object[] { "ArrayList", new ArrayList<>(ORIGINAL), ORIGINAL }, new Object[] { "COWAL", new CopyOnWriteArrayList<>(ORIGINAL), ORIGINAL }, new Object[] { "LinkedHashSet", new LinkedHashSet<>(ORIGINAL), ORIGINAL }, new Object[] { "LinkedList", new LinkedList<>(ORIGINAL), ORIGINAL }, new Object[] { "SetFromMap", setFromMap(ORIGINAL), ORIGINAL }, new Object[] { "SimpleDeque", new SimpleDeque<>(ORIGINAL), ORIGINAL }, new Object[] { "SimpleList", new SimpleList<>(ORIGINAL), ORIGINAL }, new Object[] { "SimpleSortedSet", new SimpleSortedSet<>(ORIGINAL), ORIGINAL }, new Object[] { "TreeSet", new TreeSet<>(ORIGINAL), ORIGINAL } ).iterator(); } @DataProvider(name="emptyRemoves") public Iterator emptyRemoves() { return Arrays.asList( new Object[] { "ArrayDeque", new ArrayDeque<>(), List.of() }, new Object[] { "ArrayList", new ArrayList<>(), List.of() }, new Object[] { "COWAL", new CopyOnWriteArrayList<>(), List.of() }, new Object[] { "LinkedHashSet", new LinkedHashSet<>(), List.of() }, new Object[] { "LinkedList", new LinkedList<>(), List.of() }, new Object[] { "SetFromMap", setFromMap(List.of()), List.of() }, new Object[] { "SimpleDeque", new SimpleDeque<>(), List.of() }, new Object[] { "SimpleList", new SimpleList<>(), List.of() }, new Object[] { "SimpleSortedSet", new SimpleSortedSet<>(), List.of() }, new Object[] { "TreeSet", new TreeSet<>(), List.of() } ).iterator(); } @DataProvider(name="serializable") public Iterator serializable() { return Arrays.asList( new Object[] { "ArrayDeque", new ArrayDeque<>(ORIGINAL), ORIGINAL }, new Object[] { "ArrayList", new ArrayList<>(ORIGINAL), ORIGINAL }, new Object[] { "AsList", Arrays.asList(ORIGINAL.toArray()), ORIGINAL }, new Object[] { "COWAL", new CopyOnWriteArrayList<>(ORIGINAL), ORIGINAL }, new Object[] { "LinkedHashSet", new LinkedHashSet<>(ORIGINAL), ORIGINAL }, new Object[] { "LinkedList", new LinkedList<>(ORIGINAL), ORIGINAL }, new Object[] { "ListOf", ORIGINAL, ORIGINAL }, new Object[] { "SetFromMap", setFromMap(ORIGINAL), ORIGINAL }, new Object[] { "TreeSet", new TreeSet<>(ORIGINAL), ORIGINAL }, new Object[] { "UnmodColl", ucoll(new ArrayList<>(ORIGINAL)), ORIGINAL }, new Object[] { "UnmodSet", uset(new LinkedHashSet<>(ORIGINAL)), ORIGINAL } ).iterator(); } @DataProvider(name="notSerializable") public Iterator notSerializable() { return Arrays.asList( new Object[] { "ArrayDeque", new ArrayDeque<>(ORIGINAL).reversed() }, new Object[] { "ArrayList", new ArrayList<>(ORIGINAL).reversed() }, new Object[] { "AsList", Arrays.asList(ORIGINAL.toArray()).reversed() }, new Object[] { "COWAL", new CopyOnWriteArrayList<>(ORIGINAL).reversed() }, new Object[] { "LinkedHashSet", new LinkedHashSet<>(ORIGINAL).reversed() }, new Object[] { "LinkedList", new LinkedList<>(ORIGINAL).reversed() }, new Object[] { "ListOf", ORIGINAL.reversed() }, new Object[] { "SetFromMap", setFromMap(ORIGINAL).reversed() }, new Object[] { "UnmodColl", ucoll(new ArrayList<>(ORIGINAL)).reversed() }, new Object[] { "UnmodSet", uset(new LinkedHashSet<>(ORIGINAL)).reversed() } ).iterator(); } @DataProvider(name="doubleReverse") public Iterator doubleReverse() { return Arrays.asList( new Object[] { "ArrayDeque", new ArrayDeque<>(ORIGINAL) }, new Object[] { "ArrayList", new ArrayList<>(ORIGINAL) }, new Object[] { "AsList", Arrays.asList(ORIGINAL.toArray()) }, new Object[] { "COWAL", new CopyOnWriteArrayList<>(ORIGINAL) }, new Object[] { "LinkedHashSet", new LinkedHashSet<>(ORIGINAL) }, new Object[] { "LinkedList", new LinkedList<>(ORIGINAL) }, new Object[] { "ListOf", ORIGINAL }, new Object[] { "SimpleDeque", new SimpleDeque<>(ORIGINAL) }, new Object[] { "SimpleList", new SimpleList<>(ORIGINAL) }, new Object[] { "SimpleSortedSet", new SimpleSortedSet<>(ORIGINAL) } ).iterator(); } @DataProvider(name="unmodifiable") public Iterator unmodifiable() { return Arrays.asList( new Object[] { "ListOf", ORIGINAL, ORIGINAL }, new Object[] { "ListOfSub", ORIGINAL.subList(1, 3), ORIGINAL.subList(1, 3) }, new Object[] { "SingleList", Collections.singletonList("a"), List.of("a") }, new Object[] { "UnmodColl", ucoll(new ArrayList<>(ORIGINAL)), ORIGINAL }, new Object[] { "UnmodList", ulist(new ArrayList<>(ORIGINAL)), ORIGINAL }, new Object[] { "UnmodNav", unav(new TreeSet<>(ORIGINAL)), ORIGINAL }, new Object[] { "UnmodSet", uset(new LinkedHashSet<>(ORIGINAL)), ORIGINAL }, new Object[] { "UnmodSorted", usorted(new TreeSet<>(ORIGINAL)), ORIGINAL } ).iterator(); } @DataProvider(name="checkedList") public Iterator checkedList() { return Arrays.asList( new Object[] { "ChkList", cklist(new ArrayList<>(ORIGINAL)), ORIGINAL } ).iterator(); } @DataProvider(name="checkedNavSet") public Iterator checkedNavSet() { return Arrays.asList( new Object[] { "ChkNav", cknav(new TreeSet<>(ORIGINAL)), ORIGINAL } ).iterator(); } @DataProvider(name="checkedSortedSet") public Iterator checkedSortedSet() { return Arrays.asList( new Object[] { "ChkSorted", cksorted(new TreeSet<>(ORIGINAL)), ORIGINAL } ).iterator(); } // mode bit tests for subList testing boolean reverseList(int mode) { return (mode & 1) != 0; } boolean reverseSub(int mode) { return (mode & 2) != 0; } boolean isReversed(int mode) { return reverseList(mode) ^ reverseSub(mode); } List applyMode(int mode, List base) { var list = reverseList(mode) ? base.reversed() : base; var sub = list.subList(2, 5); return reverseSub(mode) ? sub.reversed() : sub; } /** * Generate cases for testing subLists. For each different List implementation, generate 4 * cases from the two bits of the testing mode int value: * * (bit 1) if true, the List is reversed * (bit 2) if true, the subList is reversed * * @return the generated cases */ @DataProvider(name="subListMods") public Iterator subListMods() { var cases = new ArrayList(); for (int mode = 0; mode < 4; mode++) { cases.addAll(Arrays.asList( new Object[] { "ArrayList", mode, new ArrayList<>(ORIGINAL), ORIGINAL }, new Object[] { "COWAL", mode, new CopyOnWriteArrayList<>(ORIGINAL), ORIGINAL }, new Object[] { "LinkedList", mode, new LinkedList<>(ORIGINAL), ORIGINAL }, new Object[] { "SimpleList", mode, new SimpleList<>(ORIGINAL), ORIGINAL } )); } return cases.iterator(); } @DataProvider(name="iteratorMods") public Iterator iteratorMods() { var cases = new ArrayList(); for (boolean rev : List.of(false, true)) { cases.addAll(Arrays.asList( new Object[] { "ArrayList", rev, new ArrayList<>(ORIGINAL), ORIGINAL }, new Object[] { "LinkedList", rev, new LinkedList<>(ORIGINAL), ORIGINAL }, new Object[] { "SimpleList", rev, new SimpleList<>(ORIGINAL), ORIGINAL } )); } return cases.iterator(); } @DataProvider(name="subListIteratorMods") public Iterator subListIteratorMods() { var cases = new ArrayList(); for (int mode = 0; mode < 4; mode++) { cases.addAll(Arrays.asList( new Object[] { "ArrayList", mode, new ArrayList<>(ORIGINAL), ORIGINAL }, new Object[] { "LinkedList", mode, new LinkedList<>(ORIGINAL), ORIGINAL }, new Object[] { "SimpleList", mode, new SimpleList<>(ORIGINAL), ORIGINAL } )); } return cases.iterator(); } // ========== Assertions ========== /** * Basic checks over the contents of a SequencedCollection, * compared to a reference List, in one direction. * * @param seq the SequencedCollection under test * @param ref the reference List */ public void checkContents1(SequencedCollection seq, List ref) { var list1 = new ArrayList(); for (var s : seq) list1.add(s); assertEquals(list1, ref); var list2 = new ArrayList(); seq.forEach(list2::add); assertEquals(list2, ref); var list3 = Arrays.asList(seq.toArray()); assertEquals(list3, ref); var list4 = Arrays.asList(seq.toArray(new String[0])); assertEquals(list4, ref); var list5 = Arrays.asList(seq.toArray(String[]::new)); assertEquals(list5, ref); var list6 = seq.stream().toList(); assertEquals(list6, ref); var list7 = seq.parallelStream().toList(); assertEquals(list7, ref); assertEquals(seq.size(), ref.size()); assertEquals(seq.isEmpty(), ref.isEmpty()); for (var s : ref) { assertTrue(seq.contains(s)); } } /** * Check the contents of a SequencedCollection against a reference List, * in both directions. * * @param seq the SequencedCollection under test * @param ref the reference List */ public void checkContents(SequencedCollection seq, List ref) { checkContents1(seq, ref); var rref = copyReversed(ref); var rseq = seq.reversed(); checkContents1(rseq, rref); var rrseq = rseq.reversed(); checkContents1(rrseq, ref); } /** * Check that modification operations will throw UnsupportedOperationException, * in one direction. * * @param seq the SequencedCollection under test */ public void checkUnmodifiable1(SequencedCollection seq) { final var UOE = UnsupportedOperationException.class; assertThrows(UOE, () -> seq.add("x")); assertThrows(UOE, () -> seq.clear()); assertThrows(UOE, () -> { var it = seq.iterator(); it.next(); it.remove(); }); assertThrows(UOE, () -> seq.removeIf(x -> true)); assertThrows(UOE, () -> seq.addFirst("x")); assertThrows(UOE, () -> seq.addLast("x")); assertThrows(UOE, () -> seq.removeFirst()); assertThrows(UOE, () -> seq.removeLast()); // TODO these ops should throw unconditionally, but they don't in some implementations // assertThrows(UOE, () -> seq.addAll(List.of())); // assertThrows(UOE, () -> seq.remove("x")); // assertThrows(UOE, () -> seq.removeAll(List.of())); // assertThrows(UOE, () -> seq.removeIf(x -> false)); // assertThrows(UOE, () -> seq.retainAll(seq)); assertThrows(UOE, () -> seq.addAll(seq)); assertThrows(UOE, () -> seq.remove(seq.iterator().next())); assertThrows(UOE, () -> seq.removeAll(seq)); assertThrows(UOE, () -> seq.retainAll(List.of())); } /** * Check that modification operations will throw UnsupportedOperationException, * in both directions. * * @param seq the SequencedCollection under test */ public void checkUnmodifiable(SequencedCollection seq) { checkUnmodifiable1(seq); checkUnmodifiable1(seq.reversed()); } static final Class CCE = ClassCastException.class; public void checkCheckedList(List list) { List objList = (List)(List)list; assertThrows(CCE, () -> { objList.addFirst(new Object()); }); assertThrows(CCE, () -> { objList.addLast(new Object()); }); assertThrows(CCE, () -> { objList.reversed().addFirst(new Object()); }); assertThrows(CCE, () -> { objList.reversed().addLast(new Object()); }); } public void checkCheckedNavSet(NavigableSet set) { NavigableSet objSet = (NavigableSet)(NavigableSet)set; assertThrows(CCE, () -> { objSet.add(new Object()); }); assertThrows(CCE, () -> { objSet.reversed().add(new Object()); }); } public void checkCheckedSortedSet(SortedSet set) { SortedSet objSet = (SortedSet)(SortedSet)set; assertThrows(CCE, () -> { objSet.add(new Object()); }); assertThrows(CCE, () -> { objSet.reversed().add(new Object()); }); } // ========== Tests ========== @Test(dataProvider="all") public void testFundamentals(String label, SequencedCollection seq, List ref) { checkContents(seq, ref); } @Test(dataProvider="populated") public void testGetFirst(String label, SequencedCollection seq, List ref) { assertEquals(seq.getFirst(), ref.get(0)); assertEquals(seq.reversed().getFirst(), ref.get(ref.size() - 1)); checkContents(seq, ref); } @Test(dataProvider="populated") public void testGetLast(String label, SequencedCollection seq, List ref) { assertEquals(seq.getLast(), ref.get(ref.size() - 1)); assertEquals(seq.reversed().getLast(), ref.get(0)); checkContents(seq, ref); } @Test(dataProvider="empties") public void testEmptyGetFirst(String label, SequencedCollection seq, List ref) { assertThrows(NoSuchElementException.class, () -> seq.getFirst()); assertThrows(NoSuchElementException.class, () -> seq.reversed().getFirst()); checkContents(seq, ref); } @Test(dataProvider="empties") public void testEmptyGetLast(String label, SequencedCollection seq, List ref) { assertThrows(NoSuchElementException.class, () -> seq.getLast()); assertThrows(NoSuchElementException.class, () -> seq.reversed().getLast()); checkContents(seq, ref); } @Test(dataProvider="adds") public void testAddFirst(String label, SequencedCollection seq, List baseref) { var ref = new ArrayList<>(baseref); ref.add(0, "x"); seq.addFirst("x"); checkContents(seq, ref); } @Test(dataProvider="adds") public void testAddFirstRev(String label, SequencedCollection seq, List baseref) { var ref = new ArrayList<>(baseref); ref.add("x"); seq.reversed().addFirst("x"); checkContents(seq, ref); } @Test(dataProvider="adds") public void testAddLast(String label, SequencedCollection seq, List baseref) { var ref = new ArrayList<>(baseref); ref.add("x"); seq.addLast("x"); checkContents(seq, ref); } @Test(dataProvider="adds") public void testAddLastRev(String label, SequencedCollection seq, List baseref) { var ref = new ArrayList<>(baseref); ref.add(0, "x"); seq.reversed().addLast("x"); checkContents(seq, ref); } @Test(dataProvider="unpositionedAdd") public void testUnpositionedAdd(String label, SequencedCollection seq, List baseref) { var ref = new ArrayList<>(baseref); ref.add("x"); seq.add("x"); checkContents(seq, ref); } @Test(dataProvider="unpositionedAdd") public void testUnpositionedAddRev(String label, SequencedCollection seq, List baseref) { var ref = new ArrayList<>(baseref); ref.add("x"); seq.reversed().add("x"); checkContents(seq, ref); } @Test(dataProvider="removes") public void testRemoveFirst(String label, SequencedCollection seq, List baseref) { var ref = new ArrayList<>(baseref); var exp = ref.remove(0); var act = seq.removeFirst(); assertEquals(act, exp); checkContents(seq, ref); } @Test(dataProvider="removes") public void testRemoveFirstRev(String label, SequencedCollection seq, List baseref) { var ref = new ArrayList<>(baseref); var exp = ref.remove(ref.size() - 1); var act = seq.reversed().removeFirst(); assertEquals(act, exp); checkContents(seq, ref); } @Test(dataProvider="removes") public void testRemoveLast(String label, SequencedCollection seq, List baseref) { var ref = new ArrayList<>(baseref); var exp = ref.remove(ref.size() - 1); var act = seq.removeLast(); assertEquals(act, exp); checkContents(seq, ref); } @Test(dataProvider="removes") public void testRemoveLastRev(String label, SequencedCollection seq, List baseref) { var ref = new ArrayList<>(baseref); var exp = ref.remove(0); var act = seq.reversed().removeLast(); assertEquals(act, exp); checkContents(seq, ref); } @Test(dataProvider="emptyRemoves") public void testEmptyRemoveFirst(String label, SequencedCollection seq, List baseref) { assertThrows(NoSuchElementException.class, () -> seq.removeFirst()); assertThrows(NoSuchElementException.class, () -> seq.reversed().removeFirst()); checkContents(seq, baseref); } @Test(dataProvider="emptyRemoves") public void testEmptyRemoveLast(String label, SequencedCollection seq, List baseref) { assertThrows(NoSuchElementException.class, () -> seq.removeLast()); assertThrows(NoSuchElementException.class, () -> seq.reversed().removeLast()); checkContents(seq, baseref); } @Test(dataProvider="serializable") public void testSerializable(String label, SequencedCollection seq, List ref) throws ClassNotFoundException, IOException { var baos = new ByteArrayOutputStream(); try (var oos = new ObjectOutputStream(baos)) { oos.writeObject(seq); } try (var bais = new ByteArrayInputStream(baos.toByteArray()); var ois = new ObjectInputStream(bais)) { var seq2 = (SequencedCollection) ois.readObject(); checkContents(seq2, ref); } } @Test(dataProvider="notSerializable") public void testNotSerializable(String label, SequencedCollection seq) throws ClassNotFoundException, IOException { var baos = new ByteArrayOutputStream(); try (var oos = new ObjectOutputStream(baos)) { assertThrows(ObjectStreamException.class, () -> oos.writeObject(seq)); } } @Test(dataProvider="doubleReverse") public void testDoubleReverse(String label, SequencedCollection seq) { var rrseq = seq.reversed().reversed(); assertSame(rrseq, seq); } @Test(dataProvider="unmodifiable") public void testUnmodifiable(String label, SequencedCollection seq, List ref) { checkUnmodifiable(seq); checkContents(seq, ref); } @Test(dataProvider="checkedList") public void testCheckedList(String label, List list, List ref) { checkCheckedList(list); checkContents(list, ref); } @Test(dataProvider="checkedNavSet") public void testCheckedNavSet(String label, NavigableSet set, List ref) { checkCheckedNavSet(set); checkContents(set, ref); } @Test(dataProvider="checkedSortedSet") public void testCheckedSortedSet(String label, SortedSet set, List ref) { checkCheckedSortedSet(set); checkContents(set, ref); } // Indexes for subList modification tests: // 0 1 2 3 4 5 6 // a, b, c, d, e, f, g // c, d, e @Test(dataProvider="subListMods") public void testSubListGet(String label, int mode, List list, List base) { var sub = applyMode(mode, list); assertEquals(sub.getFirst(), isReversed(mode) ? "e" : "c"); assertEquals(sub.getLast(), isReversed(mode) ? "c" : "e"); } @Test(dataProvider="subListMods") public void testSubListAddFirst(String label, int mode, List list, List base) { var refList = new ArrayList<>(base); var sub = applyMode(mode, list); var refSub = new ArrayList<>(sub); refList.add(isReversed(mode) ? 5 : 2, "x"); sub.addFirst("x"); refSub.add(0, "x"); checkContents(sub, refSub); checkContents(list, refList); } @Test(dataProvider="subListMods") public void testSubListAddLast(String label, int mode, List list, List base) { var refList = new ArrayList<>(base); var sub = applyMode(mode, list); var refSub = new ArrayList<>(sub); refList.add(isReversed(mode) ? 2 : 5, "x"); sub.addLast("x"); refSub.add("x"); checkContents(sub, refSub); checkContents(list, refList); } @Test(dataProvider="subListMods") public void testSubListRemoveFirst(String label, int mode, List list, List base) { var refList = new ArrayList<>(base); var sub = applyMode(mode, list); var refSub = new ArrayList<>(sub); refList.remove(isReversed(mode) ? 4 : 2); var act = sub.removeFirst(); var exp = refSub.remove(0); assertEquals(act, exp); checkContents(sub, refSub); checkContents(list, refList); } @Test(dataProvider="subListMods") public void testSubListRemoveLast(String label, int mode, List list, List base) { var refList = new ArrayList<>(base); var sub = applyMode(mode, list); var refSub = new ArrayList<>(sub); refList.remove(isReversed(mode) ? 2 : 4); var act = sub.removeLast(); var exp = refSub.remove(refSub.size() - 1); assertEquals(act, exp); checkContents(sub, refSub); checkContents(list, refList); } @Test(dataProvider="subListMods") public void testSubListAddAllFirst(String label, int mode, List list, List base) { var refList = new ArrayList<>(base); var sub = applyMode(mode, list); var refSub = new ArrayList<>(sub); if (isReversed(mode)) refList.addAll(5, List.of("y", "x")); else refList.addAll(2, List.of("x", "y")); sub.addAll(0, List.of("x", "y")); refSub.addAll(0, List.of("x", "y")); checkContents(sub, refSub); checkContents(list, refList); } @Test(dataProvider="subListMods") public void testSubListAddAllLast(String label, int mode, List list, List base) { var refList = new ArrayList<>(base); var sub = applyMode(mode, list); var refSub = new ArrayList<>(sub); if (isReversed(mode)) refList.addAll(2, List.of("y", "x")); else refList.addAll(5, List.of("x", "y")); sub.addAll(List.of("x", "y")); refSub.addAll(List.of("x", "y")); checkContents(sub, refSub); checkContents(list, refList); } @Test(dataProvider="iteratorMods") public void testListIteratorAdd(String label, boolean rev, List list, List base) { var ref = new ArrayList<>(base); var it = (rev ? list.reversed() : list).listIterator(); ref.add(rev ? 5 : 2, "x"); it.next(); it.next(); it.add("x"); assertEquals(it.next(), rev ? "e" : "c"); checkContents(list, ref); } @Test(dataProvider="iteratorMods") public void testListIteratorSet(String label, boolean rev, List list, List base) { var ref = new ArrayList<>(base); var it = (rev ? list.reversed() : list).listIterator(); ref.set(rev ? 5 : 1, "x"); it.next(); it.next(); it.set("x"); assertEquals(it.next(), rev ? "e" : "c"); checkContents(list, ref); } @Test(dataProvider="iteratorMods") public void testListIteratorRemove(String label, boolean rev, List list, List base) { var ref = new ArrayList<>(base); var it = (rev ? list.reversed() : list).listIterator(); ref.remove(rev ? 5 : 1); it.next(); it.next(); it.remove(); assertEquals(it.next(), rev ? "e" : "c"); checkContents(list, ref); } // SubList ListIterator modification tests. @Test(dataProvider="subListIteratorMods") public void testSubListIteratorAdd(String label, int mode, List list, List base) { var refList = new ArrayList<>(base); var sub = applyMode(mode, list); var refSub = new ArrayList<>(sub); var it = sub.listIterator(); it.next(); it.add("x"); refList.add(isReversed(mode) ? 4 : 3, "x"); refSub.add(1, "x"); assertEquals(it.next(), "d"); checkContents(sub, refSub); checkContents(list, refList); } @Test(dataProvider="subListIteratorMods") public void testSubListIteratorSet(String label, int mode, List list, List base) { var refList = new ArrayList<>(base); var sub = applyMode(mode, list); var refSub = new ArrayList<>(sub); var it = sub.listIterator(); it.next(); it.set("x"); refList.set(isReversed(mode) ? 4 : 2, "x"); refSub.set(0, "x"); assertEquals(it.next(), "d"); checkContents(sub, refSub); checkContents(list, refList); } @Test(dataProvider="subListIteratorMods") public void testSubListIteratorRemove(String label, int mode, List list, List base) { var refList = new ArrayList<>(base); var sub = applyMode(mode, list); var refSub = new ArrayList<>(sub); var it = sub.listIterator(); it.next(); it.remove(); refList.remove(isReversed(mode) ? 4 : 2); refSub.remove(0); assertEquals(it.next(), "d"); checkContents(sub, refSub); checkContents(list, refList); } }