blob: 2ef179587070e84302aa7112e2ac493bcfd8da65 [file] [log] [blame]
/**
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.inject.grapher;
import com.google.common.collect.ImmutableSet;
import com.google.inject.AbstractModule;
import com.google.inject.Binding;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.TypeLiteral;
import com.google.inject.grapher.TransitiveDependencyVisitor;
import com.google.inject.name.Names;
import com.google.inject.spi.ConstructorBinding;
import com.google.inject.spi.ConvertedConstantBinding;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.HasDependencies;
import com.google.inject.spi.InstanceBinding;
import com.google.inject.spi.LinkedKeyBinding;
import com.google.inject.spi.ProviderBinding;
import com.google.inject.spi.ProviderInstanceBinding;
import com.google.inject.spi.ProviderKeyBinding;
import java.util.Collection;
import java.util.Set;
import junit.framework.TestCase;
/**
* Tests for {@link TransitiveDependencyVisitor}.
*
* @author phopkins@gmail.com (Pete Hopkins)
*/
public class TransitiveDependencyVisitorTest extends TestCase {
private TransitiveDependencyVisitor visitor;
@Override
protected void setUp() throws Exception {
super.setUp();
visitor = new TransitiveDependencyVisitor();
}
public void testVisitConstructor() {
Binding<?> binding = getBinding(Key.get(ConstructedClass.class));
Collection<Key<?>> dependencies = visitor.visitConstructor((ConstructorBinding<?>) binding);
assertDependencies(dependencies, Key.get(A.class), Key.get(B.class), Key.get(C.class),
Key.get(D.class));
}
public void testVisitConvertedConstant() {
Binding<?> binding = getBinding(Key.get(Integer.class, Names.named("number")),
new ConvertedConstantModule());
Collection<Key<?>> dependencies = visitor.visitConvertedConstant(
(ConvertedConstantBinding<?>) binding);
assertDependencies(dependencies, Key.get(String.class, Names.named("number")));
}
public void testVisitInstance() {
Binding<?> binding = getBinding(Key.get(ConstructedClass.class), new InstanceModule());
Collection<Key<?>> dependencies = visitor.visitInstance(
(InstanceBinding<?>) binding);
// Dependencies will only be on the field- and method-injected classes.
assertDependencies(dependencies, Key.get(A.class), Key.get(D.class));
}
public void testVisitInstance_instanceHasDependencies() {
Binding<?> binding = getBinding(Key.get(Interface.class), new HasDependenciesModule());
Collection<Key<?>> dependencies = visitor.visitInstance(
(InstanceBinding<?>) binding);
// Dependencies should only be on the stated
// HasDependencies#getDependencies() values
assertDependencies(dependencies, Key.get(G.class));
}
public void testVisitLinkedKey() {
Binding<?> binding = getBinding(Key.get(Interface.class), new LinkedKeyModule());
Collection<Key<?>> dependencies = visitor.visitLinkedKey((LinkedKeyBinding<?>) binding);
// Dependency should be to the class this interface is bound to.
assertDependencies(dependencies, Key.get(ConstructedClass.class));
}
public void testVisitProviderBinding() {
Binding<?> binding = getBinding(Key.get(new TypeLiteral<Provider<ConstructedClass>>() {}));
Collection<Key<?>> dependencies = visitor.visitProviderBinding((ProviderBinding<?>) binding);
assertDependencies(dependencies, Key.get(ConstructedClass.class));
}
public void testVisitProviderInstance() {
Binding<?> binding = getBinding(Key.get(ConstructedClass.class),
new ProviderInstanceModule());
Collection<Key<?>> dependencies = visitor.visitProviderInstance(
(ProviderInstanceBinding<?>) binding);
// Dependencies will only be on the field- and method-injected classes.
assertDependencies(dependencies, Key.get(E.class), Key.get(F.class));
}
public void testVisitProviderKey() {
Binding<?> binding = getBinding(Key.get(ConstructedClass.class), new ProviderKeyModule());
Collection<Key<?>> dependencies = visitor.visitProviderKey((ProviderKeyBinding<?>) binding);
// Dependency should be to the class that provides this one.
assertDependencies(dependencies, Key.get(ConstructedClassProvider.class));
}
private Binding<?> getBinding(Key<?> key, Module... modules) {
return Guice.createInjector(modules).getBinding(key);
}
private void assertDependencies(Collection<Key<?>> dependencies, Key<?>... keys) {
assertNotNull("Dependencies should not be null", dependencies);
assertEquals("There should be " + keys.length + " dependencies",
keys.length, dependencies.size());
for (Key<?> key : keys) {
assertTrue("Dependencies should contain " + key, dependencies.contains(key));
}
}
private static class A {}
private static class B {}
private static class C {}
private static class D {}
private static class E {}
private static class F {}
private static class G {}
private static interface Interface {}
private static class ConstructedClass implements Interface {
@Inject A a;
ConstructedClass() {}
@Inject ConstructedClass(B b, C c) {}
@Inject void setD(D d) {}
}
private static class ConstructedClassProvider implements Provider<ConstructedClass> {
@Inject E e;
ConstructedClassProvider() {}
@Inject ConstructedClassProvider(A a, B b, C c) {}
@Inject void setF(F f) {}
public ConstructedClass get() {
return null;
}
}
private static class HasDependenciesClass implements Interface, HasDependencies {
@Inject A a;
@Inject B b;
public Set<Dependency<?>> getDependencies() {
return ImmutableSet.<Dependency<?>>of(Dependency.get(Key.get(G.class)));
}
}
private static class ConvertedConstantModule extends AbstractModule {
@Override
protected void configure() {
bindConstant().annotatedWith(Names.named("number")).to("2008");
}
}
private static class InstanceModule extends AbstractModule {
@Override
protected void configure() {
bind(ConstructedClass.class).toInstance(new ConstructedClass());
}
}
private static class LinkedKeyModule extends AbstractModule {
@Override
protected void configure() {
bind(Interface.class).to(ConstructedClass.class);
}
}
private static class ProviderInstanceModule extends AbstractModule {
@Override
protected void configure() {
bind(ConstructedClass.class).toProvider(new ConstructedClassProvider());
}
}
private static class HasDependenciesModule extends AbstractModule {
@Override
protected void configure() {
bind(Interface.class).toInstance(new HasDependenciesClass());
}
}
private static class ProviderKeyModule extends AbstractModule {
@Override
protected void configure() {
bind(ConstructedClass.class).toProvider(ConstructedClassProvider.class);
}
}
}