blob: 2c29cf4077882cb5be6208610c6d89b411381ccf [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.spi;
import com.google.common.base.Nullable;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
import com.google.inject.AbstractModule;
import static com.google.inject.Asserts.assertContains;
import com.google.inject.Binding;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.Scope;
import com.google.inject.Scopes;
import com.google.inject.Singleton;
import com.google.inject.Stage;
import com.google.inject.name.Names;
import java.lang.reflect.Constructor;
import java.util.List;
import java.util.logging.Logger;
import junit.framework.TestCase;
/**
* @author jessewilson@google.com (Jesse Wilson)
*/
public class SpiBindingsTest extends TestCase {
public void testBindConstant() {
checkInjector(
new AbstractModule() {
protected void configure() {
bindConstant().annotatedWith(Names.named("one")).to(1);
}
},
new FailingElementVisitor() {
@Override public <T> Void visitBinding(Binding<T> binding) {
assertTrue(binding instanceof InstanceBinding);
assertEquals(Key.get(Integer.class, Names.named("one")), binding.getKey());
return null;
}
}
);
}
public void testToInstanceBinding() {
checkInjector(
new AbstractModule() {
protected void configure() {
bind(String.class).toInstance("A");
}
},
new FailingElementVisitor() {
@Override public <T> Void visitBinding(Binding<T> binding) {
assertTrue(binding instanceof InstanceBinding);
assertContains(binding.getSource().toString(), "SpiBindingsTest.java");
assertEquals(Key.get(String.class), binding.getKey());
binding.acceptTargetVisitor(new FailingTargetVisitor<T>() {
@Override public Void visitInstance(InstanceBinding<T> binding) {
assertEquals("A", binding.getInstance());
return null;
}
});
return null;
}
}
);
}
public void testToProviderBinding() {
final Provider<String> stringProvider = new StringProvider();
checkInjector(
new AbstractModule() {
protected void configure() {
bind(String.class).toProvider(stringProvider);
}
},
new FailingElementVisitor() {
@Override public <T> Void visitBinding(Binding<T> binding) {
assertTrue(binding instanceof ProviderInstanceBinding);
assertContains(binding.getSource().toString(), "SpiBindingsTest.java");
assertEquals(Key.get(String.class), binding.getKey());
binding.acceptTargetVisitor(new FailingTargetVisitor<T>() {
@Override public Void visitProviderInstance(ProviderInstanceBinding<T> binding) {
assertSame(stringProvider, binding.getProviderInstance());
return null;
}
});
return null;
}
}
);
}
public void testToProviderKeyBinding() {
checkInjector(
new AbstractModule() {
protected void configure() {
bind(String.class).toProvider(StringProvider.class);
}
},
new FailingElementVisitor() {
@Override public <T> Void visitBinding(Binding<T> binding) {
assertTrue(binding instanceof ProviderKeyBinding);
assertContains(binding.getSource().toString(), "SpiBindingsTest.java");
assertEquals(Key.get(String.class), binding.getKey());
binding.acceptTargetVisitor(new FailingTargetVisitor<T>() {
@Override public Void visitProviderKey(ProviderKeyBinding<T> binding) {
assertEquals(Key.get(StringProvider.class), binding.getProviderKey());
return null;
}
});
return null;
}
}
);
}
public void testToKeyBinding() {
final Key<String> aKey = Key.get(String.class, Names.named("a"));
final Key<String> bKey = Key.get(String.class, Names.named("b"));
checkInjector(
new AbstractModule() {
protected void configure() {
bind(aKey).to(bKey);
bind(bKey).toInstance("B");
}
},
new FailingElementVisitor() {
@Override public <T> Void visitBinding(Binding<T> binding) {
assertTrue(binding instanceof LinkedKeyBinding);
assertContains(binding.getSource().toString(), "SpiBindingsTest.java");
assertEquals(aKey, binding.getKey());
binding.acceptTargetVisitor(new FailingTargetVisitor<T>() {
@Override public Void visitLinkedKey(LinkedKeyBinding<T> binding) {
assertEquals(bKey, binding.getLinkedKey());
return null;
}
});
return null;
}
},
new FailingElementVisitor() {
@Override public <T> Void visitBinding(Binding<T> binding) {
assertEquals(bKey, binding.getKey());
return null;
}
}
);
}
public void testToConstructorBinding() {
checkInjector(
new AbstractModule() {
protected void configure() {
bind(D.class);
}
},
new FailingElementVisitor() {
@Override public <T> Void visitBinding(Binding<T> binding) {
assertTrue(binding instanceof ConstructorBinding);
assertContains(binding.getSource().toString(), "SpiBindingsTest.java");
assertEquals(Key.get(D.class), binding.getKey());
binding.acceptTargetVisitor(new FailingTargetVisitor<T>() {
@Override public Void visitConstructor(ConstructorBinding<T> binding) {
Constructor<?> expected = D.class.getDeclaredConstructors()[0];
assertEquals(expected, binding.getConstructor());
return null;
}
});
return null;
}
}
);
}
public void testConstantBinding() {
checkInjector(
new AbstractModule() {
protected void configure() {
bindConstant().annotatedWith(Names.named("one")).to(1);
}
},
new FailingElementVisitor() {
@Override public <T> Void visitBinding(Binding<T> binding) {
assertTrue(binding instanceof InstanceBinding);
assertContains(binding.getSource().toString(), "SpiBindingsTest.java");
assertEquals(Key.get(Integer.class, Names.named("one")), binding.getKey());
binding.acceptTargetVisitor(new FailingTargetVisitor<T>() {
@Override public Void visitInstance(InstanceBinding<T> binding) {
assertEquals(1, binding.getInstance());
return null;
}
});
return null;
}
}
);
}
public void testConvertedConstantBinding() {
Injector injector = Guice.createInjector(new AbstractModule() {
protected void configure() {
bindConstant().annotatedWith(Names.named("one")).to("1");
}
});
Binding<Integer> binding = injector.getBinding(Key.get(Integer.class, Names.named("one")));
assertEquals(Key.get(Integer.class, Names.named("one")), binding.getKey());
assertContains(binding.getSource().toString(), "SpiBindingsTest.java");
assertTrue(binding instanceof ConvertedConstantBinding);
binding.acceptTargetVisitor(new FailingTargetVisitor<Integer>() {
@Override public Void visitConvertedConstant(ConvertedConstantBinding<Integer> binding) {
assertEquals((Integer) 1, binding.getValue());
return null;
}
});
}
public void testProviderBinding() {
Injector injector = Guice.createInjector(new AbstractModule() {
protected void configure() {
bind(String.class).toInstance("A");
}
});
Key<Provider<String>> providerOfStringKey = new Key<Provider<String>>() {};
Binding<Provider<String>> binding = injector.getBinding(providerOfStringKey);
assertEquals(providerOfStringKey, binding.getKey());
assertContains(binding.getSource().toString(), "SpiBindingsTest.java");
assertTrue(binding instanceof ProviderBinding);
binding.acceptTargetVisitor(new FailingTargetVisitor<Provider<String>>() {
@Override public Void visitProviderBinding(ProviderBinding<?> binding) {
assertEquals(Key.get(String.class), binding.getProvidedKey());
return null;
}
});
}
public void testScopes() {
checkInjector(
new AbstractModule() {
protected void configure() {
bind(String.class).annotatedWith(Names.named("a"))
.toProvider(StringProvider.class).in(Singleton.class);
bind(String.class).annotatedWith(Names.named("b"))
.toProvider(StringProvider.class).in(Scopes.SINGLETON);
bind(String.class).annotatedWith(Names.named("c"))
.toProvider(StringProvider.class).asEagerSingleton();
bind(String.class).annotatedWith(Names.named("d"))
.toProvider(StringProvider.class);
}
},
new FailingElementVisitor() {
@Override public <T> Void visitBinding(Binding<T> command) {
assertEquals(Key.get(String.class, Names.named("a")), command.getKey());
command.acceptScopingVisitor(new FailingBindingScopingVisitor() {
@Override public Void visitScope(Scope scope) {
// even though we bound with an annotation, the injector always uses instances
assertSame(Scopes.SINGLETON, scope);
return null;
}
});
return null;
}
},
new FailingElementVisitor() {
@Override public <T> Void visitBinding(Binding<T> command) {
assertEquals(Key.get(String.class, Names.named("b")), command.getKey());
command.acceptScopingVisitor(new FailingBindingScopingVisitor() {
@Override public Void visitScope(Scope scope) {
assertSame(Scopes.SINGLETON, scope);
return null;
}
});
return null;
}
},
new FailingElementVisitor() {
@Override public <T> Void visitBinding(Binding<T> command) {
assertEquals(Key.get(String.class, Names.named("c")), command.getKey());
command.acceptScopingVisitor(new FailingBindingScopingVisitor() {
@Override public Void visitEagerSingleton() {
return null;
}
});
return null;
}
},
new FailingElementVisitor() {
@Override public <T> Void visitBinding(Binding<T> command) {
assertEquals(Key.get(String.class, Names.named("d")), command.getKey());
command.acceptScopingVisitor(new FailingBindingScopingVisitor() {
@Override public Void visitNoScoping() {
return null;
}
});
return null;
}
}
);
}
public void checkInjector(Module module, ElementVisitor<?>... visitors) {
Injector injector = Guice.createInjector(module);
List<Binding<?>> bindings = Lists.newArrayList(
Iterables.filter(injector.getBindings().values(), isUserBinding));
orderByKey.sort(bindings);
assertEquals(bindings.size(), visitors.length);
for (int i = 0; i < visitors.length; i++) {
ElementVisitor<?> visitor = visitors[i];
Binding<?> binding = bindings.get(i);
binding.acceptVisitor(visitor);
}
}
private final Predicate<Binding<?>> isUserBinding = new Predicate<Binding<?>>() {
private final ImmutableSet<Key<?>> BUILT_IN_BINDINGS = ImmutableSet.of(
Key.get(Injector.class), Key.get(Stage.class), Key.get(Logger.class));
public boolean apply(@Nullable Binding<?> binding) {
return !BUILT_IN_BINDINGS.contains(binding.getKey());
}
};
private final Ordering<Binding<?>> orderByKey = new Ordering<Binding<?>>() {
public int compare(Binding<?> a, Binding<?> b) {
return a.getKey().toString().compareTo(b.getKey().toString());
}
};
private static class StringProvider implements Provider<String> {
public String get() {
return "A";
}
}
private static class C { }
private static class D extends C {
@Inject public D(Injector unused) { }
}
}