/*
* Copyright (C) 2008 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.testing.google;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Sets.newTreeSet;
import static com.google.common.collect.testing.SampleElements.Strings.AFTER_LAST;
import static com.google.common.collect.testing.SampleElements.Strings.AFTER_LAST_2;
import static com.google.common.collect.testing.SampleElements.Strings.BEFORE_FIRST;
import static com.google.common.collect.testing.SampleElements.Strings.BEFORE_FIRST_2;
import static junit.framework.Assert.assertEquals;
import com.google.common.annotations.GwtCompatible;
import com.google.common.collect.ContiguousSet;
import com.google.common.collect.DiscreteDomains;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
import com.google.common.collect.Range;
import com.google.common.collect.Ranges;
import com.google.common.collect.Sets;
import com.google.common.collect.testing.TestCollectionGenerator;
import com.google.common.collect.testing.TestCollidingSetGenerator;
import com.google.common.collect.testing.TestIntegerSortedSetGenerator;
import com.google.common.collect.testing.TestSetGenerator;
import com.google.common.collect.testing.TestStringListGenerator;
import com.google.common.collect.testing.TestStringSetGenerator;
import com.google.common.collect.testing.TestStringSortedSetGenerator;
import com.google.common.collect.testing.TestUnhashableCollectionGenerator;
import com.google.common.collect.testing.UnhashableObject;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
/**
* Generators of different types of sets and derived collections from sets.
*
* @author Kevin Bourrillion
* @author Jared Levy
* @author Hayward Chan
*/
@GwtCompatible(emulated = true)
public class SetGenerators {
public static class ImmutableSetCopyOfGenerator extends TestStringSetGenerator {
@Override protected Set<String> create(String[] elements) {
return ImmutableSet.copyOf(elements);
}
}
public static class ImmutableSetWithBadHashesGenerator
extends TestCollidingSetGenerator
// Work around a GWT compiler bug. Not explicitly listing this will
// cause the createArray() method missing in the generated javascript.
// TODO: Remove this once the GWT bug is fixed.
implements TestCollectionGenerator<Object> {
@Override
public Set<Object> create(Object... elements) {
return ImmutableSet.copyOf(elements);
}
}
public static class DegeneratedImmutableSetGenerator
extends TestStringSetGenerator {
// Make sure we get what we think we're getting, or else this test
// is pointless
@SuppressWarnings("cast")
@Override protected Set<String> create(String[] elements) {
return (ImmutableSet<String>)
ImmutableSet.of(elements[0], elements[0]);
}
}
public static class ImmutableSortedSetCopyOfGenerator
extends TestStringSortedSetGenerator {
@Override protected SortedSet<String> create(String[] elements) {
return ImmutableSortedSet.copyOf(elements);
}
}
public static class ImmutableSortedSetHeadsetGenerator
extends TestStringSortedSetGenerator {
@Override protected SortedSet<String> create(String[] elements) {
List<String> list = Lists.newArrayList(elements);
list.add("zzz");
return ImmutableSortedSet.copyOf(list)
.headSet("zzy");
}
}
public static class ImmutableSortedSetTailsetGenerator
extends TestStringSortedSetGenerator {
@Override protected SortedSet<String> create(String[] elements) {
List<String> list = Lists.newArrayList(elements);
list.add("\0");
return ImmutableSortedSet.copyOf(list)
.tailSet("\0\0");
}
}
public static class ImmutableSortedSetSubsetGenerator
extends TestStringSortedSetGenerator {
@Override protected SortedSet<String> create(String[] elements) {
List<String> list = Lists.newArrayList(elements);
list.add("\0");
list.add("zzz");
return ImmutableSortedSet.copyOf(list)
.subSet("\0\0", "zzy");
}
}
public static class ImmutableSortedSetExplicitComparator
extends TestStringSetGenerator {
private static final Comparator<String> STRING_REVERSED
= Collections.reverseOrder();
@Override protected SortedSet<String> create(String[] elements) {
return ImmutableSortedSet.orderedBy(STRING_REVERSED)
.add(elements)
.build();
}
@Override public List<String> order(List<String> insertionOrder) {
Collections.sort(insertionOrder, Collections.reverseOrder());
return insertionOrder;
}
}
public static class ImmutableSortedSetExplicitSuperclassComparatorGenerator
extends TestStringSetGenerator {
private static final Comparator<Comparable<?>> COMPARABLE_REVERSED
= Collections.reverseOrder();
@Override protected SortedSet<String> create(String[] elements) {
return new ImmutableSortedSet.Builder<String>(COMPARABLE_REVERSED)
.add(elements)
.build();
}
@Override public List<String> order(List<String> insertionOrder) {
Collections.sort(insertionOrder, Collections.reverseOrder());
return insertionOrder;
}
}
public static class ImmutableSortedSetReversedOrderGenerator
extends TestStringSetGenerator {
@Override protected SortedSet<String> create(String[] elements) {
return ImmutableSortedSet.<String>reverseOrder()
.addAll(Arrays.asList(elements).iterator())
.build();
}
@Override public List<String> order(List<String> insertionOrder) {
Collections.sort(insertionOrder, Collections.reverseOrder());
return insertionOrder;
}
}
public static class ImmutableSortedSetUnhashableGenerator
extends TestUnhashableSetGenerator {
@Override public Set<UnhashableObject> create(
UnhashableObject[] elements) {
return ImmutableSortedSet.copyOf(elements);
}
}
public static class ImmutableSetAsListGenerator
extends TestStringListGenerator {
@Override protected List<String> create(String[] elements) {
return ImmutableSet.copyOf(elements).asList();
}
}
public static class ImmutableSortedSetAsListGenerator
extends TestStringListGenerator {
@Override protected List<String> create(String[] elements) {
Comparator<String> comparator = createExplicitComparator(elements);
ImmutableSet<String> set = ImmutableSortedSet.copyOf(
comparator, Arrays.asList(elements));
return set.asList();
}
}
public static class ImmutableSortedSetSubsetAsListGenerator
extends TestStringListGenerator {
@Override protected List<String> create(String[] elements) {
Comparator<String> comparator = createExplicitComparator(elements);
ImmutableSortedSet.Builder<String> builder
= ImmutableSortedSet.orderedBy(comparator);
builder.add(BEFORE_FIRST);
builder.add(elements);
builder.add(AFTER_LAST);
return builder.build().subSet(BEFORE_FIRST_2,
AFTER_LAST).asList();
}
}
public static class ImmutableSortedSetAsListSubListGenerator
extends TestStringListGenerator {
@Override protected List<String> create(String[] elements) {
Comparator<String> comparator = createExplicitComparator(elements);
ImmutableSortedSet.Builder<String> builder
= ImmutableSortedSet.orderedBy(comparator);
builder.add(BEFORE_FIRST);
builder.add(elements);
builder.add(AFTER_LAST);
return builder.build().asList().subList(1, elements.length + 1);
}
}
public static class ImmutableSortedsetSubsetAsListSubListGenerator
extends TestStringListGenerator {
@Override protected List<String> create(String[] elements) {
Comparator<String> comparator = createExplicitComparator(elements);
ImmutableSortedSet.Builder<String> builder
= ImmutableSortedSet.orderedBy(comparator);
builder.add(BEFORE_FIRST);
builder.add(BEFORE_FIRST_2);
builder.add(elements);
builder.add(AFTER_LAST);
builder.add(AFTER_LAST_2);
return builder.build().subSet(BEFORE_FIRST_2,
AFTER_LAST_2)
.asList().subList(1, elements.length + 1);
}
}
public abstract static class TestUnhashableSetGenerator
extends TestUnhashableCollectionGenerator<Set<UnhashableObject>>
implements TestSetGenerator<UnhashableObject> {
}
private static Ordering<String> createExplicitComparator(
String[] elements) {
// Collapse equal elements, which Ordering.explicit() doesn't support, while
// maintaining the ordering by first occurrence.
Set<String> elementsPlus = Sets.newLinkedHashSet();
elementsPlus.add(BEFORE_FIRST);
elementsPlus.add(BEFORE_FIRST_2);
elementsPlus.addAll(Arrays.asList(elements));
elementsPlus.add(AFTER_LAST);
elementsPlus.add(AFTER_LAST_2);
return Ordering.explicit(Lists.newArrayList(elementsPlus));
}
/*
* All the ContiguousSet generators below manually reject nulls here. In principle, we'd like to
* defer that to Range, since it's Range.asSet() that's used to create the sets. However, that
* gets messy here, and we already have null tests for Range.
*/
/*
* These generators also rely on consecutive integer inputs (not necessarily in order, but no
* holes).
*/
// SetCreationTester has some tests that pass in duplicates. Dedup them.
private static <E extends Comparable<? super E>> SortedSet<E> nullCheckedTreeSet(E[] elements) {
SortedSet<E> set = newTreeSet();
for (E element : elements) {
// Explicit null check because TreeSet wrongly accepts add(null) when empty.
set.add(checkNotNull(element));
}
return set;
}
public static class ContiguousSetGenerator extends AbstractContiguousSetGenerator {
@Override protected SortedSet<Integer> create(Integer[] elements) {
return checkedCreate(nullCheckedTreeSet(elements));
}
}
public static class ContiguousSetHeadsetGenerator extends AbstractContiguousSetGenerator {
@Override protected SortedSet<Integer> create(Integer[] elements) {
SortedSet<Integer> set = nullCheckedTreeSet(elements);
int tooHigh = (set.isEmpty()) ? 0 : set.last() + 1;
set.add(tooHigh);
return checkedCreate(set).headSet(tooHigh);
}
}
public static class ContiguousSetTailsetGenerator extends AbstractContiguousSetGenerator {
@Override protected SortedSet<Integer> create(Integer[] elements) {
SortedSet<Integer> set = nullCheckedTreeSet(elements);
int tooLow = (set.isEmpty()) ? 0 : set.first() - 1;
set.add(tooLow);
return checkedCreate(set).tailSet(tooLow + 1);
}
}
public static class ContiguousSetSubsetGenerator extends AbstractContiguousSetGenerator {
@Override protected SortedSet<Integer> create(Integer[] elements) {
SortedSet<Integer> set = nullCheckedTreeSet(elements);
if (set.isEmpty()) {
/*
* The (tooLow + 1, tooHigh) arguments below would be invalid because tooLow would be
* greater than tooHigh.
*/
return Ranges.openClosed(0, 1).asSet(DiscreteDomains.integers()).subSet(0, 1);
}
int tooHigh = set.last() + 1;
int tooLow = set.first() - 1;
set.add(tooHigh);
set.add(tooLow);
return checkedCreate(set).subSet(tooLow + 1, tooHigh);
}
}
private abstract static class AbstractContiguousSetGenerator
extends TestIntegerSortedSetGenerator {
protected final ContiguousSet<Integer> checkedCreate(SortedSet<Integer> elementsSet) {
List<Integer> elements = newArrayList(elementsSet);
/*
* A ContiguousSet can't have holes. If a test demands a hole, it should be changed so that it
* doesn't need one, or it should be suppressed for ContiguousSet.
*/
for (int i = 0; i < elements.size() - 1; i++) {
assertEquals(elements.get(i) + 1, (int) elements.get(i + 1));
}
Range<Integer> range =
(elements.isEmpty()) ? Ranges.closedOpen(0, 0) : Ranges.encloseAll(elements);
return range.asSet(DiscreteDomains.integers());
}
}
}