PageRenderTime 86ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://github.com/peterlynch/spice
Java | 448 lines | 361 code | 51 blank | 36 comment | 0 complexity | fb2c91412103eb1bc5cc9502dd1a944c MD5 | raw file
  1. /**
  2. * Copyright (C) 2007 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.Asserts.assertNotSerializable;
  19. import com.google.inject.internal.util.ImmutableList;
  20. import com.google.inject.internal.util.Iterables;
  21. import com.google.inject.internal.util.Lists;
  22. import com.google.inject.name.Named;
  23. import com.google.inject.name.Names;
  24. import com.google.inject.spi.Message;
  25. import com.google.inject.util.Providers;
  26. import java.io.IOException;
  27. import java.util.Comparator;
  28. import java.util.Date;
  29. import java.util.List;
  30. import java.util.concurrent.Callable;
  31. import java.util.logging.Handler;
  32. import java.util.logging.LogRecord;
  33. import java.util.logging.Logger;
  34. import junit.framework.TestCase;
  35. /**
  36. * @author crazybob@google.com (Bob Lee)
  37. */
  38. public class BinderTest extends TestCase {
  39. private final Logger loggerToWatch = Logger.getLogger(Guice.class.getName());
  40. private final List<LogRecord> logRecords = Lists.newArrayList();
  41. private final Handler fakeHandler = new Handler() {
  42. public void publish(LogRecord logRecord) {
  43. logRecords.add(logRecord);
  44. }
  45. public void flush() {}
  46. public void close() throws SecurityException {}
  47. };
  48. Provider<Foo> fooProvider;
  49. @Override protected void setUp() throws Exception {
  50. super.setUp();
  51. loggerToWatch.addHandler(fakeHandler);
  52. }
  53. @Override protected void tearDown() throws Exception {
  54. loggerToWatch.removeHandler(fakeHandler);
  55. super.tearDown();
  56. }
  57. public void testProviderFromBinder() {
  58. Guice.createInjector(new Module() {
  59. public void configure(Binder binder) {
  60. fooProvider = binder.getProvider(Foo.class);
  61. try {
  62. fooProvider.get();
  63. } catch (IllegalStateException e) { /* expected */ }
  64. }
  65. });
  66. assertNotNull(fooProvider.get());
  67. }
  68. static class Foo {}
  69. public void testMissingBindings() {
  70. try {
  71. Guice.createInjector(new AbstractModule() {
  72. public void configure() {
  73. getProvider(Runnable.class);
  74. bind(Comparator.class);
  75. requireBinding(Key.get(new TypeLiteral<Callable<String>>() {}));
  76. bind(Date.class).annotatedWith(Names.named("date"));
  77. }
  78. });
  79. } catch (CreationException e) {
  80. assertEquals(4, e.getErrorMessages().size());
  81. assertContains(e.getMessage(),
  82. "1) No implementation for java.lang.Runnable was bound.",
  83. "at " + getClass().getName(),
  84. "2) No implementation for " + Comparator.class.getName() + " was bound.",
  85. "at " + getClass().getName(),
  86. "3) No implementation for java.util.concurrent.Callable<java.lang.String> was bound.",
  87. "at " + getClass().getName(),
  88. "4) No implementation for java.util.Date annotated with @"
  89. + Named.class.getName() + "(value=date) was bound.",
  90. "at " + getClass().getName());
  91. }
  92. }
  93. public void testMissingDependency() {
  94. try {
  95. Guice.createInjector(new AbstractModule() {
  96. public void configure() {
  97. bind(NeedsRunnable.class);
  98. }
  99. });
  100. } catch (CreationException e) {
  101. assertEquals(1, e.getErrorMessages().size());
  102. assertContains(e.getMessage(),
  103. "No implementation for java.lang.Runnable was bound.",
  104. "for field at " + NeedsRunnable.class.getName(), ".runnable(BinderTest.java:",
  105. "at " + getClass().getName(), ".configure(BinderTest.java:");
  106. }
  107. }
  108. static class NeedsRunnable {
  109. @Inject Runnable runnable;
  110. }
  111. public void testDanglingConstantBinding() {
  112. try {
  113. Guice.createInjector(new AbstractModule() {
  114. @Override public void configure() {
  115. bindConstant();
  116. }
  117. });
  118. fail();
  119. } catch (CreationException expected) {
  120. assertContains(expected.getMessage(),
  121. "1) Missing constant value. Please call to(...).",
  122. "at " + getClass().getName());
  123. }
  124. }
  125. public void testRecursiveBinding() {
  126. try {
  127. Guice.createInjector(new AbstractModule() {
  128. @Override public void configure() {
  129. bind(Runnable.class).to(Runnable.class);
  130. }
  131. });
  132. fail();
  133. } catch (CreationException expected) {
  134. assertContains(expected.getMessage(),
  135. "1) Binding points to itself.",
  136. "at " + getClass().getName(), ".configure(BinderTest.java:");
  137. }
  138. }
  139. public void testBindingNullConstant() {
  140. try {
  141. Guice.createInjector(new AbstractModule() {
  142. @Override public void configure() {
  143. String none = null;
  144. bindConstant().annotatedWith(Names.named("nullOne")).to(none);
  145. bind(String.class).annotatedWith(Names.named("nullTwo")).toInstance(none);
  146. }
  147. });
  148. fail();
  149. } catch (CreationException expected) {
  150. assertContains(expected.getMessage(),
  151. "1) Binding to null instances is not allowed. Use toProvider(Providers.of(null))",
  152. "2) Binding to null instances is not allowed. Use toProvider(Providers.of(null))");
  153. }
  154. }
  155. public void testToStringOnBinderApi() {
  156. try {
  157. Guice.createInjector(new AbstractModule() {
  158. @Override public void configure() {
  159. assertEquals("Binder", binder().toString());
  160. assertEquals("Provider<java.lang.Integer>", getProvider(Integer.class).toString());
  161. assertEquals("Provider<java.util.List<java.lang.String>>",
  162. getProvider(Key.get(new TypeLiteral<List<String>>() {})).toString());
  163. assertEquals("BindingBuilder<java.lang.Integer>",
  164. bind(Integer.class).toString());
  165. assertEquals("BindingBuilder<java.lang.Integer>",
  166. bind(Integer.class).annotatedWith(Names.named("a")).toString());
  167. assertEquals("ConstantBindingBuilder", bindConstant().toString());
  168. assertEquals("ConstantBindingBuilder",
  169. bindConstant().annotatedWith(Names.named("b")).toString());
  170. assertEquals("AnnotatedElementBuilder",
  171. binder().newPrivateBinder().expose(Integer.class).toString());
  172. }
  173. });
  174. fail();
  175. } catch (CreationException ignored) {
  176. }
  177. }
  178. public void testNothingIsSerializableInBinderApi() {
  179. try {
  180. Guice.createInjector(new AbstractModule() {
  181. @Override public void configure() {
  182. try {
  183. assertNotSerializable(binder());
  184. assertNotSerializable(getProvider(Integer.class));
  185. assertNotSerializable(getProvider(Key.get(new TypeLiteral<List<String>>() {})));
  186. assertNotSerializable(bind(Integer.class));
  187. assertNotSerializable(bind(Integer.class).annotatedWith(Names.named("a")));
  188. assertNotSerializable(bindConstant());
  189. assertNotSerializable(bindConstant().annotatedWith(Names.named("b")));
  190. } catch (IOException e) {
  191. fail(e.getMessage());
  192. }
  193. }
  194. });
  195. fail();
  196. } catch (CreationException ignored) {
  197. }
  198. }
  199. /**
  200. * Although {@code String[].class} isn't equal to {@code new
  201. * GenericArrayTypeImpl(String.class)}, Guice should treat these two types
  202. * interchangeably.
  203. */
  204. public void testArrayTypeCanonicalization() {
  205. final String[] strings = new String[] { "A" };
  206. final Integer[] integers = new Integer[] { 1 };
  207. Injector injector = Guice.createInjector(new AbstractModule() {
  208. protected void configure() {
  209. bind(String[].class).toInstance(strings);
  210. bind(new TypeLiteral<Integer[]>() {}).toInstance(integers);
  211. }
  212. });
  213. assertSame(integers, injector.getInstance(Key.get(new TypeLiteral<Integer[]>() {})));
  214. assertSame(integers, injector.getInstance(new Key<Integer[]>() {}));
  215. assertSame(integers, injector.getInstance(Integer[].class));
  216. assertSame(strings, injector.getInstance(Key.get(new TypeLiteral<String[]>() {})));
  217. assertSame(strings, injector.getInstance(new Key<String[]>() {}));
  218. assertSame(strings, injector.getInstance(String[].class));
  219. try {
  220. Guice.createInjector(new AbstractModule() {
  221. protected void configure() {
  222. bind(String[].class).toInstance(new String[] { "A" });
  223. bind(new TypeLiteral<String[]>() {}).toInstance(new String[] { "B" });
  224. }
  225. });
  226. fail();
  227. } catch (CreationException expected) {
  228. assertContains(expected.getMessage(),
  229. "1) A binding to java.lang.String[] was already configured at " + getClass().getName(),
  230. "at " + getClass().getName(), ".configure(BinderTest.java:");
  231. assertContains(expected.getMessage(), "1 error");
  232. }
  233. // passes because duplicates are ignored
  234. injector = Guice.createInjector(new AbstractModule() {
  235. protected void configure() {
  236. bind(String[].class).toInstance(strings);
  237. bind(new TypeLiteral<String[]>() {}).toInstance(strings);
  238. }
  239. });
  240. assertSame(strings, injector.getInstance(Key.get(new TypeLiteral<String[]>() {})));
  241. assertSame(strings, injector.getInstance(new Key<String[]>() {}));
  242. assertSame(strings, injector.getInstance(String[].class));
  243. }
  244. /**
  245. * Untargetted bindings should follow @ImplementedBy and @ProvidedBy
  246. * annotations if they exist. Otherwise the class should be constructed
  247. * directly.
  248. */
  249. public void testUntargettedBinding() {
  250. Injector injector = Guice.createInjector(new AbstractModule() {
  251. protected void configure() {
  252. bind(HasProvidedBy1.class);
  253. bind(HasImplementedBy1.class);
  254. bind(HasProvidedBy2.class);
  255. bind(HasImplementedBy2.class);
  256. bind(JustAClass.class);
  257. }
  258. });
  259. assertNotNull(injector.getInstance(HasProvidedBy1.class));
  260. assertNotNull(injector.getInstance(HasImplementedBy1.class));
  261. assertNotSame(HasProvidedBy2.class,
  262. injector.getInstance(HasProvidedBy2.class).getClass());
  263. assertSame(ExtendsHasImplementedBy2.class,
  264. injector.getInstance(HasImplementedBy2.class).getClass());
  265. assertSame(JustAClass.class, injector.getInstance(JustAClass.class).getClass());
  266. }
  267. public void testPartialInjectorGetInstance() {
  268. Injector injector = Guice.createInjector();
  269. try {
  270. injector.getInstance(MissingParameter.class);
  271. fail();
  272. } catch (ConfigurationException expected) {
  273. assertContains(expected.getMessage(),
  274. "1) Could not find a suitable constructor in " + NoInjectConstructor.class.getName(),
  275. "at " + MissingParameter.class.getName() + ".<init>(BinderTest.java:");
  276. }
  277. }
  278. public void testUserReportedError() {
  279. final Message message = new Message(getClass(), "Whoops!");
  280. try {
  281. Guice.createInjector(new AbstractModule() {
  282. protected void configure() {
  283. addError(message);
  284. }
  285. });
  286. fail();
  287. } catch (CreationException expected) {
  288. assertSame(message, Iterables.getOnlyElement(expected.getErrorMessages()));
  289. }
  290. }
  291. public void testUserReportedErrorsAreAlsoLogged() {
  292. try {
  293. Guice.createInjector(new AbstractModule() {
  294. protected void configure() {
  295. addError(new Message(ImmutableList.of(), "Whoops!", new IllegalArgumentException()));
  296. }
  297. });
  298. fail();
  299. } catch (CreationException expected) {
  300. }
  301. LogRecord logRecord = Iterables.getOnlyElement(this.logRecords);
  302. assertContains(logRecord.getMessage(),
  303. "An exception was caught and reported. Message: java.lang.IllegalArgumentException");
  304. }
  305. public void testBindingToProvider() {
  306. try {
  307. Guice.createInjector(new AbstractModule() {
  308. protected void configure() {
  309. bind(new TypeLiteral<Provider<String>>() {}).toInstance(Providers.of("A"));
  310. }
  311. });
  312. fail();
  313. } catch (CreationException expected) {
  314. assertContains(expected.getMessage(),
  315. "1) Binding to Provider is not allowed.",
  316. "at " + BinderTest.class.getName(), "configure(BinderTest.java:");
  317. }
  318. }
  319. public void testCannotBindToGuiceTypes() {
  320. final Named red = Names.named("red");
  321. try {
  322. Guice.createInjector(new AbstractModule() {
  323. protected void configure() {
  324. bind(AbstractModule.class).annotatedWith(red)
  325. .toProvider(Providers.<AbstractModule>of(null));
  326. bind(Binder.class).annotatedWith(red).toProvider(Providers.<Binder>of(null));
  327. bind(Binding.class).annotatedWith(red).toProvider(Providers.<Binding>of(null));
  328. bind(Injector.class).annotatedWith(red).toProvider(Providers.<Injector>of(null));
  329. bind(Key.class).annotatedWith(red).toProvider(Providers.<Key>of(null));
  330. bind(Module.class).annotatedWith(red).toProvider(Providers.<Module>of(null));
  331. bind(Provider.class).annotatedWith(red).toProvider(Providers.<Provider>of(null));
  332. bind(Scope.class).annotatedWith(red).toProvider(Providers.<Scope>of(null));
  333. bind(TypeLiteral.class).annotatedWith(red).toProvider(Providers.<TypeLiteral>of(null));
  334. bind(new TypeLiteral<Key<String>>() {}).toProvider(Providers.<Key<String>>of(null));
  335. }
  336. });
  337. fail();
  338. } catch (CreationException expected) {
  339. assertContains(expected.getMessage(),
  340. "Binding to core guice framework type is not allowed: AbstractModule.",
  341. "Binding to core guice framework type is not allowed: Binder.",
  342. "Binding to core guice framework type is not allowed: Binding.",
  343. "Binding to core guice framework type is not allowed: Injector.",
  344. "Binding to core guice framework type is not allowed: Key.",
  345. "Binding to core guice framework type is not allowed: Module.",
  346. "Binding to Provider is not allowed.",
  347. "Binding to core guice framework type is not allowed: Scope.",
  348. "Binding to core guice framework type is not allowed: TypeLiteral.",
  349. "Binding to core guice framework type is not allowed: Key.");
  350. }
  351. }
  352. static class MissingParameter {
  353. @Inject MissingParameter(NoInjectConstructor noInjectConstructor) {}
  354. }
  355. static class NoInjectConstructor {
  356. private NoInjectConstructor() {}
  357. }
  358. @ProvidedBy(HasProvidedBy1Provider.class)
  359. interface HasProvidedBy1 {}
  360. static class HasProvidedBy1Provider implements Provider<HasProvidedBy1> {
  361. public HasProvidedBy1 get() {
  362. return new HasProvidedBy1() {};
  363. }
  364. }
  365. @ImplementedBy(ImplementsHasImplementedBy1.class)
  366. interface HasImplementedBy1 {}
  367. static class ImplementsHasImplementedBy1 implements HasImplementedBy1 {}
  368. @ProvidedBy(HasProvidedBy2Provider.class)
  369. static class HasProvidedBy2 {}
  370. static class HasProvidedBy2Provider implements Provider<HasProvidedBy2> {
  371. public HasProvidedBy2 get() {
  372. return new HasProvidedBy2() {};
  373. }
  374. }
  375. @ImplementedBy(ExtendsHasImplementedBy2.class)
  376. static class HasImplementedBy2 {}
  377. static class ExtendsHasImplementedBy2 extends HasImplementedBy2 {}
  378. static class JustAClass {}
  379. // public void testBindInterfaceWithoutImplementation() {
  380. // Guice.createInjector(new AbstractModule() {
  381. // protected void configure() {
  382. // bind(Runnable.class);
  383. // }
  384. // }).getInstance(Runnable.class);
  385. // }
  386. enum Roshambo { ROCK, SCISSORS, PAPER }
  387. public void testInjectRawProvider() {
  388. try {
  389. Guice.createInjector().getInstance(Provider.class);
  390. fail();
  391. } catch (ConfigurationException expected) {
  392. Asserts.assertContains(expected.getMessage(),
  393. "1) Cannot inject a Provider that has no type parameter",
  394. "while locating " + Provider.class.getName());
  395. }
  396. }
  397. }