1 /** 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 17 package com.google.inject.grapher; 18 19 import com.google.common.collect.ImmutableSet; 20 import com.google.inject.AbstractModule; 21 import com.google.inject.Binding; 22 import com.google.inject.Guice; 23 import com.google.inject.Inject; 24 import com.google.inject.Key; 25 import com.google.inject.Module; 26 import com.google.inject.Provider; 27 import com.google.inject.TypeLiteral; 28 import com.google.inject.name.Names; 29 import com.google.inject.spi.ConstructorBinding; 30 import com.google.inject.spi.ConvertedConstantBinding; 31 import com.google.inject.spi.Dependency; 32 import com.google.inject.spi.HasDependencies; 33 import com.google.inject.spi.InstanceBinding; 34 import com.google.inject.spi.LinkedKeyBinding; 35 import com.google.inject.spi.ProviderBinding; 36 import com.google.inject.spi.ProviderInstanceBinding; 37 import com.google.inject.spi.ProviderKeyBinding; 38 39 import junit.framework.TestCase; 40 41 import java.util.Collection; 42 import java.util.Set; 43 44 /** 45 * Tests for {@link TransitiveDependencyVisitor}. 46 * 47 * @author phopkins@gmail.com (Pete Hopkins) 48 */ 49 public class TransitiveDependencyVisitorTest extends TestCase { 50 private TransitiveDependencyVisitor visitor; 51 52 @Override setUp()53 protected void setUp() throws Exception { 54 super.setUp(); 55 56 visitor = new TransitiveDependencyVisitor(); 57 } 58 testVisitConstructor()59 public void testVisitConstructor() { 60 Binding<?> binding = getBinding(Key.get(ConstructedClass.class)); 61 Collection<Key<?>> dependencies = visitor.visit((ConstructorBinding<?>) binding); 62 63 assertDependencies(dependencies, Key.get(A.class), Key.get(B.class), Key.get(C.class), 64 Key.get(D.class)); 65 } 66 testVisitConvertedConstant()67 public void testVisitConvertedConstant() { 68 Binding<?> binding = getBinding(Key.get(Integer.class, Names.named("number")), 69 new ConvertedConstantModule()); 70 Collection<Key<?>> dependencies = visitor.visit( 71 (ConvertedConstantBinding<?>) binding); 72 73 assertDependencies(dependencies, Key.get(String.class, Names.named("number"))); 74 } 75 testVisitInstance()76 public void testVisitInstance() { 77 Binding<?> binding = getBinding(Key.get(ConstructedClass.class), new InstanceModule()); 78 Collection<Key<?>> dependencies = visitor.visit( 79 (InstanceBinding<?>) binding); 80 81 // Dependencies will only be on the field- and method-injected classes. 82 assertDependencies(dependencies, Key.get(A.class), Key.get(D.class)); 83 } 84 testVisitInstance_instanceHasDependencies()85 public void testVisitInstance_instanceHasDependencies() { 86 Binding<?> binding = getBinding(Key.get(Interface.class), new HasDependenciesModule()); 87 Collection<Key<?>> dependencies = visitor.visit( 88 (InstanceBinding<?>) binding); 89 90 // Dependencies should only be on the stated 91 // HasDependencies#getDependencies() values 92 assertDependencies(dependencies, Key.get(G.class)); 93 } 94 testVisitLinkedKey()95 public void testVisitLinkedKey() { 96 Binding<?> binding = getBinding(Key.get(Interface.class), new LinkedKeyModule()); 97 Collection<Key<?>> dependencies = visitor.visit((LinkedKeyBinding<?>) binding); 98 99 // Dependency should be to the class this interface is bound to. 100 assertDependencies(dependencies, Key.get(ConstructedClass.class)); 101 } 102 testVisitProviderBinding()103 public void testVisitProviderBinding() { 104 Binding<?> binding = getBinding(Key.get(new TypeLiteral<Provider<ConstructedClass>>() {})); 105 Collection<Key<?>> dependencies = visitor.visit((ProviderBinding<?>) binding); 106 107 assertDependencies(dependencies, Key.get(ConstructedClass.class)); 108 } 109 testVisitProviderInstance()110 public void testVisitProviderInstance() { 111 Binding<?> binding = getBinding(Key.get(ConstructedClass.class), 112 new ProviderInstanceModule()); 113 Collection<Key<?>> dependencies = visitor.visit( 114 (ProviderInstanceBinding<?>) binding); 115 116 // Dependencies will only be on the field- and method-injected classes. 117 assertDependencies(dependencies, Key.get(E.class), Key.get(F.class)); 118 } 119 testVisitProviderKey()120 public void testVisitProviderKey() { 121 Binding<?> binding = getBinding(Key.get(ConstructedClass.class), new ProviderKeyModule()); 122 Collection<Key<?>> dependencies = visitor.visit((ProviderKeyBinding<?>) binding); 123 124 // Dependency should be to the class that provides this one. 125 assertDependencies(dependencies, Key.get(ConstructedClassProvider.class)); 126 } 127 getBinding(Key<?> key, Module... modules)128 private Binding<?> getBinding(Key<?> key, Module... modules) { 129 return Guice.createInjector(modules).getBinding(key); 130 } 131 assertDependencies(Collection<Key<?>> dependencies, Key<?>... keys)132 private void assertDependencies(Collection<Key<?>> dependencies, Key<?>... keys) { 133 assertNotNull("Dependencies should not be null", dependencies); 134 assertEquals("There should be " + keys.length + " dependencies", 135 keys.length, dependencies.size()); 136 137 for (Key<?> key : keys) { 138 assertTrue("Dependencies should contain " + key, dependencies.contains(key)); 139 } 140 } 141 142 private static class A {} 143 private static class B {} 144 private static class C {} 145 private static class D {} 146 private static class E {} 147 private static class F {} 148 private static class G {} 149 150 private static interface Interface {} 151 152 private static class ConstructedClass implements Interface { 153 @Inject A a; ConstructedClass()154 ConstructedClass() {} ConstructedClass(B b, C c)155 @Inject ConstructedClass(B b, C c) {} setD(D d)156 @Inject void setD(D d) {} 157 } 158 159 private static class ConstructedClassProvider implements Provider<ConstructedClass> { 160 @Inject E e; ConstructedClassProvider()161 ConstructedClassProvider() {} ConstructedClassProvider(A a, B b, C c)162 @Inject ConstructedClassProvider(A a, B b, C c) {} setF(F f)163 @Inject void setF(F f) {} 164 get()165 public ConstructedClass get() { 166 return null; 167 } 168 } 169 170 private static class HasDependenciesClass implements Interface, HasDependencies { 171 @Inject A a; 172 @Inject B b; 173 getDependencies()174 public Set<Dependency<?>> getDependencies() { 175 return ImmutableSet.<Dependency<?>>of(Dependency.get(Key.get(G.class))); 176 } 177 } 178 179 private static class ConvertedConstantModule extends AbstractModule { 180 @Override configure()181 protected void configure() { 182 bindConstant().annotatedWith(Names.named("number")).to("2008"); 183 } 184 } 185 186 private static class InstanceModule extends AbstractModule { 187 @Override configure()188 protected void configure() { 189 bind(ConstructedClass.class).toInstance(new ConstructedClass()); 190 } 191 } 192 193 private static class LinkedKeyModule extends AbstractModule { 194 @Override configure()195 protected void configure() { 196 bind(Interface.class).to(ConstructedClass.class); 197 } 198 } 199 200 private static class ProviderInstanceModule extends AbstractModule { 201 @Override configure()202 protected void configure() { 203 bind(ConstructedClass.class).toProvider(new ConstructedClassProvider()); 204 } 205 } 206 207 private static class HasDependenciesModule extends AbstractModule { 208 @Override configure()209 protected void configure() { 210 bind(Interface.class).toInstance(new HasDependenciesClass()); 211 } 212 } 213 214 private static class ProviderKeyModule extends AbstractModule { 215 @Override configure()216 protected void configure() { 217 bind(ConstructedClass.class).toProvider(ConstructedClassProvider.class); 218 } 219 } 220 } 221