/*******************************************************************************
* Copyright (c) 2006-2010 eBay Inc. All Rights Reserved.
* 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
*******************************************************************************/
package org.ebayopensource.turmeric.tools.codegen.builders;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.ebayopensource.turmeric.runtime.common.exceptions.ServiceException;
import org.ebayopensource.turmeric.runtime.common.impl.utils.LogManager;
import org.ebayopensource.turmeric.runtime.sif.service.Service;
import org.ebayopensource.turmeric.runtime.sif.service.ServiceFactory;
import org.ebayopensource.turmeric.tools.codegen.CodeGenContext;
import org.ebayopensource.turmeric.tools.codegen.SourceGenerator;
import org.ebayopensource.turmeric.tools.codegen.exception.CodeGenFailedException;
import org.ebayopensource.turmeric.tools.codegen.util.CodeGenConstants;
import org.ebayopensource.turmeric.tools.codegen.util.CodeGenUtil;
import org.ebayopensource.turmeric.tools.codegen.util.ContextClassLoaderUtil;
import org.ebayopensource.turmeric.tools.codegen.util.IntrospectUtil;
import com.sun.codemodel.JBlock;
import com.sun.codemodel.JClass;
import com.sun.codemodel.JCodeModel;
import com.sun.codemodel.JConditional;
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JExpr;
import com.sun.codemodel.JExpression;
import com.sun.codemodel.JFieldRef;
import com.sun.codemodel.JFieldVar;
import com.sun.codemodel.JInvocation;
import com.sun.codemodel.JMethod;
import com.sun.codemodel.JMod;
import com.sun.codemodel.JType;
import com.sun.codemodel.JVar;
/**
* Generates JUnit Tests for a Service
*
* @author rmandapati
*/
public class UnitTestGenerator extends BaseCodeGenerator implements SourceGenerator {
private static final String UNIT_TEST_BASE_CLASS = "junit.framework.TestCase";
private static final String GET_PROXY_METHOD_NAME = "getProxy";
private static final String SVC_PROXY_FIELD_NAME = "m_proxy";
private static final String TEST_EXCEPTION_MSG = "Response is Null";
private static Logger s_logger = LogManager.getInstance(UnitTestGenerator.class);
private static UnitTestGenerator s_unitTestGenerator = new UnitTestGenerator();
private UnitTestGenerator() {}
public static UnitTestGenerator getInstance() {
return s_unitTestGenerator;
}
private Logger getLogger() {
return s_logger;
}
public boolean continueOnError() {
return true;
}
public void generate(CodeGenContext codeGenCtx) throws CodeGenFailedException {
String qualifiedInterfaceName = codeGenCtx.getServiceInterfaceClassName();
Class<?> interfaceClass = ContextClassLoaderUtil.loadRequiredClass(qualifiedInterfaceName);
JCodeModel jCodeModel = new JCodeModel();
String unitTestClassName =
getUnitTestClassName(codeGenCtx.getServiceAdminName(), qualifiedInterfaceName);
JDefinedClass unitTestClass = createNewClass(jCodeModel, unitTestClassName);
extendTestClass(unitTestClass, UNIT_TEST_BASE_CLASS, jCodeModel);
addField(jCodeModel, interfaceClass, unitTestClass);
addConstructor(jCodeModel, unitTestClass);
addGetProxyMethod(unitTestClass, interfaceClass, jCodeModel, codeGenCtx);
addTestMethods(interfaceClass, unitTestClass, jCodeModel);
String projectRoot = codeGenCtx.getProjectRoot();
if(CodeGenUtil.isEmptyString(projectRoot))
generateJavaFile(codeGenCtx, unitTestClass, CodeGenConstants.TEST_GEN_FOLDER);
else
generateJavaFile(codeGenCtx, unitTestClass, projectRoot, CodeGenConstants.TEST_GEN_FOLDER);
if (codeGenCtx.getInputOptions().isNoCompile() == false) {
compileJavaFilesNoException(
codeGenCtx.getGeneratedJavaFiles(),
codeGenCtx.getBinLocation());
}
getLogger().log(Level.INFO, "Successfully generated " + unitTestClassName);
}
private String getUnitTestClassName(String svcName, String interfaceClassName) {
String unitTestClassName = CodeGenUtil.makeFirstLetterUpper(svcName) + "Test";
return generateQualifiedClassName(interfaceClassName, "test", unitTestClassName);
}
private void extendTestClass(
JDefinedClass unitTestClass,
String className,
JCodeModel jCodeModel) throws CodeGenFailedException {
JClass testBaseClass = createDirectClass(jCodeModel, UNIT_TEST_BASE_CLASS);
extend(unitTestClass, testBaseClass);
}
private void addConstructor(JCodeModel jCodeModel, JDefinedClass unitTestClass)
throws CodeGenFailedException {
//---------------------------------------------------------------
// generates:
// public <Class Name>(String testcaseName) {
// super(testcaseName);
// }
//---------------------------------------------------------------
JMethod constructor = unitTestClass.constructor(JMod.PUBLIC);
JClass stringJClass = getJClass("java.lang.String", jCodeModel);
JVar serviceParam = constructor.param(stringJClass, "testcaseName");
//---------------------------------------------------------------
// generates:
// super(testcaseName);
//---------------------------------------------------------------
JBlock contrcutorBody = constructor.body();
JInvocation superInvoker = contrcutorBody.invoke("super");
superInvoker.arg(serviceParam);
}
private void addField(JCodeModel jCodeModel, Class<?> interfaceClass,
JDefinedClass testClientClass) throws CodeGenFailedException {
// --------------------------------------------------
// adds private <InterfaceClass> m_proxy = null;
// --------------------------------------------------
JClass interfaceJClass = getJClass(interfaceClass, jCodeModel);
JFieldVar proxyField = testClientClass.field(JMod.PRIVATE,
interfaceJClass, SVC_PROXY_FIELD_NAME);
proxyField.init(JExpr._null());
}
private void addGetProxyMethod(
JDefinedClass unitTestClass,
Class<?> interfaceClass,
JCodeModel jCodeModel,
CodeGenContext codeGenCtx) throws CodeGenFailedException {
//---------------------------------------------------------------
// generates:
// private <Interface> getProxy() {}
// --------------------------------------------------------------
JClass svcJClass = getJClass(Service.class, jCodeModel);
JMethod getProxyMethod =
addMethod(unitTestClass,
GET_PROXY_METHOD_NAME,
JMod.PRIVATE,
getJClass(interfaceClass, jCodeModel));
getProxyMethod._throws(ServiceException.class);
JBlock proxyMethodBody = getProxyMethod.body();
//---------------------------------------------------------------
// generates:
// if (m_proxy == null) { .... }
//---------------------------------------------------------------
JFieldRef proxyFieldRef = JExpr.ref(SVC_PROXY_FIELD_NAME);
JConditional ifProxyCheck = proxyMethodBody._if(proxyFieldRef.eq(JExpr._null()));
JBlock proxyCheckThenBlock = ifProxyCheck._then();
/*
//---------------------------------------------------------------
// generates:
// QName qName = new QName(<NamespaceURI>, <LocalPart>);
//---------------------------------------------------------------
JClass qnameJClass = getJClass(QName.class, jCodeModel);
JInvocation newQNameInvoker = JExpr._new(qnameJClass);
newQNameInvoker.arg(JExpr.lit(codeGenCtx.getServiceQName().getNamespaceURI()));
newQNameInvoker.arg(JExpr.lit(codeGenCtx.getServiceName()));
JVar qNameJVar = proxyCheckThenBlock.decl(qnameJClass, "qName", newQNameInvoker);
*/
//-----------------------------------------------------------
// String svcAdminName = <ServiceName>;
//-----------------------------------------------------------
JClass stringJClass = getJClass(String.class, jCodeModel);
JExpression svcNameExpr = JExpr.lit(codeGenCtx.getServiceAdminName());
JVar svcAdminNameVar = proxyCheckThenBlock.decl(stringJClass, "svcAdminName", svcNameExpr);
//---------------------------------------------------------------
// generates:
// Service service = ServiceFactory.create(<ServiceName>, "production",<serviceName>_Test,null);
//---------------------------------------------------------------
JClass svcFactoryJClass = getJClass(ServiceFactory.class, jCodeModel);
JInvocation svcFactoryInvoker = svcFactoryJClass.staticInvoke("create");
svcFactoryInvoker.arg(svcAdminNameVar);
JExpression envNameExpr = JExpr.lit("production");
JVar envNameVar = proxyCheckThenBlock.decl(stringJClass, "envName", envNameExpr);
svcFactoryInvoker.arg(envNameVar);
JExpression clientNameExpr = JExpr.lit(codeGenCtx.getServiceAdminName() + "_Test");
JVar clientNameVar = proxyCheckThenBlock.decl(stringJClass, "clientName", clientNameExpr);
svcFactoryInvoker.arg(clientNameVar);
svcFactoryInvoker.arg(JExpr._null());
JVar svcVar = proxyCheckThenBlock.decl(svcJClass, "service", svcFactoryInvoker);
proxyCheckThenBlock.assign(proxyFieldRef, svcVar.invoke("getProxy"));
//------------------------------------------------
// generates:
// return m_proxy;
//------------------------------------------------
proxyMethodBody._return(proxyFieldRef);
}
private void addTestMethods(
Class<?> interfaceClass,
JDefinedClass unitTestClass,
JCodeModel jCodeModel) throws CodeGenFailedException {
List<Method> methods = IntrospectUtil.getMethods(interfaceClass);
for (Method method : methods) {
String methodName = method.getName();
//---------------------------------------------------------------
// For each interface method
// generates:
// public void test<InterfaceMethodName>() {
// }
//---------------------------------------------------------------
String testMethodName = "test" + CodeGenUtil.makeFirstLetterUpper(methodName);
JMethod testMethod =
addMethod(unitTestClass, testMethodName, jCodeModel.VOID);
testMethod._throws(Exception.class);
JBlock testMethodBody = testMethod.body();
//---------------------------------------------------------------
// generates:
// <ReturnType> result = <InitialValue>
//---------------------------------------------------------------
JType returnJType = null;
JVar resultVar = null;
Type returnType = method.getGenericReturnType();
if (returnType != null && returnType != Void.TYPE) {
returnJType = getJType(returnType, jCodeModel);
resultVar = testMethodBody.decl(returnJType, "result", getValueForType(method.getReturnType()));
}
//---------------------------------------------------------------
// generates:
// try {
// [<ReturnType> result] = getProxy().<InterfaceMethod>([<ParameterValue>]);
//
//---------------------------------------------------------------
//JTryBlock tryBlock = testMethodBody._try();
//JBlock tryBlockBody = tryBlock.body();
JInvocation getProxyInvoker = JExpr.invoke(GET_PROXY_METHOD_NAME);
JInvocation methodInvoker = getProxyInvoker.invoke(methodName);
Class<?>[] paramTypes = method.getParameterTypes();
// Size should be atmost 1
// we don't allow more than one parameter for methods of
// a servive interface
if (paramTypes != null && paramTypes.length > 0) {
// adds java comment
testMethodBody.directStatement("// TODO: REPLACE PARAMETER(S) WITH ACTUAL VALUE(S)");
methodInvoker.arg(getValueForType(paramTypes[0]));
}
if (resultVar != null) {
testMethodBody.assign(resultVar, methodInvoker);
} else {
testMethodBody.add(methodInvoker);
}
//---------------------------------------------------------------
// generates:
// catch(Exception ex) {
// ex.printStackTrace();
// }
//---------------------------------------------------------------
//JCatchBlock jCatchBlock =
// tryBlock._catch(getJClass("java.lang.Exception", jCodeModel));
//jCatchBlock.param("ex");
//JBlock catchBlockBody = jCatchBlock.body();
//catchBlockBody.directStatement("ex.printStackTrace();");
// ---------------------------------------------------------------
// generates:
// if(result==null)
// throw new Exception("Response is Null");
if (resultVar != null) {
JConditional ifResultCondition = testMethodBody._if(resultVar
.eq(JExpr._null()));
JClass ExceptionClass = getJClass(Exception.class, jCodeModel);
JInvocation invokeNewEcption = JExpr._new(ExceptionClass);
invokeNewEcption.arg(TEST_EXCEPTION_MSG);
ifResultCondition._then()._throw(invokeNewEcption);
}
// ---------------------------------------------------------------
// generates:
// // Note: Uncomment following assert statement
// // assertTrue(<Expression>);
//---------------------------------------------------------------
testMethodBody.directStatement("// TODO: FIX FOLLOWING ASSERT STATEMENT");
testMethodBody.directStatement("assertTrue(false);");
}
}
public String getFilePath(String serviceAdminName, String interfaceName) {
// TODO Auto-generated method stub
return null;
}
}