Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EvoFuzz improvements for EvoSuite #478

Open
wants to merge 49 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
7dcf4af
Update the commons-lang3 library to include LANG-1700 bug fixes
Apr 11, 2024
1dfc655
Limit GenericClass type instantiation recursion level
Apr 11, 2024
3b7d9c6
Add isAssignable check before replacingParameterReference
Apr 11, 2024
f19447d
Check type assignability for the field parameter before replacing it
Apr 11, 2024
4fceb51
Return genericSuperClass only if possible
Apr 11, 2024
1f7732f
Refactor variable names in getWithParameterSuperclass()
Apr 11, 2024
2d072b9
Return new instance of typeVariableMap when calling getTypeVariableMap()
Apr 11, 2024
d8d4642
Fix a bug in getTypeVariableMap()
Apr 11, 2024
5ba8416
Fix the bug in clearGeneratorCache
Apr 11, 2024
f765f16
Prioritize non-type parameterized generators in getRandomGenerator()
Apr 11, 2024
c2097a7
Refactor a variable name in a method in MethodStatement.java to refle…
Apr 11, 2024
ce054a0
Check type compatibility of variable before assigning it to the retur…
Apr 11, 2024
0267c90
Add a log message to the assertion error for debugging
Apr 11, 2024
c2046b0
Prevent recursive generic type instantiation for the wildcard types
Apr 11, 2024
3623114
Map variable type to itself if there is no match
Apr 11, 2024
36d2481
Increase MAX_GENERIC_DEPTH 3 to 15
cinemamoon Oct 11, 2023
04804c3
Check loops in type variable mappings before generic type variable in…
Apr 11, 2024
288cd44
Revert "Fix a bug in getTypeVariableMap()"
Apr 11, 2024
457fb62
Fix the bug in getTypeVariableMap()
Apr 11, 2024
f7865e7
Replace EvoLogger in VarMap with class specific Logger
Apr 11, 2024
50c59be
Refactor line breaks for the code readability
Apr 11, 2024
ea19ea9
Add a debug routine to check type compatibilities functionalities
Apr 11, 2024
4894e66
Add missing import classes
Apr 11, 2024
a5907e8
Replace replaceTypeVariable implementations with the updated Apache-c…
Apr 11, 2024
e9c9aa7
Fix a bug that incompletely compares type variables
Apr 11, 2024
022637b
Attempts a generic type variable instantiation with max_generic_depth…
Apr 11, 2024
1523bfa
Update the new commons-lang3 library to include new bug fixes
Apr 11, 2024
8a69184
Add a mutation operator for a fieldReference parameter
Apr 11, 2024
2c90f1d
Change a directory environment variable into project root directory
Apr 11, 2024
a74589c
Update pom.xml in runtime to use local maven repository
Apr 11, 2024
de2a774
Update local-maven-repo to include *.jar
Apr 11, 2024
ef853c5
Add readme.md describing the usage of local repo
Apr 11, 2024
bb7d15f
Remove unnecessary configuration within pom.xml of runtime module
Apr 11, 2024
370d230
Refactor to remove unnecessary changes in comparison with original Ev…
Apr 12, 2024
1a7c555
Replace String concatenations with StringBuffer to efficiently constr…
Apr 12, 2024
4e3db6a
Fix a possible bug in SandBoxing
Apr 12, 2024
ab2a74e
Remove an attempt to mutate field reference
Apr 12, 2024
5601eff
Limit the recursion depth of canBeInstantiatedTo()
Apr 12, 2024
2c9d47f
Add additional allowed RuntimePermission
Apr 12, 2024
b699588
Modify assertion start condition
Apr 12, 2024
7f5989e
Fix the bug discovered by SPOON-65 in SBST'20 benchmark
Apr 12, 2024
e71028b
Add additional type compatibilities checks
Apr 12, 2024
d76a32d
Fix a bug discovered by GUAVA-128 in SBST'20 benchmark
Apr 12, 2024
af97384
Fix a bug discovered by GUAVA-22 in SBST'20 benchmark
Apr 12, 2024
664d29d
Fix a bug that wrongly parses classPaths
Apr 12, 2024
25c0bb5
Fix the NPE when setting test generation strategy
Apr 12, 2024
c0cbfe5
Generate Object type if we cannot find proper parameter type
Apr 12, 2024
f0578bf
Fix a null pointer exception
Apr 12, 2024
cff675d
Reflect code review for PR#15
May 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ master/dependency-reduced-pom.xml
shaded/dependency-reduced-pom.xml
standalone_runtime/dependency-reduced-pom.xml
nbactions.xml
!./local-maven-repo/org/apache/commons/commons-lang3/3.12.0-fix-LANG-1700/*.jar
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "libs/commons-lang"]
path = libs/commons-lang
url = https://github.com/cinemamoon/commons-lang.git
2 changes: 1 addition & 1 deletion client/src/main/java/org/evosuite/TestSuiteGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ protected void postProcessTests(TestSuiteChromosome testSuite) {
LoggingUtils.getEvoLogger().info("* " + ClientProcess.getPrettyPrintIdentifier() + "Generating assertions");
// progressMonitor.setCurrentPhase("Generating assertions");
ClientServices.getInstance().getClientNode().changeState(ClientState.ASSERTION_GENERATION);
if (!TimeController.getInstance().hasTimeToExecuteATestCase()) {
if(!TimeController.getInstance().isThereStillTimeInThisPhase()) {
LoggingUtils.getEvoLogger().info("* " + ClientProcess.getPrettyPrintIdentifier()
+ "Skipping assertion generation because not enough time is left");
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.evosuite.ga;

public class RecursiveConstructionFailedException extends ConstructionFailedException {

private static final long serialVersionUID = -2934799333306971428L;
public RecursiveConstructionFailedException(String reason) {
super(reason);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,9 @@ private void addDependencies4Line() {
ClassLoader loader = TestGenerationContext.getInstance().getClassLoaderForSUT();
BytecodeInstructionPool pool = BytecodeInstructionPool.getInstance(loader);
BytecodeInstruction instruction = pool.getFirstInstructionAtLineNumber(line.getClassName(), line.getMethod(), line.getLine());
if(instruction == null) {
return;
}
Set<ControlDependency> cds = instruction.getControlDependencies();
if (cds.size() == 0)
this.currentGoals.add(ff);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ public static List<String> getScaffoldingImports(boolean wasSecurityException, L
list.add(adapter.afterEach().getCanonicalName());
}

if (wasSecurityException || TestSuiteWriterUtils.shouldResetProperties(results)) {
if (Properties.RESET_STATIC_FIELDS || wasSecurityException || TestSuiteWriterUtils.shouldResetProperties(results)) {
list.add(getAdapter().afterAll().getCanonicalName());
}

Expand Down Expand Up @@ -576,7 +576,7 @@ private String getResetPropertiesCommand() {

private void generateAfterClass(StringBuilder bd, boolean wasSecurityException, List<ExecutionResult> results) {

if (wasSecurityException || TestSuiteWriterUtils.shouldResetProperties(results)) {
if (Properties.RESET_STATIC_FIELDS || wasSecurityException || TestSuiteWriterUtils.shouldResetProperties(results)) {
bd.append(METHOD_SPACE);
bd.append("@").append(getAdapter().afterAll().getSimpleName()).append("\n");
bd.append(METHOD_SPACE);
Expand All @@ -586,7 +586,6 @@ private void generateAfterClass(StringBuilder bd, boolean wasSecurityException,
bd.append(BLOCK_SPACE);
bd.append("Sandbox.resetDefaultSecurityManager(); \n");
}

if (wasSecurityException) {
bd.append(BLOCK_SPACE);
bd.append(EXECUTOR_SERVICE + ".shutdownNow(); \n");
Expand Down
26 changes: 19 additions & 7 deletions client/src/main/java/org/evosuite/setup/TestCluster.java
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,6 @@ private void cacheGenerators(GenericClass<?> clazz) throws ConstructionFailedExc
continue;
}


// Set owner type parameters from new return type
GenericAccessibleObject<?> newGenerator = generator.copyWithOwnerFromReturnType(instantiatedGeneratorClazz);

Expand Down Expand Up @@ -462,11 +461,16 @@ private void cacheGenerators(GenericClass<?> clazz) throws ConstructionFailedExc
}

logger.debug("Current generator: {}", newGenerator);
if ((!hadTypeParameters && generatorClazz.equals(clazz))
|| clazz.isAssignableFrom(newGenerator.getGeneratedType())) {
logger.debug("Got new generator: {} which generated: {}",
newGenerator, newGenerator.getGeneratedClass());
if ((!hadTypeParameters && generatorClazz.equals(clazz)) || clazz.isAssignableFrom(newGenerator.getGeneratedType())) {
logger.debug("Got new generator: {} which generated: {}", newGenerator, newGenerator.getGeneratedClass());
logger.debug("{} vs {}", (!hadTypeParameters && generatorClazz.equals(clazz)), clazz.isAssignableFrom(newGenerator.getGeneratedType()));
if(Properties.DEBUG && !clazz.hasTypeVariables()) {
logger.warn("{} has no type variables", clazz);
if(!newGenerator.getGeneratedClass().canBeInstantiatedTo(clazz)) {
logger.error("{} cannot be assigned to {}", newGenerator.getGeneratedClass(), clazz);
throw new Error("should not happen");
}
}
targetGenerators.add(newGenerator);

} else if (logger.isDebugEnabled()) {
Expand Down Expand Up @@ -511,7 +515,7 @@ private void cacheGenerators(GenericClass<?> clazz) throws ConstructionFailedExc
* @param target
*/
public void clearGeneratorCache(GenericClass<?> target) {
generatorCache.clear();
generatorCache.remove(target);
}

/**
Expand Down Expand Up @@ -1070,7 +1074,15 @@ public GenericAccessibleObject<?> getRandomGenerator(GenericClass<?> clazz,
}
}

generator = Randomness.choice(candidates);
Set<GenericAccessibleObject<?>> candidatesWithNoTypeParameters = candidates.stream().
filter(p -> !p.hasTypeParameters()).
collect(Collectors.toCollection(LinkedHashSet::new));

if(!candidatesWithNoTypeParameters.isEmpty()) {
generator = Randomness.choice(candidatesWithNoTypeParameters);
}else{
generator = Randomness.choice(candidates);
}
logger.debug("Chosen generator: " + generator);
}

Expand Down
30 changes: 17 additions & 13 deletions client/src/main/java/org/evosuite/testcase/TestCodeVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import dk.brics.automaton.RegExp;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.TypeUtils;
import org.evosuite.PackageInfo;
import org.evosuite.Properties;
Expand Down Expand Up @@ -1152,7 +1151,7 @@ public void visitFunctionalMockStatement(FunctionalMockStatement st) {
// return;
// }

String result = "";
StringBuffer result = new StringBuffer();

//by construction, we should avoid cases like:
// Object obj = mock(Foo.class);
Expand All @@ -1166,13 +1165,11 @@ public void visitFunctionalMockStatement(FunctionalMockStatement st) {

//Foo foo = mock(Foo.class);
String variableType = getClassName(retval);
result += variableType + " " + getVariableName(retval);

result += " = ";
result.append(variableType).append(" ").append(getVariableName(retval)).append(" = ");
if (!variableType.equals(rawClassName)) {
//this can happen in case of generics, eg
//Foo<String> foo = (Foo<String>) mock(Foo.class);
result += "(" + variableType + ") ";
result.append("(").append(variableType).append(") ");
}

/*
Expand All @@ -1196,9 +1193,9 @@ public void visitFunctionalMockStatement(FunctionalMockStatement st) {
}

if (st instanceof FunctionalMockForAbstractClassStatement) {
result += "mock(" + rawClassName + ".class, CALLS_REAL_METHODS);" + NEWLINE;
result.append("mock(").append(rawClassName).append(".class, CALLS_REAL_METHODS);").append(NEWLINE);
} else {
result += "mock(" + rawClassName + ".class, new " + ViolatedAssumptionAnswer.class.getSimpleName() + "());" + NEWLINE;
result.append("mock(").append(rawClassName).append(".class, new ").append(ViolatedAssumptionAnswer.class.getSimpleName()).append("());").append(NEWLINE);
}

//when(...).thenReturn(...)
Expand All @@ -1208,6 +1205,9 @@ public void visitFunctionalMockStatement(FunctionalMockStatement st) {
}

List<VariableReference> params = st.getParameters(md.getID());
if(params == null) {
continue;
}

GenericClass<?> returnType = md.getReturnClass();
// Class<?> returnType = md.getMethod().getReturnType();
Expand Down Expand Up @@ -1243,9 +1243,9 @@ public void visitFunctionalMockStatement(FunctionalMockStatement st) {
// tests we import MockitoExtension class
//parameter_string = "doReturn(" + parameter_string.replaceAll(", ", ").doReturn(") + ")";
//result += parameter_string+".when("+getVariableName(retval)+")";
result += "doReturn(" + parameter_string + ").when(" + getVariableName(retval) + ")";
result += "." + md.getMethodName() + "(" + md.getInputParameterMatchers() + ");";
result += NEWLINE;
result.append("doReturn(").append(parameter_string).append(").when(").append(getVariableName(retval)).append(")");
result.append(".").append(md.getMethodName()).append("(").append(md.getInputParameterMatchers()).append(");").append(NEWLINE);

}

testCode += result;
Expand Down Expand Up @@ -1494,7 +1494,11 @@ public String generateCatchBlock(AbstractStatement statement, Throwable exceptio
result += " catch(" + getClassName(Throwable.class) + " e) {" + NEWLINE;
}
} else {
result += " catch(" + getClassName(ex) + " e) {" + NEWLINE;
String className = getClassName(ex);
if(className.contains("MockitoMock")) {
className = getClassName(Throwable.class);
}
result += " catch(" + className + " e) {" + NEWLINE;
}

// adding the message of the exception
Expand Down Expand Up @@ -1539,7 +1543,7 @@ public String generateCatchBlock(AbstractStatement statement, Throwable exceptio
}

private String getSourceClassName(Throwable exception) {
if (exception.getStackTrace().length == 0) {
if(exception.getStackTrace() == null || exception.getStackTrace().length == 0) {
return null;
}
return exception.getStackTrace()[0].getClassName();
Expand Down
20 changes: 14 additions & 6 deletions client/src/main/java/org/evosuite/testcase/TestFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -1356,6 +1356,16 @@ it is not a functional mock (which can be used only once)
return ret;
}

private VariableReference createOrReuseVariable(TestCase test, Type parameterType,
int position, int recursionDepth, VariableReference exclude, boolean allowNull,
boolean excludeCalleeGenerators, boolean canUseMocks)
throws ConstructionFailedException {
VariableReference ref = _createOrReuseVariable(test, parameterType, position, recursionDepth, exclude, allowNull, excludeCalleeGenerators, canUseMocks);
if(!ref.isAssignableTo(parameterType)) {
throw new ConstructionFailedException(ref + " cannot be assigned to " + parameterType);
}
return ref;
}

/**
* In the given {@code test} case, tries to create a new variable of type {@code parameterType}
Expand All @@ -1369,7 +1379,7 @@ it is not a functional mock (which can be used only once)
* @return
* @throws ConstructionFailedException
*/
private VariableReference createOrReuseVariable(TestCase test, Type parameterType,
private VariableReference _createOrReuseVariable(TestCase test, Type parameterType,
int position, int recursionDepth, VariableReference exclude, boolean allowNull,
boolean excludeCalleeGenerators, boolean canUseMocks)
throws ConstructionFailedException {
Expand Down Expand Up @@ -2418,15 +2428,13 @@ public List<VariableReference> satisfyParameters(TestCase test, VariableReferenc
throw new ConstructionFailedException(
"Failed to create variable for type " + parameterType + " at position " + position);
}
if(!var.isAssignableTo(parameterType)) {
throw new ConstructionFailedException(var + " cannot be assigned to " + parameterType);
}
}

assert !(!allowNullForParameter && ConstraintHelper.isNull(var, test));

// Generics instantiation may lead to invalid types, so better
// double check
if (!var.isAssignableTo(parameterType)) {
throw new ConstructionFailedException("Error: " + var + " is not assignable to " + parameterType);
}
parameters.add(var);

int currentLength = test.size();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@
*/
package org.evosuite.testcase.statements;

import org.apache.commons.lang3.reflect.TypeUtils;
import org.evosuite.Properties;
import org.evosuite.runtime.util.Inputs;
import org.evosuite.testcase.TestCase;
import org.evosuite.testcase.variable.ArrayIndex;
import org.evosuite.testcase.variable.NullReference;
import org.evosuite.testcase.variable.VariableReference;
import org.evosuite.utils.LoggingUtils;
import org.evosuite.utils.Randomness;
import org.evosuite.utils.generic.GenericUtils;

Expand Down Expand Up @@ -186,6 +188,10 @@ public void replaceParameterReference(VariableReference var, int numParameter) t
throw new IllegalArgumentException("Out of range index " + numParameter + " from list of size " + parameters.size());
}

if(!TypeUtils.isAssignable(var.getType(), parameters.get(numParameter).getType())) {
throw new IllegalArgumentException(var.getType() + " cannot be assigned to " + parameters.get(numParameter).getType());
}

parameters.set(numParameter, var);
}

Expand Down Expand Up @@ -245,7 +251,6 @@ protected boolean mutateParameter(TestCase test, int numParameter) {
}
}


// If there are fewer objects than parameters of that type,
// we consider adding an instance
if (getNumParametersOfType(parameter.getVariableClass()) + 1 > objects.size()) {
Expand All @@ -266,7 +271,14 @@ protected boolean mutateParameter(TestCase test, int numParameter) {
} else if (copy != null && replacement == copy.getReturnValue()) {
test.addStatement(copy, getPosition());
}
replaceParameterReference(replacement, numParameter);

try {
replaceParameterReference(replacement, numParameter);
}catch(IllegalArgumentException e) {
LoggingUtils.getEvoLogger().warn(e.getMessage());
return false;
}

return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.evosuite.testcase.fm.MethodDescriptor;
import org.evosuite.testcase.variable.ConstantValue;
import org.evosuite.testcase.variable.VariableReference;
import org.evosuite.utils.LoggingUtils;
import org.evosuite.utils.generic.GenericAccessibleObject;
import org.evosuite.utils.generic.GenericClass;
import org.evosuite.utils.generic.GenericClassFactory;
Expand Down Expand Up @@ -529,8 +530,11 @@ private Class<?> getExpectedParameterType(int i) {
return md.getMethod().getReturnType();
}
}

throw new AssertionError("");
LoggingUtils.getEvoLogger().error("Error for finding expected parameter type: " + i + ", " + mockedMethods);
// TODO: This should not happen and if it is, some bugs are triggered. '
// Since 'return Object.class' can improve code coverage instead of giving it up, I do not forcefully trigger Error.
// This should be fixed (find the root causes of bugs and ..)
return Object.class;
}

//------------ override methods ---------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,19 +225,19 @@ public void execute() throws InvocationTargetException,
InstantiationException, CodeUnderTestException {
Object callee_object;
try {
java.lang.reflect.Type[] parameterTypes = method.getParameterTypes();
java.lang.reflect.Type[] exactParameterTypes = method.getParameterTypes();
for (int i = 0; i < parameters.size(); i++) {
VariableReference parameterVar = parameters.get(i);
inputs[i] = parameterVar.getObject(scope);
if (inputs[i] == null && method.getMethod().getParameterTypes()[i].isPrimitive()) {
throw new CodeUnderTestException(new NullPointerException());
}
if (inputs[i] != null && !TypeUtils.isAssignable(inputs[i].getClass(), parameterTypes[i])) {
if (inputs[i] != null && !TypeUtils.isAssignable(inputs[i].getClass(), exactParameterTypes[i])) {
// TODO: This used to be a check of the declared type, but the problem is that
// Generic types are not updated during execution, so this may fail:
//!parameterVar.isAssignableTo(parameterTypes[i])) {
//!parameterVar.isAssignableTo(exactParameterTypes[i])) {
throw new CodeUnderTestException(
new UncompilableCodeException("Cannot assign " + parameterVar.getVariableClass().getName() + " to " + parameterTypes[i]));
new UncompilableCodeException("Cannot assign " + parameterVar.getVariableClass().getName() + " to " + exactParameterTypes[i]));
}
}

Expand Down Expand Up @@ -271,6 +271,11 @@ public void execute() throws InvocationTargetException,
}
}

// This should be checked as the test code emulation of Evosuite is incomplete
if(ret != null && !TypeUtils.isAssignable(ret.getClass(), retval.getType())) {
throw new CodeUnderTestException(
new UncompilableCodeException("variable and return value type does not match"));
}

try {
retval.setObject(scope, ret);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,10 @@ public T getGenericInstantiationFromReturnValue(GenericClass<?> generatedType)
+ concreteType.getTypeName());
GenericClass<?> instantiation = concreteType.getGenericInstantiation(concreteTypes);
logger.debug("Got instantiation for " + parameter + ": " + instantiation);
if (!instantiation.satisfiesBoundaries(parameter, concreteTypes)) {

Map<TypeVariable<?>, Type> ownerVariableMap = new HashMap<>();
ownerVariableMap.putAll(this.getOwnerClass().getTypeVariableMap());
if (!instantiation.satisfiesBoundaries(parameter, ownerVariableMap)) {
logger.info("Type parameter does not satisfy boundaries: " + parameter
+ " " + instantiation);
logger.info(Arrays.asList(parameter.getBounds()).toString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ public interface GenericClass<T extends GenericClass<T>> extends Serializable {
* @param otherType is the class we want to generate
* @return whether this generic class can be instantiated to the given type.
*/
boolean canBeInstantiatedTo(GenericClass<?> otherType, int recursionLevel);

boolean canBeInstantiatedTo(GenericClass<?> otherType);

/**
Expand Down
Loading