PageRenderTime 67ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/spice-inject/guice-patches/vanilla.test/com/google/inject/DuplicateBindingsTest.java

https://github.com/peterlynch/spice
Java | 422 lines | 314 code | 63 blank | 45 comment | 7 complexity | 546013187b2894750784adc79339c513 MD5 | raw file
  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. package com.google.inject;
  17. import static com.google.inject.Asserts.assertContains;
  18. import static com.google.inject.name.Names.named;
  19. import com.google.inject.internal.util.Lists;
  20. import java.lang.annotation.Annotation;
  21. import java.lang.reflect.Constructor;
  22. import java.util.Arrays;
  23. import java.util.Collection;
  24. import java.util.LinkedHashSet;
  25. import java.util.List;
  26. import java.util.logging.Logger;
  27. import junit.framework.TestCase;
  28. import com.google.inject.spi.Element;
  29. import com.google.inject.spi.Elements;
  30. import com.google.inject.util.Providers;
  31. /**
  32. * A suite of tests for duplicate bindings.
  33. *
  34. * @author sameb@google.com (Sam Berlin)
  35. */
  36. public class DuplicateBindingsTest extends TestCase {
  37. private FooImpl foo = new FooImpl();
  38. private Provider<Foo> pFoo = Providers.<Foo>of(new FooImpl());
  39. private Class<? extends Provider<? extends Foo>> pclFoo = FooProvider.class;
  40. private Class<? extends Foo> clFoo = FooImpl.class;
  41. private Constructor<FooImpl> cFoo = FooImpl.cxtor();
  42. public void testDuplicateBindingsAreIgnored() {
  43. Injector injector = Guice.createInjector(
  44. new SimpleModule(foo, pFoo, pclFoo, clFoo, cFoo),
  45. new SimpleModule(foo, pFoo, pclFoo, clFoo, cFoo)
  46. );
  47. List<Key<?>> bindings = Lists.newArrayList(injector.getAllBindings().keySet());
  48. removeBasicBindings(bindings);
  49. // Ensure only one binding existed for each type.
  50. assertTrue(bindings.remove(Key.get(Foo.class, named("instance"))));
  51. assertTrue(bindings.remove(Key.get(Foo.class, named("pInstance"))));
  52. assertTrue(bindings.remove(Key.get(Foo.class, named("pKey"))));
  53. assertTrue(bindings.remove(Key.get(Foo.class, named("linkedKey"))));
  54. assertTrue(bindings.remove(Key.get(FooImpl.class)));
  55. assertTrue(bindings.remove(Key.get(Foo.class, named("constructor"))));
  56. assertTrue(bindings.remove(Key.get(FooProvider.class))); // JIT binding
  57. assertEquals(bindings.toString(), 0, bindings.size());
  58. }
  59. public void testElementsDeduplicate() {
  60. List<Element> elements = Elements.getElements(
  61. new SimpleModule(foo, pFoo, pclFoo, clFoo, cFoo),
  62. new SimpleModule(foo, pFoo, pclFoo, clFoo, cFoo)
  63. );
  64. assertEquals(12, elements.size());
  65. assertEquals(6, new LinkedHashSet<Element>(elements).size());
  66. }
  67. public void testSameScopeInstanceIgnored() {
  68. Guice.createInjector(
  69. new ScopedModule(Scopes.SINGLETON, foo, pFoo, pclFoo, clFoo, cFoo),
  70. new ScopedModule(Scopes.SINGLETON, foo, pFoo, pclFoo, clFoo, cFoo)
  71. );
  72. Guice.createInjector(
  73. new ScopedModule(Scopes.NO_SCOPE, foo, pFoo, pclFoo, clFoo, cFoo),
  74. new ScopedModule(Scopes.NO_SCOPE, foo, pFoo, pclFoo, clFoo, cFoo)
  75. );
  76. }
  77. public void testSameScopeAnnotationIgnored() {
  78. Guice.createInjector(
  79. new AnnotatedScopeModule(Singleton.class, foo, pFoo, pclFoo, clFoo, cFoo),
  80. new AnnotatedScopeModule(Singleton.class, foo, pFoo, pclFoo, clFoo, cFoo)
  81. );
  82. }
  83. public void testMixedAnnotationAndScopeForSingletonIgnored() {
  84. Guice.createInjector(
  85. new ScopedModule(Scopes.SINGLETON, foo, pFoo, pclFoo, clFoo, cFoo),
  86. new AnnotatedScopeModule(Singleton.class, foo, pFoo, pclFoo, clFoo, cFoo)
  87. );
  88. }
  89. public void testMixedScopeAndUnscopedIgnored() {
  90. Guice.createInjector(
  91. new SimpleModule(foo, pFoo, pclFoo, clFoo, cFoo),
  92. new ScopedModule(Scopes.NO_SCOPE, foo, pFoo, pclFoo, clFoo, cFoo)
  93. );
  94. }
  95. public void testMixedScopeFails() {
  96. try {
  97. Guice.createInjector(
  98. new SimpleModule(foo, pFoo, pclFoo, clFoo, cFoo),
  99. new ScopedModule(Scopes.SINGLETON, foo, pFoo, pclFoo, clFoo, cFoo)
  100. );
  101. fail("expected exception");
  102. } catch(CreationException ce) {
  103. assertContains(ce.getMessage(),
  104. "A binding to " + Foo.class.getName() + " annotated with " + named("pInstance") + " was already configured at " + SimpleModule.class.getName(),
  105. "at " + ScopedModule.class.getName(),
  106. "A binding to " + Foo.class.getName() + " annotated with " + named("pKey") + " was already configured at " + SimpleModule.class.getName(),
  107. "at " + ScopedModule.class.getName(),
  108. "A binding to " + Foo.class.getName() + " annotated with " + named("linkedKey") + " was already configured at " + SimpleModule.class.getName(),
  109. "at " + ScopedModule.class.getName(),
  110. "A binding to " + FooImpl.class.getName() + " was already configured at " + SimpleModule.class.getName(),
  111. "at " + ScopedModule.class.getName(),
  112. "A binding to " + Foo.class.getName() + " annotated with " + named("constructor") + " was already configured at " + SimpleModule.class.getName(),
  113. "at " + ScopedModule.class.getName());
  114. }
  115. }
  116. @SuppressWarnings("unchecked")
  117. public void testMixedTargetsFails() {
  118. try {
  119. Guice.createInjector(
  120. new SimpleModule(foo, pFoo, pclFoo, clFoo, cFoo),
  121. new SimpleModule(new FooImpl(), Providers.<Foo>of(new FooImpl()),
  122. (Class)BarProvider.class, (Class)Bar.class, (Constructor)Bar.cxtor())
  123. );
  124. fail("expected exception");
  125. } catch(CreationException ce) {
  126. assertContains(ce.getMessage(),
  127. "A binding to " + Foo.class.getName() + " annotated with " + named("pInstance") + " was already configured at " + SimpleModule.class.getName(),
  128. "at " + SimpleModule.class.getName(),
  129. "A binding to " + Foo.class.getName() + " annotated with " + named("pKey") + " was already configured at " + SimpleModule.class.getName(),
  130. "at " + SimpleModule.class.getName(),
  131. "A binding to " + Foo.class.getName() + " annotated with " + named("linkedKey") + " was already configured at " + SimpleModule.class.getName(),
  132. "at " + SimpleModule.class.getName(),
  133. "A binding to " + Foo.class.getName() + " annotated with " + named("constructor") + " was already configured at " + SimpleModule.class.getName(),
  134. "at " + SimpleModule.class.getName());
  135. }
  136. }
  137. public void testExceptionInEqualsThrowsCreationException() {
  138. try {
  139. Guice.createInjector(new ThrowingModule(), new ThrowingModule());
  140. fail("expected exception");
  141. } catch(CreationException ce) {
  142. assertContains(ce.getMessage(),
  143. "A binding to " + Foo.class.getName() + " was already configured at " + ThrowingModule.class.getName(),
  144. "and an error was thrown while checking duplicate bindings. Error: java.lang.RuntimeException: Boo!",
  145. "at " + ThrowingModule.class.getName());
  146. }
  147. }
  148. public void testChildInjectorDuplicateParentFail() {
  149. Injector injector = Guice.createInjector(
  150. new SimpleModule(foo, pFoo, pclFoo, clFoo, cFoo)
  151. );
  152. try {
  153. injector.createChildInjector(
  154. new SimpleModule(foo, pFoo, pclFoo, clFoo, cFoo)
  155. );
  156. fail("expected exception");
  157. } catch(CreationException ce) {
  158. assertContains(ce.getMessage(),
  159. "A binding to " + Foo.class.getName() + " annotated with " + named("pInstance") + " was already configured at " + SimpleModule.class.getName(),
  160. "at " + SimpleModule.class.getName(),
  161. "A binding to " + Foo.class.getName() + " annotated with " + named("pKey") + " was already configured at " + SimpleModule.class.getName(),
  162. "at " + SimpleModule.class.getName(),
  163. "A binding to " + Foo.class.getName() + " annotated with " + named("linkedKey") + " was already configured at " + SimpleModule.class.getName(),
  164. "at " + SimpleModule.class.getName(),
  165. "A binding to " + Foo.class.getName() + " annotated with " + named("constructor") + " was already configured at " + SimpleModule.class.getName(),
  166. "at " + SimpleModule.class.getName());
  167. }
  168. }
  169. public void testDuplicatesSolelyInChildIgnored() {
  170. Injector injector = Guice.createInjector();
  171. injector.createChildInjector(
  172. new SimpleModule(foo, pFoo, pclFoo, clFoo, cFoo),
  173. new SimpleModule(foo, pFoo, pclFoo, clFoo, cFoo)
  174. );
  175. }
  176. public void testDifferentBindingTypesFail() {
  177. List<Element> elements = Elements.getElements(
  178. new FailedModule(foo, pFoo, pclFoo, clFoo, cFoo)
  179. );
  180. // Make sure every combination of the elements with another element fails.
  181. // This ensures that duplication checks the kind of binding also.
  182. for(Element e1 : elements) {
  183. for(Element e2: elements) {
  184. // if they're the same, this shouldn't fail.
  185. try {
  186. Guice.createInjector(Elements.getModule(Arrays.asList(e1, e2)));
  187. if(e1 != e2) {
  188. fail("must fail!");
  189. }
  190. } catch(CreationException expected) {
  191. if(e1 != e2) {
  192. assertContains(expected.getMessage(),
  193. "A binding to " + Foo.class.getName() + " was already configured at " + FailedModule.class.getName(),
  194. "at " + FailedModule.class.getName());
  195. } else {
  196. throw expected;
  197. }
  198. }
  199. }
  200. }
  201. }
  202. public void testJitBindingsAreCheckedAfterConversions() {
  203. Guice.createInjector(new AbstractModule() {
  204. @Override
  205. protected void configure() {
  206. bind(A.class);
  207. bind(A.class).to(RealA.class);
  208. }
  209. });
  210. }
  211. private static class RealA extends A {}
  212. @ImplementedBy(RealA.class) private static class A {}
  213. private void removeBasicBindings(Collection<Key<?>> bindings) {
  214. bindings.remove(Key.get(Injector.class));
  215. bindings.remove(Key.get(Logger.class));
  216. bindings.remove(Key.get(Stage.class));
  217. }
  218. private static class ThrowingModule extends AbstractModule {
  219. @Override
  220. protected void configure() {
  221. bind(Foo.class).toInstance(new Foo() {
  222. @Override
  223. public boolean equals(Object obj) {
  224. throw new RuntimeException("Boo!");
  225. }
  226. });
  227. }
  228. }
  229. private static abstract class FooModule extends AbstractModule {
  230. protected final FooImpl foo;
  231. protected final Provider<Foo> pFoo;
  232. protected final Class<? extends Provider<? extends Foo>> pclFoo;
  233. protected final Class<? extends Foo> clFoo;
  234. protected final Constructor<FooImpl> cFoo;
  235. FooModule(FooImpl foo, Provider<Foo> pFoo, Class<? extends Provider<? extends Foo>> pclFoo,
  236. Class<? extends Foo> clFoo, Constructor<FooImpl> cFoo) {
  237. this.foo = foo;
  238. this.pFoo = pFoo;
  239. this.pclFoo = pclFoo;
  240. this.clFoo = clFoo;
  241. this.cFoo = cFoo;
  242. }
  243. }
  244. private static class FailedModule extends FooModule {
  245. FailedModule(FooImpl foo, Provider<Foo> pFoo, Class<? extends Provider<? extends Foo>> pclFoo,
  246. Class<? extends Foo> clFoo, Constructor<FooImpl> cFoo) {
  247. super(foo, pFoo, pclFoo, clFoo, cFoo);
  248. }
  249. protected void configure() {
  250. // InstanceBinding
  251. bind(Foo.class).toInstance(foo);
  252. // ProviderInstanceBinding
  253. bind(Foo.class).toProvider(pFoo);
  254. // ProviderKeyBinding
  255. bind(Foo.class).toProvider(pclFoo);
  256. // LinkedKeyBinding
  257. bind(Foo.class).to(clFoo);
  258. // ConstructorBinding
  259. bind(Foo.class).toConstructor(cFoo);
  260. }
  261. }
  262. private static class SimpleModule extends FooModule {
  263. SimpleModule(FooImpl foo, Provider<Foo> pFoo, Class<? extends Provider<? extends Foo>> pclFoo,
  264. Class<? extends Foo> clFoo, Constructor<FooImpl> cFoo) {
  265. super(foo, pFoo, pclFoo, clFoo, cFoo);
  266. }
  267. protected void configure() {
  268. // InstanceBinding
  269. bind(Foo.class).annotatedWith(named("instance")).toInstance(foo);
  270. // ProviderInstanceBinding
  271. bind(Foo.class).annotatedWith(named("pInstance")).toProvider(pFoo);
  272. // ProviderKeyBinding
  273. bind(Foo.class).annotatedWith(named("pKey")).toProvider(pclFoo);
  274. // LinkedKeyBinding
  275. bind(Foo.class).annotatedWith(named("linkedKey")).to(clFoo);
  276. // UntargettedBinding / ConstructorBinding
  277. bind(FooImpl.class);
  278. // ConstructorBinding
  279. bind(Foo.class).annotatedWith(named("constructor")).toConstructor(cFoo);
  280. }
  281. }
  282. private static class ScopedModule extends FooModule {
  283. private final Scope scope;
  284. ScopedModule(Scope scope, FooImpl foo, Provider<Foo> pFoo,
  285. Class<? extends Provider<? extends Foo>> pclFoo, Class<? extends Foo> clFoo,
  286. Constructor<FooImpl> cFoo) {
  287. super(foo, pFoo, pclFoo, clFoo, cFoo);
  288. this.scope = scope;
  289. }
  290. protected void configure() {
  291. // ProviderInstanceBinding
  292. bind(Foo.class).annotatedWith(named("pInstance")).toProvider(pFoo).in(scope);
  293. // ProviderKeyBinding
  294. bind(Foo.class).annotatedWith(named("pKey")).toProvider(pclFoo).in(scope);
  295. // LinkedKeyBinding
  296. bind(Foo.class).annotatedWith(named("linkedKey")).to(clFoo).in(scope);
  297. // UntargettedBinding / ConstructorBinding
  298. bind(FooImpl.class).in(scope);
  299. // ConstructorBinding
  300. bind(Foo.class).annotatedWith(named("constructor")).toConstructor(cFoo).in(scope);
  301. }
  302. }
  303. private static class AnnotatedScopeModule extends FooModule {
  304. private final Class<? extends Annotation> scope;
  305. AnnotatedScopeModule(Class<? extends Annotation> scope, FooImpl foo, Provider<Foo> pFoo,
  306. Class<? extends Provider<? extends Foo>> pclFoo, Class<? extends Foo> clFoo,
  307. Constructor<FooImpl> cFoo) {
  308. super(foo, pFoo, pclFoo, clFoo, cFoo);
  309. this.scope = scope;
  310. }
  311. protected void configure() {
  312. // ProviderInstanceBinding
  313. bind(Foo.class).annotatedWith(named("pInstance")).toProvider(pFoo).in(scope);
  314. // ProviderKeyBinding
  315. bind(Foo.class).annotatedWith(named("pKey")).toProvider(pclFoo).in(scope);
  316. // LinkedKeyBinding
  317. bind(Foo.class).annotatedWith(named("linkedKey")).to(clFoo).in(scope);
  318. // UntargettedBinding / ConstructorBinding
  319. bind(FooImpl.class).in(scope);
  320. // ConstructorBinding
  321. bind(Foo.class).annotatedWith(named("constructor")).toConstructor(cFoo).in(scope);
  322. }
  323. }
  324. private static interface Foo {}
  325. private static class FooImpl implements Foo {
  326. @Inject public FooImpl() {}
  327. private static Constructor<FooImpl> cxtor() {
  328. try {
  329. return FooImpl.class.getConstructor();
  330. } catch (SecurityException e) {
  331. throw new RuntimeException(e);
  332. } catch (NoSuchMethodException e) {
  333. throw new RuntimeException(e);
  334. }
  335. }
  336. }
  337. private static class FooProvider implements Provider<Foo> {
  338. public Foo get() {
  339. return new FooImpl();
  340. }
  341. }
  342. private static class Bar implements Foo {
  343. @Inject public Bar() {}
  344. private static Constructor<Bar> cxtor() {
  345. try {
  346. return Bar.class.getConstructor();
  347. } catch (SecurityException e) {
  348. throw new RuntimeException(e);
  349. } catch (NoSuchMethodException e) {
  350. throw new RuntimeException(e);
  351. }
  352. }
  353. }
  354. private static class BarProvider implements Provider<Foo> {
  355. public Foo get() {
  356. return new Bar();
  357. }
  358. }
  359. }