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