001/*
002 * Copyright (C) 2008 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.google.common.collect.testing.google;
018
019import static com.google.common.base.Preconditions.checkNotNull;
020import static com.google.common.collect.Lists.newArrayList;
021import static com.google.common.collect.Sets.newTreeSet;
022import static com.google.common.collect.testing.SampleElements.Strings.AFTER_LAST;
023import static com.google.common.collect.testing.SampleElements.Strings.AFTER_LAST_2;
024import static com.google.common.collect.testing.SampleElements.Strings.BEFORE_FIRST;
025import static com.google.common.collect.testing.SampleElements.Strings.BEFORE_FIRST_2;
026import static junit.framework.Assert.assertEquals;
027
028import com.google.common.annotations.GwtCompatible;
029import com.google.common.annotations.GwtIncompatible;
030import com.google.common.collect.ContiguousSet;
031import com.google.common.collect.DiscreteDomain;
032import com.google.common.collect.ImmutableSet;
033import com.google.common.collect.ImmutableSortedSet;
034import com.google.common.collect.Lists;
035import com.google.common.collect.Ordering;
036import com.google.common.collect.Range;
037import com.google.common.collect.Sets;
038import com.google.common.collect.testing.TestCollectionGenerator;
039import com.google.common.collect.testing.TestCollidingSetGenerator;
040import com.google.common.collect.testing.TestIntegerSortedSetGenerator;
041import com.google.common.collect.testing.TestSetGenerator;
042import com.google.common.collect.testing.TestStringListGenerator;
043import com.google.common.collect.testing.TestStringSetGenerator;
044import com.google.common.collect.testing.TestStringSortedSetGenerator;
045import com.google.common.collect.testing.TestUnhashableCollectionGenerator;
046import com.google.common.collect.testing.UnhashableObject;
047import java.util.Arrays;
048import java.util.Collections;
049import java.util.Comparator;
050import java.util.List;
051import java.util.Set;
052import java.util.SortedSet;
053
054/**
055 * Generators of different types of sets and derived collections from sets.
056 *
057 * @author Kevin Bourrillion
058 * @author Jared Levy
059 * @author Hayward Chan
060 */
061@GwtCompatible(emulated = true)
062@ElementTypesAreNonnullByDefault
063public class SetGenerators {
064
065  public static class ImmutableSetCopyOfGenerator extends TestStringSetGenerator {
066    @Override
067    protected Set<String> create(String[] elements) {
068      return ImmutableSet.copyOf(elements);
069    }
070  }
071
072  public static class ImmutableSetUnsizedBuilderGenerator extends TestStringSetGenerator {
073    @Override
074    protected Set<String> create(String[] elements) {
075      ImmutableSet.Builder<String> builder = ImmutableSet.builder();
076      for (String e : elements) {
077        builder.add(e);
078      }
079      return builder.build();
080    }
081  }
082
083  public static class ImmutableSetSizedBuilderGenerator extends TestStringSetGenerator {
084    @Override
085    protected Set<String> create(String[] elements) {
086      ImmutableSet.Builder<String> builder =
087          ImmutableSet.builderWithExpectedSize(Sets.newHashSet(elements).size());
088      for (String e : elements) {
089        builder.add(e);
090      }
091      return builder.build();
092    }
093  }
094
095  public static class ImmutableSetTooBigBuilderGenerator extends TestStringSetGenerator {
096    @Override
097    protected Set<String> create(String[] elements) {
098      ImmutableSet.Builder<String> builder =
099          ImmutableSet.builderWithExpectedSize(Sets.newHashSet(elements).size() + 1);
100      for (String e : elements) {
101        builder.add(e);
102      }
103      return builder.build();
104    }
105  }
106
107  public static class ImmutableSetTooSmallBuilderGenerator extends TestStringSetGenerator {
108    @Override
109    protected Set<String> create(String[] elements) {
110      ImmutableSet.Builder<String> builder =
111          ImmutableSet.builderWithExpectedSize(Math.max(0, Sets.newHashSet(elements).size() - 1));
112      for (String e : elements) {
113        builder.add(e);
114      }
115      return builder.build();
116    }
117  }
118
119  public static class ImmutableSetWithBadHashesGenerator extends TestCollidingSetGenerator
120      // Work around a GWT compiler bug.  Not explicitly listing this will
121      // cause the createArray() method missing in the generated javascript.
122      // TODO: Remove this once the GWT bug is fixed.
123      implements TestCollectionGenerator<Object> {
124    @Override
125    public Set<Object> create(Object... elements) {
126      return ImmutableSet.copyOf(elements);
127    }
128  }
129
130  public static class DegeneratedImmutableSetGenerator extends TestStringSetGenerator {
131    // Make sure we get what we think we're getting, or else this test
132    // is pointless
133    @SuppressWarnings("cast")
134    @Override
135    protected Set<String> create(String[] elements) {
136      return (ImmutableSet<String>) ImmutableSet.of(elements[0], elements[0]);
137    }
138  }
139
140  public static class ImmutableSortedSetCopyOfGenerator extends TestStringSortedSetGenerator {
141    @Override
142    protected SortedSet<String> create(String[] elements) {
143      return ImmutableSortedSet.copyOf(elements);
144    }
145  }
146
147  public static class ImmutableSortedSetHeadsetGenerator extends TestStringSortedSetGenerator {
148    @Override
149    protected SortedSet<String> create(String[] elements) {
150      List<String> list = Lists.newArrayList(elements);
151      list.add("zzz");
152      return ImmutableSortedSet.copyOf(list).headSet("zzy");
153    }
154  }
155
156  public static class ImmutableSortedSetTailsetGenerator extends TestStringSortedSetGenerator {
157    @Override
158    protected SortedSet<String> create(String[] elements) {
159      List<String> list = Lists.newArrayList(elements);
160      list.add("\0");
161      return ImmutableSortedSet.copyOf(list).tailSet("\0\0");
162    }
163  }
164
165  public static class ImmutableSortedSetSubsetGenerator extends TestStringSortedSetGenerator {
166    @Override
167    protected SortedSet<String> create(String[] elements) {
168      List<String> list = Lists.newArrayList(elements);
169      list.add("\0");
170      list.add("zzz");
171      return ImmutableSortedSet.copyOf(list).subSet("\0\0", "zzy");
172    }
173  }
174
175  @GwtIncompatible // NavigableSet
176  public static class ImmutableSortedSetDescendingGenerator extends TestStringSortedSetGenerator {
177    @Override
178    protected SortedSet<String> create(String[] elements) {
179      return ImmutableSortedSet.<String>reverseOrder().add(elements).build().descendingSet();
180    }
181  }
182
183  public static class ImmutableSortedSetExplicitComparator extends TestStringSetGenerator {
184
185    private static final Comparator<String> STRING_REVERSED = Collections.reverseOrder();
186
187    @Override
188    protected SortedSet<String> create(String[] elements) {
189      return ImmutableSortedSet.orderedBy(STRING_REVERSED).add(elements).build();
190    }
191
192    @Override
193    public List<String> order(List<String> insertionOrder) {
194      Collections.sort(insertionOrder, Collections.reverseOrder());
195      return insertionOrder;
196    }
197  }
198
199  public static class ImmutableSortedSetExplicitSuperclassComparatorGenerator
200      extends TestStringSetGenerator {
201
202    private static final Comparator<Comparable<?>> COMPARABLE_REVERSED = Collections.reverseOrder();
203
204    @Override
205    protected SortedSet<String> create(String[] elements) {
206      return new ImmutableSortedSet.Builder<String>(COMPARABLE_REVERSED).add(elements).build();
207    }
208
209    @Override
210    public List<String> order(List<String> insertionOrder) {
211      Collections.sort(insertionOrder, Collections.reverseOrder());
212      return insertionOrder;
213    }
214  }
215
216  public static class ImmutableSortedSetReversedOrderGenerator extends TestStringSetGenerator {
217
218    @Override
219    protected SortedSet<String> create(String[] elements) {
220      return ImmutableSortedSet.<String>reverseOrder()
221          .addAll(Arrays.asList(elements).iterator())
222          .build();
223    }
224
225    @Override
226    public List<String> order(List<String> insertionOrder) {
227      Collections.sort(insertionOrder, Collections.reverseOrder());
228      return insertionOrder;
229    }
230  }
231
232  public static class ImmutableSortedSetUnhashableGenerator extends TestUnhashableSetGenerator {
233    @Override
234    public Set<UnhashableObject> create(UnhashableObject[] elements) {
235      return ImmutableSortedSet.copyOf(elements);
236    }
237  }
238
239  public static class ImmutableSetAsListGenerator extends TestStringListGenerator {
240    @Override
241    protected List<String> create(String[] elements) {
242      return ImmutableSet.copyOf(elements).asList();
243    }
244  }
245
246  public static class ImmutableSortedSetAsListGenerator extends TestStringListGenerator {
247    @Override
248    protected List<String> create(String[] elements) {
249      Comparator<String> comparator = createExplicitComparator(elements);
250      ImmutableSet<String> set = ImmutableSortedSet.copyOf(comparator, Arrays.asList(elements));
251      return set.asList();
252    }
253  }
254
255  public static class ImmutableSortedSetSubsetAsListGenerator extends TestStringListGenerator {
256    @Override
257    protected List<String> create(String[] elements) {
258      Comparator<String> comparator = createExplicitComparator(elements);
259      ImmutableSortedSet.Builder<String> builder = ImmutableSortedSet.orderedBy(comparator);
260      builder.add(BEFORE_FIRST);
261      builder.add(elements);
262      builder.add(AFTER_LAST);
263      return builder.build().subSet(BEFORE_FIRST_2, AFTER_LAST).asList();
264    }
265  }
266
267  @GwtIncompatible // NavigableSet
268  public static class ImmutableSortedSetDescendingAsListGenerator extends TestStringListGenerator {
269    @Override
270    protected List<String> create(String[] elements) {
271      Comparator<String> comparator = createExplicitComparator(elements).reverse();
272      return ImmutableSortedSet.orderedBy(comparator)
273          .add(elements)
274          .build()
275          .descendingSet()
276          .asList();
277    }
278  }
279
280  public static class ImmutableSortedSetAsListSubListGenerator extends TestStringListGenerator {
281    @Override
282    protected List<String> create(String[] elements) {
283      Comparator<String> comparator = createExplicitComparator(elements);
284      ImmutableSortedSet.Builder<String> builder = ImmutableSortedSet.orderedBy(comparator);
285      builder.add(BEFORE_FIRST);
286      builder.add(elements);
287      builder.add(AFTER_LAST);
288      return builder.build().asList().subList(1, elements.length + 1);
289    }
290  }
291
292  public static class ImmutableSortedSetSubsetAsListSubListGenerator
293      extends TestStringListGenerator {
294    @Override
295    protected List<String> create(String[] elements) {
296      Comparator<String> comparator = createExplicitComparator(elements);
297      ImmutableSortedSet.Builder<String> builder = ImmutableSortedSet.orderedBy(comparator);
298      builder.add(BEFORE_FIRST);
299      builder.add(BEFORE_FIRST_2);
300      builder.add(elements);
301      builder.add(AFTER_LAST);
302      builder.add(AFTER_LAST_2);
303      return builder
304          .build()
305          .subSet(BEFORE_FIRST_2, AFTER_LAST_2)
306          .asList()
307          .subList(1, elements.length + 1);
308    }
309  }
310
311  public abstract static class TestUnhashableSetGenerator
312      extends TestUnhashableCollectionGenerator<Set<UnhashableObject>>
313      implements TestSetGenerator<UnhashableObject> {}
314
315  private static Ordering<String> createExplicitComparator(String[] elements) {
316    // Collapse equal elements, which Ordering.explicit() doesn't support, while
317    // maintaining the ordering by first occurrence.
318    Set<String> elementsPlus = Sets.newLinkedHashSet();
319    elementsPlus.add(BEFORE_FIRST);
320    elementsPlus.add(BEFORE_FIRST_2);
321    elementsPlus.addAll(Arrays.asList(elements));
322    elementsPlus.add(AFTER_LAST);
323    elementsPlus.add(AFTER_LAST_2);
324    return Ordering.explicit(Lists.newArrayList(elementsPlus));
325  }
326
327  /*
328   * All the ContiguousSet generators below manually reject nulls here. In principle, we'd like to
329   * defer that to Range, since it's ContiguousSet.create() that's used to create the sets. However,
330   * that gets messy here, and we already have null tests for Range.
331   */
332
333  /*
334   * These generators also rely on consecutive integer inputs (not necessarily in order, but no
335   * holes).
336   */
337
338  // SetCreationTester has some tests that pass in duplicates. Dedup them.
339  private static <E extends Comparable<? super E>> SortedSet<E> nullCheckedTreeSet(E[] elements) {
340    SortedSet<E> set = newTreeSet();
341    for (E element : elements) {
342      // Explicit null check because TreeSet wrongly accepts add(null) when empty.
343      set.add(checkNotNull(element));
344    }
345    return set;
346  }
347
348  public static class ContiguousSetGenerator extends AbstractContiguousSetGenerator {
349    @Override
350    protected SortedSet<Integer> create(Integer[] elements) {
351      return checkedCreate(nullCheckedTreeSet(elements));
352    }
353  }
354
355  public static class ContiguousSetHeadsetGenerator extends AbstractContiguousSetGenerator {
356    @Override
357    protected SortedSet<Integer> create(Integer[] elements) {
358      SortedSet<Integer> set = nullCheckedTreeSet(elements);
359      int tooHigh = set.isEmpty() ? 0 : set.last() + 1;
360      set.add(tooHigh);
361      return checkedCreate(set).headSet(tooHigh);
362    }
363  }
364
365  public static class ContiguousSetTailsetGenerator extends AbstractContiguousSetGenerator {
366    @Override
367    protected SortedSet<Integer> create(Integer[] elements) {
368      SortedSet<Integer> set = nullCheckedTreeSet(elements);
369      int tooLow = set.isEmpty() ? 0 : set.first() - 1;
370      set.add(tooLow);
371      return checkedCreate(set).tailSet(tooLow + 1);
372    }
373  }
374
375  public static class ContiguousSetSubsetGenerator extends AbstractContiguousSetGenerator {
376    @Override
377    protected SortedSet<Integer> create(Integer[] elements) {
378      SortedSet<Integer> set = nullCheckedTreeSet(elements);
379      if (set.isEmpty()) {
380        /*
381         * The (tooLow + 1, tooHigh) arguments below would be invalid because tooLow would be
382         * greater than tooHigh.
383         */
384        return ContiguousSet.create(Range.openClosed(0, 1), DiscreteDomain.integers()).subSet(0, 1);
385      }
386      int tooHigh = set.last() + 1;
387      int tooLow = set.first() - 1;
388      set.add(tooHigh);
389      set.add(tooLow);
390      return checkedCreate(set).subSet(tooLow + 1, tooHigh);
391    }
392  }
393
394  @GwtIncompatible // NavigableSet
395  public static class ContiguousSetDescendingGenerator extends AbstractContiguousSetGenerator {
396    @Override
397    protected SortedSet<Integer> create(Integer[] elements) {
398      return checkedCreate(nullCheckedTreeSet(elements)).descendingSet();
399    }
400
401    /** Sorts the elements in reverse natural order. */
402    @Override
403    public List<Integer> order(List<Integer> insertionOrder) {
404      Collections.sort(insertionOrder, Ordering.<Integer>natural().reverse());
405      return insertionOrder;
406    }
407  }
408
409  private abstract static class AbstractContiguousSetGenerator
410      extends TestIntegerSortedSetGenerator {
411    protected final ContiguousSet<Integer> checkedCreate(SortedSet<Integer> elementsSet) {
412      List<Integer> elements = newArrayList(elementsSet);
413      /*
414       * A ContiguousSet can't have holes. If a test demands a hole, it should be changed so that it
415       * doesn't need one, or it should be suppressed for ContiguousSet.
416       */
417      for (int i = 0; i < elements.size() - 1; i++) {
418        assertEquals(elements.get(i) + 1, (int) elements.get(i + 1));
419      }
420      Range<Integer> range =
421          elements.isEmpty() ? Range.closedOpen(0, 0) : Range.encloseAll(elements);
422      return ContiguousSet.create(range, DiscreteDomain.integers());
423    }
424  }
425}