--- /dev/null 2012-12-10 07:41:39.297440197 -0800 +++ new/test/java/util/CollectionExtensionMethods/ListExtensionMethodsTest.java 2012-12-10 13:27:31.494690066 -0800 @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2012 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.LinkedList; +import java.util.ListIterator; +import java.util.concurrent.atomic.AtomicInteger; + +import org.testng.annotations.Test; + +import java.lang.reflect.Constructor; +import java.util.ConcurrentModificationException; +import java.util.function.Predicate; + +import static org.testng.Assert.*; + +/** + * @test + * @library testlibrary + * @build CollectionAsserts CollectionSupplier + * @run testng ListExtensionMethodsTest + * @summary Unit tests for extension methods on List + */ +public class ListExtensionMethodsTest { + + private static final String[] LIST_CLASSES = { + "java.util.ArrayList", + "java.util.LinkedList", + "java.util.Vector", + "java.util.concurrent.CopyOnWriteArrayList" + }; + + private static final String[] LIST_CME_CLASSES = { + "java.util.ArrayList", + "java.util.Vector" + }; + + private static final Predicate P_EVEN = x -> 0 == x % 2; + private static final Predicate P_ODD = x -> 0 != x % 2; + + private static final Comparator BIT_COUNT_COMPARATOR = + (x, y) -> Integer.bitCount(x) - Integer.bitCount(y); + + private static final Comparator ATOMIC_INTEGER_COMPARATOR = + (x, y) -> x.intValue() - y.intValue(); + + @Test + public void testForNullPointerException() throws Exception { + final CollectionSupplier supplier = new CollectionSupplier(LIST_CLASSES, 10); + for (final CollectionSupplier.TestCase test : supplier.get()) { + final List list = ((List) test.collection); + try { + list.forEach(null); + fail("forEach with null Block did not throw NPE"); + } catch (NullPointerException nx) {} + try { + list.removeAll((Predicate) null); + fail("removeAll with null Predicate did not throw NPE"); + } catch (NullPointerException nx) {} + try { + list.replaceAll(null); + fail("replaceAll with null UnaryOperator did not throw NPE"); + } catch (NullPointerException nx) {} + try { + list.sort(null); + fail("sort with null Comparator did not throw NPE"); + } catch (NullPointerException nx) {} + } + } + + @Test + public void testForEach() throws Exception { + final CollectionSupplier supplier = new CollectionSupplier(LIST_CLASSES, 1000); + for (final CollectionSupplier.TestCase test : supplier.get()) { + final List original = ((List) test.original); + final List list = ((List) test.collection); + final List actual = new LinkedList<>(); + list.forEach(actual::add); + CollectionAsserts.assertContents(actual, list); + CollectionAsserts.assertContents(actual, original); + } + } + + @Test + public void testRemoveAll() throws Exception { + final CollectionSupplier supplier = new CollectionSupplier(LIST_CLASSES, 1000); + for (final CollectionSupplier.TestCase test : supplier.get()) { + final List original = ((List) test.original); + final List list = ((List) test.collection); + list.removeAll(P_ODD); + for (final int i : list) { + assertTrue((i % 2) == 0); + } + final ListIterator li = list.listIterator(); + for (final int i : original) { + if (i % 2 == 0) { + assertEquals(li.next().intValue(), i); + } + } + assertFalse(li.hasNext()); + list.removeAll(P_EVEN); + assertTrue(list.isEmpty()); + } + } + + @Test + public void testReplaceAll() throws Exception { + final int scale = 3; + final CollectionSupplier supplier = new CollectionSupplier(LIST_CLASSES, 1000); + for (final CollectionSupplier.TestCase test : supplier.get()) { + final List original = ((List) test.original); + final List list = ((List) test.collection); + list.replaceAll(x -> scale * x); + for (int i=0; i < original.size(); i++) { + assertTrue(list.get(i) == (scale * original.get(i)), "mismatch at index " + i); + } + } + } + + @Test + public void testSort() throws Exception { + final CollectionSupplier supplier = new CollectionSupplier(LIST_CLASSES, 1000); + for (final CollectionSupplier.TestCase test : supplier.get()) { + final List original = ((List) test.original); + final List list = ((List) test.collection); + CollectionSupplier.shuffle(list); + list.sort(Integer::compare); + CollectionAsserts.assertSorted(list, Integer::compare); + if (test.name.startsWith("reverse")) { + Collections.reverse(list); + } + CollectionAsserts.assertContents(list, original); + + /* disabled until java.util.Comparators is availlable + CollectionSupplier.shuffle(list); + list.sort(Comparators.naturalOrder()); + CollectionAsserts.assertSorted(list, Comparators.naturalOrder()); + if (test.name.startsWith("reverse")) { + Collections.reverse(list); + } + CollectionAsserts.assertContents(list, original); + + CollectionSupplier.shuffle(list); + list.sort(Comparators.reverseOrder()); + CollectionAsserts.assertSorted(list, Comparators.reverseOrder()); + if (!test.name.startsWith("reverse")) { + Collections.reverse(list); + } + CollectionAsserts.assertContents(list, original); + */ + + CollectionSupplier.shuffle(list); + list.sort(BIT_COUNT_COMPARATOR); + CollectionAsserts.assertSorted(list, BIT_COUNT_COMPARATOR); + // check sort by verifying that bitCount increases and never drops + int minBitCount = 0; + int bitCount; + for (final Integer i : list) { + bitCount = Integer.bitCount(i); + assertTrue(bitCount >= minBitCount); + minBitCount = bitCount; + } + + @SuppressWarnings("unchecked") + final Class> type = + (Class>) Class.forName(test.className); + final Constructor> defaultConstructor = type.getConstructor(); + final List incomparables = defaultConstructor.newInstance(); + + for (int i=0; i < test.original.size(); i++) { + incomparables.add(new AtomicInteger(i)); + } + CollectionSupplier.shuffle(incomparables); + incomparables.sort(ATOMIC_INTEGER_COMPARATOR); + for (int i=0; i < test.original.size(); i++) { + assertEquals(i, incomparables.get(i).intValue()); + } + } + } + + @Test + public void testRemoveAllThrowsCME() throws Exception { + final CollectionSupplier supplier = new CollectionSupplier(LIST_CME_CLASSES, 100); + for (final CollectionSupplier.TestCase test : supplier.get()) { + final List list = ((List) test.collection); + if (list.size() <= 1) { + continue; + } + boolean gotException = false; + try { + // bad predicate that modifies its list, should throw CME + list.removeAll(list::add); + } catch (ConcurrentModificationException cme) { + gotException = true; + } + if (!gotException) { + fail("expected CME was not thrown from " + test); + } + } + } + + @Test + public void testReplaceAllThrowsCME() throws Exception { + final CollectionSupplier supplier = new CollectionSupplier(LIST_CME_CLASSES, 100); + for (final CollectionSupplier.TestCase test : supplier.get()) { + final List list = ((List) test.collection); + if (list.size() <= 1) { + continue; + } + boolean gotException = false; + try { + // bad predicate that modifies its list, should throw CME + list.replaceAll(x -> {int n = 3 * x; list.add(n); return n;}); + } catch (ConcurrentModificationException cme) { + gotException = true; + } + if (!gotException) { + fail("expected CME was not thrown from " + test); + } + } + } + + @Test + public void testSortThrowsCME() throws Exception { + final CollectionSupplier supplier = new CollectionSupplier(LIST_CME_CLASSES, 100); + for (final CollectionSupplier.TestCase test : supplier.get()) { + final List list = ((List) test.collection); + if (list.size() <= 1) { + continue; + } + boolean gotException = false; + try { + // bad predicate that modifies its list, should throw CME + list.sort((x, y) -> {list.add(x); return x - y;}); + } catch (ConcurrentModificationException cme) { + gotException = true; + } + if (!gotException) { + fail("expected CME was not thrown from " + test); + } + } + } + +}