• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 Google Inc.
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.inject.internal;
18 
19 import static com.google.inject.internal.RealMapBinder.entryOfJavaxProviderOf;
20 import static com.google.inject.internal.RealMapBinder.entryOfProviderOf;
21 import static com.google.inject.internal.RealMapBinder.mapOf;
22 import static com.google.inject.internal.RealMapBinder.mapOfCollectionOfJavaxProviderOf;
23 import static com.google.inject.internal.RealMapBinder.mapOfCollectionOfProviderOf;
24 import static com.google.inject.internal.RealMapBinder.mapOfJavaxProviderOf;
25 import static com.google.inject.internal.RealMapBinder.mapOfProviderOf;
26 import static com.google.inject.internal.RealMapBinder.mapOfSetOfJavaxProviderOf;
27 import static com.google.inject.internal.RealMapBinder.mapOfSetOfProviderOf;
28 import static com.google.inject.internal.RealMultibinder.collectionOfJavaxProvidersOf;
29 import static com.google.inject.internal.RealMultibinder.collectionOfProvidersOf;
30 import static com.google.inject.internal.RealMultibinder.setOf;
31 import static com.google.inject.internal.SpiUtils.BindType.INSTANCE;
32 import static com.google.inject.internal.SpiUtils.BindType.LINKED;
33 import static com.google.inject.internal.SpiUtils.BindType.PROVIDER_INSTANCE;
34 import static com.google.inject.internal.SpiUtils.BindType.PROVIDER_KEY;
35 import static com.google.inject.internal.SpiUtils.VisitType.BOTH;
36 import static com.google.inject.internal.SpiUtils.VisitType.INJECTOR;
37 import static com.google.inject.internal.SpiUtils.VisitType.MODULE;
38 import static junit.framework.Assert.assertEquals;
39 import static junit.framework.Assert.assertFalse;
40 import static junit.framework.Assert.assertNotNull;
41 import static junit.framework.Assert.assertNull;
42 import static junit.framework.Assert.assertTrue;
43 import static junit.framework.Assert.fail;
44 
45 import com.google.common.base.Joiner;
46 import com.google.common.base.Objects;
47 import com.google.common.base.Optional;
48 import com.google.common.collect.ImmutableMap;
49 import com.google.common.collect.ImmutableSet;
50 import com.google.common.collect.Lists;
51 import com.google.common.collect.Maps;
52 import com.google.common.collect.Multimap;
53 import com.google.common.collect.MultimapBuilder;
54 import com.google.common.collect.Sets;
55 import com.google.inject.Binding;
56 import com.google.inject.Guice;
57 import com.google.inject.Injector;
58 import com.google.inject.Key;
59 import com.google.inject.Module;
60 import com.google.inject.Provider;
61 import com.google.inject.TypeLiteral;
62 import com.google.inject.internal.Indexer.IndexedBinding;
63 import com.google.inject.internal.RealMapBinder.ProviderMapEntry;
64 import com.google.inject.multibindings.MapBinderBinding;
65 import com.google.inject.multibindings.MultibinderBinding;
66 import com.google.inject.multibindings.MultibindingsTargetVisitor;
67 import com.google.inject.multibindings.OptionalBinderBinding;
68 import com.google.inject.spi.DefaultBindingTargetVisitor;
69 import com.google.inject.spi.Element;
70 import com.google.inject.spi.Elements;
71 import com.google.inject.spi.InstanceBinding;
72 import com.google.inject.spi.LinkedKeyBinding;
73 import com.google.inject.spi.ProviderInstanceBinding;
74 import com.google.inject.spi.ProviderKeyBinding;
75 import com.google.inject.spi.ProviderLookup;
76 import java.util.HashSet;
77 import java.util.List;
78 import java.util.Map;
79 import java.util.Set;
80 
81 /**
82  * Utilities for testing the Multibinder & MapBinder extension SPI.
83  *
84  * @author sameb@google.com (Sam Berlin)
85  */
86 public class SpiUtils {
87 
88   private static final boolean HAS_JAVA_OPTIONAL;
89 
90   static {
91     Class<?> optional = null;
92     try {
93       optional = Class.forName("java.util.Optional");
94     } catch (ClassNotFoundException ignored) {
95     }
96     HAS_JAVA_OPTIONAL = optional != null;
97   }
98 
99   /** The kind of test we should perform. A live Injector, a raw Elements (Module) test, or both. */
100   enum VisitType {
101     INJECTOR,
102     MODULE,
103     BOTH
104   }
105 
106   /**
107    * Asserts that MapBinderBinding visitors for work correctly.
108    *
109    * @param <T> The type of the binding
110    * @param mapKey The key the map belongs to.
111    * @param keyType the TypeLiteral of the key of the map
112    * @param valueType the TypeLiteral of the value of the map
113    * @param modules The modules that define the mapbindings
114    * @param visitType The kind of test we should perform. A live Injector, a raw Elements (Module)
115    *     test, or both.
116    * @param allowDuplicates If duplicates are allowed.
117    * @param expectedMapBindings The number of other mapbinders we expect to see.
118    * @param results The kind of bindings contained in the mapbinder.
119    */
assertMapVisitor( Key<T> mapKey, TypeLiteral<?> keyType, TypeLiteral<?> valueType, Iterable<? extends Module> modules, VisitType visitType, boolean allowDuplicates, int expectedMapBindings, MapResult... results)120   static <T> void assertMapVisitor(
121       Key<T> mapKey,
122       TypeLiteral<?> keyType,
123       TypeLiteral<?> valueType,
124       Iterable<? extends Module> modules,
125       VisitType visitType,
126       boolean allowDuplicates,
127       int expectedMapBindings,
128       MapResult... results) {
129     if (visitType == null) {
130       fail("must test something");
131     }
132 
133     if (visitType == BOTH || visitType == INJECTOR) {
134       mapInjectorTest(
135           mapKey, keyType, valueType, modules, allowDuplicates, expectedMapBindings, results);
136     }
137 
138     if (visitType == BOTH || visitType == MODULE) {
139       mapModuleTest(
140           mapKey, keyType, valueType, modules, allowDuplicates, expectedMapBindings, results);
141     }
142   }
143 
144   @SuppressWarnings("unchecked")
mapInjectorTest( Key<T> mapKey, TypeLiteral<?> keyType, TypeLiteral<?> valueType, Iterable<? extends Module> modules, boolean allowDuplicates, int expectedMapBindings, MapResult... results)145   private static <T> void mapInjectorTest(
146       Key<T> mapKey,
147       TypeLiteral<?> keyType,
148       TypeLiteral<?> valueType,
149       Iterable<? extends Module> modules,
150       boolean allowDuplicates,
151       int expectedMapBindings,
152       MapResult... results) {
153     Injector injector = Guice.createInjector(modules);
154     Visitor<T> visitor = new Visitor<>();
155     Binding<T> mapBinding = injector.getBinding(mapKey);
156     MapBinderBinding<T> mapbinder = (MapBinderBinding<T>) mapBinding.acceptTargetVisitor(visitor);
157     assertNotNull(mapbinder);
158     assertEquals(keyType, mapbinder.getKeyTypeLiteral());
159     assertEquals(valueType, mapbinder.getValueTypeLiteral());
160     assertEquals(allowDuplicates, mapbinder.permitsDuplicates());
161     List<Map.Entry<?, Binding<?>>> entries = Lists.newArrayList(mapbinder.getEntries());
162     List<MapResult> mapResults = Lists.newArrayList(results);
163     assertEquals(
164         "wrong entries, expected: " + mapResults + ", but was: " + entries,
165         mapResults.size(),
166         entries.size());
167 
168     for (MapResult result : mapResults) {
169       Map.Entry<?, Binding<?>> found = null;
170       for (Map.Entry<?, Binding<?>> entry : entries) {
171         Object key = entry.getKey();
172         Binding<?> value = entry.getValue();
173         if (key.equals(result.k) && matches(value, result.v)) {
174           found = entry;
175           break;
176         }
177       }
178       if (found == null) {
179         fail("Could not find entry: " + result + " in remaining entries: " + entries);
180       } else {
181         assertTrue(
182             "mapBinder doesn't contain: " + found.getValue(),
183             mapbinder.containsElement(found.getValue()));
184         entries.remove(found);
185       }
186     }
187 
188     if (!entries.isEmpty()) {
189       fail("Found all entries of: " + mapResults + ", but more were left over: " + entries);
190     }
191 
192     Key<?> mapOfJavaxProvider = mapKey.ofType(mapOfJavaxProviderOf(keyType, valueType));
193     Key<?> mapOfProvider = mapKey.ofType(mapOfProviderOf(keyType, valueType));
194     Key<?> mapOfSetOfProvider = mapKey.ofType(mapOfSetOfProviderOf(keyType, valueType));
195     Key<?> mapOfSetOfJavaxProvider = mapKey.ofType(mapOfSetOfJavaxProviderOf(keyType, valueType));
196     Key<?> mapOfCollectionOfProvider =
197         mapKey.ofType(mapOfCollectionOfProviderOf(keyType, valueType));
198     Key<?> mapOfCollectionOfJavaxProvider =
199         mapKey.ofType(mapOfCollectionOfJavaxProviderOf(keyType, valueType));
200     Key<?> mapOfSet = mapKey.ofType(mapOf(keyType, setOf(valueType)));
201     Key<?> setOfEntry = mapKey.ofType(setOf(entryOfProviderOf(keyType, valueType)));
202     Key<?> setOfJavaxEntry = mapKey.ofType(setOf(entryOfJavaxProviderOf(keyType, valueType)));
203     Key<?> collectionOfProvidersOfEntryOfProvider =
204         mapKey.ofType(collectionOfProvidersOf(entryOfProviderOf(keyType, valueType)));
205     Key<?> collectionOfJavaxProvidersOfEntryOfProvider =
206         mapKey.ofType(collectionOfJavaxProvidersOf(entryOfProviderOf(keyType, valueType)));
207     boolean entrySetMatch = false;
208     boolean javaxEntrySetMatch = false;
209     boolean mapJavaxProviderMatch = false;
210     boolean mapProviderMatch = false;
211     boolean mapSetMatch = false;
212     boolean mapSetProviderMatch = false;
213     boolean mapSetJavaxProviderMatch = false;
214     boolean mapCollectionProviderMatch = false;
215     boolean mapCollectionJavaxProviderMatch = false;
216     boolean collectionOfProvidersOfEntryOfProviderMatch = false;
217     boolean collectionOfJavaxProvidersOfEntryOfProviderMatch = false;
218     List<Object> otherMapBindings = Lists.newArrayList();
219     List<Binding> otherMatches = Lists.newArrayList();
220     Multimap<Object, IndexedBinding> indexedEntries =
221         MultimapBuilder.hashKeys().hashSetValues().build();
222     Indexer indexer = new Indexer(injector);
223     int duplicates = 0;
224     for (Binding b : injector.getAllBindings().values()) {
225       boolean contains = mapbinder.containsElement(b);
226       Object visited = b.acceptTargetVisitor(visitor);
227       if (visited instanceof MapBinderBinding) {
228         if (visited.equals(mapbinder)) {
229           assertTrue(contains);
230         } else {
231           otherMapBindings.add(visited);
232         }
233       } else if (b.getKey().equals(mapOfProvider)) {
234         assertTrue(contains);
235         mapProviderMatch = true;
236       } else if (b.getKey().equals(mapOfJavaxProvider)) {
237         assertTrue(contains);
238         mapJavaxProviderMatch = true;
239       } else if (b.getKey().equals(mapOfSet)) {
240         assertTrue(contains);
241         mapSetMatch = true;
242       } else if (b.getKey().equals(mapOfSetOfProvider)) {
243         assertTrue(contains);
244         mapSetProviderMatch = true;
245       } else if (b.getKey().equals(mapOfSetOfJavaxProvider)) {
246         assertTrue(contains);
247         mapSetJavaxProviderMatch = true;
248       } else if (b.getKey().equals(mapOfCollectionOfProvider)) {
249         assertTrue(contains);
250         mapCollectionProviderMatch = true;
251       } else if (b.getKey().equals(mapOfCollectionOfJavaxProvider)) {
252         assertTrue(contains);
253         mapCollectionJavaxProviderMatch = true;
254       } else if (b.getKey().equals(setOfEntry)) {
255         assertTrue(contains);
256         entrySetMatch = true;
257         // Validate that this binding is also a MultibinderBinding.
258         assertTrue(b.acceptTargetVisitor(visitor) instanceof MultibinderBinding);
259       } else if (b.getKey().equals(setOfJavaxEntry)) {
260         assertTrue(contains);
261         javaxEntrySetMatch = true;
262       } else if (b.getKey().equals(collectionOfProvidersOfEntryOfProvider)) {
263         assertTrue(contains);
264         collectionOfProvidersOfEntryOfProviderMatch = true;
265       } else if (b.getKey().equals(collectionOfJavaxProvidersOfEntryOfProvider)) {
266         assertTrue(contains);
267         collectionOfJavaxProvidersOfEntryOfProviderMatch = true;
268       } else if (contains) {
269         if (b instanceof ProviderInstanceBinding) {
270           ProviderInstanceBinding<?> pib = (ProviderInstanceBinding<?>) b;
271           if (pib.getUserSuppliedProvider() instanceof ProviderMapEntry) {
272             // weird casting required to workaround compilation issues with jdk6
273             ProviderMapEntry<?, ?> pme =
274                 (ProviderMapEntry<?, ?>) (Provider) pib.getUserSuppliedProvider();
275             Binding<?> valueBinding = injector.getBinding(pme.getValueKey());
276             if (indexer.isIndexable(valueBinding)
277                 && !indexedEntries.put(pme.getKey(), valueBinding.acceptTargetVisitor(indexer))) {
278               duplicates++;
279             }
280           }
281         }
282         otherMatches.add(b);
283       }
284     }
285 
286     int sizeOfOther = otherMatches.size();
287     if (allowDuplicates) {
288       sizeOfOther--; // account for 1 duplicate binding
289     }
290     // Multiply by two because each has a value and Map.Entry.
291     int expectedSize = 2 * (mapResults.size() + duplicates);
292     assertEquals(
293         "Incorrect other matches:\n\t" + Joiner.on("\n\t").join(otherMatches),
294         expectedSize,
295         sizeOfOther);
296     assertTrue(entrySetMatch);
297     assertTrue(javaxEntrySetMatch);
298     assertTrue(mapProviderMatch);
299     assertTrue(mapJavaxProviderMatch);
300     assertTrue(collectionOfProvidersOfEntryOfProviderMatch);
301     assertTrue(collectionOfJavaxProvidersOfEntryOfProviderMatch);
302     assertEquals(allowDuplicates, mapSetMatch);
303     assertEquals(allowDuplicates, mapSetProviderMatch);
304     assertEquals(allowDuplicates, mapSetJavaxProviderMatch);
305     assertEquals(allowDuplicates, mapCollectionJavaxProviderMatch);
306     assertEquals(allowDuplicates, mapCollectionProviderMatch);
307     assertEquals(
308         "other MapBindings found: " + otherMapBindings,
309         expectedMapBindings,
310         otherMapBindings.size());
311   }
312 
313   @SuppressWarnings("unchecked")
mapModuleTest( Key<T> mapKey, TypeLiteral<?> keyType, TypeLiteral<?> valueType, Iterable<? extends Module> modules, boolean allowDuplicates, int expectedMapBindings, MapResult<?, ?>... results)314   private static <T> void mapModuleTest(
315       Key<T> mapKey,
316       TypeLiteral<?> keyType,
317       TypeLiteral<?> valueType,
318       Iterable<? extends Module> modules,
319       boolean allowDuplicates,
320       int expectedMapBindings,
321       MapResult<?, ?>... results) {
322     Set<Element> elements = ImmutableSet.copyOf(Elements.getElements(modules));
323     Visitor<T> visitor = new Visitor<>();
324     MapBinderBinding<T> mapbinder = null;
325     Map<Key<?>, Binding<?>> keyMap = Maps.newHashMap();
326     for (Element element : elements) {
327       if (element instanceof Binding) {
328         Binding<?> binding = (Binding<?>) element;
329         keyMap.put(binding.getKey(), binding);
330         if (binding.getKey().equals(mapKey)) {
331           mapbinder = (MapBinderBinding<T>) ((Binding<T>) binding).acceptTargetVisitor(visitor);
332         }
333       }
334     }
335     assertNotNull(mapbinder);
336 
337     List<MapResult<?, ?>> mapResults = Lists.newArrayList(results);
338 
339     // Make sure the entries returned from getEntries(elements) are correct.
340     // Because getEntries() can return duplicates, make sure to continue searching, even
341     // after we find one match.
342     List<Map.Entry<?, Binding<?>>> entries = Lists.newArrayList(mapbinder.getEntries(elements));
343     for (MapResult<?, ?> result : mapResults) {
344       List<Map.Entry<?, Binding<?>>> foundEntries = Lists.newArrayList();
345       for (Map.Entry<?, Binding<?>> entry : entries) {
346         Object key = entry.getKey();
347         Binding<?> value = entry.getValue();
348         if (key.equals(result.k) && matches(value, result.v)) {
349           assertTrue(
350               "mapBinder doesn't contain: " + entry.getValue(),
351               mapbinder.containsElement(entry.getValue()));
352           foundEntries.add(entry);
353         }
354       }
355       assertTrue(
356           "Could not find entry: " + result + " in remaining entries: " + entries,
357           !foundEntries.isEmpty());
358 
359       entries.removeAll(foundEntries);
360     }
361 
362     assertTrue(
363         "Found all entries of: " + mapResults + ", but more were left over: " + entries,
364         entries.isEmpty());
365 
366     assertEquals(keyType, mapbinder.getKeyTypeLiteral());
367     assertEquals(valueType, mapbinder.getValueTypeLiteral());
368 
369     Key<?> mapOfProvider = mapKey.ofType(mapOfProviderOf(keyType, valueType));
370     Key<?> mapOfJavaxProvider = mapKey.ofType(mapOfJavaxProviderOf(keyType, valueType));
371     Key<?> mapOfSetOfProvider = mapKey.ofType(mapOfSetOfProviderOf(keyType, valueType));
372     Key<?> mapOfSetOfJavaxProvider = mapKey.ofType(mapOfSetOfJavaxProviderOf(keyType, valueType));
373     Key<?> mapOfCollectionOfProvider =
374         mapKey.ofType(mapOfCollectionOfProviderOf(keyType, valueType));
375     Key<?> mapOfCollectionOfJavaxProvider =
376         mapKey.ofType(mapOfCollectionOfJavaxProviderOf(keyType, valueType));
377     Key<?> mapOfSet = mapKey.ofType(mapOf(keyType, setOf(valueType)));
378     Key<?> setOfEntry = mapKey.ofType(setOf(entryOfProviderOf(keyType, valueType)));
379     Key<?> setOfJavaxEntry = mapKey.ofType(setOf(entryOfJavaxProviderOf(keyType, valueType)));
380     Key<?> collectionOfProvidersOfEntryOfProvider =
381         mapKey.ofType(collectionOfProvidersOf(entryOfProviderOf(keyType, valueType)));
382     Key<?> collectionOfJavaxProvidersOfEntryOfProvider =
383         mapKey.ofType(collectionOfJavaxProvidersOf(entryOfProviderOf(keyType, valueType)));
384     boolean entrySetMatch = false;
385     boolean entrySetJavaxMatch = false;
386     boolean mapProviderMatch = false;
387     boolean mapJavaxProviderMatch = false;
388     boolean mapSetMatch = false;
389     boolean mapSetProviderMatch = false;
390     boolean mapSetJavaxProviderMatch = false;
391     boolean mapCollectionProviderMatch = false;
392     boolean mapCollectionJavaxProviderMatch = false;
393     boolean collectionOfProvidersOfEntryOfProviderMatch = false;
394     boolean collectionOfJavaxProvidersOfEntryOfProviderMatch = false;
395     List<Object> otherMapBindings = Lists.newArrayList();
396     List<Element> otherMatches = Lists.newArrayList();
397     List<Element> otherElements = Lists.newArrayList();
398     Indexer indexer = new Indexer(null);
399     Multimap<Object, IndexedBinding> indexedEntries =
400         MultimapBuilder.hashKeys().hashSetValues().build();
401     int duplicates = 0;
402     for (Element element : elements) {
403       boolean contains = mapbinder.containsElement(element);
404       if (!contains) {
405         otherElements.add(element);
406       }
407       boolean matched = false;
408       Key key = null;
409       Binding b = null;
410       if (element instanceof Binding) {
411         b = (Binding) element;
412         if (b instanceof ProviderInstanceBinding) {
413           ProviderInstanceBinding<?> pb = (ProviderInstanceBinding<?>) b;
414           if (pb.getUserSuppliedProvider() instanceof ProviderMapEntry) {
415             // weird casting required to workaround jdk6 compilation problems
416             ProviderMapEntry<?, ?> pme =
417                 (ProviderMapEntry<?, ?>) (Provider) pb.getUserSuppliedProvider();
418             Binding<?> valueBinding = keyMap.get(pme.getValueKey());
419             if (indexer.isIndexable(valueBinding)
420                 && !indexedEntries.put(pme.getKey(), valueBinding.acceptTargetVisitor(indexer))) {
421               duplicates++;
422             }
423           }
424         }
425 
426         key = b.getKey();
427         Object visited = b.acceptTargetVisitor(visitor);
428         if (visited instanceof MapBinderBinding) {
429           matched = true;
430           if (visited.equals(mapbinder)) {
431             assertTrue(contains);
432           } else {
433             otherMapBindings.add(visited);
434           }
435         }
436       } else if (element instanceof ProviderLookup) {
437         key = ((ProviderLookup) element).getKey();
438       }
439 
440       if (!matched && key != null) {
441         if (key.equals(mapOfProvider)) {
442           matched = true;
443           assertTrue(contains);
444           mapProviderMatch = true;
445         } else if (key.equals(mapOfJavaxProvider)) {
446           matched = true;
447           assertTrue(contains);
448           mapJavaxProviderMatch = true;
449         } else if (key.equals(mapOfSet)) {
450           matched = true;
451           assertTrue(contains);
452           mapSetMatch = true;
453         } else if (key.equals(mapOfSetOfProvider)) {
454           matched = true;
455           assertTrue(contains);
456           mapSetProviderMatch = true;
457         } else if (key.equals(mapOfSetOfJavaxProvider)) {
458           matched = true;
459           assertTrue(contains);
460           mapSetJavaxProviderMatch = true;
461         } else if (key.equals(mapOfCollectionOfProvider)) {
462           matched = true;
463           assertTrue(contains);
464           mapCollectionProviderMatch = true;
465         } else if (key.equals(mapOfCollectionOfJavaxProvider)) {
466           matched = true;
467           assertTrue(contains);
468           mapCollectionJavaxProviderMatch = true;
469         } else if (key.equals(setOfEntry)) {
470           matched = true;
471           assertTrue(contains);
472           entrySetMatch = true;
473           // Validate that this binding is also a MultibinderBinding.
474           if (b != null) {
475             assertTrue(b.acceptTargetVisitor(visitor) instanceof MultibinderBinding);
476           }
477         } else if (key.equals(setOfJavaxEntry)) {
478           matched = true;
479           assertTrue(contains);
480           entrySetJavaxMatch = true;
481         } else if (key.equals(collectionOfProvidersOfEntryOfProvider)) {
482           matched = true;
483           assertTrue(contains);
484           collectionOfProvidersOfEntryOfProviderMatch = true;
485         } else if (key.equals(collectionOfJavaxProvidersOfEntryOfProvider)) {
486           matched = true;
487           assertTrue(contains);
488           collectionOfJavaxProvidersOfEntryOfProviderMatch = true;
489         }
490       }
491 
492       if (!matched && contains) {
493         otherMatches.add(element);
494       }
495     }
496 
497     int otherMatchesSize = otherMatches.size();
498     if (allowDuplicates) {
499       otherMatchesSize--; // allow for 1 duplicate binding
500     }
501     // Multiply by 2 because each has a value, and Map.Entry
502     int expectedSize = (mapResults.size() + duplicates) * 2;
503     assertEquals(
504         "incorrect number of contains, leftover matches:\n" + Joiner.on("\n\t").join(otherMatches),
505         expectedSize,
506         otherMatchesSize);
507 
508     assertTrue(entrySetMatch);
509     assertTrue(entrySetJavaxMatch);
510     assertTrue(mapProviderMatch);
511     assertTrue(mapJavaxProviderMatch);
512     assertTrue(collectionOfProvidersOfEntryOfProviderMatch);
513     assertTrue(collectionOfJavaxProvidersOfEntryOfProviderMatch);
514     assertEquals(allowDuplicates, mapSetMatch);
515     assertEquals(allowDuplicates, mapSetProviderMatch);
516     assertEquals(allowDuplicates, mapSetJavaxProviderMatch);
517     assertEquals(allowDuplicates, mapCollectionProviderMatch);
518     assertEquals(allowDuplicates, mapCollectionJavaxProviderMatch);
519     assertEquals(
520         "other MapBindings found: " + otherMapBindings,
521         expectedMapBindings,
522         otherMapBindings.size());
523 
524     // Validate that we can construct an injector out of the remaining bindings.
525     Guice.createInjector(Elements.getModule(otherElements));
526   }
527 
528   /**
529    * Asserts that MultibinderBinding visitors work correctly.
530    *
531    * @param <T> The type of the binding
532    * @param setKey The key the set belongs to.
533    * @param elementType the TypeLiteral of the element
534    * @param modules The modules that define the multibindings
535    * @param visitType The kind of test we should perform. A live Injector, a raw Elements (Module)
536    *     test, or both.
537    * @param allowDuplicates If duplicates are allowed.
538    * @param expectedMultibindings The number of other multibinders we expect to see.
539    * @param results The kind of bindings contained in the multibinder.
540    */
assertSetVisitor( Key<Set<T>> setKey, TypeLiteral<?> elementType, Iterable<? extends Module> modules, VisitType visitType, boolean allowDuplicates, int expectedMultibindings, BindResult... results)541   static <T> void assertSetVisitor(
542       Key<Set<T>> setKey,
543       TypeLiteral<?> elementType,
544       Iterable<? extends Module> modules,
545       VisitType visitType,
546       boolean allowDuplicates,
547       int expectedMultibindings,
548       BindResult... results) {
549     if (visitType == null) {
550       fail("must test something");
551     }
552 
553     if (visitType == BOTH || visitType == INJECTOR) {
554       setInjectorTest(
555           setKey, elementType, modules, allowDuplicates, expectedMultibindings, results);
556     }
557 
558     if (visitType == BOTH || visitType == MODULE) {
559       setModuleTest(setKey, elementType, modules, allowDuplicates, expectedMultibindings, results);
560     }
561   }
562 
563   @SuppressWarnings("unchecked")
setInjectorTest( Key<Set<T>> setKey, TypeLiteral<?> elementType, Iterable<? extends Module> modules, boolean allowDuplicates, int otherMultibindings, BindResult... results)564   private static <T> void setInjectorTest(
565       Key<Set<T>> setKey,
566       TypeLiteral<?> elementType,
567       Iterable<? extends Module> modules,
568       boolean allowDuplicates,
569       int otherMultibindings,
570       BindResult... results) {
571     Key<?> collectionOfProvidersKey = setKey.ofType(collectionOfProvidersOf(elementType));
572     Key<?> collectionOfJavaxProvidersKey = setKey.ofType(collectionOfJavaxProvidersOf(elementType));
573     Injector injector = Guice.createInjector(modules);
574     Visitor<Set<T>> visitor = new Visitor<>();
575     Binding<Set<T>> binding = injector.getBinding(setKey);
576     MultibinderBinding<Set<T>> multibinder =
577         (MultibinderBinding<Set<T>>) binding.acceptTargetVisitor(visitor);
578     assertNotNull(multibinder);
579     assertEquals(elementType, multibinder.getElementTypeLiteral());
580     assertEquals(allowDuplicates, multibinder.permitsDuplicates());
581     List<Binding<?>> elements = Lists.newArrayList(multibinder.getElements());
582     List<BindResult> bindResults = Lists.newArrayList(results);
583     assertEquals(
584         "wrong bind elements, expected: " + bindResults + ", but was: " + multibinder.getElements(),
585         bindResults.size(),
586         elements.size());
587 
588     for (BindResult result : bindResults) {
589       Binding found = null;
590       for (Binding item : elements) {
591         if (matches(item, result)) {
592           found = item;
593           break;
594         }
595       }
596       if (found == null) {
597         fail("Could not find element: " + result + " in remaining elements: " + elements);
598       } else {
599         elements.remove(found);
600       }
601     }
602 
603     if (!elements.isEmpty()) {
604       fail("Found all elements of: " + bindResults + ", but more were left over: " + elements);
605     }
606 
607     Set<Binding> setOfElements = new HashSet<Binding>(multibinder.getElements());
608     Set<IndexedBinding> setOfIndexed = Sets.newHashSet();
609     Indexer indexer = new Indexer(injector);
610     for (Binding<?> oneBinding : setOfElements) {
611       setOfIndexed.add(oneBinding.acceptTargetVisitor(indexer));
612     }
613 
614     List<Object> otherMultibinders = Lists.newArrayList();
615     List<Binding> otherContains = Lists.newArrayList();
616     boolean collectionOfProvidersMatch = false;
617     boolean collectionOfJavaxProvidersMatch = false;
618     for (Binding b : injector.getAllBindings().values()) {
619       boolean contains = multibinder.containsElement(b);
620       Key key = b.getKey();
621       Object visited = b.acceptTargetVisitor(visitor);
622       if (visited != null) {
623         if (visited.equals(multibinder)) {
624           assertTrue(contains);
625         } else {
626           otherMultibinders.add(visited);
627         }
628       } else if (setOfElements.contains(b)) {
629         assertTrue(contains);
630       } else if (key.equals(collectionOfProvidersKey)) {
631         assertTrue(contains);
632         collectionOfProvidersMatch = true;
633       } else if (key.equals(collectionOfJavaxProvidersKey)) {
634         assertTrue(contains);
635         collectionOfJavaxProvidersMatch = true;
636       } else if (contains) {
637         if (!indexer.isIndexable(b) || !setOfIndexed.contains(b.acceptTargetVisitor(indexer))) {
638           otherContains.add(b);
639         }
640       }
641     }
642 
643     assertTrue(collectionOfProvidersMatch);
644     assertTrue(collectionOfJavaxProvidersMatch);
645 
646     if (allowDuplicates) {
647       assertEquals("contained more than it should: " + otherContains, 1, otherContains.size());
648     } else {
649       assertTrue("contained more than it should: " + otherContains, otherContains.isEmpty());
650     }
651     assertEquals(
652         "other multibindings found: " + otherMultibinders,
653         otherMultibindings,
654         otherMultibinders.size());
655   }
656 
657   @SuppressWarnings("unchecked")
setModuleTest( Key<Set<T>> setKey, TypeLiteral<?> elementType, Iterable<? extends Module> modules, boolean allowDuplicates, int otherMultibindings, BindResult... results)658   private static <T> void setModuleTest(
659       Key<Set<T>> setKey,
660       TypeLiteral<?> elementType,
661       Iterable<? extends Module> modules,
662       boolean allowDuplicates,
663       int otherMultibindings,
664       BindResult... results) {
665     Key<?> collectionOfProvidersKey = setKey.ofType(collectionOfProvidersOf(elementType));
666     Key<?> collectionOfJavaxProvidersKey = setKey.ofType(collectionOfJavaxProvidersOf(elementType));
667     List<BindResult> bindResults = Lists.newArrayList(results);
668     List<Element> elements = Elements.getElements(modules);
669     Visitor<T> visitor = new Visitor<>();
670     MultibinderBinding<Set<T>> multibinder = null;
671     for (Element element : elements) {
672       if (element instanceof Binding && ((Binding) element).getKey().equals(setKey)) {
673         multibinder = (MultibinderBinding<Set<T>>) ((Binding) element).acceptTargetVisitor(visitor);
674         break;
675       }
676     }
677     assertNotNull(multibinder);
678 
679     assertEquals(elementType, multibinder.getElementTypeLiteral());
680     List<Object> otherMultibinders = Lists.newArrayList();
681     Set<Element> otherContains = new HashSet<>();
682     List<Element> otherElements = Lists.newArrayList();
683     int duplicates = 0;
684     Set<IndexedBinding> setOfIndexed = Sets.newHashSet();
685     Indexer indexer = new Indexer(null);
686     boolean collectionOfProvidersMatch = false;
687     boolean collectionOfJavaxProvidersMatch = false;
688     for (Element element : elements) {
689       boolean contains = multibinder.containsElement(element);
690       if (!contains) {
691         otherElements.add(element);
692       }
693       boolean matched = false;
694       Key key = null;
695       if (element instanceof Binding) {
696         Binding binding = (Binding) element;
697         if (indexer.isIndexable(binding)
698             && !setOfIndexed.add((IndexedBinding) binding.acceptTargetVisitor(indexer))) {
699           duplicates++;
700         }
701         key = binding.getKey();
702         Object visited = binding.acceptTargetVisitor(visitor);
703         if (visited != null) {
704           matched = true;
705           if (visited.equals(multibinder)) {
706             assertTrue(contains);
707           } else {
708             otherMultibinders.add(visited);
709           }
710         }
711       }
712 
713       if (collectionOfProvidersKey.equals(key)) {
714         assertTrue(contains);
715         assertFalse(matched);
716         collectionOfProvidersMatch = true;
717       } else if (collectionOfJavaxProvidersKey.equals(key)) {
718         assertTrue(contains);
719         assertFalse(matched);
720         collectionOfJavaxProvidersMatch = true;
721       } else if (!matched && contains) {
722         otherContains.add(element);
723       }
724     }
725 
726     if (allowDuplicates) {
727       assertEquals(
728           "wrong contained elements: " + otherContains,
729           bindResults.size() + 1 + duplicates,
730           otherContains.size());
731     } else {
732       assertEquals(
733           "wrong contained elements: " + otherContains,
734           bindResults.size() + duplicates,
735           otherContains.size());
736     }
737 
738     assertEquals(
739         "other multibindings found: " + otherMultibinders,
740         otherMultibindings,
741         otherMultibinders.size());
742     assertTrue(collectionOfProvidersMatch);
743     assertTrue(collectionOfJavaxProvidersMatch);
744 
745     // Validate that we can construct an injector out of the remaining bindings.
746     Guice.createInjector(Elements.getModule(otherElements));
747   }
748 
749   /**
750    * Asserts that OptionalBinderBinding visitors for work correctly.
751    *
752    * @param <T> The type of the binding
753    * @param keyType The key OptionalBinder is binding
754    * @param modules The modules that define the bindings
755    * @param visitType The kind of test we should perform. A live Injector, a raw Elements (Module)
756    *     test, or both.
757    * @param expectedOtherOptionalBindings the # of other optional bindings we expect to see.
758    * @param expectedDefault the expected default binding, or null if none
759    * @param expectedActual the expected actual binding, or null if none
760    * @param expectedUserLinkedActual the user binding that is the actual binding, used if neither
761    *     the default nor actual are set and a user binding existed for the type.
762    */
assertOptionalVisitor( Key<T> keyType, Iterable<? extends Module> modules, VisitType visitType, int expectedOtherOptionalBindings, BindResult<?> expectedDefault, BindResult<?> expectedActual, BindResult<?> expectedUserLinkedActual)763   static <T> void assertOptionalVisitor(
764       Key<T> keyType,
765       Iterable<? extends Module> modules,
766       VisitType visitType,
767       int expectedOtherOptionalBindings,
768       BindResult<?> expectedDefault,
769       BindResult<?> expectedActual,
770       BindResult<?> expectedUserLinkedActual) {
771     if (visitType == null) {
772       fail("must test something");
773     }
774 
775     // if java.util.Optional is bound, there'll be twice as many as we expect.
776     if (HAS_JAVA_OPTIONAL) {
777       expectedOtherOptionalBindings *= 2;
778     }
779 
780     if (visitType == BOTH || visitType == INJECTOR) {
781       optionalInjectorTest(
782           keyType,
783           modules,
784           expectedOtherOptionalBindings,
785           expectedDefault,
786           expectedActual,
787           expectedUserLinkedActual);
788     }
789 
790     if (visitType == BOTH || visitType == MODULE) {
791       optionalModuleTest(
792           keyType,
793           modules,
794           expectedOtherOptionalBindings,
795           expectedDefault,
796           expectedActual,
797           expectedUserLinkedActual);
798     }
799   }
800 
801   @SuppressWarnings({"unchecked", "rawtypes"})
optionalInjectorTest( Key<T> keyType, Iterable<? extends Module> modules, int expectedOtherOptionalBindings, BindResult<?> expectedDefault, BindResult<?> expectedActual, BindResult<?> expectedUserLinkedActual)802   private static <T> void optionalInjectorTest(
803       Key<T> keyType,
804       Iterable<? extends Module> modules,
805       int expectedOtherOptionalBindings,
806       BindResult<?> expectedDefault,
807       BindResult<?> expectedActual,
808       BindResult<?> expectedUserLinkedActual) {
809     if (expectedUserLinkedActual != null) {
810       assertNull("cannot have actual if expecting user binding", expectedActual);
811       assertNull("cannot have default if expecting user binding", expectedDefault);
812     }
813 
814     Key<Optional<T>> optionalKey =
815         keyType.ofType(RealOptionalBinder.optionalOf(keyType.getTypeLiteral()));
816     Key<?> javaOptionalKey =
817         HAS_JAVA_OPTIONAL
818             ? keyType.ofType(RealOptionalBinder.javaOptionalOf(keyType.getTypeLiteral()))
819             : null;
820     Injector injector = Guice.createInjector(modules);
821     Binding<Optional<T>> optionalBinding = injector.getBinding(optionalKey);
822     Visitor visitor = new Visitor();
823     OptionalBinderBinding<Optional<T>> optionalBinder =
824         (OptionalBinderBinding<Optional<T>>) optionalBinding.acceptTargetVisitor(visitor);
825     assertNotNull(optionalBinder);
826     assertEquals(optionalKey, optionalBinder.getKey());
827 
828     Binding<?> javaOptionalBinding = null;
829     OptionalBinderBinding<?> javaOptionalBinder = null;
830     if (HAS_JAVA_OPTIONAL) {
831       javaOptionalBinding = injector.getBinding(javaOptionalKey);
832       javaOptionalBinder =
833           (OptionalBinderBinding<?>) javaOptionalBinding.acceptTargetVisitor(visitor);
834       assertNotNull(javaOptionalBinder);
835       assertEquals(javaOptionalKey, javaOptionalBinder.getKey());
836     }
837 
838     if (expectedDefault == null) {
839       assertNull("did not expect a default binding", optionalBinder.getDefaultBinding());
840       if (HAS_JAVA_OPTIONAL) {
841         assertNull("did not expect a default binding", javaOptionalBinder.getDefaultBinding());
842       }
843     } else {
844       assertTrue(
845           "expectedDefault: "
846               + expectedDefault
847               + ", actualDefault: "
848               + optionalBinder.getDefaultBinding(),
849           matches(optionalBinder.getDefaultBinding(), expectedDefault));
850       if (HAS_JAVA_OPTIONAL) {
851         assertTrue(
852             "expectedDefault: "
853                 + expectedDefault
854                 + ", actualDefault: "
855                 + javaOptionalBinder.getDefaultBinding(),
856             matches(javaOptionalBinder.getDefaultBinding(), expectedDefault));
857       }
858     }
859 
860     if (expectedActual == null && expectedUserLinkedActual == null) {
861       assertNull(optionalBinder.getActualBinding());
862       if (HAS_JAVA_OPTIONAL) {
863         assertNull(javaOptionalBinder.getActualBinding());
864       }
865     } else if (expectedActual != null) {
866       assertTrue(
867           "expectedActual: "
868               + expectedActual
869               + ", actualActual: "
870               + optionalBinder.getActualBinding(),
871           matches(optionalBinder.getActualBinding(), expectedActual));
872       if (HAS_JAVA_OPTIONAL) {
873         assertTrue(
874             "expectedActual: "
875                 + expectedActual
876                 + ", actualActual: "
877                 + javaOptionalBinder.getActualBinding(),
878             matches(javaOptionalBinder.getActualBinding(), expectedActual));
879       }
880     } else if (expectedUserLinkedActual != null) {
881       assertTrue(
882           "expectedUserLinkedActual: "
883               + expectedUserLinkedActual
884               + ", actualActual: "
885               + optionalBinder.getActualBinding(),
886           matches(optionalBinder.getActualBinding(), expectedUserLinkedActual));
887       if (HAS_JAVA_OPTIONAL) {
888         assertTrue(
889             "expectedUserLinkedActual: "
890                 + expectedUserLinkedActual
891                 + ", actualActual: "
892                 + javaOptionalBinder.getActualBinding(),
893             matches(javaOptionalBinder.getActualBinding(), expectedUserLinkedActual));
894       }
895     }
896 
897     Key<Optional<javax.inject.Provider<T>>> optionalJavaxProviderKey =
898         keyType.ofType(RealOptionalBinder.optionalOfJavaxProvider(keyType.getTypeLiteral()));
899     Key<?> javaOptionalJavaxProviderKey =
900         HAS_JAVA_OPTIONAL
901             ? keyType.ofType(
902                 RealOptionalBinder.javaOptionalOfJavaxProvider(keyType.getTypeLiteral()))
903             : null;
904     Key<Optional<Provider<T>>> optionalProviderKey =
905         keyType.ofType(RealOptionalBinder.optionalOfProvider(keyType.getTypeLiteral()));
906     Key<?> javaOptionalProviderKey =
907         HAS_JAVA_OPTIONAL
908             ? keyType.ofType(RealOptionalBinder.javaOptionalOfProvider(keyType.getTypeLiteral()))
909             : null;
910 
911     boolean keyMatch = false;
912     boolean optionalKeyMatch = false;
913     boolean javaOptionalKeyMatch = false;
914     boolean optionalJavaxProviderKeyMatch = false;
915     boolean javaOptionalJavaxProviderKeyMatch = false;
916     boolean optionalProviderKeyMatch = false;
917     boolean javaOptionalProviderKeyMatch = false;
918     boolean defaultMatch = false;
919     boolean actualMatch = false;
920     List<Object> otherOptionalBindings = Lists.newArrayList();
921     List<Binding> otherMatches = Lists.newArrayList();
922     for (Binding b : injector.getAllBindings().values()) {
923       boolean contains = optionalBinder.containsElement(b);
924       if (HAS_JAVA_OPTIONAL) {
925         assertEquals(contains, javaOptionalBinder.containsElement(b));
926       }
927       Object visited = b.acceptTargetVisitor(visitor);
928       if (visited instanceof OptionalBinderBinding) {
929         if (visited.equals(optionalBinder)) {
930           assertTrue(contains);
931         } else if (HAS_JAVA_OPTIONAL && visited.equals(javaOptionalBinder)) {
932           assertTrue(contains);
933         } else {
934           otherOptionalBindings.add(visited);
935         }
936       }
937       if (b.getKey().equals(keyType)) {
938         // keyType might match because a user bound it
939         // (which is possible in a purely absent OptionalBinder)
940         assertEquals(expectedDefault != null || expectedActual != null, contains);
941         if (contains) {
942           keyMatch = true;
943         }
944       } else if (b.getKey().equals(optionalKey)) {
945         assertTrue(contains);
946         optionalKeyMatch = true;
947       } else if (b.getKey().equals(javaOptionalKey)) {
948         assertTrue(contains);
949         javaOptionalKeyMatch = true;
950       } else if (b.getKey().equals(optionalJavaxProviderKey)) {
951         assertTrue(contains);
952         optionalJavaxProviderKeyMatch = true;
953       } else if (b.getKey().equals(javaOptionalJavaxProviderKey)) {
954         assertTrue(contains);
955         javaOptionalJavaxProviderKeyMatch = true;
956       } else if (b.getKey().equals(optionalProviderKey)) {
957         assertTrue(contains);
958         optionalProviderKeyMatch = true;
959       } else if (b.getKey().equals(javaOptionalProviderKey)) {
960         assertTrue(contains);
961         javaOptionalProviderKeyMatch = true;
962       } else if (expectedDefault != null && matches(b, expectedDefault)) {
963         assertTrue(contains);
964         defaultMatch = true;
965       } else if (expectedActual != null && matches(b, expectedActual)) {
966         assertTrue(contains);
967         actualMatch = true;
968       } else if (contains) {
969         otherMatches.add(b);
970       }
971     }
972 
973     assertEquals(otherMatches.toString(), 0, otherMatches.size());
974     // only expect a keymatch if either default or actual are set
975     assertEquals(expectedDefault != null || expectedActual != null, keyMatch);
976     assertTrue(optionalKeyMatch);
977     assertTrue(optionalJavaxProviderKeyMatch);
978     assertTrue(optionalProviderKeyMatch);
979     assertEquals(HAS_JAVA_OPTIONAL, javaOptionalKeyMatch);
980     assertEquals(HAS_JAVA_OPTIONAL, javaOptionalJavaxProviderKeyMatch);
981     assertEquals(HAS_JAVA_OPTIONAL, javaOptionalProviderKeyMatch);
982     assertEquals(expectedDefault != null, defaultMatch);
983     assertEquals(expectedActual != null, actualMatch);
984     assertEquals(
985         "other OptionalBindings found: " + otherOptionalBindings,
986         expectedOtherOptionalBindings,
987         otherOptionalBindings.size());
988   }
989 
990   @SuppressWarnings({"unchecked", "rawtypes"})
optionalModuleTest( Key<T> keyType, Iterable<? extends Module> modules, int expectedOtherOptionalBindings, BindResult<?> expectedDefault, BindResult<?> expectedActual, BindResult<?> expectedUserLinkedActual)991   private static <T> void optionalModuleTest(
992       Key<T> keyType,
993       Iterable<? extends Module> modules,
994       int expectedOtherOptionalBindings,
995       BindResult<?> expectedDefault,
996       BindResult<?> expectedActual,
997       BindResult<?> expectedUserLinkedActual) {
998     if (expectedUserLinkedActual != null) {
999       assertNull("cannot have actual if expecting user binding", expectedActual);
1000       assertNull("cannot have default if expecting user binding", expectedDefault);
1001     }
1002     Set<Element> elements = ImmutableSet.copyOf(Elements.getElements(modules));
1003     Map<Key<?>, Binding<?>> indexed = index(elements);
1004     Key<Optional<T>> optionalKey =
1005         keyType.ofType(RealOptionalBinder.optionalOf(keyType.getTypeLiteral()));
1006     Key<?> javaOptionalKey =
1007         HAS_JAVA_OPTIONAL
1008             ? keyType.ofType(RealOptionalBinder.javaOptionalOf(keyType.getTypeLiteral()))
1009             : null;
1010     Visitor visitor = new Visitor();
1011     OptionalBinderBinding<Optional<T>> optionalBinder = null;
1012     OptionalBinderBinding<?> javaOptionalBinder = null;
1013     Key<?> defaultKey = null;
1014     Key<?> actualKey = null;
1015 
1016     Binding optionalBinding = indexed.get(optionalKey);
1017     optionalBinder =
1018         (OptionalBinderBinding<Optional<T>>) optionalBinding.acceptTargetVisitor(visitor);
1019 
1020     if (HAS_JAVA_OPTIONAL) {
1021       Binding javaOptionalBinding = indexed.get(javaOptionalKey);
1022       javaOptionalBinder = (OptionalBinderBinding) javaOptionalBinding.acceptTargetVisitor(visitor);
1023     }
1024 
1025     // Locate the defaultKey & actualKey
1026     for (Element element : elements) {
1027       if (optionalBinder.containsElement(element) && element instanceof Binding) {
1028         Binding binding = (Binding) element;
1029         if (isSourceEntry(binding, RealOptionalBinder.Source.DEFAULT)) {
1030           defaultKey = binding.getKey();
1031         } else if (isSourceEntry(binding, RealOptionalBinder.Source.ACTUAL)) {
1032           actualKey = binding.getKey();
1033         }
1034       }
1035     }
1036     assertNotNull(optionalBinder);
1037     if (HAS_JAVA_OPTIONAL) {
1038       assertNotNull(javaOptionalBinder);
1039     }
1040     assertEquals(expectedDefault == null, defaultKey == null);
1041     assertEquals(expectedActual == null, actualKey == null);
1042 
1043     Key<Optional<javax.inject.Provider<T>>> optionalJavaxProviderKey =
1044         keyType.ofType(RealOptionalBinder.optionalOfJavaxProvider(keyType.getTypeLiteral()));
1045     Key<?> javaOptionalJavaxProviderKey =
1046         HAS_JAVA_OPTIONAL
1047             ? keyType.ofType(
1048                 RealOptionalBinder.javaOptionalOfJavaxProvider(keyType.getTypeLiteral()))
1049             : null;
1050     Key<Optional<Provider<T>>> optionalProviderKey =
1051         keyType.ofType(RealOptionalBinder.optionalOfProvider(keyType.getTypeLiteral()));
1052     Key<?> javaOptionalProviderKey =
1053         HAS_JAVA_OPTIONAL
1054             ? keyType.ofType(RealOptionalBinder.javaOptionalOfProvider(keyType.getTypeLiteral()))
1055             : null;
1056     boolean keyMatch = false;
1057     boolean optionalKeyMatch = false;
1058     boolean javaOptionalKeyMatch = false;
1059     boolean optionalJavaxProviderKeyMatch = false;
1060     boolean javaOptionalJavaxProviderKeyMatch = false;
1061     boolean optionalProviderKeyMatch = false;
1062     boolean javaOptionalProviderKeyMatch = false;
1063     boolean defaultMatch = false;
1064     boolean actualMatch = false;
1065     List<Object> otherOptionalElements = Lists.newArrayList();
1066     List<Element> otherContains = Lists.newArrayList();
1067     List<Element> nonContainedElements = Lists.newArrayList();
1068     for (Element element : elements) {
1069       boolean contains = optionalBinder.containsElement(element);
1070       if (HAS_JAVA_OPTIONAL) {
1071         assertEquals(contains, javaOptionalBinder.containsElement(element));
1072       }
1073       if (!contains) {
1074         nonContainedElements.add(element);
1075       }
1076       Key key = null;
1077       Binding b = null;
1078       if (element instanceof Binding) {
1079         b = (Binding) element;
1080         key = b.getKey();
1081         Object visited = b.acceptTargetVisitor(visitor);
1082         if (visited instanceof OptionalBinderBinding) {
1083           if (visited.equals(optionalBinder)) {
1084             assertTrue(contains);
1085           } else if (HAS_JAVA_OPTIONAL && visited.equals(javaOptionalBinder)) {
1086             assertTrue(contains);
1087           } else {
1088             otherOptionalElements.add(visited);
1089           }
1090         }
1091       } else if (element instanceof ProviderLookup) {
1092         key = ((ProviderLookup) element).getKey();
1093       }
1094 
1095       if (key != null && key.equals(keyType)) {
1096         // keyType might match because a user bound it
1097         // (which is possible in a purely absent OptionalBinder)
1098         assertEquals(expectedDefault != null || expectedActual != null, contains);
1099         if (contains) {
1100           keyMatch = true;
1101         }
1102       } else if (key != null && key.equals(optionalKey)) {
1103         assertTrue(contains);
1104         optionalKeyMatch = true;
1105       } else if (key != null && key.equals(javaOptionalKey)) {
1106         assertTrue(contains);
1107         javaOptionalKeyMatch = true;
1108       } else if (key != null && key.equals(optionalJavaxProviderKey)) {
1109         assertTrue(contains);
1110         optionalJavaxProviderKeyMatch = true;
1111       } else if (key != null && key.equals(javaOptionalJavaxProviderKey)) {
1112         assertTrue(contains);
1113         javaOptionalJavaxProviderKeyMatch = true;
1114       } else if (key != null && key.equals(optionalProviderKey)) {
1115         assertTrue(contains);
1116         optionalProviderKeyMatch = true;
1117       } else if (key != null && key.equals(javaOptionalProviderKey)) {
1118         assertTrue(contains);
1119         javaOptionalProviderKeyMatch = true;
1120       } else if (key != null && key.equals(defaultKey)) {
1121         assertTrue(contains);
1122         if (b != null) { // otherwise it might just be a ProviderLookup into it
1123           assertTrue(
1124               "expected: " + expectedDefault + ", but was: " + b, matches(b, expectedDefault));
1125           defaultMatch = true;
1126         }
1127       } else if (key != null && key.equals(actualKey)) {
1128         assertTrue(contains);
1129         if (b != null) { // otherwise it might just be a ProviderLookup into it
1130           assertTrue("expected: " + expectedActual + ", but was: " + b, matches(b, expectedActual));
1131           actualMatch = true;
1132         }
1133       } else if (contains) {
1134         otherContains.add(element);
1135       }
1136     }
1137 
1138     // only expect a keymatch if either default or actual are set
1139     assertEquals(expectedDefault != null || expectedActual != null, keyMatch);
1140     assertTrue(optionalKeyMatch);
1141     assertTrue(optionalJavaxProviderKeyMatch);
1142     assertTrue(optionalProviderKeyMatch);
1143     assertEquals(HAS_JAVA_OPTIONAL, javaOptionalKeyMatch);
1144     assertEquals(HAS_JAVA_OPTIONAL, javaOptionalJavaxProviderKeyMatch);
1145     assertEquals(HAS_JAVA_OPTIONAL, javaOptionalProviderKeyMatch);
1146     assertEquals(expectedDefault != null, defaultMatch);
1147     assertEquals(expectedActual != null, actualMatch);
1148     assertEquals(otherContains.toString(), 0, otherContains.size());
1149     assertEquals(
1150         "other OptionalBindings found: " + otherOptionalElements,
1151         expectedOtherOptionalBindings,
1152         otherOptionalElements.size());
1153 
1154     // Validate that we can construct an injector out of the remaining bindings.
1155     Guice.createInjector(Elements.getModule(nonContainedElements));
1156   }
1157 
isSourceEntry(Binding b, RealOptionalBinder.Source type)1158   private static boolean isSourceEntry(Binding b, RealOptionalBinder.Source type) {
1159     switch (type) {
1160       case ACTUAL:
1161         return b.getKey().getAnnotation() instanceof RealOptionalBinder.Actual;
1162       case DEFAULT:
1163         return b.getKey().getAnnotation() instanceof RealOptionalBinder.Default;
1164       default:
1165         throw new IllegalStateException("invalid type: " + type);
1166     }
1167   }
1168 
1169   /** Returns the subset of elements that have keys, indexed by them. */
index(Iterable<Element> elements)1170   private static Map<Key<?>, Binding<?>> index(Iterable<Element> elements) {
1171     ImmutableMap.Builder<Key<?>, Binding<?>> builder = ImmutableMap.builder();
1172     for (Element element : elements) {
1173       if (element instanceof Binding) {
1174         builder.put(((Binding) element).getKey(), (Binding) element);
1175       }
1176     }
1177     return builder.build();
1178   }
1179 
instance(K k, V v)1180   static <K, V> MapResult instance(K k, V v) {
1181     return new MapResult<K, V>(k, new BindResult<V>(INSTANCE, v, null));
1182   }
1183 
linked(K k, Class<? extends V> clazz)1184   static <K, V> MapResult linked(K k, Class<? extends V> clazz) {
1185     return new MapResult<K, V>(k, new BindResult<V>(LINKED, null, Key.get(clazz)));
1186   }
1187 
linked(K k, Key<? extends V> key)1188   static <K, V> MapResult linked(K k, Key<? extends V> key) {
1189     return new MapResult<K, V>(k, new BindResult<V>(LINKED, null, key));
1190   }
1191 
providerInstance(K k, V v)1192   static <K, V> MapResult providerInstance(K k, V v) {
1193     return new MapResult<K, V>(k, new BindResult<V>(PROVIDER_INSTANCE, v, null));
1194   }
1195 
1196   static class MapResult<K, V> {
1197     private final K k;
1198     private final BindResult<V> v;
1199 
MapResult(K k, BindResult<V> v)1200     MapResult(K k, BindResult<V> v) {
1201       this.k = k;
1202       this.v = v;
1203     }
1204 
1205     @Override
toString()1206     public String toString() {
1207       return "entry[key[" + k + "],value[" + v + "]]";
1208     }
1209   }
1210 
matches(Binding<?> item, BindResult<?> result)1211   private static boolean matches(Binding<?> item, BindResult<?> result) {
1212     switch (result.type) {
1213       case INSTANCE:
1214         if (item instanceof InstanceBinding
1215             && ((InstanceBinding) item).getInstance().equals(result.instance)) {
1216           return true;
1217         }
1218         break;
1219       case LINKED:
1220         if (item instanceof LinkedKeyBinding
1221             && ((LinkedKeyBinding) item).getLinkedKey().equals(result.key)) {
1222           return true;
1223         }
1224         break;
1225       case PROVIDER_INSTANCE:
1226         if (item instanceof ProviderInstanceBinding
1227             && Objects.equal(
1228                 ((ProviderInstanceBinding) item).getUserSuppliedProvider().get(),
1229                 result.instance)) {
1230           return true;
1231         }
1232         break;
1233       case PROVIDER_KEY:
1234         if (item instanceof ProviderKeyBinding
1235             && ((ProviderKeyBinding) item).getProviderKey().equals(result.key)) {
1236           return true;
1237         }
1238         break;
1239     }
1240     return false;
1241   }
1242 
instance(T t)1243   static <T> BindResult<T> instance(T t) {
1244     return new BindResult<T>(INSTANCE, t, null);
1245   }
1246 
linked(Class<? extends T> clazz)1247   static <T> BindResult<T> linked(Class<? extends T> clazz) {
1248     return new BindResult<T>(LINKED, null, Key.get(clazz));
1249   }
1250 
linked(Key<? extends T> key)1251   static <T> BindResult<T> linked(Key<? extends T> key) {
1252     return new BindResult<T>(LINKED, null, key);
1253   }
1254 
providerInstance(T t)1255   static <T> BindResult<T> providerInstance(T t) {
1256     return new BindResult<T>(PROVIDER_INSTANCE, t, null);
1257   }
1258 
providerKey(Key<T> key)1259   static <T> BindResult<T> providerKey(Key<T> key) {
1260     return new BindResult<T>(PROVIDER_KEY, null, key);
1261   }
1262 
1263   /** The kind of binding. */
1264   static enum BindType {
1265     INSTANCE,
1266     LINKED,
1267     PROVIDER_INSTANCE,
1268     PROVIDER_KEY
1269   }
1270   /** The result of the binding. */
1271   static class BindResult<T> {
1272     private final BindType type;
1273     private final Key<?> key;
1274     private final T instance;
1275 
BindResult(BindType type, T instance, Key<?> key)1276     private BindResult(BindType type, T instance, Key<?> key) {
1277       this.type = type;
1278       this.instance = instance;
1279       this.key = key;
1280     }
1281 
1282     @Override
toString()1283     public String toString() {
1284       switch (type) {
1285         case INSTANCE:
1286           return "instance[" + instance + "]";
1287         case LINKED:
1288           return "linkedKey[" + key + "]";
1289         case PROVIDER_INSTANCE:
1290           return "providerInstance[" + instance + "]";
1291         case PROVIDER_KEY:
1292           return "providerKey[" + key + "]";
1293       }
1294       return null;
1295     }
1296   }
1297 
1298   private static class Visitor<T> extends DefaultBindingTargetVisitor<T, Object>
1299       implements MultibindingsTargetVisitor<T, Object> {
1300 
1301     @Override
visit(MultibinderBinding<? extends T> multibinding)1302     public Object visit(MultibinderBinding<? extends T> multibinding) {
1303       return multibinding;
1304     }
1305 
1306     @Override
visit(MapBinderBinding<? extends T> mapbinding)1307     public Object visit(MapBinderBinding<? extends T> mapbinding) {
1308       return mapbinding;
1309     }
1310 
1311     @Override
visit(OptionalBinderBinding<? extends T> optionalbinding)1312     public Object visit(OptionalBinderBinding<? extends T> optionalbinding) {
1313       return optionalbinding;
1314     }
1315   }
1316 }
1317