gt: 		copy.trace = trace.lazyClone();
context: /**
   * Copyright (C) 2010-2016 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 <http://www.gnu.org/licenses/>.
   */
  package org.evosuite.testcase.execution;
  
  import org.evosuite.assertion.OutputTrace;
  import org.evosuite.coverage.io.input.InputCoverageGoal;
  import org.evosuite.coverage.io.output.OutputCoverageGoal;
  import org.evosuite.coverage.mutation.Mutation;
  import org.evosuite.testcase.TestCase;
  import org.evosuite.testcase.statements.Statement;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  import java.util.*;
  
  public class ExecutionResult implements Cloneable {
  
  	private static final Logger logger = LoggerFactory.getLogger(ExecutionResult.class);
  	
  	/** Test case that produced this execution result */
  	public TestCase test;
  
  	/** Mutation that was active during execution */
  	public Mutation mutation;
  
  	/** Map statement number to raised exception */
  	protected Map<Integer, Throwable> exceptions = new HashMap<Integer, Throwable>();
  
  	/** Record for each exception if it was explicitly thrown 
  	 * 
  	 * <p>
  	 * FIXME: internal data structures should never be null...
  	 * */
  	public Map<Integer, Boolean> explicitExceptions = new HashMap<Integer, Boolean>();
  
  	/** Trace recorded during execution */
  	protected ExecutionTrace trace;
  
  	/** Duration of execution */
  	protected long executionTime = 0L;
  
  	/** Number of statements executed */
  	protected int executedStatements = 0;
  
  	/** Was there a permission denied during execution? */
  	protected boolean hasSecurityException = false;
  
  	/** Set of System properties that were read during test execution */
  	protected Set<String> readProperties;
  	
  	/**
  	 * Keep track of whether any System property was written
  	 */
  	protected boolean wasAnyPropertyWritten;
  	
  	/*
  	 * Regression Object Distance
  	 */
  	public double regressionObjectDistance = 0;
  	
  	/**
  	 * @return the executedStatements
  	 */
  	public int getExecutedStatements() {
  		return executedStatements;
  	}
  
  	/**
  	 * @param executedStatements
  	 *            the executedStatements to set
  	 */
  	public void setExecutedStatements(int executedStatements) {
  		this.executedStatements = executedStatements;
  	}
  
  	/** Output traces produced by observers */
  	protected final Map<Class<?>, OutputTrace<?>> traces = new HashMap<Class<?>, OutputTrace<?>>();
  
      private Map<Integer, Set<InputCoverageGoal>> inputGoals = new LinkedHashMap<>();
  
      private Map<Integer, Set<OutputCoverageGoal>> outputGoals = new LinkedHashMap<>();
  
  	// experiment .. tried to remember intermediately calculated ControlFlowDistances .. no real speed up
  	//	public Map<Branch, ControlFlowDistance> intermediateDistances;
  
  	/**
  	 * Default constructor when executing without mutation
  	 * 
  	 * @param t
  	 *            a {@link org.evosuite.testcase.TestCase} object.
  	 */
  	public ExecutionResult(TestCase t) {
  		trace = null;
  		mutation = null;
  		test = t;
  	}
  
  	/**
  	 * <p>
  	 * Copy the input map data into internal structures
  	 * </p>
  	 * 
  	 * @param data
  	 *            a {@link java.util.Map} object. It has a mapping from test
  	 *            sequence position toward thrown exception
  	 */
  	public void setThrownExceptions(Map<Integer, Throwable> data) {
  		exceptions.clear();
  		for (Integer position : data.keySet()) {
  			reportNewThrownException(position, data.get(position));
  		}
  	}
  
  	
  	/**
  	 * <p>
  	 * getFirstPositionOfThrownException
  	 * </p>
  	 * 
  	 * @return a {@link java.lang.Integer} object.
  	 */
  	public Integer getFirstPositionOfThrownException() {
  		Integer min = null;
  		for (Integer position : exceptions.keySet()) {
  			if (min == null || position < min) {
  				min = position;
  			}
  		}
  		return min;
  	}
  
  	/**
  	 * <p>
  	 * reportNewThrownException
  	 * </p>
  	 * 
  	 * @param position
  	 *            a {@link java.lang.Integer} object.
  	 * @param t
  	 *            a {@link java.lang.Throwable} object.
  	 */
  	public void reportNewThrownException(Integer position, Throwable t) {
  		exceptions.put(position, t);
  	}
  
  	/**
  	 * <p>
  	 * getPositionsWhereExceptionsWereThrown
  	 * </p>
  	 * 
  	 * @return a {@link java.util.Set} object.
  	 */
  	public Set<Integer> getPositionsWhereExceptionsWereThrown() {
  		return exceptions.keySet();
  	}
  
  	/**
  	 * <p>
  	 * getAllThrownExceptions
  	 * </p>
  	 * 
  	 * @return a {@link java.util.Collection} object.
  	 */
  	public Collection<Throwable> getAllThrownExceptions() {
  		return exceptions.values();
  	}
  
  	/**
  	 * <p>
  	 * isThereAnExceptionAtPosition
  	 * </p>
  	 * 
  	 * @param position
  	 *            a {@link java.lang.Integer} object.
  	 * @return a boolean.
  	 */
  	public boolean isThereAnExceptionAtPosition(Integer position) {
  		return exceptions.containsKey(position);
  	}
  
  	/**
  	 * <p>
  	 * noThrownExceptions
  	 * </p>
  	 * 
  	 * @return a boolean.
  	 */
  	public boolean noThrownExceptions() {
  		return exceptions.isEmpty();
  	}
  
  	/**
  	 * <p>
  	 * getExceptionThrownAtPosition
  	 * </p>
  	 * 
  	 * @param position
  	 *            a {@link java.lang.Integer} object.
  	 * @return a {@link java.lang.Throwable} object.
  	 */
  	public Throwable getExceptionThrownAtPosition(Integer position) {
  		return exceptions.get(position);
  	}
  
  	/**
  	 * <p>
  	 * getNumberOfThrownExceptions
  	 * </p>
  	 * 
  	 * @return a int.
  	 */
  	public int getNumberOfThrownExceptions() {
  		return exceptions.size();
  	}
  
  	/**
  	 * shouldn't be used
  	 * 
  	 * @return a {@link java.util.Map} object.
  	 */
  	@Deprecated
  	public Map<Integer, Throwable> exposeExceptionMapping() {
  		return exceptions;
  	}
  
  	/**
  	 * 
  	 * @return Mapping of statement indexes and thrown exceptions.
  	 */
  	public Map<Integer, Throwable> getCopyOfExceptionMapping() {
  		Map<Integer, Throwable> copy = new HashMap<Integer, Throwable>();
  		copy.putAll(exceptions);
  		return copy;
  	}
  
  	/**
  	 * Constructor when executing with mutation
  	 * 
  	 * @param t
  	 *            a {@link org.evosuite.testcase.TestCase} object.
  	 * @param m
  	 *            a {@link org.evosuite.coverage.mutation.Mutation} object.
  	 */
  	public ExecutionResult(TestCase t, Mutation m) {
  		trace = null;
  		mutation = m;
  		test = t;
  	}
  
  	/**
  	 * Accessor to the execution trace
  	 * 
  	 * @return a {@link org.evosuite.testcase.execution.ExecutionTrace} object.
  	 */
  	public ExecutionTrace getTrace() {
  		return trace;
  	}
  
  	/**
  	 * Set execution trace to different value
  	 * 
  	 * @param trace
  	 *            a {@link org.evosuite.testcase.execution.ExecutionTrace} object.
  	 */
  	public void setTrace(ExecutionTrace trace) throws IllegalArgumentException{
  		if(trace==null){
  			throw new IllegalArgumentException("Trace cannot be null");
  		}
  		this.trace = trace;
  	}
  
  	/**
  	 * Store a new output trace
  	 * 
  	 * @param trace
  	 *            a {@link org.evosuite.assertion.OutputTrace} object.
  	 * @param clazz
  	 *            a {@link java.lang.Class} object.
  	 */
  	public void setTrace(OutputTrace<?> trace, Class<?> clazz) {
  		traces.put(clazz, trace);
  	}
  
  	/**
  	 * Accessor for output trace produced by an observer of a particular class
  	 * 
  	 * @param clazz
  	 *            a {@link java.lang.Class} object.
  	 * @return a {@link org.evosuite.assertion.OutputTrace} object.
  	 */
  	public OutputTrace<?> getTrace(Class<?> clazz) {
  		return traces.get(clazz);
  	}
  
  	/**
  	 * Accessor for the output traces produced by observers
  	 * 
  	 * @return a {@link java.util.Collection} object.
  	 */
  	public Collection<OutputTrace<?>> getTraces() {
  		return traces.values();
  	}
  
  	/**
  	 * Was the reason for termination a timeout?
  	 * 
  	 * @return a boolean.
  	 */
  	public boolean hasTimeout() {
  		if (test == null)
  			return false;
  
  		int size = test.size();
  		if (exceptions.containsKey(size)) {
  			if (exceptions.get(size) instanceof TestCaseExecutor.TimeoutExceeded) {
  				return true;
  			}
  		}
  
  		return false;
  	}
  
  	/**
  	 * Does the test contain an exception caused in the test itself?
  	 * 
  	 * @return a boolean.
  	 */
  	public boolean hasTestException() {
  		if (test == null)
  			return false;
  
  		for (Throwable t : exceptions.values()) {
  			if (t instanceof CodeUnderTestException)
  				return true;
  		}
  
  		return false;
  	}
  
  	/**
  	 * Is there an undeclared exception in the trace?
  	 * 
  	 * @return a boolean.
  	 */
  	public boolean hasUndeclaredException() {
  		if (test == null)
  			return false;
  
  		for (Integer i : exceptions.keySet()) {
  			Throwable t = exceptions.get(i);
  			// Exceptions can be placed at test.size(), e.g. for timeouts
  			assert i>=0 && i<=test.size() : "Exception "+t+" at position "+i+" in test of length "+test.size()+": "+test.toCode(exceptions);
  			if(i >= test.size())
  				continue;
  			
  			if (!test.getStatement(i).getDeclaredExceptions().contains(t.getClass()))
  				return true;
  		}
  
  		return false;
  	}
  
  	/**
  	 * Returns true if any of the executed statements was a reflection statement
  	 *
  	 * @return
       */
  	public boolean calledReflection() {
  		int executedStatements = getExecutedStatements();
  		for(int numStatement = 0; numStatement < executedStatements; numStatement++) {
  			Statement s = test.getStatement(numStatement);
  			if(s.isReflectionStatement())
  				return true;
  		}
  		return false;
  	}
  
  
  
  	/**
  	 * check if the test case threw any security exception
  	 * 
  	 * @return
  	 */
  	public boolean hasSecurityException() {
  		return hasSecurityException;
  	}
  
  	public void setSecurityException(boolean value) {
  		logger.debug("Changing hasSecurityException from "+hasSecurityException +" to "+value);
  		hasSecurityException = value;
  	}
  
  	/**
  	 * @return the executionTime
  	 */
  	public long getExecutionTime() {
  		return executionTime;
  	}
  
  	/**
  	 * @param executionTime
  	 *            the executionTime to set
  	 */
  	public void setExecutionTime(long executionTime) {
  		this.executionTime = executionTime;
  	}
  
  	/** {@inheritDoc} */
  	@Override
  	public ExecutionResult clone() {
  		ExecutionResult copy = new ExecutionResult(test, mutation);
  		copy.exceptions.putAll(exceptions);
  