View Javadoc

1   /*
2    * Grapht, an open source dependency injector.
3    * Copyright 2014-2015 various contributors (see CONTRIBUTORS.txt)
4    * Copyright 2010-2014 Regents of the University of Minnesota
5    *
6    * This program is free software; you can redistribute it and/or modify
7    * it under the terms of the GNU Lesser General Public License as
8    * published by the Free Software Foundation; either version 2.1 of the
9    * License, or (at your option) any later version.
10   *
11   * This program is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13   * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14   * details.
15   *
16   * You should have received a copy of the GNU General Public License along with
17   * this program; if not, write to the Free Software Foundation, Inc., 51
18   * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19   */
20  package org.grouplens.grapht;
21  
22  import org.grouplens.grapht.annotation.AnnotationBuilder;
23  import org.grouplens.grapht.reflect.internal.types.*;
24  import org.junit.Assert;
25  import org.junit.Test;
26  
27  import javax.inject.Named;
28  
29  public class InjectorBuilderTest {
30      @Test
31      public void testNewInstanceProviderCachePolicy() throws Exception {
32          // Test that injecting a new-instance provider creates
33          // new instances each time
34          InjectorBuilder b = InjectorBuilder.create().setProviderInjectionEnabled(true);
35          b.bind(CycleA.class).unshared().to(CycleA.class);
36          b.bind(CycleB.class).shared().to(CycleB.class);
37          Injector i = b.build();
38          
39          CycleB cycleB = i.getInstance(CycleB.class);
40          
41          Assert.assertNotSame(cycleB.pa.get(), cycleB.pa.get());
42      }
43      
44      @Test
45      public void testMemoizedProviderCachePolicy() throws Exception {
46          // Test that injecting a memoized provider into a new instance
47          // reuses the same instance
48          InjectorBuilder b = InjectorBuilder.create().setProviderInjectionEnabled(true);
49          b.bind(CycleA.class).shared().to(CycleA.class);
50          b.bind(CycleB.class).unshared().to(CycleB.class);
51          Injector i = b.build();
52          
53          CycleB b1 = i.getInstance(CycleB.class);
54          CycleB b2 = i.getInstance(CycleB.class);
55          
56          Assert.assertNotSame(b1, b2);
57          Assert.assertSame(b1.pa, b2.pa);
58          Assert.assertSame(b1.pa.get(), b2.pa.get());
59      }
60      
61      @Test
62      public void testProviderInjectionCycleBreaking() throws Exception {
63          InjectorBuilder b = InjectorBuilder.create().setProviderInjectionEnabled(true);
64          Injector i = b.build();
65          
66          CycleA cycleA = i.getInstance(CycleA.class);
67          Assert.assertNotNull(cycleA.b);
68          Assert.assertSame(cycleA, cycleA.b.pa.get());
69      }
70      
71      @Test
72      public void testSimpleProviderInjection() throws Exception {
73          InjectorBuilder b = InjectorBuilder.create().setProviderInjectionEnabled(true);
74          Injector i = b.build();
75          
76          TypeD d = i.getInstance(TypeD.class);
77          Assert.assertNotNull(d.getProvider());
78          
79          // assert that default configuration was used
80          TypeC c = d.getProvider().get();
81          Assert.assertEquals(5, c.getIntValue());
82          Assert.assertTrue(c.getInterfaceA() instanceof TypeB);
83          Assert.assertTrue(c.getTypeA() instanceof TypeB);
84          Assert.assertTrue(c.getInterfaceB() instanceof TypeB);
85          Assert.assertTrue(c.getTypeB() instanceof TypeB);
86      }
87      
88      @Test
89      public void testNewInstanceCachePolicy() throws Exception {
90          // Test that setting the cache policy to NEW_INSTANCE 
91          // overrides default MEMOIZE behavior
92          InjectorBuilder b = InjectorBuilder.create();
93          b.bind(InterfaceA.class).unshared().to(TypeA.class);
94          b.bind(InterfaceB.class).to(TypeB.class);
95          Injector i = b.build();
96          
97          InterfaceA a1 = i.getInstance(InterfaceA.class);
98          InterfaceA a2 = i.getInstance(InterfaceA.class);
99          InterfaceB b1 = i.getInstance(InterfaceB.class);
100         InterfaceB b2 = i.getInstance(InterfaceB.class);
101         
102         Assert.assertTrue(a1 instanceof TypeA);
103         Assert.assertTrue(a2 instanceof TypeA);
104         Assert.assertNotSame(a1, a2);
105         
106         Assert.assertTrue(b1 instanceof TypeB);
107         Assert.assertTrue(b2 instanceof TypeB);
108         Assert.assertSame(b1, b2);
109     }
110     
111     @Test
112     public void testMemoizeCachePolicy() throws Exception {
113         // Test that setting the cache policy to MEMOIZE
114         // overrides the default NEW_INSTANCE behavior
115         InjectorBuilder b = InjectorBuilder.create();
116         b.setDefaultCachePolicy(CachePolicy.NEW_INSTANCE);
117         b.bind(InterfaceA.class).shared().to(TypeA.class);
118         b.bind(InterfaceB.class).to(TypeB.class);
119         Injector i = b.build();
120         
121         InterfaceA a1 = i.getInstance(InterfaceA.class);
122         InterfaceA a2 = i.getInstance(InterfaceA.class);
123         InterfaceB b1 = i.getInstance(InterfaceB.class);
124         InterfaceB b2 = i.getInstance(InterfaceB.class);
125         
126         Assert.assertTrue(a1 instanceof TypeA);
127         Assert.assertTrue(a2 instanceof TypeA);
128         Assert.assertSame(a1, a2);
129         
130         Assert.assertTrue(b1 instanceof TypeB);
131         Assert.assertTrue(b2 instanceof TypeB);
132         Assert.assertNotSame(b1, b2);
133     }
134     
135     @Test
136     public void testMemoizeDefaultCachePolicy() throws Exception {
137         // Test that using the default binding cache policy 
138         // correctly uses the default MEMOIZE policy of the injector
139         InjectorBuilder b = InjectorBuilder.create();
140         b.setDefaultCachePolicy(CachePolicy.MEMOIZE);
141         b.bind(InterfaceA.class).to(TypeA.class);
142         b.bind(InterfaceB.class).to(TypeB.class);
143         Injector i = b.build();
144         
145         InterfaceA a1 = i.getInstance(InterfaceA.class);
146         InterfaceA a2 = i.getInstance(InterfaceA.class);
147         InterfaceB b1 = i.getInstance(InterfaceB.class);
148         InterfaceB b2 = i.getInstance(InterfaceB.class);
149         
150         Assert.assertTrue(a1 instanceof TypeA);
151         Assert.assertTrue(a2 instanceof TypeA);
152         Assert.assertSame(a1, a2);
153         
154         Assert.assertTrue(b1 instanceof TypeB);
155         Assert.assertTrue(b2 instanceof TypeB);
156         Assert.assertSame(b1, b2);
157     }
158     
159     @Test
160     public void testNewInstanceDefaultCachePolicy() throws Exception {
161         // Test that using the default binding cache policy 
162         // correctly uses the default MEMOIZE policy of the injector
163         InjectorBuilder b = InjectorBuilder.create();
164         b.setDefaultCachePolicy(CachePolicy.NEW_INSTANCE);
165         b.bind(InterfaceA.class).to(TypeA.class);
166         b.bind(InterfaceB.class).to(TypeB.class);
167         Injector i = b.build();
168         
169         InterfaceA a1 = i.getInstance(InterfaceA.class);
170         InterfaceA a2 = i.getInstance(InterfaceA.class);
171         InterfaceB b1 = i.getInstance(InterfaceB.class);
172         InterfaceB b2 = i.getInstance(InterfaceB.class);
173         
174         Assert.assertTrue(a1 instanceof TypeA);
175         Assert.assertTrue(a2 instanceof TypeA);
176         Assert.assertNotSame(a1, a2);
177         
178         Assert.assertTrue(b1 instanceof TypeB);
179         Assert.assertTrue(b2 instanceof TypeB);
180         Assert.assertNotSame(b1, b2);        
181     }
182     
183     @Test
184     public void testInjectorBuilderWithAnnotatedBindings() throws Exception {
185         // Test that injector building works as expected
186         TypeA a1 = new TypeA();
187         InterfaceA a2 = new TypeA();
188         TypeB b1 = new TypeB();
189         InterfaceB b2 = new TypeB();
190         
191         InjectorBuilder b = InjectorBuilder.create();
192         b.bind(TypeA.class).to(a1);
193         b.bind(InterfaceA.class).withQualifier(RoleA.class).to(a2);
194         b.bind(TypeB.class).to(b1);
195         b.bind(InterfaceB.class).withQualifier(RoleD.class).to(b2);
196         Injector i = b.build();
197         
198         TypeC c = i.getInstance(TypeC.class);
199         Assert.assertEquals(5, c.getIntValue());
200         Assert.assertSame(a1, c.getTypeA());
201         Assert.assertSame(a2, c.getInterfaceA());
202         Assert.assertSame(b1, c.getTypeB());
203         Assert.assertSame(b2, c.getInterfaceB());
204         
205         // now assert that it memoizes instances and merges graphs properly
206         Assert.assertSame(a1, i.getInstance(TypeA.class));
207         Assert.assertSame(a2, i.getInstance(new AnnotationBuilder<RoleA>(RoleA.class).build(), InterfaceA.class));
208         Assert.assertSame(b1, i.getInstance(TypeB.class));
209         Assert.assertSame(b2, i.getInstance(new AnnotationBuilder<RoleD>(RoleD.class).build(), InterfaceB.class));
210     }
211     
212     @Test
213     public void testInjectorBuilderWithNamedBindings() throws Exception {
214         InjectorBuilder b = InjectorBuilder.create();
215         b.bind(String.class).withQualifier(new AnnotationBuilder<Named>(Named.class).set("value", "unused").build()).to("shouldn't see this"); // extra binding to make sure it's skipped
216         b.bind(String.class).withQualifier(new AnnotationBuilder<Named>(Named.class).set("value", "test1").build()).to("hello world");
217         Injector i = b.build();
218         
219         NamedType c = i.getInstance(NamedType.class);
220         Assert.assertEquals("hello world", c.getNamedString());
221         Assert.assertEquals("hello world", i.getInstance(new AnnotationBuilder<Named>(Named.class).set("value", "test1").build(), String.class));
222     }
223     
224     @Test(expected=InjectionException.class)
225     public void testInjectorMissingNamedBinding() throws Exception {
226         InjectorBuilder b = InjectorBuilder.create();
227         b.bind(String.class).withQualifier(new AnnotationBuilder<Named>(Named.class).set("value", "unused").build()).to("shouldn't see this"); // extra binding to make sure it's skipped
228         Injector i = b.build();
229         
230         // since we don't have a 'test1' bound, the resolver cannot find 
231         // a usable constructor for String (although it has the default constructor,
232         // it defines others that are not injectable).
233         i.getInstance(NamedType.class);
234     }
235     
236     @Test(expected=InjectionException.class)
237     public void testInjectorNoConstructor() throws Exception {
238         InjectorBuilder b = InjectorBuilder.create();
239         b.bind(ShouldWork.class).to(NotInjectable.class);
240         Injector i = b.build();
241         
242         i.getInstance(ShouldWork.class);
243     }
244 
245     @Test
246     public void testNullBinding() throws InjectionException {
247         InjectorBuilder b = InjectorBuilder.create();
248         b.bind(InterfaceA.class).toNull();
249         Injector i = b.build();
250         TypeN n = i.getInstance(TypeN.class);
251         Assert.assertNotNull(n);
252         Assert.assertNull(n.getObject());
253     }
254 
255     @Test(expected=ConstructionException.class)
256     public void testBadNullBinding() throws InjectionException {
257         InjectorBuilder b = InjectorBuilder.create();
258         b.bind(InterfaceA.class).toNull();
259         Injector i = b.build();
260         i.getInstance(TypeN2.class);
261     }
262     
263     public static interface ShouldWork { }
264     
265     public static class NotInjectable implements ShouldWork {
266         public NotInjectable(Object o) { }
267     }
268 }