Home | History | Annotate | Download | only in grapher
      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 (at) gmail.com (Pete Hopkins)
     48  */
     49 public class TransitiveDependencyVisitorTest extends TestCase {
     50   private TransitiveDependencyVisitor visitor;
     51 
     52   @Override
     53   protected void setUp() throws Exception {
     54     super.setUp();
     55 
     56     visitor = new TransitiveDependencyVisitor();
     57   }
     58 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    128   private Binding<?> getBinding(Key<?> key, Module... modules) {
    129     return Guice.createInjector(modules).getBinding(key);
    130   }
    131 
    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;
    154     ConstructedClass() {}
    155     @Inject ConstructedClass(B b, C c) {}
    156     @Inject void setD(D d) {}
    157   }
    158 
    159   private static class ConstructedClassProvider implements Provider<ConstructedClass> {
    160     @Inject E e;
    161     ConstructedClassProvider() {}
    162     @Inject ConstructedClassProvider(A a, B b, C c) {}
    163     @Inject void setF(F f) {}
    164 
    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 
    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
    181     protected void configure() {
    182       bindConstant().annotatedWith(Names.named("number")).to("2008");
    183     }
    184   }
    185 
    186   private static class InstanceModule extends AbstractModule {
    187     @Override
    188     protected void configure() {
    189       bind(ConstructedClass.class).toInstance(new ConstructedClass());
    190     }
    191   }
    192 
    193   private static class LinkedKeyModule extends AbstractModule {
    194     @Override
    195     protected void configure() {
    196       bind(Interface.class).to(ConstructedClass.class);
    197     }
    198   }
    199 
    200   private static class ProviderInstanceModule extends AbstractModule {
    201     @Override
    202     protected void configure() {
    203       bind(ConstructedClass.class).toProvider(new ConstructedClassProvider());
    204     }
    205   }
    206 
    207   private static class HasDependenciesModule extends AbstractModule {
    208     @Override
    209     protected void configure() {
    210       bind(Interface.class).toInstance(new HasDependenciesClass());
    211     }
    212   }
    213 
    214   private static class ProviderKeyModule extends AbstractModule {
    215     @Override
    216     protected void configure() {
    217       bind(ConstructedClass.class).toProvider(ConstructedClassProvider.class);
    218     }
    219   }
    220 }
    221