org.evosuite.testcase.statements.ConstructorStatement Maven / Gradle / Ivy
The newest version!
/**
* Copyright (C) 2010-2018 Gordon Fraser, Andrea Arcuri and EvoSuite
* contributors
*
* This file is part of EvoSuite.
*
* EvoSuite is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3.0 of the License, or
* (at your option) any later version.
*
* EvoSuite is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with EvoSuite. If not, see .
*/
package org.evosuite.testcase.statements;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.reflect.TypeUtils;
import org.evosuite.Properties;
import org.evosuite.runtime.annotation.Constraints;
import org.evosuite.testcase.TestCase;
import org.evosuite.testcase.TestFactory;
import org.evosuite.testcase.variable.VariableReference;
import org.evosuite.testcase.variable.VariableReferenceImpl;
import org.evosuite.testcase.execution.CodeUnderTestException;
import org.evosuite.testcase.execution.EvosuiteError;
import org.evosuite.testcase.execution.Scope;
import org.evosuite.testcase.execution.UncompilableCodeException;
import org.evosuite.utils.generic.GenericConstructor;
import org.evosuite.utils.Randomness;
import org.objectweb.asm.Type;
import org.evosuite.dse.VM;
/**
* This statement represents a constructor call
*
* @author Gordon Fraser
*/
public class ConstructorStatement extends EntityWithParametersStatement {
private static final long serialVersionUID = -3035570485633271957L;
private GenericConstructor constructor;
private static final List primitiveClasses = Arrays.asList("char", "int", "short",
"long", "boolean",
"float", "double",
"byte");
/**
*
* Constructor for ConstructorStatement.
*
*
* @param tc
* a {@link org.evosuite.testcase.TestCase} object.
* @param constructor
* a {@link java.lang.reflect.Constructor} object.
* @param parameters
* a {@link java.util.List} object.
*/
public ConstructorStatement(TestCase tc, GenericConstructor constructor,
List parameters) {
super(tc, new VariableReferenceImpl(tc, constructor.getOwnerClass()),parameters,
constructor.getConstructor().getAnnotations(), constructor.getConstructor().getParameterAnnotations());
this.constructor = constructor;
}
/**
* This constructor allows you to use an already existing VariableReference
* as retvar. This should only be done, iff an old statement is replaced
* with this statement. And already existing objects should in the future
* reference this object.
*
* @param tc
* a {@link org.evosuite.testcase.TestCase} object.
* @param constructor
* a {@link java.lang.reflect.Constructor} object.
* @param retvar
* a {@link org.evosuite.testcase.variable.VariableReference} object.
* @param parameters
* a {@link java.util.List} object.
*/
public ConstructorStatement(TestCase tc, GenericConstructor constructor,
VariableReference retvar, List parameters) {
super(tc, retvar, parameters,
constructor.getConstructor().getAnnotations(), constructor.getConstructor().getParameterAnnotations());
assert (tc.size() > retvar.getStPosition()); //as an old statement should be replaced by this statement
this.constructor = constructor;
}
/**
*
* Constructor for ConstructorStatement.
*
*
* @param tc
* a {@link org.evosuite.testcase.TestCase} object.
* @param constructor
* a {@link java.lang.reflect.Constructor} object.
* @param retvar
* a {@link org.evosuite.testcase.variable.VariableReference} object.
* @param parameters
* a {@link java.util.List} object.
* @param check
* a boolean.
*/
protected ConstructorStatement(TestCase tc, GenericConstructor constructor,
VariableReference retvar, List parameters, boolean check) {
super(tc, retvar, parameters,
constructor.getConstructor().getAnnotations(), constructor.getConstructor().getParameterAnnotations());
assert check == false;
this.constructor = constructor;
}
/**
*
* Getter for the field constructor
.
*
*
* @return a {@link java.lang.reflect.Constructor} object.
*/
public GenericConstructor getConstructor() {
return constructor;
}
/**
*
* Setter for the field constructor
.
*
*
* @param constructor
* a {@link java.lang.reflect.Constructor} object.
*/
public void setConstructor(GenericConstructor constructor) {
this.constructor = constructor;
retval.setType(constructor.getReturnType());
}
/**
*
* getReturnType
*
*
* @param clazz
* a {@link java.lang.Class} object.
* @return a {@link java.lang.String} object.
*/
public static String getReturnType(Class> clazz) {
String retVal = ClassUtils.getShortClassName(clazz);
if (primitiveClasses.contains(retVal))
return clazz.getSimpleName();
return retVal;
}
// TODO: Handle inner classes (need instance parameter for newInstance)
/** {@inheritDoc} */
@Override
public Throwable execute(final Scope scope, PrintStream out)
throws InvocationTargetException, IllegalArgumentException,
InstantiationException, IllegalAccessException {
//PrintStream old_out = System.out;
//PrintStream old_err = System.err;
//System.setOut(out);
//System.setErr(out);
logger.trace("Executing constructor " + constructor.toString());
final Object[] inputs = new Object[parameters.size()];
Throwable exceptionThrown = null;
try {
return super.exceptionHandler(new Executer() {
@Override
public void execute() throws InvocationTargetException,
IllegalArgumentException, IllegalAccessException,
InstantiationException, CodeUnderTestException {
java.lang.reflect.Type[] parameterTypes = constructor.getParameterTypes();
for (int i = 0; i < parameters.size(); i++) {
VariableReference parameterVar = parameters.get(i);
try {
inputs[i] = parameterVar.getObject(scope);
} catch (CodeUnderTestException e) {
throw e;
//throw new CodeUnderTestException(e.getCause());
// throw CodeUnderTestException.throwException(e.getCause());
} catch (Throwable e) {
//FIXME: this does not seem to propagate to client root. Is this normal behavior?
logger.error("Class " + Properties.TARGET_CLASS
+ ". Error encountered: " + e);
assert (false);
throw new EvosuiteError(e);
}
if (inputs[i] != null && !TypeUtils.isAssignable(inputs[i].getClass(), parameterTypes[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])) {
throw new CodeUnderTestException(
new UncompilableCodeException("Cannot assign "+parameterVar.getVariableClass().getName() +" to "+parameterTypes[i]));
}
if(inputs[i] == null && constructor.getConstructor().getParameterTypes()[i].isPrimitive()) {
throw new CodeUnderTestException(new NullPointerException());
}
}
// If this is a non-static member class, the first parameter must not be null
if (constructor.getConstructor().getDeclaringClass().isMemberClass()
&& !Modifier.isStatic(constructor.getConstructor().getDeclaringClass().getModifiers())) {
if (inputs[0] == null) {
// throw new NullPointerException();
throw new CodeUnderTestException(new NullPointerException());
}
}
Object ret = constructor.getConstructor().newInstance(inputs);
try {
// assert(retval.getVariableClass().isAssignableFrom(ret.getClass())) :"we want an " + retval.getVariableClass() + " but got an " + ret.getClass();
retval.setObject(scope, ret);
} catch (CodeUnderTestException e) {
throw e;
// throw CodeUnderTestException.throwException(e);
} catch (Throwable e) {
throw new EvosuiteError(e);
}
}
@Override
public Set> throwableExceptions() {
Set> t = new LinkedHashSet>();
t.add(InvocationTargetException.class);
return t;
}
});
} catch (InvocationTargetException e) {
VM.disableCallBacks();
exceptionThrown = e.getCause();
if (logger.isDebugEnabled()) {
try {
logger.debug("Exception thrown in constructor: " + e.getCause());
}
//this can happen if SUT throws exception on toString
catch (Exception ex) {
logger.debug("Exception thrown in constructor and SUT gives issue when calling e.getCause()",
ex);
}
}
}
return exceptionThrown;
}
/** {@inheritDoc} */
@Override
public Statement copy(TestCase newTestCase, int offset) {
ArrayList new_params = new ArrayList();
for (VariableReference r : parameters) {
new_params.add(r.copy(newTestCase, offset));
}
AbstractStatement copy = new ConstructorStatement(newTestCase,
constructor.copy(), new_params);
// copy.assertions = copyAssertions(newTestCase, offset);
return copy;
}
/**
*
* getParameterReferences
*
*
* @return a {@link java.util.List} object.
*/
public List getParameterReferences() {
return parameters;
}
/* (non-Javadoc)
* @see org.evosuite.testcase.StatementInterface#getNumParameters()
*/
@Override
public int getNumParameters() {
return parameters.size();
}
/** {@inheritDoc} */
@Override
public boolean equals(Object s) {
if (this == s)
return true;
if (s == null)
return false;
if (getClass() != s.getClass())
return false;
ConstructorStatement ms = (ConstructorStatement) s;
if (ms.parameters.size() != parameters.size())
return false;
if (!this.constructor.equals(ms.constructor))
return false;
for (int i = 0; i < parameters.size(); i++) {
if (!parameters.get(i).equals(ms.parameters.get(i)))
return false;
}
return retval.equals(ms.retval);
}
/** {@inheritDoc} */
@Override
public int hashCode() {
final int prime = 41;
int result = 1;
result = prime * result + ((constructor == null) ? 0 : constructor.hashCode());
result = prime * result + ((parameters == null) ? 0 : parameters.hashCode());
return result;
}
/*
* (non-Javadoc)
*
* @see org.evosuite.testcase.Statement#getDeclaredExceptions()
*/
/** {@inheritDoc} */
@Override
public Set> getDeclaredExceptions() {
Set> ex = super.getDeclaredExceptions();
ex.addAll(Arrays.asList(constructor.getConstructor().getExceptionTypes()));
return ex;
}
/**
* Go through parameters of constructor call and apply local search
*
* @param test
* @param factory
*/
/* (non-Javadoc)
* @see org.evosuite.testcase.AbstractStatement#mutate(org.evosuite.testcase.TestCase, org.evosuite.testcase.TestFactory)
*/
@Override
public boolean mutate(TestCase test, TestFactory factory) {
if (Randomness.nextDouble() >= Properties.P_CHANGE_PARAMETER)
return false;
Constraints constraint = constructor.getConstructor().getAnnotation(Constraints.class);
if(constraint!=null && constraint.notMutable()){
return false;
}
List parameters = getParameterReferences();
if (parameters.isEmpty())
return false;
double pParam = 1.0/parameters.size();
boolean changed = false;
for(int numParameter = 0; numParameter < parameters.size(); numParameter++) {
if(Randomness.nextDouble() < pParam) {
if(mutateParameter(test, numParameter))
changed = true;
}
}
return changed;
}
@Override
public boolean isAccessible() {
if(!constructor.isAccessible())
return false;
return super.isAccessible();
}
/* (non-Javadoc)
* @see org.evosuite.testcase.StatementInterface#isValid()
*/
/** {@inheritDoc} */
@Override
public boolean isValid() {
assert (super.isValid());
for (VariableReference v : parameters) {
v.getStPosition();
}
return true;
}
/** {@inheritDoc} */
@Override
public boolean same(Statement s) {
if (this == s)
return true;
if (s == null)
return false;
if (getClass() != s.getClass())
return false;
ConstructorStatement ms = (ConstructorStatement) s;
if (ms.parameters.size() != parameters.size())
return false;
if (!this.constructor.equals(ms.constructor))
return false;
for (int i = 0; i < parameters.size(); i++) {
if (!parameters.get(i).same(ms.parameters.get(i)))
return false;
}
return retval.same(ms.retval);
}
/** {@inheritDoc} */
@Override
public GenericConstructor getAccessibleObject() {
return constructor;
}
/** {@inheritDoc} */
@Override
public boolean isAssignmentStatement() {
return false;
}
/* (non-Javadoc)
* @see org.evosuite.testcase.StatementInterface#changeClassLoader(java.lang.ClassLoader)
*/
/** {@inheritDoc} */
@Override
public void changeClassLoader(ClassLoader loader) {
constructor.changeClassLoader(loader);
super.changeClassLoader(loader);
}
@Override
public String toString() {
return constructor.getName() + Type.getConstructorDescriptor(constructor.getConstructor());
}
@Override
public String getDescriptor() {
return constructor.getDescriptor();
}
@Override
public String getDeclaringClassName() {
return constructor.getDeclaringClass().getCanonicalName();
}
@Override
public String getMethodName() {
return "";
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy