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}