Skip to content

Commit

Permalink
test params generator: handling java futures
Browse files Browse the repository at this point in the history
  • Loading branch information
yaronyam committed Nov 30, 2017
1 parent 237de9f commit a50dda0
Show file tree
Hide file tree
Showing 15 changed files with 205 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
public class JavaTestBuilderImpl implements LangTestBuilder {
private static final Logger LOG = Logger.getInstance(JavaTestBuilderImpl.class.getName());
private static final Set<String> STRING_TYPES = ImmutableSet.of("java.lang.String", "java.lang.Object");
private static Type DEFAULT_TYPE = new Type("java.lang.String", "String", "java.lang", false, false, false, false, false, new ArrayList<Type>());
private static Type DEFAULT_STRING_TYPE = new Type("java.lang.String", "String", "java.lang", false, false, false, false, false, new ArrayList<Type>());
private final TestBuilder.ParamRole paramRole; //todo consider removing. not used anymore
private final Method testedMethod;
protected final String NEW_INITIALIZER = "new ";
Expand Down Expand Up @@ -95,22 +95,23 @@ void buildJavaParam(Map<String, String> replacementTypes, Map<String, String> de
String typeName = resolveTypeName(resolvedType, replacementTypes);
if (!resolvedType.getCanonicalName().equals(typeName)) {
final String[] typeInitExp = typeName.split("<VAL>");
testBuilder.append(typeInitExp[0]);
for (int i = 1; i < typeInitExp.length; i++) {
Type genericTypeParam;
if (resolvedType.getComposedTypes().size() >= i) {
genericTypeParam = resolvedType.getComposedTypes().get(i - 1);
} else {
genericTypeParam = DEFAULT_TYPE;
}
if (TestBuilderUtil.looksLikeObjectKeyInGroovyMap(typeInitExp[i], genericTypeParam.getCanonicalName())) {
testBuilder.append("(");
}
buildCallParam(replacementTypes, defaultTypeValues, testBuilder, new Node<Param>(new SyntheticParam(genericTypeParam, genericTypeParam.getName(), false),paramNode,paramNode.getDepth()));
if (TestBuilderUtil.looksLikeObjectKeyInGroovyMap(typeInitExp[i], genericTypeParam.getCanonicalName())) {
testBuilder.append(")");
if (typeInitExp.length == 0) {
Type genericTypeParam = safeGetComposedTypeAtIndex(resolvedType, 0);
buildCallParam(replacementTypes, defaultTypeValues, testBuilder, new Node<Param>(new SyntheticParam(genericTypeParam, genericTypeParam.getName(), false), paramNode, paramNode.getDepth()));
}
else {
testBuilder.append(typeInitExp[0]);
for (int i = 1; i < typeInitExp.length; i++) {
Type genericTypeParam = safeGetComposedTypeAtIndex(resolvedType, i-1);
if (TestBuilderUtil.looksLikeObjectKeyInGroovyMap(typeInitExp[i], genericTypeParam.getCanonicalName())) {
testBuilder.append("(");
}
buildCallParam(replacementTypes, defaultTypeValues, testBuilder, new Node<Param>(new SyntheticParam(genericTypeParam, genericTypeParam.getName(), false),paramNode,paramNode.getDepth()));
if (TestBuilderUtil.looksLikeObjectKeyInGroovyMap(typeInitExp[i], genericTypeParam.getCanonicalName())) {
testBuilder.append(")");
}
testBuilder.append(typeInitExp[i]);
}
testBuilder.append(typeInitExp[i]);
}
}
else if (shouldContinueRecursion(paramNode)) {
Expand All @@ -134,6 +135,16 @@ else if (shouldContinueRecursion(paramNode)) {
}
}

private Type safeGetComposedTypeAtIndex(Type resolvedType, int i) {
Type genericTypeParam;
if (resolvedType.getComposedTypes().size() > i) {
genericTypeParam = resolvedType.getComposedTypes().get(i);
} else {
genericTypeParam = DEFAULT_STRING_TYPE;
}
return genericTypeParam;
}

@NotNull
protected String resolveInitializerKeyword(Type type, Method foundCtor) {
return NEW_INITIALIZER;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public interface TestBuilder {
String RESULT_VARIABLE_NAME = "expectedResult";
String renderMethodParams(Method method, Map<String, String> replacementTypes, Map<String, String> defaultTypeValues) throws Exception;

ParameterizedTestComponents buildPrameterizedTestComponents(Method method, Map<String, String> replacementTypes, Map<String, String> defaultTypeValues) throws Exception;
ParameterizedTestComponents buildPrameterizedTestComponents(Method method, Map<String, String> replacementTypesForReturn, Map<String, String> replacementTypes, Map<String, String> defaultTypeValues) throws Exception;

String renderReturnParam(Method testedMethod, Type type, String defaultName, Map<String, String> replacementTypes, Map<String, String> defaultTypeValues) throws Exception;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public String renderMethodParams(Method method, Map<String, String> replacementT
}

@Override
public ParameterizedTestComponents buildPrameterizedTestComponents(Method method, Map<String, String> replacementTypes, Map<String, String> defaultTypeValues) throws Exception {
public ParameterizedTestComponents buildPrameterizedTestComponents(Method method, Map<String, String> replacementTypesForReturn, Map<String, String> replacementTypes, Map<String, String> defaultTypeValues) throws Exception {
//a temp solution for single dimmension parameters
final LangTestBuilder testBuilder = langTestBuilderFactory.createTestBuilder(method, ParamRole.Input);
final ParameterizedTestComponents parameterizedTestComponents = new ParameterizedTestComponents();
Expand All @@ -41,7 +41,7 @@ public ParameterizedTestComponents buildPrameterizedTestComponents(Method method
}

if (method.hasReturn()) {
final String value = testBuilder.renderJavaCallParam(method.getReturnType(), RESULT_VARIABLE_NAME, replacementTypes, defaultTypeValues);
final String value = testBuilder.renderJavaCallParam(method.getReturnType(), RESULT_VARIABLE_NAME, replacementTypesForReturn, defaultTypeValues);
parameterizedTestComponents.getParamsMap().put(RESULT_VARIABLE_NAME, value);
}
parameterizedTestComponents.setMethodClassParamsStr(sb.toString());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,36 @@
package com.weirddev.testme.intellij.template.context;

import com.intellij.openapi.diagnostic.Logger;
import com.weirddev.testme.intellij.utils.ClassNameUtils;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;

/**
* Date: 31/03/2017
*
* @author Yaron Yamin
*/
@SuppressWarnings("unused")
public class TestSubjectUtils {
public class TestSubjectUtils
{
private static final Logger LOG = Logger.getInstance(TestSubjectUtils.class.getName());
public static boolean hasTestableInstanceMethod(List<Method> methods){

private static final Set<String> JAVA_FUTURE_TYPES = new HashSet<String>(Arrays.asList("java.util.concurrent.Future", "java.util.concurrent.CompletableFuture", "java.util.concurrent.RunnableFuture",
"java.util.concurrent.ForkJoinTask.AdaptedRunnableAction", "java.util.concurrent.RunnableScheduledFuture", "java.util.concurrent.ScheduledThreadPoolExecutor.ScheduledFutureTask", "java.util.concurrent.FutureTask",
"java.util.concurrent.ExecutorCompletionService.QueueingFuture", "java.util.concurrent.ForkJoinTask.AdaptedRunnable", "java.util.concurrent.ForkJoinTask.AdaptedCallable","java.util.concurrent.ForkJoinTask",
"java.util.concurrent.ForkJoinTask.AdaptedRunnableAction", "java.util.concurrent.CountedCompleter","java.util.concurrent.RecursiveTask", "java.util.concurrent.ForkJoinTask.RunnableExecuteAction",
"java.util.concurrent.CompletableFuture.AsyncSupply","java.util.concurrent.RecursiveAction","java.util.concurrent.CompletableFuture.Completion","java.util.concurrent.ScheduledFuture", "java.util.concurrent.RunnableScheduledFuture"));

public static boolean hasTestableInstanceMethod(List<Method> methods) {
for (Method method : methods) {
if (method.isTestable() && !method.isStatic()) {
return true;
}
}
return false;
}
public static boolean isMethodCalled(Method method, Method byTestedMethod){

public static boolean isMethodCalled(Method method, Method byTestedMethod) {
Set<MethodCall> methodCalls = byTestedMethod.getMethodCalls();
boolean isMethodCalled = false;
for (MethodCall methodCall : methodCalls) {
Expand All @@ -31,10 +39,11 @@ public static boolean isMethodCalled(Method method, Method byTestedMethod){
break;
}
}
LOG.debug("method "+method.getMethodId()+" searched in "+methodCalls.size()+" method calls by tested method "+byTestedMethod.getMethodId()+" - is found:"+isMethodCalled);
LOG.debug("method " + method.getMethodId() + " searched in " + methodCalls.size() + " method calls by tested method " + byTestedMethod.getMethodId() + " - is found:" + isMethodCalled);
return isMethodCalled;
}
public String formatSpockParamNamesTitle(Map<String,String> paramsMap, boolean methodHasReturn){

public String formatSpockParamNamesTitle(Map<String, String> paramsMap, boolean methodHasReturn) {
StringBuilder sb = new StringBuilder();
final Set<String> paramNameKeys = paramsMap.keySet();
final String[] paramNames = paramNameKeys.toArray(new String[]{});
Expand All @@ -54,7 +63,8 @@ else if (sb.length() > 0) {
}
return sb.toString();
}
public String formatSpockDataParameters(Map<String,String> paramsMap, String linePrefix){//todo - should accept Map<String,List<String>> paramsMap instead

public String formatSpockDataParameters(Map<String, String> paramsMap, String linePrefix) {//todo - should accept Map<String,List<String>> paramsMap instead
StringBuilder sb = new StringBuilder();
final Set<String> paramNameKeys = paramsMap.keySet();
final boolean hasInputParams = hasInputParams(paramNameKeys);
Expand Down Expand Up @@ -90,7 +100,33 @@ public String formatSpockDataParameters(Map<String,String> paramsMap, String lin
return sb.toString();
}

public boolean isJavaFuture(Type type) {
for (String javaFutureType : JAVA_FUTURE_TYPES) {
if (isSameGenericType(type, javaFutureType)) {
return true;
}
}
return isImplements(type, "java.util.concurrent.Future");
}

private boolean isImplements(Type type, String classCanonicalName) {
for (Type interfaceType : type.getImplementedInterfaces()) {
if (isSameGenericType(interfaceType, classCanonicalName)) {
return true;
}
}
return false;
}

private boolean isSameGenericType(Type type, String classCanonicalName) {
return classCanonicalName.equals(ClassNameUtils.stripGenerics(type.getCanonicalName()));
}

private boolean hasInputParams(Set<String> paramNameKeys) {
return paramNameKeys.size() > 1 || paramNameKeys.size() == 1 && !paramNameKeys.contains(TestBuilder.RESULT_VARIABLE_NAME);
}

public static Set<String> getJavaFutureTypes() {
return JAVA_FUTURE_TYPES;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public class Type {
private boolean dependenciesResolved =false;
private boolean dependenciesResolvable =false;
private boolean hasDefaultConstructor=false;
private List<Type> implementedInterfaces = new ArrayList<Type>();
/**
* true - if this is a scala case class
*/
Expand Down Expand Up @@ -89,7 +90,7 @@ public Type(PsiType psiType, @Nullable TypeDictionary typeDictionary, int maxRec
false):null;
fields = new ArrayList<Field>();
enumValues = resolveEnumValues(psiType);
dependenciesResolvable = shouldResolveAllMethods && maxRecursionDepth > 1;
dependenciesResolvable = shouldResolveAllMethods && maxRecursionDepth > 1;
methods = new ArrayList<Method>();
isFinal = isFinalType(psiClass);
if (psiClass != null && LanguageUtils.isScala(psiClass.getLanguage())) {
Expand Down Expand Up @@ -121,6 +122,7 @@ public void resolveDependencies(@Nullable TypeDictionary typeDictionary, int max

}
resolveFields(psiClass,typeDictionary,maxRecursionDepth - 1);
resolveImplementedInterfaces(psiClass,typeDictionary,shouldResolveAllMethods,maxRecursionDepth - 1);
dependenciesResolved=true;
}
}
Expand All @@ -132,6 +134,11 @@ private void resolveFields(@NotNull PsiClass psiClass, TypeDictionary typeDictio
}
}
}
private void resolveImplementedInterfaces(@NotNull PsiClass psiClass, TypeDictionary typeDictionary, boolean shouldResolveAllMethods, int maxRecursionDepth) {
for (PsiClassType psiClassType : psiClass.getImplementsListTypes()) {
implementedInterfaces.add(new Type(psiClassType, typeDictionary, maxRecursionDepth, shouldResolveAllMethods));
}
}

private boolean isFinalType(PsiClass aClass) {
return aClass != null && aClass.getModifierList()!=null && aClass.getModifierList().hasExplicitModifier(PsiModifier.FINAL);
Expand Down Expand Up @@ -290,4 +297,8 @@ public String toString() {
public boolean isCaseClass() {
return caseClass;
}

public List<Type> getImplementedInterfaces() {
return implementedInterfaces;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ class ${CLASS_NAME} {

#end
#grRenderMethodCall($method,$TESTED_CLASS.name)
#if($method.hasReturn()) assert #grRenderAssert($method)#end
#if($method.hasReturn()) assert #grRenderAssert($method)
#end
}
#end
#end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class ${CLASS_NAME} extends Specification {
#end
#foreach($method in $TESTED_CLASS.methods)
#if($method.isTestable())
#set($paraTestComponents=$TestBuilder.buildPrameterizedTestComponents($method,$grReplacementTypes,$grDefaultTypeValues))
#set($paraTestComponents=$TestBuilder.buildPrameterizedTestComponents($method,$grReplacementTypesForReturn,$grReplacementTypes,$grDefaultTypeValues))

@Unroll
def "#renderTestMethodNameAsWords($method.name)$TestSubjectUtils.formatSpockParamNamesTitle($paraTestComponents.paramsMap, $method.hasReturn())"() {
Expand All @@ -33,7 +33,7 @@ class ${CLASS_NAME} extends Specification {

#end
expect:
#grRenderParameterizedMethodCall($method, $TESTED_CLASS.name, $paraTestComponents.methodClassParamsStr)#if($method.hasReturn()) == expectedResult
#grRenderParameterizedMethodCall($method, $TESTED_CLASS.name, $paraTestComponents.methodClassParamsStr)#{if}($TestSubjectUtils.isJavaFuture($method.returnType)).get()#{end}#if($method.hasReturn()) == expectedResult
#end
#if(!$method.hasReturn())

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#parse("TestMe common macros.java")
################## Global vars ###############
#set($grReplacementTypes = {
#set($grReplacementTypesStatic = {
"java.util.Collection": "[<VAL>]",
"java.util.Deque": "new LinkedList([<VAL>])",
"java.util.List": "[<VAL>]",
Expand All @@ -22,6 +22,14 @@
"java.util.LinkedHashMap": "[<VAL>:<VAL>]",
"java.util.TreeSet": "[<VAL>] as java.util.TreeSet"
})
#set($grReplacementTypes = $grReplacementTypesStatic.clone())
#set($grReplacementTypesForReturn = $grReplacementTypesStatic.clone())
#foreach($javaFutureType in $TestSubjectUtils.javaFutureTypes)
#evaluate(${grReplacementTypes.put($javaFutureType,"java.util.concurrent.CompletableFuture.completedFuture(<VAL>)")})
#end
#foreach($javaFutureType in $TestSubjectUtils.javaFutureTypes)
#evaluate(${grReplacementTypesForReturn.put($javaFutureType,"<VAL>")})
#end
#set($grDefaultTypeValues = {
"byte": "(byte)0",
"short": "(short)0",
Expand Down Expand Up @@ -72,7 +80,7 @@
#end
##
#macro(grRenderAssert $method)
result == $TestBuilder.renderReturnParam($method,$method.returnType,"replaceMeWithExpectedResult",$grReplacementTypes,$grDefaultTypeValues)
result#if($TestSubjectUtils.isJavaFuture($method.returnType)).get()#end == $TestBuilder.renderReturnParam($method,$method.returnType,"replaceMeWithExpectedResult",$grReplacementTypesForReturn,$grDefaultTypeValues)
#end
##
#macro(grRenderMethodCall $method,$testedClassName)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#parse("TestMe common macros.java")
################## Global vars ###############
#set($replacementTypes = {
#set($replacementTypesStatic = {
"java.util.Collection": "java.util.Arrays.<TYPES>asList(<VAL>)",
"java.util.Deque": "new java.util.LinkedList<TYPES>(java.util.Arrays.asList(<VAL>))",
"java.util.List": "java.util.Arrays.<TYPES>asList(<VAL>)",
Expand All @@ -21,6 +21,14 @@
"java.util.Stack": "new java.util.Stack<TYPES>(){{push(<VAL>);}}",
"java.util.TreeSet": "new java.util.TreeSet<TYPES>(java.util.Arrays.asList(<VAL>))"
})
#set($replacementTypes = $replacementTypesStatic.clone())
#set($replacementTypesForReturn = $replacementTypesStatic.clone())
#foreach($javaFutureType in $TestSubjectUtils.javaFutureTypes)
#evaluate(${replacementTypes.put($javaFutureType,"java.util.concurrent.CompletableFuture.completedFuture(<VAL>)")})
#end
#foreach($javaFutureType in $TestSubjectUtils.javaFutureTypes)
#evaluate(${replacementTypesForReturn.put($javaFutureType,"<VAL>")})
#end
#set($defaultTypeValues = {
"byte": "(byte) 0",
"short": "(short) 0",
Expand Down Expand Up @@ -74,11 +82,11 @@
#end
##
#macro(renderJUnitAssert $method)
#renderJunitAssertMethod($method.returnType)($TestBuilder.renderReturnParam($method,$method.returnType,"replaceMeWithExpectedResult",$replacementTypes,$defaultTypeValues), result);
#renderJunitAssertMethod($method.returnType)($TestBuilder.renderReturnParam($method,$method.returnType,"replaceMeWithExpectedResult",$replacementTypesForReturn,$defaultTypeValues), result#{if}($TestSubjectUtils.isJavaFuture($method.returnType)).get()#{end});
#end
##
#macro(renderTestNgAssert $method)
assertEquals(result, $TestBuilder.renderReturnParam($method,$method.returnType,"replaceMeWithExpectedResult",$replacementTypes,$defaultTypeValues));
assertEquals(result#{if}($TestSubjectUtils.isJavaFuture($method.returnType)).get()#{end}, $TestBuilder.renderReturnParam($method,$method.returnType,"replaceMeWithExpectedResult",$replacementTypesForReturn,$defaultTypeValues));
#end
##
#macro(renderJunitAssertMethod $type)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@
"scala.Tuple12": "(<VAL>,<VAL>,<VAL>,<VAL>,<VAL>,<VAL>,<VAL>,<VAL>,<VAL>,<VAL>,<VAL>,<VAL>)",
"scala.Tuple13": "(<VAL>,<VAL>,<VAL>,<VAL>,<VAL>,<VAL>,<VAL>,<VAL>,<VAL>,<VAL>,<VAL>,<VAL>,<VAL>)"
})
#set($scReplacementTypes = $scReplacementTypesStatic.clone())
#set($scReplacementTypesForReturn = $scReplacementTypesStatic.clone())
#foreach($javaFutureType in $TestSubjectUtils.javaFutureTypes)
#evaluate(${scReplacementTypes.put($javaFutureType,"java.util.concurrent.CompletableFuture.completedFuture(<VAL>)")})
#end
#foreach($javaFutureType in $TestSubjectUtils.javaFutureTypes)
#evaluate(${scReplacementTypesForReturn.put($javaFutureType,"<VAL>")})
#end

#set($scDefaultTypeValues = {
"byte": "(byte)0",
"short": "(short)0",
Expand Down Expand Up @@ -100,7 +109,7 @@
#end
##
#macro(scRenderAssert $method)
result === $TestBuilder.renderReturnParam($method,$method.returnType,"replaceMeWithExpectedResult",$scReplacementTypes,$scDefaultTypeValues)
result#if($TestSubjectUtils.isJavaFuture($method.returnType)).get()#end === $TestBuilder.renderReturnParam($method,$method.returnType,"replaceMeWithExpectedResult",$scReplacementTypesForReturn,$scDefaultTypeValues)
#end
##
#macro(scRenderMethodCall $method,$testedClassName)
Expand Down
Loading

0 comments on commit a50dda0

Please sign in to comment.