blob: 8fa1220a6236bfbfdf66f5ebb8ca8182e999f2a5 [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.visitable;
import com.google.inject.*;
import com.google.inject.matcher.Matcher;
import com.google.inject.matcher.Matchers;
import com.google.inject.name.Names;
import com.google.inject.spi.TypeConverter;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;
import java.util.*;
/**
* @author jessewilson@google.com (Jesse Wilson)
*/
public class CommandRecorderTest extends TestCase {
protected EarlyRequestsProvider earlyRequestProvider = new EarlyRequestsProvider() {
public <T> T get(Key<T> key) {
throw new AssertionFailedError();
}
};
private CommandRecorder commandRecorder = new CommandRecorder(earlyRequestProvider);
public void testAddMessageErrorCommand() {
checkModule(
new AbstractModule() {
protected void configure() {
addError("Message", "A", "B", "C");
}
},
new FailingVisitor() {
@Override public Void visitAddMessageError(AddMessageErrorCommand command) {
assertEquals(Arrays.asList("A", "B", "C"), command.getArguments());
assertEquals("Message", command.getMessage());
return null;
}
}
);
}
public void testAddThrowableErrorCommand() {
checkModule(
new AbstractModule() {
protected void configure() {
addError(new Exception("A"));
}
},
new FailingVisitor() {
@Override public Void visitAddError(AddThrowableErrorCommand command) {
assertEquals("A", command.getThrowable().getMessage());
return null;
}
}
);
}
public void testBindConstantAnnotations() {
checkModule(
new AbstractModule() {
protected void configure() {
bindConstant().annotatedWith(SampleAnnotation.class).to("A");
bindConstant().annotatedWith(Names.named("Bee")).to("B");
}
},
new FailingVisitor() {
@Override public Void visitConstantBinding(BindConstantCommand command) {
assertEquals(Key.get(String.class, SampleAnnotation.class), command.getKey());
assertEquals("A", command.getTarget().get(null));
return null;
}
},
new FailingVisitor() {
@Override public Void visitConstantBinding(BindConstantCommand command) {
assertEquals(Key.get(String.class, Names.named("Bee")), command.getKey());
assertEquals("B", command.getTarget().get(null));
return null;
}
}
);
}
public void testBindConstantTypes() {
checkModule(
new AbstractModule() {
protected void configure() {
bindConstant().annotatedWith(Names.named("String")).to("A");
bindConstant().annotatedWith(Names.named("int")).to(2);
bindConstant().annotatedWith(Names.named("long")).to(3L);
bindConstant().annotatedWith(Names.named("boolean")).to(false);
bindConstant().annotatedWith(Names.named("double")).to(5.0d);
bindConstant().annotatedWith(Names.named("float")).to(6.0f);
bindConstant().annotatedWith(Names.named("short")).to((short) 7);
bindConstant().annotatedWith(Names.named("char")).to('h');
bindConstant().annotatedWith(Names.named("Class")).to(Iterator.class);
bindConstant().annotatedWith(Names.named("Enum")).to(CoinSide.TAILS);
}
},
new FailingVisitor() {
@Override public Void visitConstantBinding(BindConstantCommand command) {
assertEquals(Key.get(String.class, Names.named("String")), command.getKey());
assertEquals("A", command.getTarget().get(null));
return null;
}
},
new FailingVisitor() {
@Override public Void visitConstantBinding(BindConstantCommand command) {
assertEquals(Key.get(Integer.class, Names.named("int")), command.getKey());
assertEquals(2, command.getTarget().get(null));
return null;
}
},
new FailingVisitor() {
@Override public Void visitConstantBinding(BindConstantCommand command) {
assertEquals(Key.get(Long.class, Names.named("long")), command.getKey());
assertEquals(3L, command.getTarget().get(null));
return null;
}
},
new FailingVisitor() {
@Override public Void visitConstantBinding(BindConstantCommand command) {
assertEquals(Key.get(Boolean.class, Names.named("boolean")), command.getKey());
assertEquals(false, command.getTarget().get(null));
return null;
}
},
new FailingVisitor() {
@Override public Void visitConstantBinding(BindConstantCommand command) {
assertEquals(Key.get(Double.class, Names.named("double")), command.getKey());
assertEquals(5.0d, command.getTarget().get(null));
return null;
}
},
new FailingVisitor() {
@Override public Void visitConstantBinding(BindConstantCommand command) {
assertEquals(Key.get(Float.class, Names.named("float")), command.getKey());
assertEquals(6.0f, command.getTarget().get(null));
return null;
}
},
new FailingVisitor() {
@Override public Void visitConstantBinding(BindConstantCommand command) {
assertEquals(Key.get(Short.class, Names.named("short")), command.getKey());
assertEquals((short) 7, command.getTarget().get(null));
return null;
}
},
new FailingVisitor() {
@Override public Void visitConstantBinding(BindConstantCommand command) {
assertEquals(Key.get(Character.class, Names.named("char")), command.getKey());
assertEquals('h', command.getTarget().get(null));
return null;
}
},
new FailingVisitor() {
@Override public Void visitConstantBinding(BindConstantCommand command) {
assertEquals(Key.get(Class.class, Names.named("Class")), command.getKey());
assertEquals(Iterator.class, command.getTarget().get(null));
return null;
}
},
new FailingVisitor() {
@Override public Void visitConstantBinding(BindConstantCommand command) {
assertEquals(Key.get(CoinSide.class, Names.named("Enum")), command.getKey());
assertEquals(CoinSide.TAILS, command.getTarget().get(null));
return null;
}
}
);
}
public void testBindKeysNoAnnotations() {
FailingVisitor keyChecker = new FailingVisitor() {
@Override public Void visitBinding(BindCommand command) {
assertEquals(Key.get(String.class), command.getKey());
return null;
}
};
checkModule(
new AbstractModule() {
protected void configure() {
bind(String.class).toInstance("A");
bind(new TypeLiteral<String>() {
}).toInstance("B");
bind(Key.get(String.class)).toInstance("C");
}
},
keyChecker,
keyChecker,
keyChecker
);
}
public void testBindKeysWithAnnotationType() {
FailingVisitor annotationChecker = new FailingVisitor() {
@Override public Void visitBinding(BindCommand command) {
assertEquals(Key.get(String.class, SampleAnnotation.class), command.getKey());
return null;
}
};
checkModule(
new AbstractModule() {
protected void configure() {
bind(String.class).annotatedWith(SampleAnnotation.class).toInstance("A");
bind(new TypeLiteral<String>() {
}).annotatedWith(SampleAnnotation.class).toInstance("B");
}
},
annotationChecker,
annotationChecker
);
}
public void testBindKeysWithAnnotationInstance() {
FailingVisitor annotationChecker = new FailingVisitor() {
@Override public Void visitBinding(BindCommand command) {
assertEquals(Key.get(String.class, Names.named("a")), command.getKey());
return null;
}
};
checkModule(
new AbstractModule() {
protected void configure() {
bind(String.class).annotatedWith(Names.named("a")).toInstance("B");
bind(new TypeLiteral<String>() {
}).annotatedWith(Names.named("a")).toInstance("C");
}
},
annotationChecker,
annotationChecker
);
}
public void testBindToProvider() {
checkModule(
new AbstractModule() {
protected void configure() {
bind(String.class).toProvider(new Provider<String>() {
public String get() {
return "A";
}
});
bind(List.class).toProvider(ListProvider.class);
bind(Collection.class).toProvider(Key.get(ListProvider.class));
}
},
new FailingVisitor() {
@Override public <T> Void visitBinding(BindCommand<T> command) {
assertEquals(Key.get(String.class), command.getKey());
assertEquals("A", command.getTarget().getProvider(null).get());
return null;
}
},
new FailingVisitor() {
@Override public <T> Void visitBinding(BindCommand<T> command) {
assertEquals(Key.get(List.class), command.getKey());
assertNull(command.getTarget().get(null));
assertEquals(Key.get(ListProvider.class), command.getTarget().getProviderKey(null));
return null;
}
},
new FailingVisitor() {
@Override public <T> Void visitBinding(BindCommand<T> command) {
assertEquals(Key.get(Collection.class), command.getKey());
assertNull(command.getTarget().get(null));
assertEquals(Key.get(ListProvider.class), command.getTarget().getProviderKey(null));
return null;
}
}
);
}
public void testBindToLinkedBinding() {
checkModule(
new AbstractModule() {
protected void configure() {
bind(List.class).to(ArrayList.class);
bind(Map.class).to(new TypeLiteral<HashMap<Integer, String>>() { });
bind(Set.class).to(Key.get(TreeSet.class, SampleAnnotation.class));
}
},
new FailingVisitor() {
@Override public <T> Void visitBinding(BindCommand<T> command) {
assertEquals(Key.get(List.class), command.getKey());
assertEquals(Key.get(ArrayList.class), command.getTarget().getKey(null));
return null;
}
},
new FailingVisitor() {
@Override public <T> Void visitBinding(BindCommand<T> command) {
assertEquals(Key.get(Map.class), command.getKey());
assertEquals(Key.get(new TypeLiteral<HashMap<Integer, String>>() {}), command.getTarget().getKey(null));
return null;
}
},
new FailingVisitor() {
@Override public <T> Void visitBinding(BindCommand<T> command) {
assertEquals(Key.get(Set.class), command.getKey());
assertEquals(Key.get(TreeSet.class, SampleAnnotation.class), command.getTarget().getKey(null));
return null;
}
}
);
}
public void testBindToInstance() {
checkModule(
new AbstractModule() {
protected void configure() {
bind(String.class).toInstance("A");
}
},
new FailingVisitor() {
@Override public <T> Void visitBinding(BindCommand<T> command) {
assertEquals(Key.get(String.class), command.getKey());
assertEquals("A", command.getTarget().get(null));
return null;
}
}
);
}
public void testBindInScopes() {
checkModule(
new AbstractModule() {
protected void configure() {
bind(List.class).to(ArrayList.class).in(Scopes.SINGLETON);
bind(Map.class).to(HashMap.class).in(Singleton.class);
bind(Set.class).to(TreeSet.class).asEagerSingleton();
}
},
new FailingVisitor() {
@Override public <T> Void visitBinding(BindCommand<T> command) {
assertEquals(Key.get(List.class), command.getKey());
assertEquals(Scopes.SINGLETON, command.getScoping().getScope(null));
assertNull(command.getScoping().getScopeAnnotation(null));
assertFalse(command.getScoping().isEagerSingleton());
return null;
}
},
new FailingVisitor() {
@Override public <T> Void visitBinding(BindCommand<T> command) {
assertEquals(Key.get(Map.class), command.getKey());
assertEquals(Singleton.class, command.getScoping().getScopeAnnotation(null));
assertNull(command.getScoping().getScope(null));
assertFalse(command.getScoping().isEagerSingleton());
return null;
}
},
new FailingVisitor() {
@Override public <T> Void visitBinding(BindCommand<T> command) {
assertEquals(Key.get(Set.class), command.getKey());
assertNull(command.getScoping().getScopeAnnotation(null));
assertNull(command.getScoping().getScope(null));
assertTrue(command.getScoping().isEagerSingleton());
return null;
}
}
);
}
public void testBindIntercepor() {
final Matcher<Class> classMatcher = Matchers.subclassesOf(List.class);
final Matcher<Object> methodMatcher = Matchers.any();
final MethodInterceptor methodInterceptor = new MethodInterceptor() {
public Object invoke(MethodInvocation methodInvocation) {
return null;
}
};
checkModule(
new AbstractModule() {
protected void configure() {
bindInterceptor(classMatcher, methodMatcher, methodInterceptor);
}
},
new FailingVisitor() {
@Override public Void visitBindInterceptor(BindInterceptorCommand command) {
assertSame(classMatcher, command.getClassMatcher());
assertSame(methodMatcher, command.getMethodMatcher());
assertEquals(Arrays.asList(methodInterceptor), command.getInterceptors());
return null;
}
}
);
}
public void testBindScope() {
checkModule(
new AbstractModule() {
protected void configure() {
bindScope(SampleAnnotation.class, Scopes.NO_SCOPE);
}
},
new FailingVisitor() {
@Override public Void visitBindScope(BindScopeCommand command) {
assertSame(SampleAnnotation.class, command.getAnnotationType());
assertSame(Scopes.NO_SCOPE, command.getScope());
return null;
}
}
);
}
public void testConvertToTypes() {
final TypeConverter typeConverter = new TypeConverter() {
public Object convert(String value, TypeLiteral<?> toType) {
return value;
}
};
checkModule(
new AbstractModule() {
protected void configure() {
convertToTypes(Matchers.any(), typeConverter);
}
},
new FailingVisitor() {
@Override public Void visitConvertToTypes(ConvertToTypesCommand command) {
assertSame(typeConverter, command.getTypeConverter());
assertSame(Matchers.any(), command.getTypeMatcher());
return null;
}
}
);
}
public void testGetProvider() {
final List<Key> calls = new ArrayList<Key>();
earlyRequestProvider = new EarlyRequestsProvider() {
@SuppressWarnings({"unchecked"})
public <T> T get(Key<T> key) {
calls.add(key);
return (T) "A";
}
};
commandRecorder = new CommandRecorder(earlyRequestProvider);
checkModule(
new AbstractModule() {
protected void configure() {
Provider<String> keyGetProvider = getProvider(Key.get(String.class, SampleAnnotation.class));
assertEquals("A", keyGetProvider.get());
assertEquals(Key.get(String.class, SampleAnnotation.class), calls.get(0));
Provider<String> typeGetProvider = getProvider(String.class);
assertEquals("A", typeGetProvider.get());
assertEquals(Key.get(String.class), calls.get(1));
assertEquals(2, calls.size());
}
},
new FailingVisitor() {
@Override public Void visitGetProviderCommand(GetProviderCommand command) {
assertEquals(Key.get(String.class, SampleAnnotation.class), command.getKey());
assertEquals(earlyRequestProvider, command.getEarlyRequestsProvider());
return null;
}
},
new FailingVisitor() {
@Override public Void visitGetProviderCommand(GetProviderCommand command) {
assertEquals(Key.get(String.class), command.getKey());
assertEquals(earlyRequestProvider, command.getEarlyRequestsProvider());
return null;
}
}
);
}
public void testRequestStaticInjection() {
checkModule(
new AbstractModule() {
protected void configure() {
requestStaticInjection(ArrayList.class);
}
},
new FailingVisitor() {
@Override public Void visitRequestStaticInjection(RequestStaticInjectionCommand command) {
assertEquals(Arrays.asList(ArrayList.class), command.getTypes());
return null;
}
}
);
}
/**
* Ensures the module performs the commands consistent with {@code visitors}.
*/
protected void checkModule(Module module, Command.Visitor<?>... visitors) {
commandRecorder.recordCommands(module);
assertEquals(commandRecorder.getCommands().size(), visitors.length);
for (int i = 0; i < visitors.length; i++) {
Command.Visitor<?> visitor = visitors[i];
Command command = commandRecorder.getCommands().get(i);
command.acceptVisitor(visitor);
}
}
private static class ListProvider implements Provider<List> {
public List get() {
return new ArrayList();
}
}
private static class FailingVisitor implements Command.Visitor<Void> {
public Void visitAddMessageError(AddMessageErrorCommand command) {
throw new AssertionFailedError();
}
public Void visitAddError(AddThrowableErrorCommand command) {
throw new AssertionFailedError();
}
public Void visitBindInterceptor(BindInterceptorCommand command) {
throw new AssertionFailedError();
}
public Void visitBindScope(BindScopeCommand command) {
throw new AssertionFailedError();
}
public Void visitRequestStaticInjection(RequestStaticInjectionCommand command) {
throw new AssertionFailedError();
}
public Void visitConstantBinding(BindConstantCommand command) {
throw new AssertionFailedError();
}
public Void visitConvertToTypes(ConvertToTypesCommand command) {
throw new AssertionFailedError();
}
public <T> Void visitBinding(BindCommand<T> command) {
throw new AssertionFailedError();
}
public Void visitGetProviderCommand(GetProviderCommand command) {
throw new AssertionFailedError();
}
}
@Retention(RUNTIME)
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@BindingAnnotation
public @interface SampleAnnotation { }
public enum CoinSide { HEADS, TAILS }
}