/**
* Copyright 2011-2015 John Ericksen
*
* 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 org.androidtransfuse.gen;
import org.androidtransfuse.adapter.*;
import org.androidtransfuse.adapter.classes.ASTClassFactory;
import org.androidtransfuse.analysis.AnalysisContext;
import org.androidtransfuse.analysis.Analyzer;
import org.androidtransfuse.analysis.SimpleAnalysisContextFactory;
import org.androidtransfuse.analysis.astAnalyzer.ASTInjectionAspect;
import org.androidtransfuse.analysis.astAnalyzer.VirtualProxyAspect;
import org.androidtransfuse.analysis.repository.InjectionNodeBuilderRepository;
import org.androidtransfuse.bootstrap.Bootstrap;
import org.androidtransfuse.bootstrap.Bootstraps;
import org.androidtransfuse.gen.target.*;
import org.androidtransfuse.gen.variableBuilder.InjectionNodeBuilder;
import org.androidtransfuse.gen.variableBuilder.VariableBuilder;
import org.androidtransfuse.gen.variableBuilder.VariableInjectionBuilder;
import org.androidtransfuse.gen.variableBuilder.VariableInjectionBuilderFactory;
import org.androidtransfuse.model.*;
import org.junit.Before;
import org.junit.Test;
import javax.inject.Inject;
import javax.inject.Provider;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
* @author John Ericksen
*/
@Bootstrap
public class InjectionFragmentGeneratorTest {
@Inject
private InjectionFragmentGeneratorHarness fragmentGeneratorHarness;
@Inject
private CodeGenerationUtil codeGenerationUtil;
@Inject
private Provider<VariableInjectionBuilder> variableInjectionBuilderProvider;
@Inject
private VariableInjectionBuilderFactory variableInjectionBuilderFactory;
@Inject
private ASTClassFactory astClassFactory;
@Inject
private Analyzer analyzer;
@Inject
private SimpleAnalysisContextFactory contextFactory;
private AnalysisContext context;
@Inject
private InjectionNodeBuilderRepository injectionNodeBuilderRepository;
@Before
public void setUp() {
Bootstraps.inject(this);
context = contextFactory.buildContext();
}
@Test
public void testConstrictorInjection() throws Exception {
ASTType constructorInjectableType = astClassFactory.getType(ConstructorInjectable.class);
ASTConstructor constructor = constructorInjectableType.getConstructors().iterator().next();
InjectionNode injectionNode = new InjectionNode(new InjectionSignature(constructorInjectableType));
injectionNode.addAspect(VariableBuilder.class, variableInjectionBuilderProvider.get());
//setup constructor injection
ConstructorInjectionPoint constructorInjectionPoint = new ConstructorInjectionPoint(constructorInjectableType, constructor);
constructorInjectionPoint.addInjectionNode(buildInjectionNode(InjectionTarget.class));
getInjectionAspect(injectionNode).set(constructorInjectionPoint);
ConstructorInjectable constructorInjectable = buildInstance(ConstructorInjectable.class, injectionNode);
assertNotNull(constructorInjectable.getInjectionTarget());
}
@Test
public void testMethodInjection() throws Exception {
InjectionNode injectionNode = buildInjectionNode(MethodInjectable.class);
ASTType containingType = astClassFactory.getType(MethodInjectable.class);
ASTMethod method = getMethod("setInjectionTarget", containingType);
MethodInjectionPoint methodInjectionPoint = new MethodInjectionPoint(containingType, containingType, method);
methodInjectionPoint.addInjectionNode(buildInjectionNode(InjectionTarget.class));
getInjectionAspect(injectionNode).addGroup().add(methodInjectionPoint);
MethodInjectable methodInjectable = buildInstance(MethodInjectable.class, injectionNode);
assertNotNull(methodInjectable.getInjectionTarget());
}
@Test
public void testFieldInjection() throws Exception {
InjectionNode injectionNode = buildInjectionNode(FieldInjectable.class);
ASTType containingType = astClassFactory.getType(FieldInjectable.class);
ASTField field = getField("injectionTarget", containingType);
FieldInjectionPoint fieldInjectionPoint = new FieldInjectionPoint(containingType, containingType, field, buildInjectionNode(InjectionTarget.class));
getInjectionAspect(injectionNode).addGroup().add(fieldInjectionPoint);
FieldInjectable fieldInjectable = buildInstance(FieldInjectable.class, injectionNode);
assertNotNull(fieldInjectable.getInjectionTarget());
}
@Test
public void testDelayedProxyInjection() throws Exception {
ASTType delayedProxyType = astClassFactory.getType(DelayedProxyDependency.class);
ASTConstructor delayedProxyConstructor = delayedProxyType.getConstructors().iterator().next();
InjectionNode injectionNode = new InjectionNode(new InjectionSignature(astClassFactory.getType(DelayedProxy.class)),
new InjectionSignature(astClassFactory.getType(DelayedProxyTarget.class)));
injectionNode.addAspect(VariableBuilder.class, variableInjectionBuilderProvider.get());
VirtualProxyAspect proxyAspect = new VirtualProxyAspect();
proxyAspect.getProxyInterfaces().add(astClassFactory.getType(DelayedProxy.class));
injectionNode.addAspect(proxyAspect);
//setup constructor injection
ConstructorInjectionPoint constructorInjectionPoint = new ConstructorInjectionPoint(delayedProxyType, delayedProxyConstructor);
InjectionNode dependencyInjectionNode = new InjectionNode(new InjectionSignature(delayedProxyType));
dependencyInjectionNode.addAspect(VariableBuilder.class, variableInjectionBuilderProvider.get());
constructorInjectionPoint.addInjectionNode(dependencyInjectionNode);
getInjectionAspect(injectionNode).set(constructorInjectionPoint);
//reference circle
ConstructorInjectionPoint dependencyConstructorInjectionPoint = new ConstructorInjectionPoint(delayedProxyType, delayedProxyConstructor);
dependencyConstructorInjectionPoint.addInjectionNode(injectionNode);
getInjectionAspect(dependencyInjectionNode).set(dependencyConstructorInjectionPoint);
DelayedProxyTarget proxyTarget = buildInstance(DelayedProxyTarget.class, injectionNode);
assertNotNull(proxyTarget.getDelayedProxyDependency());
assertNotNull(proxyTarget.getDelayedProxyDependency().getDelayedProxy());
}
@Test
public void testVariableBuilder() throws Exception {
InjectionNode injectionNode = buildInjectionNode(VariableBuilderInjectable.class);
ASTType containingType = astClassFactory.getType(VariableBuilderInjectable.class);
ASTField field = getField("target", containingType);
FieldInjectionPoint fieldInjectionPoint = new FieldInjectionPoint(containingType, containingType, field, buildInjectionNode(VariableTarget.class));
getInjectionAspect(injectionNode).addGroup().add(fieldInjectionPoint);
injectionNodeBuilderRepository.putType(VariableTarget.class, new InjectionNodeBuilder() {
@Override
public InjectionNode buildInjectionNode(ASTBase target, InjectionSignature signature, AnalysisContext context) {
return analyzer.analyze(signature, context);
}
});
VariableBuilderInjectable vbInjectable = buildInstance(VariableBuilderInjectable.class, injectionNode);
assertNotNull(vbInjectable.getTarget());
}
@Test
public void testProviderBuilder() throws Exception {
injectionNodeBuilderRepository.putType(VariableTarget.class, variableInjectionBuilderFactory.buildProviderInjectionNodeBuilder(
astClassFactory.getType(VariableTargetProvider.class)));
InjectionNode injectionNode = buildInjectionNode(VariableTarget.class);
ASTType providerType = astClassFactory.getType(VariableTargetProvider.class);
InjectionNode providerInjectionNode = analyzer.analyze(providerType, providerType, context);
providerInjectionNode.addAspect(VariableBuilder.class, variableInjectionBuilderProvider.get());
injectionNode.addAspect(VariableBuilder.class, variableInjectionBuilderFactory.buildProviderVariableBuilder(providerInjectionNode));
VariableTarget target = buildInstance(VariableTarget.class, injectionNode);
assertNotNull(target);
}
private InjectionNode buildInjectionNode(Class<?> instanceClass) {
InjectionNode injectionNode = new InjectionNode(new InjectionSignature(astClassFactory.getType(instanceClass)));
injectionNode.addAspect(VariableBuilder.class, variableInjectionBuilderProvider.get());
ASTConstructor constructor = injectionNode.getASTType().getConstructors().iterator().next();
ConstructorInjectionPoint noArgConstructorInjectionPoint = new ConstructorInjectionPoint(injectionNode.getASTType(), constructor);
getInjectionAspect(injectionNode).set(noArgConstructorInjectionPoint);
return injectionNode;
}
private <T> T buildInstance(Class<T> instanceClass, InjectionNode injectionNode) throws Exception {
PackageClass providerPackageClass = new PackageClass(instanceClass).append("Provider");
fragmentGeneratorHarness.buildProvider(injectionNode, providerPackageClass);
ClassLoader classLoader = codeGenerationUtil.build();
Class<Provider> generatedFactoryClass = (Class<Provider>) classLoader.loadClass(providerPackageClass.getCanonicalName());
assertNotNull(generatedFactoryClass);
Provider provider = generatedFactoryClass.newInstance();
Object result = provider.get();
assertEquals(instanceClass, result.getClass());
return (T) result;
}
private ASTInjectionAspect getInjectionAspect(InjectionNode injectionNode) {
if (!injectionNode.containsAspect(ASTInjectionAspect.class)) {
injectionNode.addAspect(new ASTInjectionAspect());
}
return injectionNode.getAspect(ASTInjectionAspect.class);
}
private ASTMethod getMethod(String name, ASTType containingType) {
for (ASTMethod astMethod : containingType.getMethods()) {
if(astMethod.getName().equals(name)){
return astMethod;
}
}
return null;
}
private ASTField getField(String name, ASTType containingType) {
for (ASTField astField : containingType.getFields()) {
if(astField.getName().equals(name)){
return astField;
}
}
return null;
}
}