1 /* 2 * Copyright (C) 2007 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.collect; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import com.google.common.annotations.GwtCompatible; 22 import com.google.common.annotations.GwtIncompatible; 23 import com.google.common.base.Equivalence; 24 import com.google.common.collect.ImmutableSet.Builder; 25 import com.google.common.collect.testing.ListTestSuiteBuilder; 26 import com.google.common.collect.testing.SetTestSuiteBuilder; 27 import com.google.common.collect.testing.TestStringSetGenerator; 28 import com.google.common.collect.testing.features.CollectionFeature; 29 import com.google.common.collect.testing.features.CollectionSize; 30 import com.google.common.collect.testing.google.SetGenerators.DegeneratedImmutableSetGenerator; 31 import com.google.common.collect.testing.google.SetGenerators.ImmutableSetAsListGenerator; 32 import com.google.common.collect.testing.google.SetGenerators.ImmutableSetCopyOfGenerator; 33 import com.google.common.collect.testing.google.SetGenerators.ImmutableSetSizedBuilderGenerator; 34 import com.google.common.collect.testing.google.SetGenerators.ImmutableSetTooBigBuilderGenerator; 35 import com.google.common.collect.testing.google.SetGenerators.ImmutableSetTooSmallBuilderGenerator; 36 import com.google.common.collect.testing.google.SetGenerators.ImmutableSetUnsizedBuilderGenerator; 37 import com.google.common.collect.testing.google.SetGenerators.ImmutableSetWithBadHashesGenerator; 38 import com.google.common.testing.CollectorTester; 39 import com.google.common.testing.EqualsTester; 40 import java.util.Arrays; 41 import java.util.Collection; 42 import java.util.Collections; 43 import java.util.Iterator; 44 import java.util.List; 45 import java.util.Set; 46 import java.util.function.BiPredicate; 47 import java.util.stream.Collector; 48 import junit.framework.Test; 49 import junit.framework.TestSuite; 50 51 /** 52 * Unit test for {@link ImmutableSet}. 53 * 54 * @author Kevin Bourrillion 55 * @author Jared Levy 56 * @author Nick Kralevich 57 */ 58 @GwtCompatible(emulated = true) 59 public class ImmutableSetTest extends AbstractImmutableSetTest { 60 61 @GwtIncompatible // suite suite()62 public static Test suite() { 63 TestSuite suite = new TestSuite(); 64 65 suite.addTest( 66 SetTestSuiteBuilder.using(new ImmutableSetCopyOfGenerator()) 67 .named(ImmutableSetTest.class.getName()) 68 .withFeatures( 69 CollectionSize.ANY, 70 CollectionFeature.KNOWN_ORDER, 71 CollectionFeature.SERIALIZABLE, 72 CollectionFeature.ALLOWS_NULL_QUERIES) 73 .createTestSuite()); 74 75 suite.addTest( 76 SetTestSuiteBuilder.using(new ImmutableSetUnsizedBuilderGenerator()) 77 .named(ImmutableSetTest.class.getName() + ", with unsized builder") 78 .withFeatures( 79 CollectionSize.ANY, 80 CollectionFeature.KNOWN_ORDER, 81 CollectionFeature.SERIALIZABLE, 82 CollectionFeature.ALLOWS_NULL_QUERIES) 83 .createTestSuite()); 84 85 suite.addTest( 86 SetTestSuiteBuilder.using( 87 new TestStringSetGenerator() { 88 @Override 89 protected Set<String> create(String[] elements) { 90 ImmutableSet.Builder<String> builder = ImmutableSet.builder(); 91 builder.forceJdk(); 92 builder.add(elements); 93 return builder.build(); 94 } 95 }) 96 .named(ImmutableSetTest.class.getName() + ", with JDK builder") 97 .withFeatures( 98 CollectionSize.ANY, 99 CollectionFeature.KNOWN_ORDER, 100 CollectionFeature.SERIALIZABLE, 101 CollectionFeature.ALLOWS_NULL_QUERIES) 102 .createTestSuite()); 103 104 suite.addTest( 105 SetTestSuiteBuilder.using(new ImmutableSetSizedBuilderGenerator()) 106 .named(ImmutableSetTest.class.getName() + ", with exactly sized builder") 107 .withFeatures( 108 CollectionSize.ANY, 109 CollectionFeature.KNOWN_ORDER, 110 CollectionFeature.SERIALIZABLE, 111 CollectionFeature.ALLOWS_NULL_QUERIES) 112 .createTestSuite()); 113 114 suite.addTest( 115 SetTestSuiteBuilder.using(new ImmutableSetTooBigBuilderGenerator()) 116 .named(ImmutableSetTest.class.getName() + ", with oversized builder") 117 .withFeatures( 118 CollectionSize.ANY, 119 CollectionFeature.KNOWN_ORDER, 120 CollectionFeature.SERIALIZABLE, 121 CollectionFeature.ALLOWS_NULL_QUERIES) 122 .createTestSuite()); 123 124 suite.addTest( 125 SetTestSuiteBuilder.using(new ImmutableSetTooSmallBuilderGenerator()) 126 .named(ImmutableSetTest.class.getName() + ", with undersized builder") 127 .withFeatures( 128 CollectionSize.ANY, 129 CollectionFeature.KNOWN_ORDER, 130 CollectionFeature.SERIALIZABLE, 131 CollectionFeature.ALLOWS_NULL_QUERIES) 132 .createTestSuite()); 133 134 suite.addTest( 135 SetTestSuiteBuilder.using(new ImmutableSetWithBadHashesGenerator()) 136 .named(ImmutableSetTest.class.getName() + ", with bad hashes") 137 .withFeatures( 138 CollectionSize.ANY, 139 CollectionFeature.KNOWN_ORDER, 140 CollectionFeature.ALLOWS_NULL_QUERIES) 141 .createTestSuite()); 142 143 suite.addTest( 144 SetTestSuiteBuilder.using(new DegeneratedImmutableSetGenerator()) 145 .named(ImmutableSetTest.class.getName() + ", degenerate") 146 .withFeatures( 147 CollectionSize.ONE, 148 CollectionFeature.KNOWN_ORDER, 149 CollectionFeature.ALLOWS_NULL_QUERIES) 150 .createTestSuite()); 151 152 suite.addTest( 153 ListTestSuiteBuilder.using(new ImmutableSetAsListGenerator()) 154 .named("ImmutableSet.asList") 155 .withFeatures( 156 CollectionSize.ANY, 157 CollectionFeature.REJECTS_DUPLICATES_AT_CREATION, 158 CollectionFeature.SERIALIZABLE, 159 CollectionFeature.ALLOWS_NULL_QUERIES) 160 .createTestSuite()); 161 162 suite.addTestSuite(ImmutableSetTest.class); 163 suite.addTestSuite(FloodingTest.class); 164 165 return suite; 166 } 167 168 @Override of()169 protected <E extends Comparable<? super E>> Set<E> of() { 170 return ImmutableSet.of(); 171 } 172 173 @Override of(E e)174 protected <E extends Comparable<? super E>> Set<E> of(E e) { 175 return ImmutableSet.of(e); 176 } 177 178 @Override of(E e1, E e2)179 protected <E extends Comparable<? super E>> Set<E> of(E e1, E e2) { 180 return ImmutableSet.of(e1, e2); 181 } 182 183 @Override of(E e1, E e2, E e3)184 protected <E extends Comparable<? super E>> Set<E> of(E e1, E e2, E e3) { 185 return ImmutableSet.of(e1, e2, e3); 186 } 187 188 @Override of(E e1, E e2, E e3, E e4)189 protected <E extends Comparable<? super E>> Set<E> of(E e1, E e2, E e3, E e4) { 190 return ImmutableSet.of(e1, e2, e3, e4); 191 } 192 193 @Override of(E e1, E e2, E e3, E e4, E e5)194 protected <E extends Comparable<? super E>> Set<E> of(E e1, E e2, E e3, E e4, E e5) { 195 return ImmutableSet.of(e1, e2, e3, e4, e5); 196 } 197 198 @SuppressWarnings("unchecked") 199 @Override of( E e1, E e2, E e3, E e4, E e5, E e6, E... rest)200 protected <E extends Comparable<? super E>> Set<E> of( 201 E e1, E e2, E e3, E e4, E e5, E e6, E... rest) { 202 return ImmutableSet.of(e1, e2, e3, e4, e5, e6, rest); 203 } 204 205 @Override copyOf(E[] elements)206 protected <E extends Comparable<? super E>> Set<E> copyOf(E[] elements) { 207 return ImmutableSet.copyOf(elements); 208 } 209 210 @Override copyOf(Collection<? extends E> elements)211 protected <E extends Comparable<? super E>> Set<E> copyOf(Collection<? extends E> elements) { 212 return ImmutableSet.copyOf(elements); 213 } 214 215 @Override copyOf(Iterable<? extends E> elements)216 protected <E extends Comparable<? super E>> Set<E> copyOf(Iterable<? extends E> elements) { 217 return ImmutableSet.copyOf(elements); 218 } 219 220 @Override copyOf(Iterator<? extends E> elements)221 protected <E extends Comparable<? super E>> Set<E> copyOf(Iterator<? extends E> elements) { 222 return ImmutableSet.copyOf(elements); 223 } 224 testCreation_allDuplicates()225 public void testCreation_allDuplicates() { 226 ImmutableSet<String> set = ImmutableSet.copyOf(Lists.newArrayList("a", "a")); 227 assertTrue(set instanceof SingletonImmutableSet); 228 assertEquals(Lists.newArrayList("a"), Lists.newArrayList(set)); 229 } 230 testCreation_oneDuplicate()231 public void testCreation_oneDuplicate() { 232 // now we'll get the varargs overload 233 ImmutableSet<String> set = 234 ImmutableSet.of("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "a"); 235 assertEquals( 236 Lists.newArrayList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"), 237 Lists.newArrayList(set)); 238 } 239 testCreation_manyDuplicates()240 public void testCreation_manyDuplicates() { 241 // now we'll get the varargs overload 242 ImmutableSet<String> set = 243 ImmutableSet.of("a", "b", "c", "c", "c", "c", "b", "b", "a", "a", "c", "c", "c", "a"); 244 assertThat(set).containsExactly("a", "b", "c").inOrder(); 245 } 246 testCreation_arrayOfArray()247 public void testCreation_arrayOfArray() { 248 String[] array = new String[] {"a"}; 249 Set<String[]> set = ImmutableSet.<String[]>of(array); 250 assertEquals(Collections.singleton(array), set); 251 } 252 253 @GwtIncompatible // ImmutableSet.chooseTableSize testChooseTableSize()254 public void testChooseTableSize() { 255 assertEquals(8, ImmutableSet.chooseTableSize(3)); 256 assertEquals(8, ImmutableSet.chooseTableSize(4)); 257 258 assertEquals(1 << 29, ImmutableSet.chooseTableSize(1 << 28)); 259 assertEquals(1 << 29, ImmutableSet.chooseTableSize((1 << 29) * 3 / 5)); 260 261 // Now we hit the cap 262 assertEquals(1 << 30, ImmutableSet.chooseTableSize(1 << 29)); 263 assertEquals(1 << 30, ImmutableSet.chooseTableSize((1 << 30) - 1)); 264 265 // Now we've gone too far 266 try { 267 ImmutableSet.chooseTableSize(1 << 30); 268 fail(); 269 } catch (IllegalArgumentException expected) { 270 } 271 } 272 273 @GwtIncompatible // RegularImmutableSet.table not in emulation testResizeTable()274 public void testResizeTable() { 275 verifyTableSize(100, 2, 8); 276 verifyTableSize(100, 5, 8); 277 verifyTableSize(100, 33, 64); 278 verifyTableSize(17, 17, 32); 279 verifyTableSize(17, 16, 32); 280 verifyTableSize(17, 15, 32); 281 } 282 283 @GwtIncompatible // RegularImmutableSet.table not in emulation verifyTableSize(int inputSize, int setSize, int tableSize)284 private void verifyTableSize(int inputSize, int setSize, int tableSize) { 285 Builder<Integer> builder = ImmutableSet.builder(); 286 for (int i = 0; i < inputSize; i++) { 287 builder.add(i % setSize); 288 } 289 ImmutableSet<Integer> set = builder.build(); 290 assertTrue(set instanceof RegularImmutableSet); 291 assertEquals( 292 "Input size " + inputSize + " and set size " + setSize, 293 tableSize, 294 ((RegularImmutableSet<Integer>) set).table.length); 295 } 296 testCopyOf_copiesImmutableSortedSet()297 public void testCopyOf_copiesImmutableSortedSet() { 298 ImmutableSortedSet<String> sortedSet = ImmutableSortedSet.of("a"); 299 ImmutableSet<String> copy = ImmutableSet.copyOf(sortedSet); 300 assertNotSame(sortedSet, copy); 301 } 302 testToImmutableSet()303 public void testToImmutableSet() { 304 Collector<String, ?, ImmutableSet<String>> collector = ImmutableSet.toImmutableSet(); 305 Equivalence<ImmutableSet<String>> equivalence = 306 Equivalence.equals().onResultOf(ImmutableSet::asList); 307 CollectorTester.of(collector, equivalence) 308 .expectCollects(ImmutableSet.of("a", "b", "c", "d"), "a", "b", "a", "c", "b", "b", "d"); 309 } 310 testToImmutableSet_duplicates()311 public void testToImmutableSet_duplicates() { 312 class TypeWithDuplicates { 313 final int a; 314 final int b; 315 316 TypeWithDuplicates(int a, int b) { 317 this.a = a; 318 this.b = b; 319 } 320 321 @Override 322 public int hashCode() { 323 return a; 324 } 325 326 @Override 327 public boolean equals(Object obj) { 328 return obj instanceof TypeWithDuplicates && ((TypeWithDuplicates) obj).a == a; 329 } 330 331 public boolean fullEquals(TypeWithDuplicates other) { 332 return other != null && a == other.a && b == other.b; 333 } 334 } 335 336 Collector<TypeWithDuplicates, ?, ImmutableSet<TypeWithDuplicates>> collector = 337 ImmutableSet.toImmutableSet(); 338 BiPredicate<ImmutableSet<TypeWithDuplicates>, ImmutableSet<TypeWithDuplicates>> equivalence = 339 (set1, set2) -> { 340 if (!set1.equals(set2)) { 341 return false; 342 } 343 for (int i = 0; i < set1.size(); i++) { 344 if (!set1.asList().get(i).fullEquals(set2.asList().get(i))) { 345 return false; 346 } 347 } 348 return true; 349 }; 350 TypeWithDuplicates a = new TypeWithDuplicates(1, 1); 351 TypeWithDuplicates b1 = new TypeWithDuplicates(2, 1); 352 TypeWithDuplicates b2 = new TypeWithDuplicates(2, 2); 353 TypeWithDuplicates c = new TypeWithDuplicates(3, 1); 354 CollectorTester.of(collector, equivalence) 355 .expectCollects(ImmutableSet.of(a, b1, c), a, b1, c, b2); 356 } 357 358 @GwtIncompatible // GWT is single threaded testCopyOf_threadSafe()359 public void testCopyOf_threadSafe() { 360 verifyThreadSafe(); 361 } 362 363 @Override builder()364 <E extends Comparable<E>> Builder<E> builder() { 365 return ImmutableSet.builder(); 366 } 367 368 @Override getComplexBuilderSetLastElement()369 int getComplexBuilderSetLastElement() { 370 return LAST_COLOR_ADDED; 371 } 372 testEquals()373 public void testEquals() { 374 new EqualsTester() 375 .addEqualityGroup(ImmutableSet.of(), ImmutableSet.of()) 376 .addEqualityGroup(ImmutableSet.of(1), ImmutableSet.of(1), ImmutableSet.of(1, 1)) 377 .addEqualityGroup(ImmutableSet.of(1, 2, 1), ImmutableSet.of(2, 1, 1)) 378 .testEquals(); 379 } 380 381 /** 382 * The maximum allowed probability of falsely detecting a hash flooding attack if the input is 383 * randomly generated. 384 */ 385 private static final double HASH_FLOODING_FPP = 0.001; 386 testReuseBuilderReducingHashTableSizeWithPowerOfTwoTotalElements()387 public void testReuseBuilderReducingHashTableSizeWithPowerOfTwoTotalElements() { 388 ImmutableSet.Builder<Object> builder = ImmutableSet.builderWithExpectedSize(6); 389 builder.add(0); 390 ImmutableSet<Object> unused = builder.build(); 391 ImmutableSet<Object> subject = builder.add(1).add(2).add(3).build(); 392 assertFalse(subject.contains(4)); 393 } 394 395 public static class FloodingTest extends AbstractHashFloodingTest<Set<Object>> { FloodingTest()396 public FloodingTest() { 397 super( 398 Arrays.asList(ConstructionPathway.values()), 399 n -> n * Math.log(n), 400 ImmutableList.of( 401 QueryOp.create( 402 "contains", 403 (s, o) -> { 404 boolean unused = s.contains(o); 405 }, 406 Math::log))); 407 } 408 /** All the ways to construct an ImmutableSet. */ 409 enum ConstructionPathway implements Construction<Set<Object>> { 410 OF { 411 @Override create(List<?> list)412 public ImmutableSet<Object> create(List<?> list) { 413 Object o1 = list.get(0); 414 Object o2 = list.get(1); 415 Object o3 = list.get(2); 416 Object o4 = list.get(3); 417 Object o5 = list.get(4); 418 Object o6 = list.get(5); 419 Object[] rest = list.subList(6, list.size()).toArray(); 420 return ImmutableSet.of(o1, o2, o3, o4, o5, o6, rest); 421 } 422 }, 423 COPY_OF_ARRAY { 424 @Override create(List<?> list)425 public ImmutableSet<Object> create(List<?> list) { 426 return ImmutableSet.copyOf(list.toArray()); 427 } 428 }, 429 COPY_OF_LIST { 430 @Override create(List<?> list)431 public ImmutableSet<Object> create(List<?> list) { 432 return ImmutableSet.copyOf(list); 433 } 434 }, 435 BUILDER_ADD_ONE_BY_ONE { 436 @Override create(List<?> list)437 public ImmutableSet<Object> create(List<?> list) { 438 ImmutableSet.Builder<Object> builder = ImmutableSet.builder(); 439 for (Object o : list) { 440 builder.add(o); 441 } 442 return builder.build(); 443 } 444 }, 445 BUILDER_ADD_ARRAY { 446 @Override create(List<?> list)447 public ImmutableSet<Object> create(List<?> list) { 448 ImmutableSet.Builder<Object> builder = ImmutableSet.builder(); 449 builder.add(list.toArray()); 450 return builder.build(); 451 } 452 }, 453 BUILDER_ADD_LIST { 454 @Override create(List<?> list)455 public ImmutableSet<Object> create(List<?> list) { 456 ImmutableSet.Builder<Object> builder = ImmutableSet.builder(); 457 builder.addAll(list); 458 return builder.build(); 459 } 460 }; 461 } 462 } 463 } 464