blob: af6e48fa08330e47426384d81698356b08814733 [file] [log] [blame]
limpbizkit50192702008-05-01 09:55:02 +00001/**
2 * Copyright (C) 2008 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
17package com.google.inject.multibindings;
18
limpbizkiteab76472008-05-26 19:45:12 +000019import static com.google.inject.Asserts.assertContains;
sberlin75fcf6f2010-09-20 00:42:24 +000020import static com.google.inject.multibindings.SpiUtils.assertSetVisitor;
21import static com.google.inject.multibindings.SpiUtils.instance;
22import static com.google.inject.multibindings.SpiUtils.providerInstance;
23import static com.google.inject.multibindings.SpiUtils.VisitType.BOTH;
24import static com.google.inject.multibindings.SpiUtils.VisitType.MODULE;
25import static com.google.inject.name.Names.named;
26import static java.lang.annotation.RetentionPolicy.RUNTIME;
sberlin680c8b52010-06-11 19:11:13 +000027
sberlin75fcf6f2010-09-20 00:42:24 +000028import java.lang.annotation.Annotation;
29import java.lang.annotation.ElementType;
30import java.lang.annotation.Retention;
31import java.lang.annotation.RetentionPolicy;
32import java.lang.annotation.Target;
33import java.lang.reflect.Method;
34import java.util.Arrays;
35import java.util.Collections;
36import java.util.HashSet;
37import java.util.List;
38import java.util.Set;
39
40import junit.framework.TestCase;
41
42import com.google.inject.AbstractModule;
limpbizkitddb38622008-12-29 05:21:16 +000043import com.google.inject.Binding;
limpbizkit9532e622008-06-18 08:20:54 +000044import com.google.inject.BindingAnnotation;
45import com.google.inject.CreationException;
46import com.google.inject.Guice;
47import com.google.inject.Injector;
48import com.google.inject.Key;
49import com.google.inject.Module;
50import com.google.inject.Provider;
51import com.google.inject.ProvisionException;
sberlin8bc83872010-04-26 02:12:22 +000052import com.google.inject.Stage;
limpbizkit9532e622008-06-18 08:20:54 +000053import com.google.inject.TypeLiteral;
sberlind9c913a2011-06-26 21:02:54 +000054import com.google.common.collect.ImmutableList;
55import com.google.common.collect.ImmutableSet;
56import com.google.common.collect.Sets;
limpbizkit50192702008-05-01 09:55:02 +000057import com.google.inject.name.Names;
limpbizkitddb38622008-12-29 05:21:16 +000058import com.google.inject.spi.Dependency;
59import com.google.inject.spi.HasDependencies;
sberlin8bc83872010-04-26 02:12:22 +000060import com.google.inject.spi.InstanceBinding;
61import com.google.inject.spi.LinkedKeyBinding;
limpbizkitd8750fd2009-08-10 23:30:46 +000062import com.google.inject.util.Modules;
limpbizkit50192702008-05-01 09:55:02 +000063import com.google.inject.util.Providers;
sberlin680c8b52010-06-11 19:11:13 +000064
limpbizkit50192702008-05-01 09:55:02 +000065/**
66 * @author jessewilson@google.com (Jesse Wilson)
67 */
68public class MultibinderTest extends TestCase {
69
70 final TypeLiteral<Set<String>> setOfString = new TypeLiteral<Set<String>>() {};
71 final TypeLiteral<Set<Integer>> setOfInteger = new TypeLiteral<Set<Integer>>() {};
sberlin75fcf6f2010-09-20 00:42:24 +000072 final TypeLiteral<String> stringType = TypeLiteral.get(String.class);
73 final TypeLiteral<Integer> intType = TypeLiteral.get(Integer.class);
limpbizkit50192702008-05-01 09:55:02 +000074
75 public void testMultibinderAggregatesMultipleModules() {
76 Module abc = new AbstractModule() {
77 protected void configure() {
78 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class);
79 multibinder.addBinding().toInstance("A");
80 multibinder.addBinding().toInstance("B");
81 multibinder.addBinding().toInstance("C");
82 }
83 };
84 Module de = new AbstractModule() {
85 protected void configure() {
86 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class);
87 multibinder.addBinding().toInstance("D");
88 multibinder.addBinding().toInstance("E");
89 }
90 };
91
92 Injector injector = Guice.createInjector(abc, de);
sberlin75fcf6f2010-09-20 00:42:24 +000093 Key<Set<String>> setKey = Key.get(setOfString);
94 Set<String> abcde = injector.getInstance(setKey);
95 Set<String> results = setOf("A", "B", "C", "D", "E");
limpbizkit50192702008-05-01 09:55:02 +000096
sberlin75fcf6f2010-09-20 00:42:24 +000097 assertEquals(results, abcde);
98 assertSetVisitor(setKey, stringType, setOf(abc, de), BOTH, false, 0, instance("A"),
99 instance("B"), instance("C"), instance("D"), instance("E"));
limpbizkit50192702008-05-01 09:55:02 +0000100 }
101
102 public void testMultibinderAggregationForAnnotationInstance() {
sberlin75fcf6f2010-09-20 00:42:24 +0000103 Module module = new AbstractModule() {
limpbizkit50192702008-05-01 09:55:02 +0000104 protected void configure() {
105 Multibinder<String> multibinder
106 = Multibinder.newSetBinder(binder(), String.class, Names.named("abc"));
107 multibinder.addBinding().toInstance("A");
108 multibinder.addBinding().toInstance("B");
109
110 multibinder = Multibinder.newSetBinder(binder(), String.class, Names.named("abc"));
111 multibinder.addBinding().toInstance("C");
112 }
sberlin75fcf6f2010-09-20 00:42:24 +0000113 };
114 Injector injector = Guice.createInjector(module);
limpbizkit50192702008-05-01 09:55:02 +0000115
sberlin75fcf6f2010-09-20 00:42:24 +0000116 Key<Set<String>> setKey = Key.get(setOfString, Names.named("abc"));
117 Set<String> abc = injector.getInstance(setKey);
118 Set<String> results = setOf("A", "B", "C");
119 assertEquals(results, abc);
120 assertSetVisitor(setKey, stringType, setOf(module), BOTH, false, 0, instance("A"),
121 instance("B"), instance("C"));
limpbizkit50192702008-05-01 09:55:02 +0000122 }
123
124 public void testMultibinderAggregationForAnnotationType() {
sberlin75fcf6f2010-09-20 00:42:24 +0000125 Module module = new AbstractModule() {
limpbizkit50192702008-05-01 09:55:02 +0000126 protected void configure() {
127 Multibinder<String> multibinder
128 = Multibinder.newSetBinder(binder(), String.class, Abc.class);
129 multibinder.addBinding().toInstance("A");
130 multibinder.addBinding().toInstance("B");
131
132 multibinder = Multibinder.newSetBinder(binder(), String.class, Abc.class);
133 multibinder.addBinding().toInstance("C");
134 }
sberlin75fcf6f2010-09-20 00:42:24 +0000135 };
136 Injector injector = Guice.createInjector(module);
limpbizkit50192702008-05-01 09:55:02 +0000137
sberlin75fcf6f2010-09-20 00:42:24 +0000138 Key<Set<String>> setKey = Key.get(setOfString, Abc.class);
139 Set<String> abcde = injector.getInstance(setKey);
140 Set<String> results = setOf("A", "B", "C");
141 assertEquals(results, abcde);
142 assertSetVisitor(setKey, stringType, setOf(module), BOTH, false, 0, instance("A"),
143 instance("B"), instance("C"));
limpbizkit50192702008-05-01 09:55:02 +0000144 }
145
146 public void testMultibinderWithMultipleAnnotationValueSets() {
sberlin75fcf6f2010-09-20 00:42:24 +0000147 Module module = new AbstractModule() {
limpbizkit50192702008-05-01 09:55:02 +0000148 protected void configure() {
149 Multibinder<String> abcMultibinder
150 = Multibinder.newSetBinder(binder(), String.class, named("abc"));
151 abcMultibinder.addBinding().toInstance("A");
152 abcMultibinder.addBinding().toInstance("B");
153 abcMultibinder.addBinding().toInstance("C");
154
155 Multibinder<String> deMultibinder
156 = Multibinder.newSetBinder(binder(), String.class, named("de"));
157 deMultibinder.addBinding().toInstance("D");
158 deMultibinder.addBinding().toInstance("E");
159 }
sberlin75fcf6f2010-09-20 00:42:24 +0000160 };
161 Injector injector = Guice.createInjector(module);
limpbizkit50192702008-05-01 09:55:02 +0000162
sberlin75fcf6f2010-09-20 00:42:24 +0000163 Key<Set<String>> abcSetKey = Key.get(setOfString, named("abc"));
164 Set<String> abc = injector.getInstance(abcSetKey);
165 Key<Set<String>> deSetKey = Key.get(setOfString, named("de"));
166 Set<String> de = injector.getInstance(deSetKey);
167 Set<String> abcResults = setOf("A", "B", "C");
168 assertEquals(abcResults, abc);
169 Set<String> deResults = setOf("D", "E");
170 assertEquals(deResults, de);
171 assertSetVisitor(abcSetKey, stringType, setOf(module), BOTH, false, 1, instance("A"),
172 instance("B"), instance("C"));
173 assertSetVisitor(deSetKey, stringType, setOf(module), BOTH, false, 1, instance("D"), instance("E"));
limpbizkit50192702008-05-01 09:55:02 +0000174 }
175
176 public void testMultibinderWithMultipleAnnotationTypeSets() {
sberlin75fcf6f2010-09-20 00:42:24 +0000177 Module module = new AbstractModule() {
limpbizkit50192702008-05-01 09:55:02 +0000178 protected void configure() {
179 Multibinder<String> abcMultibinder
180 = Multibinder.newSetBinder(binder(), String.class, Abc.class);
181 abcMultibinder.addBinding().toInstance("A");
182 abcMultibinder.addBinding().toInstance("B");
183 abcMultibinder.addBinding().toInstance("C");
184
185 Multibinder<String> deMultibinder
186 = Multibinder.newSetBinder(binder(), String.class, De.class);
187 deMultibinder.addBinding().toInstance("D");
188 deMultibinder.addBinding().toInstance("E");
189 }
sberlin75fcf6f2010-09-20 00:42:24 +0000190 };
191 Injector injector = Guice.createInjector(module);
limpbizkit50192702008-05-01 09:55:02 +0000192
sberlin75fcf6f2010-09-20 00:42:24 +0000193 Key<Set<String>> abcSetKey = Key.get(setOfString, Abc.class);
194 Set<String> abc = injector.getInstance(abcSetKey);
195 Key<Set<String>> deSetKey = Key.get(setOfString, De.class);
196 Set<String> de = injector.getInstance(deSetKey);
197 Set<String> abcResults = setOf("A", "B", "C");
198 assertEquals(abcResults, abc);
199 Set<String> deResults = setOf("D", "E");
200 assertEquals(deResults, de);
201 assertSetVisitor(abcSetKey, stringType, setOf(module), BOTH, false, 1, instance("A"),
202 instance("B"), instance("C"));
203 assertSetVisitor(deSetKey, stringType, setOf(module), BOTH, false, 1, instance("D"), instance("E"));
limpbizkit50192702008-05-01 09:55:02 +0000204 }
205
limpbizkit7c533ac2008-05-01 14:17:53 +0000206 public void testMultibinderWithMultipleSetTypes() {
sberlin75fcf6f2010-09-20 00:42:24 +0000207 Module module = new AbstractModule() {
limpbizkit7c533ac2008-05-01 14:17:53 +0000208 protected void configure() {
209 Multibinder.newSetBinder(binder(), String.class)
210 .addBinding().toInstance("A");
211 Multibinder.newSetBinder(binder(), Integer.class)
212 .addBinding().toInstance(1);
213 }
sberlin75fcf6f2010-09-20 00:42:24 +0000214 };
215 Injector injector = Guice.createInjector(module);
limpbizkit7c533ac2008-05-01 14:17:53 +0000216
217 assertEquals(setOf("A"), injector.getInstance(Key.get(setOfString)));
218 assertEquals(setOf(1), injector.getInstance(Key.get(setOfInteger)));
sberlin75fcf6f2010-09-20 00:42:24 +0000219 assertSetVisitor(Key.get(setOfString), stringType, setOf(module), BOTH, false, 1, instance("A"));
220 assertSetVisitor(Key.get(setOfInteger), intType, setOf(module), BOTH, false, 1, instance(1));
limpbizkit7c533ac2008-05-01 14:17:53 +0000221 }
222
limpbizkit50192702008-05-01 09:55:02 +0000223 public void testMultibinderWithEmptySet() {
sberlin75fcf6f2010-09-20 00:42:24 +0000224 Module module = new AbstractModule() {
limpbizkit50192702008-05-01 09:55:02 +0000225 protected void configure() {
226 Multibinder.newSetBinder(binder(), String.class);
227 }
sberlin75fcf6f2010-09-20 00:42:24 +0000228 };
229 Injector injector = Guice.createInjector(module);
limpbizkit50192702008-05-01 09:55:02 +0000230
231 Set<String> set = injector.getInstance(Key.get(setOfString));
232 assertEquals(Collections.emptySet(), set);
sberlin75fcf6f2010-09-20 00:42:24 +0000233 assertSetVisitor(Key.get(setOfString), stringType, setOf(module), BOTH, false, 0);
limpbizkit50192702008-05-01 09:55:02 +0000234 }
235
236 public void testMultibinderSetIsUnmodifiable() {
237 Injector injector = Guice.createInjector(new AbstractModule() {
238 protected void configure() {
239 Multibinder.newSetBinder(binder(), String.class)
240 .addBinding().toInstance("A");
241 }
242 });
243
244 Set<String> set = injector.getInstance(Key.get(setOfString));
245 try {
246 set.clear();
247 fail();
248 } catch(UnsupportedOperationException expected) {
249 }
250 }
251
252 public void testMultibinderSetIsLazy() {
sberlin75fcf6f2010-09-20 00:42:24 +0000253 Module module = new AbstractModule() {
limpbizkit50192702008-05-01 09:55:02 +0000254 protected void configure() {
255 Multibinder.newSetBinder(binder(), Integer.class)
256 .addBinding().toProvider(new Provider<Integer>() {
257 int nextValue = 1;
258 public Integer get() {
259 return nextValue++;
260 }
261 });
262 }
sberlin75fcf6f2010-09-20 00:42:24 +0000263 };
264 Injector injector = Guice.createInjector(module);
limpbizkit50192702008-05-01 09:55:02 +0000265
266 assertEquals(setOf(1), injector.getInstance(Key.get(setOfInteger)));
267 assertEquals(setOf(2), injector.getInstance(Key.get(setOfInteger)));
268 assertEquals(setOf(3), injector.getInstance(Key.get(setOfInteger)));
sberlin75fcf6f2010-09-20 00:42:24 +0000269 assertSetVisitor(Key.get(setOfInteger), intType, setOf(module), BOTH, false, 0, providerInstance(1));
limpbizkit50192702008-05-01 09:55:02 +0000270 }
271
272 public void testMultibinderSetForbidsDuplicateElements() {
sberlin75fcf6f2010-09-20 00:42:24 +0000273 Module module = new AbstractModule() {
limpbizkit50192702008-05-01 09:55:02 +0000274 protected void configure() {
275 final Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class);
276 multibinder.addBinding().toInstance("A");
277 multibinder.addBinding().toInstance("A");
278 }
sberlin75fcf6f2010-09-20 00:42:24 +0000279 };
280 Injector injector = Guice.createInjector(module);
limpbizkit50192702008-05-01 09:55:02 +0000281
282 try {
283 injector.getInstance(Key.get(setOfString));
284 fail();
limpbizkit49f67c02008-06-10 20:56:17 +0000285 } catch(ProvisionException expected) {
limpbizkit72d11dd2008-11-02 07:59:13 +0000286 assertContains(expected.getMessage(),
287 "1) Set injection failed due to duplicated element \"A\"");
limpbizkit50192702008-05-01 09:55:02 +0000288 }
sberlin75fcf6f2010-09-20 00:42:24 +0000289
290 // But we can still visit the module!
291 assertSetVisitor(Key.get(setOfString), stringType, setOf(module), MODULE, false, 0,
292 instance("A"), instance("A"));
limpbizkit50192702008-05-01 09:55:02 +0000293 }
sberlin75fcf6f2010-09-20 00:42:24 +0000294
limpbizkit398017a2009-06-23 06:30:37 +0000295 public void testMultibinderSetPermitDuplicateElements() {
sberlin75fcf6f2010-09-20 00:42:24 +0000296 Module ab = new AbstractModule() {
297 protected void configure() {
298 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class);
299 multibinder.addBinding().toInstance("A");
300 multibinder.addBinding().toInstance("B");
301 }
302 };
303 Module bc = new AbstractModule() {
304 protected void configure() {
305 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class);
306 multibinder.permitDuplicates();
307 multibinder.addBinding().toInstance("B");
308 multibinder.addBinding().toInstance("C");
309 }
310 };
311 Injector injector = Guice.createInjector(ab, bc);
limpbizkit398017a2009-06-23 06:30:37 +0000312
313 assertEquals(setOf("A", "B", "C"), injector.getInstance(Key.get(setOfString)));
sberlin75fcf6f2010-09-20 00:42:24 +0000314 assertSetVisitor(Key.get(setOfString), stringType, setOf(ab, bc), BOTH, true, 0,
315 instance("A"), instance("B"), instance("B"), instance("C"));
limpbizkit398017a2009-06-23 06:30:37 +0000316 }
317
318 public void testMultibinderSetPermitDuplicateCallsToPermitDuplicates() {
sberlin75fcf6f2010-09-20 00:42:24 +0000319 Module ab = new AbstractModule() {
320 protected void configure() {
321 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class);
322 multibinder.permitDuplicates();
323 multibinder.addBinding().toInstance("A");
324 multibinder.addBinding().toInstance("B");
325 }
326 };
327 Module bc = new AbstractModule() {
328 protected void configure() {
329 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class);
330 multibinder.permitDuplicates();
331 multibinder.addBinding().toInstance("B");
332 multibinder.addBinding().toInstance("C");
333 }
334 };
335 Injector injector = Guice.createInjector(ab, bc);
limpbizkit398017a2009-06-23 06:30:37 +0000336
337 assertEquals(setOf("A", "B", "C"), injector.getInstance(Key.get(setOfString)));
sberlin75fcf6f2010-09-20 00:42:24 +0000338 assertSetVisitor(Key.get(setOfString), stringType, setOf(ab, bc), BOTH, true, 0,
339 instance("A"), instance("B"), instance("B"), instance("C"));
limpbizkit398017a2009-06-23 06:30:37 +0000340 }
limpbizkit50192702008-05-01 09:55:02 +0000341
342 public void testMultibinderSetForbidsNullElements() {
343 Injector injector = Guice.createInjector(new AbstractModule() {
344 protected void configure() {
345 Multibinder.newSetBinder(binder(), String.class)
346 .addBinding().toProvider(Providers.<String>of(null));
347 }
348 });
349
350 try {
351 injector.getInstance(Key.get(setOfString));
352 fail();
limpbizkit49f67c02008-06-10 20:56:17 +0000353 } catch(ProvisionException expected) {
limpbizkit72d11dd2008-11-02 07:59:13 +0000354 assertContains(expected.getMessage(),
355 "1) Set injection failed due to null element");
limpbizkit50192702008-05-01 09:55:02 +0000356 }
357 }
358
limpbizkitd6967b92008-05-16 15:28:51 +0000359 public void testSourceLinesInMultibindings() {
360 try {
361 Guice.createInjector(new AbstractModule() {
362 @Override protected void configure() {
363 Multibinder.newSetBinder(binder(), Integer.class).addBinding();
364 }
365 });
366 fail();
limpbizkiteab76472008-05-26 19:45:12 +0000367 } catch (CreationException expected) {
limpbizkita6e0e782008-09-03 06:19:56 +0000368 assertContains(expected.getMessage(), "No implementation for java.lang.Integer",
369 "at " + getClass().getName());
limpbizkitd6967b92008-05-16 15:28:51 +0000370 }
371 }
372
limpbizkitddb38622008-12-29 05:21:16 +0000373 /**
374 * We just want to make sure that multibinder's binding depends on each of its values. We don't
375 * really care about the underlying structure of those bindings, which are implementation details.
376 */
377 public void testMultibinderDependencies() {
378 Injector injector = Guice.createInjector(new AbstractModule() {
379 protected void configure() {
380 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class);
381 multibinder.addBinding().toInstance("A");
382 multibinder.addBinding().to(Key.get(String.class, Names.named("b")));
383
384 bindConstant().annotatedWith(Names.named("b")).to("B");
385 }
386 });
387
388 Binding<Set<String>> binding = injector.getBinding(new Key<Set<String>>() {});
389 HasDependencies withDependencies = (HasDependencies) binding;
390 Set<String> elements = Sets.newHashSet();
391 for (Dependency<?> dependency : withDependencies.getDependencies()) {
392 elements.add((String) injector.getInstance(dependency.getKey()));
393 }
394 assertEquals(ImmutableSet.of("A", "B"), elements);
395 }
sberlin8bc83872010-04-26 02:12:22 +0000396
397 /**
398 * We just want to make sure that multibinder's binding depends on each of its values. We don't
399 * really care about the underlying structure of those bindings, which are implementation details.
400 */
401 public void testMultibinderDependenciesInToolStage() {
sberlin8b64d452010-12-13 02:44:36 +0000402 Injector injector = Guice.createInjector(Stage.TOOL, new AbstractModule() {
sberlin8bc83872010-04-26 02:12:22 +0000403 protected void configure() {
404 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class);
405 multibinder.addBinding().toInstance("A");
406 multibinder.addBinding().to(Key.get(String.class, Names.named("b")));
407
408 bindConstant().annotatedWith(Names.named("b")).to("B");
sberlin8b64d452010-12-13 02:44:36 +0000409 }});
sberlin8bc83872010-04-26 02:12:22 +0000410
411 Binding<Set<String>> binding = injector.getBinding(new Key<Set<String>>() {});
412 HasDependencies withDependencies = (HasDependencies) binding;
413 InstanceBinding<?> instanceBinding = null;
414 LinkedKeyBinding<?> linkedBinding = null;
415 // The non-tool stage test can test this by calling injector.getInstance to ensure
416 // the right values are returned -- in tool stage we can't do that. It's also a
417 // little difficult to validate the dependencies & bindings, because they're
418 // bindings created internally within Multibinder.
419 // To workaround this, we just validate that the dependencies lookup to a single
420 // InstanceBinding whose value is "A" and another LinkedBinding whose target is
421 // the Key of @Named("b") String=B
422 for (Dependency<?> dependency : withDependencies.getDependencies()) {
423 Binding<?> b = injector.getBinding(dependency.getKey());
424 if(b instanceof InstanceBinding) {
425 if(instanceBinding != null) {
426 fail("Already have an instance binding of: " + instanceBinding + ", and now want to add: " + b);
427 } else {
428 instanceBinding = (InstanceBinding)b;
429 }
430 } else if(b instanceof LinkedKeyBinding) {
431 if(linkedBinding != null) {
432 fail("Already have a linked binding of: " + linkedBinding + ", and now want to add: " + b);
433 } else {
434 linkedBinding = (LinkedKeyBinding)b;
435 }
436 } else {
437 fail("Unexpected dependency of: " + dependency);
438 }
439 }
440
441 assertNotNull(instanceBinding);
442 assertNotNull(linkedBinding);
443
444 assertEquals("A", instanceBinding.getInstance());
445 assertEquals(Key.get(String.class, Names.named("b")), linkedBinding.getLinkedKey());
446 }
limpbizkitddb38622008-12-29 05:21:16 +0000447
limpbizkit63a96052009-03-30 17:28:16 +0000448 /**
449 * Our implementation maintains order, but doesn't guarantee it in the API spec.
450 * TODO: specify the iteration order?
451 */
452 public void testBindOrderEqualsIterationOrder() {
453 Injector injector = Guice.createInjector(
454 new AbstractModule() {
455 protected void configure() {
456 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class);
457 multibinder.addBinding().toInstance("leonardo");
458 multibinder.addBinding().toInstance("donatello");
459 install(new AbstractModule() {
460 protected void configure() {
461 Multibinder.newSetBinder(binder(), String.class)
462 .addBinding().toInstance("michaelangelo");
463 }
464 });
465 }
466 },
467 new AbstractModule() {
468 protected void configure() {
469 Multibinder.newSetBinder(binder(), String.class).addBinding().toInstance("raphael");
470 }
471 });
472
473 List<String> inOrder = ImmutableList.copyOf(injector.getInstance(Key.get(setOfString)));
474 assertEquals(ImmutableList.of("leonardo", "donatello", "michaelangelo", "raphael"), inOrder);
475 }
476
limpbizkit50192702008-05-01 09:55:02 +0000477 @Retention(RUNTIME) @BindingAnnotation
478 @interface Abc {}
479
480 @Retention(RUNTIME) @BindingAnnotation
481 @interface De {}
482
483 private <T> Set<T> setOf(T... elements) {
limpbizkit9532e622008-06-18 08:20:54 +0000484 Set<T> result = Sets.newHashSet();
limpbizkit50192702008-05-01 09:55:02 +0000485 result.addAll(Arrays.asList(elements));
486 return result;
487 }
limpbizkitd8750fd2009-08-10 23:30:46 +0000488
489 /**
490 * With overrides, we should get the union of all multibindings.
491 */
492 public void testModuleOverrideAndMultibindings() {
493 Module ab = new AbstractModule() {
494 protected void configure() {
495 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class);
496 multibinder.addBinding().toInstance("A");
497 multibinder.addBinding().toInstance("B");
498 }
499 };
500 Module cd = new AbstractModule() {
501 protected void configure() {
502 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class);
503 multibinder.addBinding().toInstance("C");
504 multibinder.addBinding().toInstance("D");
505 }
506 };
507 Module ef = new AbstractModule() {
508 protected void configure() {
509 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class);
510 multibinder.addBinding().toInstance("E");
511 multibinder.addBinding().toInstance("F");
512 }
513 };
514
515 Module abcd = Modules.override(ab).with(cd);
516 Injector injector = Guice.createInjector(abcd, ef);
517 assertEquals(ImmutableSet.of("A", "B", "C", "D", "E", "F"),
518 injector.getInstance(Key.get(setOfString)));
519
sberlin75fcf6f2010-09-20 00:42:24 +0000520 assertSetVisitor(Key.get(setOfString), stringType, setOf(abcd, ef), BOTH, false, 0,
521 instance("A"), instance("B"), instance("C"), instance("D"), instance("E"), instance("F"));
limpbizkitd8750fd2009-08-10 23:30:46 +0000522 }
sberlin75fcf6f2010-09-20 00:42:24 +0000523
sberlin34d2f002010-05-02 20:11:28 +0000524 /**
525 * With overrides, we should get the union of all multibindings.
526 */
527 public void testModuleOverrideAndMultibindingsWithPermitDuplicates() {
sberlin75fcf6f2010-09-20 00:42:24 +0000528 Module abc = new AbstractModule() {
sberlin34d2f002010-05-02 20:11:28 +0000529 protected void configure() {
530 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class);
531 multibinder.addBinding().toInstance("A");
532 multibinder.addBinding().toInstance("B");
sberlin75fcf6f2010-09-20 00:42:24 +0000533 multibinder.addBinding().toInstance("C");
sberlin34d2f002010-05-02 20:11:28 +0000534 multibinder.permitDuplicates();
535 }
536 };
537 Module cd = new AbstractModule() {
538 protected void configure() {
539 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class);
540 multibinder.addBinding().toInstance("C");
541 multibinder.addBinding().toInstance("D");
542 multibinder.permitDuplicates();
543 }
544 };
545 Module ef = new AbstractModule() {
546 protected void configure() {
547 Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class);
548 multibinder.addBinding().toInstance("E");
549 multibinder.addBinding().toInstance("F");
550 multibinder.permitDuplicates();
551 }
552 };
553
sberlin75fcf6f2010-09-20 00:42:24 +0000554 Module abcd = Modules.override(abc).with(cd);
sberlin34d2f002010-05-02 20:11:28 +0000555 Injector injector = Guice.createInjector(abcd, ef);
556 assertEquals(ImmutableSet.of("A", "B", "C", "D", "E", "F"),
557 injector.getInstance(Key.get(setOfString)));
558
sberlin75fcf6f2010-09-20 00:42:24 +0000559 assertSetVisitor(Key.get(setOfString), stringType, setOf(abcd, ef), BOTH, true, 0,
560 instance("A"), instance("B"), instance("C"), instance("C"), instance("D"), instance("E"), instance("F"));
sberlin680c8b52010-06-11 19:11:13 +0000561 }
sberlin75fcf6f2010-09-20 00:42:24 +0000562
sberlin680c8b52010-06-11 19:11:13 +0000563 @BindingAnnotation
564 @Retention(RetentionPolicy.RUNTIME)
565 @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
566 private static @interface Marker {}
567
568 @Marker
569 public void testMultibinderMatching() throws Exception {
570 Method m = MultibinderTest.class.getDeclaredMethod("testMultibinderMatching");
571 assertNotNull(m);
572 final Annotation marker = m.getAnnotation(Marker.class);
573 Injector injector = Guice.createInjector(new AbstractModule() {
574 @Override public void configure() {
575 Multibinder<Integer> mb1 = Multibinder.newSetBinder(binder(), Integer.class, Marker.class);
576 Multibinder<Integer> mb2 = Multibinder.newSetBinder(binder(), Integer.class, marker);
577 mb1.addBinding().toInstance(1);
578 mb2.addBinding().toInstance(2);
579
580 // This assures us that the two binders are equivalent, so we expect the instance added to
581 // each to have been added to one set.
582 assertEquals(mb1, mb2);
583 }
584 });
585 TypeLiteral<Set<Integer>> t = new TypeLiteral<Set<Integer>>() {};
586 Set<Integer> s1 = injector.getInstance(Key.get(t, Marker.class));
587 Set<Integer> s2 = injector.getInstance(Key.get(t, marker));
588
589 // This assures us that the two sets are in fact equal. They may not be same set (as in Java
590 // object identical), but we shouldn't expect that, since probably Guice creates the set each
591 // time in case the elements are dependent on scope.
592 assertEquals(s1, s2);
593
594 // This ensures that MultiBinder is internally using the correct set name --
595 // making sure that instances of marker annotations have the same set name as
596 // MarkerAnnotation.class.
597 Set<Integer> expected = new HashSet<Integer>();
598 expected.add(1);
599 expected.add(2);
600 assertEquals(expected, s1);
sberlin75fcf6f2010-09-20 00:42:24 +0000601 }
limpbizkit50192702008-05-01 09:55:02 +0000602}