/**
* 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 com.sun.codemodel.*;
import org.androidtransfuse.adapter.*;
import org.androidtransfuse.adapter.classes.ASTClassFactory;
import org.androidtransfuse.bootstrap.Bootstrap;
import org.androidtransfuse.bootstrap.Bootstraps;
import org.androidtransfuse.gen.classloader.MemoryClassLoader;
import org.androidtransfuse.gen.invocationBuilder.PackageHelperGenerator;
import org.androidtransfuse.model.TypedExpression;
import org.apache.commons.io.IOUtils;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import javax.inject.Inject;
import java.io.IOException;
import java.util.*;
/**
* @author John Ericksen
*/
@Bootstrap
public class InvocationBuilderTest {
private static final PackageClass SUBDIFF_PACKAGECLASS = new PackageClass("org.androidtransfuse", "SubDiffPackage");
private static final PackageClass SUB_PACKAGECLASS = new PackageClass("org.androidtransfuse.gen", "Subclass");
private static final PackageClass TARGET_PACKAGECLASS = new PackageClass("org.androidtransfuse.gen", "Target");
private static final Map<String, List<String>> PROPERTIES = new HashMap<String, List<String>>(){{
put("Target", Arrays.asList("One", "Two", "Three", "Four"));
put("Subclass", Arrays.asList("Four"));
put("SubDiffPackage", Arrays.asList("Three", "Four"));
}};
private static final Map<String, String> METHOD_EXPECTATIONS = new HashMap<String, String>(){{
put("getOne", TARGET_PACKAGECLASS.getCanonicalName() + ":One");
put("getTwo", TARGET_PACKAGECLASS.getCanonicalName() + ":Two");
put("getThree", TARGET_PACKAGECLASS.getCanonicalName() + ":Three");
put("getPrivateFour", TARGET_PACKAGECLASS.getCanonicalName() + ":Four");
put("getSuperFour", SUB_PACKAGECLASS.getCanonicalName() + ":Four");
put("getDiffPkgThree", SUBDIFF_PACKAGECLASS.getCanonicalName() + ":Three");
put("getDiffPkgFour()", SUBDIFF_PACKAGECLASS.getCanonicalName() + ":Four");
}};
private static final List<String> METHOD_NULL_EXPECTATIONS = new ArrayList<String>(){{
add("getSuperOne");
add("getSuperTwo");
add("getSuperThree");
add("getDiffPkgOne");
add("getDiffPkgTwo");
add("getDiffPkgFour");
}};
@Inject
private CodeGenerationUtil codeGenerationUtil;
@Inject
private InvocationBuilder invocationBuilder;
@Inject
private ASTClassFactory astClassFactory;
@Inject
private ClassGenerationUtil generationUtil;
@Inject
private PackageHelperGenerator packageHelperGenerator;
private Class targetClass;
@Before
public void setup() throws ClassNotFoundException, IOException {
Bootstraps.inject(this);
// Prime generated classes
MemoryClassLoader classLoader = codeGenerationUtil.getClassLoader();
Map<String, String> source = new LinkedHashMap<String, String>();
source.put(SUBDIFF_PACKAGECLASS.getCanonicalName(), loadJavaResource(SUBDIFF_PACKAGECLASS));
source.put(SUB_PACKAGECLASS.getCanonicalName(), loadJavaResource(SUB_PACKAGECLASS));
source.put(TARGET_PACKAGECLASS.getCanonicalName(), loadJavaResource(TARGET_PACKAGECLASS));
classLoader.add(source);
targetClass = classLoader.loadClass(TARGET_PACKAGECLASS.getCanonicalName());
}
private String loadJavaResource(PackageClass packageClass) throws IOException {
String path = "/" + packageClass.getCanonicalName().replace(".", "/") + ".java";
return IOUtils.toString(InvocationBuilderTest.class.getResourceAsStream(path));
}
@Test
public void testBuilderFieldModifiers() throws Exception {
ASTType targetType = astClassFactory.getType(targetClass);
PackageClass testerName = targetType.getPackageClass().append("Tester");
ASTStringType userType = new ASTStringType(testerName.getCanonicalName());
// define class to test field invocations
JDefinedClass testerClass = generationUtil.defineClass(testerName);
testerClass._implements(Runnable.class);
JMethod runMethod = testerClass.method(JMod.PUBLIC, void.class, "run");
JBlock body = runMethod.body();
JVar targetVar = body.decl(generationUtil.ref(targetType), "target", invocationBuilder.buildConstructorCall(userType, targetType.getConstructors().iterator().next(), targetType, Collections.EMPTY_LIST));
// build field setters
for(ASTType superIter = targetType; !superIter.equals(astClassFactory.getType(Object.class)); superIter = superIter.getSuperClass()){
TypedExpression container = new TypedExpression(superIter, targetVar);
for (ASTField field : superIter.getFields()) {
body.add(invocationBuilder.buildFieldSet(userType, field, targetType, container, new TypedExpression(astClassFactory.getType(String.class), JExpr.lit(superIter.getName() + ":" + field.getName()))));
}
}
// build asserts against generated field getters
for(ASTType superIter = targetType; !superIter.equals(astClassFactory.getType(Object.class)); superIter = superIter.getSuperClass()){
TypedExpression container = new TypedExpression(superIter, targetVar);
for (ASTField field : superIter.getFields()) {
body.staticInvoke(generationUtil.ref(Assert.class), "assertEquals").arg(JExpr.lit(superIter.getName() + ":" + field.getName())).arg(invocationBuilder.buildFieldGet(userType, field, targetType, container));
}
}
packageHelperGenerator.generate();
ClassLoader classLoader = codeGenerationUtil.build();
Class<Runnable> tester = (Class<Runnable>) classLoader.loadClass(testerName.getCanonicalName());
tester.newInstance().run();
}
@Test
public void testBuilderMethodModifiers() throws Exception {
ASTType targetType = astClassFactory.getType(targetClass);
PackageClass testerName = targetType.getPackageClass().append("Tester");
ASTType userType = new ASTStringType(testerName.getCanonicalName());
// define class to test field invocations
JDefinedClass testerClass = generationUtil.defineClass(testerName);
testerClass._implements(Runnable.class);
JMethod runMethod = testerClass.method(JMod.PUBLIC, void.class, "run");
JBlock body = runMethod.body();
JVar targetVar = body.decl(generationUtil.ref(targetType), "target", invocationBuilder.buildConstructorCall(userType, targetType.getConstructors().iterator().next(), targetType, Collections.EMPTY_LIST));
// build field setters
for(ASTType superIter = targetType; !superIter.equals(astClassFactory.getType(Object.class)); superIter = superIter.getSuperClass()){
TypedExpression container = new TypedExpression(superIter, targetVar);
if(PROPERTIES.containsKey(superIter.getPackageClass().getClassName())){
List<String> setMethods = PROPERTIES.get(superIter.getPackageClass().getClassName());
for (ASTMethod method : superIter.getMethods()) {
String property = method.getName().replace("set", "");
if(method.getName().startsWith("set") && setMethods.contains(property)){
body.add(invocationBuilder.buildMethodCall(userType, targetType, method, Collections.singletonList(JExpr.lit(superIter.getName() + ":" + property)), container));
}
}
}
}
// build asserts against generated field getters
TypedExpression container = new TypedExpression(targetType, targetVar);
for(ASTType superIter = targetType; !superIter.equals(astClassFactory.getType(Object.class)); superIter = superIter.getSuperClass()){
for (ASTMethod method : superIter.getMethods()) {
if(METHOD_EXPECTATIONS.containsKey(method.getName())){
body.staticInvoke(generationUtil.ref(Assert.class), "assertEquals").arg(JExpr.lit(METHOD_EXPECTATIONS.get(method.getName()))).arg(invocationBuilder.buildMethodCall(userType, targetType, method, Collections.EMPTY_LIST, container));
}
}
}
for (ASTMethod method : targetType.getMethods()) {
if(METHOD_NULL_EXPECTATIONS.contains(method.getName())){
body.staticInvoke(generationUtil.ref(Assert.class), "assertNull").arg(invocationBuilder.buildMethodCall(userType, targetType, method, Collections.EMPTY_LIST, container));
}
}
packageHelperGenerator.generate();
ClassLoader classLoader = codeGenerationUtil.build();
Class<Runnable> tester = (Class<Runnable>) classLoader.loadClass(testerName.getCanonicalName());
tester.newInstance().run();
}
}