Java tutorial
/** * Copyright (C) 2011,2012 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 Public License as published by the Free Software Foundation, * either version 3 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 Public License for more details. * * You should have received a copy of the GNU Public License along with * EvoSuite. If not, see <http://www.gnu.org/licenses/>. */ package org.evosuite.testcase; import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang3.ClassUtils; import org.evosuite.Properties; import org.evosuite.setup.TestClusterGenerator; import org.evosuite.utils.GenericAccessibleObject; import org.evosuite.utils.GenericClass; import org.evosuite.utils.GenericField; import org.evosuite.utils.Randomness; import org.objectweb.asm.Type; import org.objectweb.asm.commons.GeneratorAdapter; /** * An assignment statement assigns a variable to another variable. This is only * used to assign to array indices * * @author Gordon Fraser */ public class AssignmentStatement extends AbstractStatement { private static final long serialVersionUID = 2051431241124468349L; protected VariableReference parameter; /** * <p> * Constructor for AssignmentStatement. * </p> * * @param tc * a {@link org.evosuite.testcase.TestCase} object. * @param var * a {@link org.evosuite.testcase.VariableReference} object. * @param value * a {@link org.evosuite.testcase.VariableReference} object. */ public AssignmentStatement(TestCase tc, VariableReference var, VariableReference value) { super(tc, var); this.parameter = value; // TODO: // Assignment of an "unassignable" type may happen if we have no generator for // the target class, as we then attempt generating a superclass and try to case // down to the actual class // } /** * <p> * getValue * </p> * * @return a {@link org.evosuite.testcase.VariableReference} object. */ public VariableReference getValue() { return this.parameter; } /** {@inheritDoc} */ @Override public StatementInterface copy(TestCase newTestCase, int offset) { try { VariableReference newParam = parameter.copy(newTestCase, offset); VariableReference newTarget; // FIXXME: Return value should always be an existing variable //if (retval.getAdditionalVariableReference() != null) newTarget = retval.copy(newTestCase, offset); //else // newTarget = retval.copy(newTestCase, offset); //newTarget = new VariableReferenceImpl(newTestCase, retval.getType()); AssignmentStatement copy = new AssignmentStatement(newTestCase, newTarget, newParam); // copy.assertions = copyAssertions(newTestCase, offset); //logger.info("Copy of statement is: " + copy.getCode()); return copy; } catch (Exception e) { logger.info("Error cloning statement {}", getCode()); logger.info("In test: {}", this.tc.toCode()); logger.info("New test: {}", newTestCase.toCode()); e.printStackTrace(); assert (false) : e.toString(); } return null; } /** {@inheritDoc} */ @Override public Throwable execute(final Scope scope, PrintStream out) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException { return super.exceptionHandler(new Executer() { @Override public void execute() throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException, CodeUnderTestException { try { final Object value = parameter.getObject(scope); retval.setObject(scope, value); //} catch (CodeUnderTestException e) { // throw CodeUnderTestException.throwException(e.getCause()); } catch (IllegalArgumentException e) { logger.error( "Error assigning value of type {} defined at statement {}, assignment statement: {}; SUT={}", parameter.getSimpleClassName(), tc.getStatement(parameter.getStPosition()).getCode(), tc.getStatement(retval.getStPosition()).getCode(), Properties.TARGET_CLASS); // FIXXME: IllegalArgumentException may happen when we only have generators // for an abstract supertype and not the concrete type that we need! throw e; } catch (CodeUnderTestException e) { throw e; } catch (Throwable e) { throw new EvosuiteError(e); } } @Override public Set<Class<? extends Throwable>> throwableExceptions() { Set<Class<? extends Throwable>> t = new HashSet<Class<? extends Throwable>>(); t.add(AssertionError.class); return t; } }); } /** {@inheritDoc} */ @Override public Set<VariableReference> getVariableReferences() { Set<VariableReference> vars = new LinkedHashSet<VariableReference>(); vars.add(retval); vars.add(parameter); if (retval.getAdditionalVariableReference() != null) vars.add(retval.getAdditionalVariableReference()); if (parameter.getAdditionalVariableReference() != null) vars.add(parameter.getAdditionalVariableReference()); vars.addAll(getAssertionReferences()); return vars; } /* (non-Javadoc) * @see org.evosuite.testcase.StatementInterface#replace(org.evosuite.testcase.VariableReference, org.evosuite.testcase.VariableReference) */ /** {@inheritDoc} */ @Override public void replace(VariableReference var1, VariableReference var2) { if (parameter.equals(var1)) parameter = var2; //else if (retval.equals(var1)) // retval = var2; else parameter.replaceAdditionalVariableReference(var1, var2); //else if (var1.equals(retval.getAdditionalVariableReference())) // retval.setAdditionalVariableReference(var2); } /** {@inheritDoc} */ @Override public int hashCode() { final int prime = 31; int result = prime + retval.hashCode() + +((parameter == null) ? 0 : parameter.hashCode()); return result; } /** {@inheritDoc} */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; AssignmentStatement other = (AssignmentStatement) obj; if (parameter == null) { if (other.parameter != null) return false; } else if (!parameter.equals(other.parameter)) return false; if (retval == null) { if (other.retval != null) return false; } else if (!retval.equals(other.retval)) return false; return true; } /* * (non-Javadoc) * * @see * org.evosuite.testcase.Statement#getBytecode(org.objectweb. * asm.commons.GeneratorAdapter) */ /** {@inheritDoc} */ @Override public void getBytecode(GeneratorAdapter mg, Map<Integer, Integer> locals, Throwable exception) { parameter.loadBytecode(mg, locals); Class<?> clazz = parameter.getVariableClass(); if (parameter.isPrimitive() && !retval.isPrimitive()) { mg.box(Type.getType(parameter.getVariableClass())); clazz = parameter.getGenericClass().getBoxedType(); } if (!clazz.equals(retval.getVariableClass())) { mg.cast(org.objectweb.asm.Type.getType(clazz), org.objectweb.asm.Type.getType(retval.getVariableClass())); } retval.storeBytecode(mg, locals); } /* * (non-Javadoc) * * @see * org.evosuite.testcase.Statement#getUniqueVariableReferences() */ /** {@inheritDoc} */ @Override public List<VariableReference> getUniqueVariableReferences() { return new ArrayList<VariableReference>(getVariableReferences()); } /* (non-Javadoc) * @see org.evosuite.testcase.StatementInterface#isValid() */ /** {@inheritDoc} */ @Override public boolean isValid() { assert (super.isValid()); parameter.getStPosition(); //if (!retval.getVariableClass().isAssignableFrom(parameter.getVariableClass())) { // logger.error("Type mismatch: " + retval.getVariableClass() + " and " // + parameter.getVariableClass()); // logger.error(tc.toCode()); //} //assert (retval.getVariableClass().isAssignableFrom(parameter.getVariableClass())); return true; } /** {@inheritDoc} */ @Override public boolean same(StatementInterface s) { if (this == s) return true; if (s == null) return false; if (getClass() != s.getClass()) return false; AssignmentStatement other = (AssignmentStatement) s; if (parameter == null) { if (other.parameter != null) return false; } else if (!parameter.same(other.parameter)) return false; if (retval == null) { if (other.retval != null) return false; } else if (!retval.same(other.retval)) return false; return true; } /** * Retrieve the set of FieldReference and ArrayIndex variables that can * serve as a replacement for retval * * @return */ private Set<VariableReference> getSourceReplacements() { Set<VariableReference> variables = new LinkedHashSet<VariableReference>(); for (int i = 0; i < retval.getStPosition() && i < tc.size(); i++) { VariableReference value = tc.getReturnValue(i); if (value == null) continue; if (value instanceof ArrayReference) { if (GenericClass.isAssignable(value.getComponentType(), parameter.getType())) { for (int index = 0; index < ((ArrayReference) value).getArrayLength(); index++) { variables.add(new ArrayIndex(tc, (ArrayReference) value, index)); } } } else if (value instanceof ArrayIndex) { // Don't need to add this because array indices are created for array statement? if (value.isAssignableFrom(parameter.getType())) { variables.add(value); } } else { if (!value.isPrimitive() && !(value instanceof NullReference)) { // add fields of this object to list for (Field field : TestClusterGenerator.getAccessibleFields(value.getVariableClass())) { FieldReference f = new FieldReference(tc, new GenericField(field, value.getGenericClass()), value); if (f.getDepth() <= 2) { if (f.isAssignableFrom(parameter.getType())) { variables.add(f); } } } } } } return variables; } /* (non-Javadoc) * @see org.evosuite.testcase.StatementInterface#mutate(org.evosuite.testcase.TestCase) */ /** {@inheritDoc} */ @Override public boolean mutate(TestCase test, TestFactory factory) { assert (isValid()); // Either mutate parameter, or source if (Randomness.nextDouble() < 0.5) { Set<VariableReference> objects = getSourceReplacements(); objects.remove(retval); objects.remove(parameter); if (!objects.isEmpty()) { VariableReference newRetVal = Randomness.choice(objects); // Need to double check, because we might try to replace e.g. // a long with an int, which is assignable // but if the long is assigned to a Long field, then it is not! if (parameter.isAssignableTo(newRetVal)) { // Need to check array status because commons lang // is sometimes confused about what is assignable if (parameter.isArray() == newRetVal.isArray()) { retval = newRetVal; assert (isValid()); return true; } } } } else { List<VariableReference> objects = test.getObjects(parameter.getType(), retval.getStPosition()); objects.remove(retval); objects.remove(parameter); if (!objects.isEmpty()) { VariableReference choice = Randomness.choice(objects); if (choice.isAssignableTo(retval)) { // Need special care if it is a wrapper class if (retval.getGenericClass().isWrapperType()) { Class<?> rawClass = ClassUtils.wrapperToPrimitive(retval.getVariableClass()); if (!retval.getVariableClass().equals(rawClass) && !retval.getVariableClass().equals(choice.getVariableClass())) { return false; } } parameter = choice; assert (isValid()); return true; } } } return false; } /** {@inheritDoc} */ @Override public GenericAccessibleObject<?> getAccessibleObject() { return null; } /** {@inheritDoc} */ @Override public boolean isAssignmentStatement() { return true; } }