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