• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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