blob: 3b05972eeeec242c5fea5d73c1dafaa15dfe1672 [file] [log] [blame]
/*
* Copyright (C) 2012 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.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.testing.EqualsTester;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.NavigableSet;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import junit.framework.TestCase;
/**
* Tests for filtered collection views.
*
* @author Louis Wasserman
*/
public class FilteredCollectionsTest extends TestCase {
private static final Predicate<Integer> EVEN =
new Predicate<Integer>() {
@Override
public boolean apply(Integer input) {
return input % 2 == 0;
}
};
private static final Predicate<Integer> PRIME_DIGIT = Predicates.in(ImmutableSet.of(2, 3, 5, 7));
private static final ImmutableList<? extends List<Integer>> SAMPLE_INPUTS =
ImmutableList.of(
ImmutableList.<Integer>of(),
ImmutableList.of(1),
ImmutableList.of(2),
ImmutableList.of(2, 3),
ImmutableList.of(1, 2),
ImmutableList.of(3, 5),
ImmutableList.of(2, 4),
ImmutableList.of(1, 2, 3, 5, 6, 8, 9));
/*
* We have a whole series of abstract test classes that "stack", so e.g. the tests for filtered
* NavigableSets inherit the tests for filtered Iterables, Collections, Sets, and SortedSets. The
* actual implementation tests are further down.
*/
public abstract static class AbstractFilteredIterableTest<C extends Iterable<Integer>>
extends TestCase {
abstract C createUnfiltered(Iterable<Integer> contents);
abstract C filter(C elements, Predicate<? super Integer> predicate);
public void testIterationOrderPreserved() {
for (List<Integer> contents : SAMPLE_INPUTS) {
C unfiltered = createUnfiltered(contents);
C filtered = filter(unfiltered, EVEN);
Iterator<Integer> filteredItr = filtered.iterator();
for (Integer i : unfiltered) {
if (EVEN.apply(i)) {
assertTrue(filteredItr.hasNext());
assertEquals(i, filteredItr.next());
}
}
assertFalse(filteredItr.hasNext());
}
}
}
public abstract static class AbstractFilteredCollectionTest<C extends Collection<Integer>>
extends AbstractFilteredIterableTest<C> {
public void testReadsThroughAdd() {
for (List<Integer> contents : SAMPLE_INPUTS) {
C unfiltered = createUnfiltered(contents);
C filterThenAdd = filter(unfiltered, EVEN);
unfiltered.add(4);
List<Integer> target = Lists.newArrayList(contents);
target.add(4);
C addThenFilter = filter(createUnfiltered(target), EVEN);
assertThat(filterThenAdd).containsExactlyElementsIn(addThenFilter);
}
}
public void testAdd() {
for (List<Integer> contents : SAMPLE_INPUTS) {
for (int toAdd = 0; toAdd < 10; toAdd++) {
boolean expectedResult = createUnfiltered(contents).add(toAdd);
C filtered = filter(createUnfiltered(contents), EVEN);
try {
assertEquals(expectedResult, filtered.add(toAdd));
assertTrue(EVEN.apply(toAdd));
} catch (IllegalArgumentException e) {
assertFalse(EVEN.apply(toAdd));
}
}
}
}
public void testRemove() {
for (List<Integer> contents : SAMPLE_INPUTS) {
for (int toRemove = 0; toRemove < 10; toRemove++) {
assertEquals(
contents.contains(toRemove) && EVEN.apply(toRemove),
filter(createUnfiltered(contents), EVEN).remove(toRemove));
}
}
}
public void testContains() {
for (List<Integer> contents : SAMPLE_INPUTS) {
for (int i = 0; i < 10; i++) {
assertEquals(
EVEN.apply(i) && contents.contains(i),
filter(createUnfiltered(contents), EVEN).contains(i));
}
}
}
public void testContainsOnDifferentType() {
for (List<Integer> contents : SAMPLE_INPUTS) {
assertFalse(filter(createUnfiltered(contents), EVEN).contains(new Object()));
}
}
public void testAddAllFailsAtomically() {
ImmutableList<Integer> toAdd = ImmutableList.of(2, 4, 3);
for (List<Integer> contents : SAMPLE_INPUTS) {
C filtered = filter(createUnfiltered(contents), EVEN);
C filteredToModify = filter(createUnfiltered(contents), EVEN);
try {
filteredToModify.addAll(toAdd);
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException expected) {
}
assertThat(filteredToModify).containsExactlyElementsIn(filtered);
}
}
public void testAddToFilterFiltered() {
for (List<Integer> contents : SAMPLE_INPUTS) {
C unfiltered = createUnfiltered(contents);
C filtered1 = filter(unfiltered, EVEN);
C filtered2 = filter(filtered1, PRIME_DIGIT);
try {
filtered2.add(4);
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException expected) {
}
try {
filtered2.add(3);
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException expected) {
}
filtered2.add(2);
}
}
public void testClearFilterFiltered() {
for (List<Integer> contents : SAMPLE_INPUTS) {
C unfiltered = createUnfiltered(contents);
C filtered1 = filter(unfiltered, EVEN);
C filtered2 = filter(filtered1, PRIME_DIGIT);
C inverseFiltered =
filter(createUnfiltered(contents), Predicates.not(Predicates.and(EVEN, PRIME_DIGIT)));
filtered2.clear();
assertThat(unfiltered).containsExactlyElementsIn(inverseFiltered);
}
}
}
public abstract static class AbstractFilteredSetTest<C extends Set<Integer>>
extends AbstractFilteredCollectionTest<C> {
public void testEqualsAndHashCode() {
for (List<Integer> contents : SAMPLE_INPUTS) {
Set<Integer> expected = Sets.newHashSet();
for (Integer i : contents) {
if (EVEN.apply(i)) {
expected.add(i);
}
}
new EqualsTester()
.addEqualityGroup(expected, filter(createUnfiltered(contents), EVEN))
.testEquals();
}
}
}
public abstract static class AbstractFilteredSortedSetTest<C extends SortedSet<Integer>>
extends AbstractFilteredSetTest<C> {
public void testFirst() {
for (List<Integer> contents : SAMPLE_INPUTS) {
C filtered = filter(createUnfiltered(contents), EVEN);
try {
Integer first = filtered.first();
assertFalse(filtered.isEmpty());
assertEquals(Ordering.natural().min(filtered), first);
} catch (NoSuchElementException e) {
assertTrue(filtered.isEmpty());
}
}
}
public void testLast() {
for (List<Integer> contents : SAMPLE_INPUTS) {
C filtered = filter(createUnfiltered(contents), EVEN);
try {
Integer first = filtered.last();
assertFalse(filtered.isEmpty());
assertEquals(Ordering.natural().max(filtered), first);
} catch (NoSuchElementException e) {
assertTrue(filtered.isEmpty());
}
}
}
@SuppressWarnings("unchecked")
public void testHeadSet() {
for (List<Integer> contents : SAMPLE_INPUTS) {
for (int i = 0; i < 10; i++) {
assertEquals(
filter((C) createUnfiltered(contents).headSet(i), EVEN),
filter(createUnfiltered(contents), EVEN).headSet(i));
}
}
}
@SuppressWarnings("unchecked")
public void testTailSet() {
for (List<Integer> contents : SAMPLE_INPUTS) {
for (int i = 0; i < 10; i++) {
assertEquals(
filter((C) createUnfiltered(contents).tailSet(i), EVEN),
filter(createUnfiltered(contents), EVEN).tailSet(i));
}
}
}
@SuppressWarnings("unchecked")
public void testSubSet() {
for (List<Integer> contents : SAMPLE_INPUTS) {
for (int i = 0; i < 10; i++) {
for (int j = i; j < 10; j++) {
assertEquals(
filter((C) createUnfiltered(contents).subSet(i, j), EVEN),
filter(createUnfiltered(contents), EVEN).subSet(i, j));
}
}
}
}
}
public abstract static class AbstractFilteredNavigableSetTest
extends AbstractFilteredSortedSetTest<NavigableSet<Integer>> {
public void testNavigableHeadSet() {
for (List<Integer> contents : SAMPLE_INPUTS) {
for (int i = 0; i < 10; i++) {
for (boolean inclusive : ImmutableList.of(true, false)) {
assertEquals(
filter(createUnfiltered(contents).headSet(i, inclusive), EVEN),
filter(createUnfiltered(contents), EVEN).headSet(i, inclusive));
}
}
}
}
public void testNavigableTailSet() {
for (List<Integer> contents : SAMPLE_INPUTS) {
for (int i = 0; i < 10; i++) {
for (boolean inclusive : ImmutableList.of(true, false)) {
assertEquals(
filter(createUnfiltered(contents).tailSet(i, inclusive), EVEN),
filter(createUnfiltered(contents), EVEN).tailSet(i, inclusive));
}
}
}
}
public void testNavigableSubSet() {
for (List<Integer> contents : SAMPLE_INPUTS) {
for (int i = 0; i < 10; i++) {
for (int j = i + 1; j < 10; j++) {
for (boolean fromInclusive : ImmutableList.of(true, false)) {
for (boolean toInclusive : ImmutableList.of(true, false)) {
NavigableSet<Integer> filterSubset =
filter(
createUnfiltered(contents).subSet(i, fromInclusive, j, toInclusive), EVEN);
NavigableSet<Integer> subsetFilter =
filter(createUnfiltered(contents), EVEN)
.subSet(i, fromInclusive, j, toInclusive);
assertEquals(filterSubset, subsetFilter);
}
}
}
}
}
}
public void testDescendingSet() {
for (List<Integer> contents : SAMPLE_INPUTS) {
NavigableSet<Integer> filtered = filter(createUnfiltered(contents), EVEN);
NavigableSet<Integer> unfiltered = createUnfiltered(filtered);
assertThat(filtered.descendingSet())
.containsExactlyElementsIn(unfiltered.descendingSet())
.inOrder();
}
}
public void testPollFirst() {
for (List<Integer> contents : SAMPLE_INPUTS) {
NavigableSet<Integer> filtered = filter(createUnfiltered(contents), EVEN);
NavigableSet<Integer> unfiltered = createUnfiltered(filtered);
assertEquals(unfiltered.pollFirst(), filtered.pollFirst());
assertEquals(unfiltered, filtered);
}
}
public void testPollLast() {
for (List<Integer> contents : SAMPLE_INPUTS) {
NavigableSet<Integer> filtered = filter(createUnfiltered(contents), EVEN);
NavigableSet<Integer> unfiltered = createUnfiltered(filtered);
assertEquals(unfiltered.pollLast(), filtered.pollLast());
assertEquals(unfiltered, filtered);
}
}
public void testNavigation() {
for (List<Integer> contents : SAMPLE_INPUTS) {
NavigableSet<Integer> filtered = filter(createUnfiltered(contents), EVEN);
NavigableSet<Integer> unfiltered = createUnfiltered(filtered);
for (int i = 0; i < 10; i++) {
assertEquals(unfiltered.lower(i), filtered.lower(i));
assertEquals(unfiltered.floor(i), filtered.floor(i));
assertEquals(unfiltered.ceiling(i), filtered.ceiling(i));
assertEquals(unfiltered.higher(i), filtered.higher(i));
}
}
}
}
// implementation tests
public static final class IterablesFilterArrayListTest
extends AbstractFilteredIterableTest<Iterable<Integer>> {
@Override
Iterable<Integer> createUnfiltered(Iterable<Integer> contents) {
return Lists.newArrayList(contents);
}
@Override
Iterable<Integer> filter(Iterable<Integer> elements, Predicate<? super Integer> predicate) {
return Iterables.filter(elements, predicate);
}
}
public static final class Collections2FilterArrayListTest
extends AbstractFilteredCollectionTest<Collection<Integer>> {
@Override
Collection<Integer> createUnfiltered(Iterable<Integer> contents) {
return Lists.newArrayList(contents);
}
@Override
Collection<Integer> filter(Collection<Integer> elements, Predicate<? super Integer> predicate) {
return Collections2.filter(elements, predicate);
}
}
public static final class SetsFilterHashSetTest extends AbstractFilteredSetTest<Set<Integer>> {
@Override
Set<Integer> createUnfiltered(Iterable<Integer> contents) {
return Sets.newHashSet(contents);
}
@Override
Set<Integer> filter(Set<Integer> elements, Predicate<? super Integer> predicate) {
return Sets.filter(elements, predicate);
}
}
public static final class SetsFilterSortedSetTest
extends AbstractFilteredSortedSetTest<SortedSet<Integer>> {
@Override
SortedSet<Integer> createUnfiltered(Iterable<Integer> contents) {
final TreeSet<Integer> result = Sets.newTreeSet(contents);
// we have to make the result not Navigable
return new ForwardingSortedSet<Integer>() {
@Override
protected SortedSet<Integer> delegate() {
return result;
}
};
}
@Override
SortedSet<Integer> filter(SortedSet<Integer> elements, Predicate<? super Integer> predicate) {
return Sets.filter(elements, predicate);
}
}
public static final class SetsFilterNavigableSetTest extends AbstractFilteredNavigableSetTest {
@Override
NavigableSet<Integer> createUnfiltered(Iterable<Integer> contents) {
return Sets.newTreeSet(contents);
}
@Override
NavigableSet<Integer> filter(
NavigableSet<Integer> elements, Predicate<? super Integer> predicate) {
return Sets.filter(elements, predicate);
}
}
/** No-op test so that the class has at least one method, making Maven's test runner happy. */
public void testNoop() {}
}