blob: 5edbbcc87163ec1bc26fbf6317651efa48c30658 [file] [log] [blame]
/*
* 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 abstract static 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")));
suite.addTestSuite(ListsImplTest.class);
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);
}
}
}