/* * Copyright (C) 2017 The Guava Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.common.collect; import static com.google.common.truth.Truth.assertThat; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.LinkedList; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Tests the package level *impl methods directly using various types of lists. */ @GwtCompatible(emulated = true) public class ListsImplTest extends TestCase { /** * Describes how a list is modifiable */ public enum Modifiability { NONE, // immutable lists BY_ELEMENT, // elements can change (set), but not structure DIRECT_ONLY, // Element can be added and removed only via direct calls, not through iterators ALL // Elements can be added and removed as well as modified. } /** Handles the creation of lists needed for the tests */ public static abstract class ListExample { private final String name; private final Modifiability modifiability; protected ListExample(String name, Modifiability modifiability) { this.name = name; this.modifiability = modifiability; } /** * Gets the name of the example */ public String getName() { return name; } /** * Creates a new list with the given contents. */ public abstract <T> List<T> createList(Class<T> listType, Collection<? extends T> contents); /** * The modifiablity of this list example. */ public Modifiability modifiability() { return modifiability; } } @GwtIncompatible // suite public static Test suite() { TestSuite suite = new TestSuite(); suite.addTest(createExampleSuite(new ArrayListExample("ArrayList"))); suite.addTest(createExampleSuite(new LinkedListExample("LinkedList"))); suite.addTest(createExampleSuite(new ArraysAsListExample("Arrays.asList"))); suite.addTest(createExampleSuite(new ImmutableListExample("ImmutableList"))); suite.addTest(createExampleSuite(new CopyOnWriteListExample("CopyOnWriteArrayList"))); return suite; } @GwtIncompatible // suite sub call private static TestSuite createExampleSuite(ListExample example) { TestSuite resultSuite = new TestSuite(ListsImplTest.class); for (Enumeration<Test> testEnum = resultSuite.tests(); testEnum.hasMoreElements();) { ListsImplTest test = (ListsImplTest) testEnum.nextElement(); test.example = example; } return resultSuite; } private ListExample example; private ListExample getExample() { // because sometimes one version with a null example is created. return example == null ? new ImmutableListExample("test") : example; } @Override public String getName() { return example == null ? super.getName() : buildTestName(); } private String buildTestName() { return super.getName() + ":" + example.getName(); } public void testHashCodeImpl() { List<Integer> base = createList(Integer.class, 1, 2, 2); List<Integer> copy = createList(Integer.class, 1, 2, 2); List<Integer> outOfOrder = createList(Integer.class, 2, 2, 1); List<Integer> diffValue = createList(Integer.class, 1, 2, 4); List<Integer> diffLength = createList(Integer.class, 1, 2); List<Integer> empty = createList(Integer.class); assertThat(Lists.hashCodeImpl(base)).isEqualTo(Lists.hashCodeImpl(copy)); assertThat(Lists.hashCodeImpl(base)).isNotEqualTo(Lists.hashCodeImpl (outOfOrder)); assertThat(Lists.hashCodeImpl(base)).isNotEqualTo(Lists.hashCodeImpl(diffValue)); assertThat(Lists.hashCodeImpl(base)).isNotEqualTo(Lists.hashCodeImpl(diffLength)); assertThat(Lists.hashCodeImpl(base)).isNotEqualTo(Lists.hashCodeImpl(empty)); } public void testEqualsImpl() { List<Integer> base = createList(Integer.class, 1, 2, 2); List<Integer> copy = createList(Integer.class, 1, 2, 2); ImmutableList<Integer> otherType = ImmutableList.of(1, 2, 2); List<Integer> outOfOrder = createList(Integer.class, 2, 2, 1); List<Integer> diffValue = createList(Integer.class, 1, 2, 3); List<Integer> diffLength = createList(Integer.class, 1, 2); List<Integer> empty = createList(Integer.class); assertThat(Lists.equalsImpl(base, copy)).isTrue(); assertThat(Lists.equalsImpl(base, otherType)).isTrue(); List<Object> unEqualItems = Arrays.asList(outOfOrder, diffValue, diffLength, empty, null, new Object()); for (Object other : unEqualItems) { assertThat(Lists.equalsImpl(base, other)).named("%s", other).isFalse(); } } public void testAddAllImpl() { if (getExample().modifiability() != Modifiability.ALL) { return; } List<String> toTest = createList(String.class); List<Iterable<String>> toAdd = ImmutableList.of( Collections.singleton("A"), Collections.emptyList(), ImmutableList.of("A", "B", "C"), ImmutableList.of("D", "E")); List<Integer> indexes = ImmutableList.of(0, 0, 1, 3); List<List<String>> expected = ImmutableList.of( ImmutableList.of("A"), ImmutableList.of("A"), ImmutableList.of("A", "A", "B", "C"), ImmutableList.of("A", "A", "D", "E", "B", "C")); String format = "Adding %s at %s"; for (int i = 0; i < toAdd.size(); i++) { int index = indexes.get(i); Iterable<String> iterableToAdd = toAdd.get(i); boolean expectedChanged = iterableToAdd.iterator().hasNext(); assertThat(Lists.addAllImpl(toTest, index, iterableToAdd)).named(format, iterableToAdd, index) .isEqualTo(expectedChanged); assertThat(toTest).named(format, iterableToAdd, index) .containsExactlyElementsIn(expected.get(i)); } } public void testIndexOfImpl_nonNull() { List<Integer> toTest = createList(Integer.class, 5, 2, -1, 2, 1, 10, 5); int[] expected = {0, 1, 2, 1, 4, 5, 0}; checkIndexOf(toTest, expected); } public void testIndexOfImpl_null() { List<String> toTest; try { toTest = createList(String.class, null, "A", "B", null, "C", null); } catch (NullPointerException e) { // example cannot handle nulls, test invalid return; } int[] expected = {0, 1, 2, 0, 4, 0}; checkIndexOf(toTest, expected); } public void testLastIndexOfImpl_nonNull() { List<Integer> toTest = createList(Integer.class, 1, 5, 6, 10, 1, 3, 2, 1, 6); int[] expected = {7, 1, 8, 3, 7, 5, 6, 7, 8}; checkLastIndexOf(toTest, expected); } public void testLastIndexOfImpl_null() { List<String> toTest; try { toTest = createList(String.class, null, "A", "B", null, "C", "B"); } catch (NullPointerException e) { // example cannot handle nulls, test invalid return; } int[] expected = {3, 1, 5, 3, 4, 5}; checkLastIndexOf(toTest, expected); } private void checkIndexOf(List<?> toTest, int[] expected) { int index = 0; for (Object obj : toTest) { String name = "toTest[" + index + "] (" + obj + ")"; assertThat(Lists.indexOfImpl(toTest, obj)) .named(name) .isEqualTo(expected[index]); index++; } } private void checkLastIndexOf(List<?> toTest, int[] expected) { int index = 0; for (Object obj : toTest) { String name = "toTest[" + index + "] (" + obj + ")"; assertThat(Lists.lastIndexOfImpl(toTest, obj)) .named(name) .isEqualTo(expected[index]); index++; } } @SafeVarargs @SuppressWarnings("varargs") private final <T> List<T> createList(Class<T> listType, T... contents) { return getExample().createList(listType, Arrays.asList(contents)); } private static final class ArrayListExample extends ListExample { protected ArrayListExample(String name) { super(name, Modifiability.ALL); } @Override public <T> List<T> createList(Class<T> listType, Collection<? extends T> contents) { return new ArrayList<>(contents); } } private static final class LinkedListExample extends ListExample { protected LinkedListExample(String name) { super(name, Modifiability.ALL); } @Override public <T> List<T> createList(Class<T> listType, Collection<? extends T> contents) { return new LinkedList<>(contents); } } @GwtIncompatible // Iterables.toArray private static final class ArraysAsListExample extends ListExample { protected ArraysAsListExample(String name) { super(name, Modifiability.BY_ELEMENT); } @Override public <T> List<T> createList(Class<T> listType, Collection<? extends T> contents) { @SuppressWarnings("unchecked") // safe by contract T[] array = Iterables.toArray(contents, listType); return Arrays.asList(array); } } private static final class ImmutableListExample extends ListExample { protected ImmutableListExample(String name) { super(name, Modifiability.NONE); } @Override public <T> List<T> createList(Class<T> listType, Collection<? extends T> contents) { return ImmutableList.copyOf(contents); } } @GwtIncompatible // CopyOnWriteArrayList private static final class CopyOnWriteListExample extends ListExample { protected CopyOnWriteListExample(String name) { super(name, Modifiability.DIRECT_ONLY); } @Override public <T> List<T> createList(Class<T> listType, Collection<? extends T> contents) { return new CopyOnWriteArrayList<>(contents); } } }