All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.evosuite.coverage.dataflow.DefUseCoverageTestFitness Maven / Gradle / Ivy

/**
 * 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.coverage.dataflow;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Set;

import org.evosuite.Properties;
import org.evosuite.Properties.Criterion;
import org.evosuite.TestGenerationContext;
import org.evosuite.coverage.statement.StatementCoverageTestFitness;
import org.evosuite.ga.Chromosome;
import org.evosuite.graphs.GraphPool;
import org.evosuite.graphs.cfg.BytecodeInstruction;
import org.evosuite.graphs.cfg.RawControlFlowGraph;
import org.evosuite.testcase.TestChromosome;
import org.evosuite.testcase.TestFitnessFunction;
import org.evosuite.testcase.execution.ExecutionResult;
import org.evosuite.testcase.execution.ExecutionTrace;
import org.evosuite.utils.ArrayUtil;

/*
 * // (0) TODO IDEA FOR AN EVO-SUITE-FEATURE: // given a test(suite) for a
 * class, check how many goals of each coverage criterion it covers // (1) DONE
 * detect which LV in which methodCall // i don't think this needs to be done
 * anymore. its not possible to cover a use in a method call for a LV without
 * covering a definition first // (2) DONE cut ExecutionTrace for
 * branch-fitness-evaluation to Trace of current object only // subTODO: first
 * mark MethodCalls in ExecutionTracer.finished_calls with a methodID and the
 * current objectID // then kick out all non-static MethodCalls for objects
 * other then the one with current objectID // if goalDef is for a LV, also
 * consider MethodCalls individually (OUTDATED! s. above) // (3) DONE cut
 * ExecutionTrace for branch-fitness-evaluation to Trace of a certain path
 * (between goalDef and overwritingDef) // subTODO: in a MethodCall from the
 * ExecutionTracer add another list holding information about the current
 * duConter // then allow for cutting the ExecutionTrace in a way that it only
 * holds data associated for duCounters in a given range // (4) DONE idea: once
 * goalDef is covered, look at all duCounterPositions of goalDef
 * (goalDefPositions): // if goalUse is covered any of these goalDefPositions,
 * return 0 // if not return the minimum over all branchUseFitness in the trace
 * // where the trace is cut between the goalDefPosition and the next
 * overwritingDefinition // turns out you don't need to cut between goalDefs and
 * overwritingDefs // all u need to do is filter out all traces where the
 * goalDef is not active for use-fitness-calculation // (5) DONE: well that
 * didn't turn out too well. you have to consider all passed definitions //
 * separately as described in (3) and (4) after all - see for example
 * MeanTestClass.mean()
 * 
 * // Other things one could/should do: (TODO-list) // - display local variable
 * names as in source code // - take different methodIds into account! // -
 * inter.method and inter.class data flow analysis - want to drop intra-part //
 * - implement DefUseCoverageSuiteFitness - DONE first rudimentary
 * implementation // - various optimizations // - DONE: for example one should
 * reuse tests that reach a certain definition or use // when looking for
 * another goal with that definition or use respectively idea: implement some
 * sort of chromosome pool for each CUT - keep track of "good" chromosomes, that
 * cover defs and uses and use them for initial population when looking for
 * goals concerning these DUs - DONE also if one would implement the above point
 * it would be very profitable to order the goals such that easy goals are
 * searched for first and for harder ones (deep in the CDG) later // - fix
 * control dependencies analysis // - implement real ReachingDefinitions
 * algorithm // - even more information in resulting tests? - cool would be to
 * mark the statements in the test that caused the covering hits to goalUse and
 * goalDef! - handle exceptions - worry about rounding errors: all that
 * normalizing is insane - should stretch the range for possible CoverageFitness
 * to something like 0-100 at least - might want to make a fitness bigger/more
 * precise then double - care for integer overflows (especially in alternative
 * fitness calculation) - DONE: private methods don't seem to be a problem at
 * all. they don't need special treatment - TODO: clean up TestSuiteGenerator! -
 * DONE: At least check for all remaining uncovered goals if they are covered by
 * the test that just covered a goal
 * 
 * - DONE: Kick out ControlDependencyTestClass-loops that take forever! - handle
 * timeouts in tests - refactor: separate DefUseCoverageGoal and
 * DefUseCoverageTestFitness - implement hashCode() functions? -
 * NoStoppingCondition .. maybe even serialize populations and resume evolving
 * later - now this is more of a theoretical one but still: - how does one find
 * the "perfect" configuration for the GA? - well build another GA to find out,
 * each chromosome is a configuration - mutation and crossovers seems very easy
 * - fitness is calculated depending on covered goals, time needed / goal,
 * consumed resources etc ... i would so love to do that :D - SearchStatistics
 * ... well ... where to start :D - i think the report is a very essential part
 * of EvoSuite - it's the way users will in the end see EvoSuite and maybe even
 * the way they interact with it (TODO? :) ) - there is so much cool stuff one
 * could do: - give a complete analysis of the CUT in terms of different
 * coverage perspectives - provide the user with the possibility to compare
 * different runs - link test run information to analysis - polish test run
 * view: - jump to different parts (fitness, tests, etc) - make things
 * "expandable" (you know hide/show all test cases with a small -/+ next to it
 * and stuff like that) - show TestCase comments - even better: link tests to
 * goals they cover, see analysis part above - mark where in a test a certain
 * goal is covered: - color lines differently depending on goal one hovers his
 * mouse above in the covered goal description - ... i could go on but i guess
 * one gets the point
 * 
 * - in order to do all that SearchStatistics should be get a complete
 * refactor-marathon-overhaul: - make distinction between HTML-generation and
 * statistics part, interlink them via .csv-files - maybe don't generate any
 * HTML at all but rather just put all relevant data in .csv-files together with
 * plots in a special directory which in turn can be visualized in all kinds of
 * ways. out the top of my head i'd say PHP would be very suited for that
 * 
 * - maybe encapsulate different HTML-generation-parts in separate classes like
 * one for Code, one for plots etc. - well just come up with a nice class model
 * is all i'm trying to say i guess - srsly though, this SearchStatistcs class
 * is a mess :D and buggy as hell too it seems - found a bug: s.
 * ExceptionTestClass: sometimes passedLine is called before enteredMethod in
 * instrumented code - so DefUseCoverage goal computation scales pretty badly,
 * why not separate goal analysis part and test creation like with -setup you
 * could run -analyze_goals or something and it would serialize the goals on
 * disc so the computed goals can be reused in later test creations ... srsly
 * analysis takes minutes on bigger CUTs! - look at
 * MultipleControlDependeciesTestClass.test(): respect that a CFGVertex can have
 * multiple branches it is control dependent on
 * 
 * 
 * things to write about: - DefUse is just awesome! - better chance of passing
 * hard branches (?) - more thorough tests - #times each branch is executed -
 * infeasible path problem - extract future work from unfinished ToDo-list ;) -
 * why alternative definition - different modes, pro and cons - average doesn't
 * take into account how many overwriting definitions there were - sum seems to
 * be the most reasonable, maybe with stretched single alternative fitness 10? -
 * harder than branch coverage - chromosomes more valuable! - see part above
 * about chromosome pool and initial population and stuff - so it makes sense to
 * recycle chromosomes - which leads to difficulty and preordering
 * 
 * Questions: - BranchCoverageGoal also treats root branches with expression
 * value true!
 */

/**
 * Evaluate fitness of a single test case with respect to one Definition-Use
 * pair
 * 
 * For more information look at the comment from method getDistance()
 * 
 * @author Andre Mis
 */
public class DefUseCoverageTestFitness extends TestFitnessFunction {

	public enum DefUsePairType {
		INTRA_METHOD, INTER_METHOD, INTRA_CLASS, PARAMETER
	};

	private static final long serialVersionUID = 1L;

	/** Constant singleFitnessTime=0l */
	public static long singleFitnessTime = 0l;

	// debugging flags
	private final static boolean DEBUG = Properties.DEFUSE_DEBUG_MODE;
	private final static boolean PRINT_DEBUG = false;

	// the Definition-Use pair
	private String goalVariable;
	private transient Use goalUse;
	private transient Definition goalDefinition;

	private DefUsePairType type;

	private TestFitnessFunction goalDefinitionFitness;
	private TestFitnessFunction goalUseFitness;

	// coverage information
	private Integer coveringObjectId = -1;
	private transient ExecutionTrace coveringTrace = null;
	private boolean covered = false;

	// constructors

	/**
	 * Creates a Definition-Use-Coverage goal for the given Definition and Use
	 * 
	 * @param def
	 *            a {@link org.evosuite.coverage.dataflow.Definition} object.
	 * @param use
	 *            a {@link org.evosuite.coverage.dataflow.Use} object.
	 * @param type
	 *            a
	 *            {@link org.evosuite.coverage.dataflow.DefUseCoverageTestFitness.DefUsePairType}
	 *            object.
	 */
	public DefUseCoverageTestFitness(Definition def, Use use, DefUsePairType type) {
		if (def == null)
			throw new IllegalArgumentException("null given for definition. type: "
			        + type.toString());
		if (use == null)
			throw new IllegalArgumentException("null given for use. def was "
			        + def.toString() + ". type: " + type.toString());

		initRegularDefUse(def, use, type);
	}

	/**
	 * Used for Parameter-Uses
	 * 
	 * Creates a goal that tries to cover the given Use
	 * 
	 * @param use
	 *            a {@link org.evosuite.coverage.dataflow.Use} object.
	 */
	public DefUseCoverageTestFitness(Use use) {
		if (!use.isParameterUse())
			throw new IllegalArgumentException(
			        "this constructor is only for Parameter-Uses");

		initParameterUse(use);
	}

	private void initRegularDefUse(Definition def, Use use, DefUsePairType type) {
		//if (!def.getVariableName().equals(use.getVariableName()))
		//	throw new IllegalArgumentException(
		//	        "expect def and use to be for the same variable: \n" + def.toString()
		//	                + "\n" + use.toString());
		if (def.isLocalDU() && !type.equals(DefUsePairType.INTRA_METHOD))
			throw new IllegalArgumentException(
			        "local variables can only be part of INTRA-METHOD pairs: \ntype:"
			                + type.toString() + "\ndef:" + def.toString() + "\nuse:"
			                + use.toString());

		this.goalDefinition = def;
		this.goalUse = use;
		this.goalVariable = def.getVariableName();
		this.goalDefinitionFitness = new StatementCoverageTestFitness(goalDefinition.getClassName(), goalDefinition.getMethodName(), goalDefinition.getInstructionId());
		this.goalUseFitness = new StatementCoverageTestFitness(goalUse.getClassName(), goalUse.getMethodName(), goalUse.getInstructionId());

		this.type = type;
	}

	private void initParameterUse(Use use) {
		goalVariable = use.getVariableName();
		goalDefinition = null;
		goalDefinitionFitness = null;
		goalUse = use;
		goalUseFitness = new StatementCoverageTestFitness(goalUse.getClassName(), goalUse.getMethodName(), goalUse.getInstructionId());

		this.type = DefUsePairType.PARAMETER;
	}

	/**
	 * {@inheritDoc}
	 * 
	 * Calculates the DefUseCoverage test fitness for this goal
	 * 
	 * Look at DefUseCoverageCalculations.calculateDUFitness() for more
	 * information
	 */
	@Override
	public double getFitness(TestChromosome individual, ExecutionResult result) {
		preFitnessDebugInfo(result, true);

		long start = System.currentTimeMillis();

		DefUseFitnessCalculator calculator = new DefUseFitnessCalculator(this,
		        individual, result);

		// Deactivate coverage archive while measuring fitness, as auxiliar fitness functions
		// could attempt to claim coverage for it in the archive
		boolean archive = Properties.TEST_ARCHIVE;
		Properties.TEST_ARCHIVE = false;

		double fitness = calculator.calculateDUFitness();

		Properties.TEST_ARCHIVE = archive;

		if (ArrayUtil.contains(Properties.CRITERION, Criterion.DEFUSE) && fitness == 0.0)
			setCovered(individual, result.getTrace(), -1); // TODO objectId wrong

		postFitnessDebugInfo(individual, result, fitness);

		singleFitnessTime += System.currentTimeMillis() - start;

		updateIndividual(this, individual, fitness);

		return fitness;
	}

	/**
	 * Used by DefUseCoverageSuiteFitness
	 * 
	 * Simply call getFitness(TestChromosome,ExecutionResult) with a dummy
	 * TestChromosome The chromosome is used only for updateIndividual()
	 * anyways.
	 * 
	 * @param result
	 *            a {@link org.evosuite.testcase.execution.ExecutionResult} object.
	 * @return a double.
	 */
	public double getFitness(ExecutionResult result) {
		TestChromosome dummy = new TestChromosome();
		return getFitness(dummy, result);
	}

	public boolean isAlias() {
		return goalDefinition != null ? !goalUse.getVariableName().equals(goalDefinition.getVariableName())
		        : false;
	}

	/**
	 * Returns the definitions to the goalVaraible coming after the
	 * goalDefinition and before the goalUse in their respective methods
	 * 
	 * @return a {@link java.util.Set} object.
	 */
	public Set getPotentialOverwritingDefinitions() {
		Set instructionsInBetween = getInstructionsInBetweenDU();
		if (goalDefinition != null)
			return DefUseExecutionTraceAnalyzer.getOverwritingDefinitionsIn(goalDefinition,
			                                                                instructionsInBetween);
		else
			return DefUseExecutionTraceAnalyzer.getDefinitionsIn(goalVariable,
			                                                     instructionsInBetween);
	}

	/**
	 * Return a set containing all CFGVertices that occur in the complete CFG
	 * after the goalDefinition and before the goalUse.
	 * 
	 * It's pretty much the union of getInstructionsAfterGoalDefinition() and
	 * getInstructionsBeforeGoalUse(), except if the DU is in one method and the
	 * goalDefinition comes before the goalUse, then the intersection of the two
	 * sets is returned.
	 * 
	 * If the goalDefinition is a Parameter-Definition only the CFGVertices
	 * before the goalUse are considered.
	 * 
	 * @return a {@link java.util.Set} object.
	 */
	public Set getInstructionsInBetweenDU() {
		Set previousInstructions = getInstructionsBeforeGoalUse();
		if (goalDefinition != null) {
			Set laterInstructions = getInstructionsAfterGoalDefinition();
			if (goalDefinition.getInstructionId() < goalUse.getInstructionId()
			        && goalDefinition.getMethodName().equals(goalUse.getMethodName())) {
				// they are in the same method and definition comes before use => intersect sets
				previousInstructions.retainAll(laterInstructions);
			} else {
				// otherwise take the union
				previousInstructions.addAll(laterInstructions);
			}
		}
		return previousInstructions;
	}

	/**
	 * Returns a set containing all CFGVertices in the goal definition method
	 * that come after the definition.
	 * 
	 * Look at ControlFlowGraph.getLaterInstructionInMethod() for details
	 * 
	 * @return a {@link java.util.Set} object.
	 */
	public Set getInstructionsAfterGoalDefinition() {
		RawControlFlowGraph cfg = GraphPool.getInstance(TestGenerationContext.getInstance().getClassLoaderForSUT()).getRawCFG(goalDefinition.getClassName(),
		                                                                                                  goalDefinition.getMethodName());
		BytecodeInstruction defVertex = cfg.getInstruction(goalDefinition.getInstructionId());
		Set r = cfg.getLaterInstructionsInMethod(defVertex);
		//		for (BytecodeInstruction v : r) {
		//			v.setMethodName(goalDefinition.getMethodName());
		//			v.setClassName(goalDefinition.getClassName());
		//		}
		return r;
	}

	/**
	 * Returns a set containing all CFGVertices in the goal use method that come
	 * before the goal use.
	 * 
	 * Look at ControlFlowGraph.getPreviousInstructionInMethod() for details
	 * 
	 * @return a {@link java.util.Set} object.
	 */
	public Set getInstructionsBeforeGoalUse() {
		RawControlFlowGraph cfg = GraphPool.getInstance(TestGenerationContext.getInstance().getClassLoaderForSUT()).getRawCFG(goalUse.getClassName(),
		                                                                                                  goalUse.getMethodName());
		BytecodeInstruction useVertex = cfg.getInstruction(goalUse.getInstructionId());
		Set r = cfg.getPreviousInstructionsInMethod(useVertex);
		//		for (BytecodeInstruction v : r) {
		//			v.setMethodName(goalUse.getMethodName());
		//			v.setClassName(goalUse.getClassName());
		//		}
		return r;
	}

	// debugging methods

	/**
	 * 

* setCovered *

* * @param individual * a {@link org.evosuite.ga.Chromosome} object. * @param trace * a {@link org.evosuite.testcase.execution.ExecutionTrace} object. * @param objectId * a {@link java.lang.Integer} object. */ public void setCovered(TestChromosome individual, ExecutionTrace trace, Integer objectId) { if (PRINT_DEBUG) { logger.debug("goal COVERED by object " + objectId); logger.debug("=============================================================="); } this.coveringObjectId = objectId; updateIndividual(this, individual, 0); if (DEBUG) if (!DefUseFitnessCalculator.traceCoversGoal(this, individual, trace)) throw new IllegalStateException("calculation flawed. goal wasn't covered"); } private void preFitnessDebugInfo(ExecutionResult result, boolean respectPrintFlag) { if (PRINT_DEBUG || !respectPrintFlag) { System.out.println("=============================================================="); System.out.println("current goal: " + toString()); System.out.println("current test:"); System.out.println(result.test.toCode()); } } private void postFitnessDebugInfo(Chromosome individual, ExecutionResult result, double fitness) { if (DEBUG) { if (fitness != 0) { if (PRINT_DEBUG) { System.out.println("goal NOT COVERED. fitness: " + fitness); System.out.println("=============================================================="); } if (DefUseFitnessCalculator.traceCoversGoal(this, individual, result.getTrace())) throw new IllegalStateException( "calculation flawed. goal was covered but fitness was " + fitness); } } } // --- Getter --- /** *

* Getter for the field coveringTrace. *

* * @return a {@link org.evosuite.testcase.execution.ExecutionTrace} object. */ public ExecutionTrace getCoveringTrace() { return coveringTrace; } /** *

* Getter for the field goalVariable. *

* * @return a {@link java.lang.String} object. */ public String getGoalVariable() { return goalVariable; } /** *

* Getter for the field coveringObjectId. *

* * @return a int. */ public int getCoveringObjectId() { return coveringObjectId; } /** *

* Getter for the field goalDefinition. *

* * @return a {@link org.evosuite.coverage.dataflow.Definition} object. */ public Definition getGoalDefinition() { return goalDefinition; } /** *

* Getter for the field goalUse. *

* * @return a {@link org.evosuite.coverage.dataflow.Use} object. */ public Use getGoalUse() { return goalUse; } /** *

* Getter for the field goalUseFitness. *

* * @return a {@link org.evosuite.testcase.TestFitnessFunction} object. */ public TestFitnessFunction getGoalUseFitness() { return goalUseFitness; } /** *

* Getter for the field goalDefinitionFitness. *

* * @return a {@link org.evosuite.testcase.TestFitnessFunction} object. */ public TestFitnessFunction getGoalDefinitionFitness() { return goalDefinitionFitness; } /** *

* isInterMethodPair *

* * @return a boolean. */ public boolean isInterMethodPair() { return type.equals(DefUsePairType.INTER_METHOD); } /** *

* isIntraClassPair *

* * @return a boolean. */ public boolean isIntraClassPair() { return type.equals(DefUsePairType.INTRA_CLASS); } /** *

* Getter for the field type. *

* * @return a * {@link org.evosuite.coverage.dataflow.DefUseCoverageTestFitness.DefUsePairType} * object. */ public DefUsePairType getType() { return type; } /** *

* isParameterGoal *

* * @return a boolean. */ public boolean isParameterGoal() { return goalDefinition == null; } // --- Inherited from Object --- /** {@inheritDoc} */ @Override public String toString() { StringBuffer r = new StringBuffer(); r.append(type.toString()); r.append("-Definition-Use-Pair"); r.append("\n\t"); if (isParameterGoal()) r.append("Parameter-Definition " + goalUse.getLocalVariableSlot() + " for method " + goalUse.getMethodName()); else r.append(goalDefinition.toString()); r.append("\n\t"); r.append(goalUse.toString()); return r.toString(); } /** {@inheritDoc} */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((goalDefinition == null) ? 0 : goalDefinition.hashCode()); result = prime * result + ((goalUse == null) ? 0 : goalUse.hashCode()); result = prime * result + ((goalVariable == null) ? 0 : goalVariable.hashCode()); result = prime * result + ((type == null) ? 0 : type.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; DefUseCoverageTestFitness other = (DefUseCoverageTestFitness) obj; if (goalDefinition == null) { if (other.goalDefinition != null) return false; } else if (!goalDefinition.equals(other.goalDefinition)) return false; if (goalUse == null) { if (other.goalUse != null) return false; } else if (!goalUse.equals(other.goalUse)) return false; if (goalVariable == null) { if (other.goalVariable != null) return false; } else if (!goalVariable.equals(other.goalVariable)) return false; if (type != other.type) return false; return true; } /* (non-Javadoc) * @see org.evosuite.testcase.TestFitnessFunction#compareTo(org.evosuite.testcase.TestFitnessFunction) */ @Override public int compareTo(TestFitnessFunction other) { if (other instanceof DefUseCoverageTestFitness) { DefUseCoverageTestFitness otherFitness = (DefUseCoverageTestFitness) other; // goalDefinition can be null for parameter goals if (goalDefinition == null || otherFitness.getGoalDefinition() == null) return goalUse.compareTo(otherFitness.getGoalUse()); if (goalDefinition.compareTo(otherFitness.getGoalDefinition()) == 0) { return goalUse.compareTo(otherFitness.getGoalUse()); } else { return goalDefinition.compareTo(otherFitness.getGoalDefinition()); } } return compareClassName(other); } /** * @return the covered */ public boolean isCovered() { return covered; } /** * @param covered * the covered to set */ public void setCovered(boolean covered) { this.covered = covered; } /* (non-Javadoc) * @see org.evosuite.testcase.TestFitnessFunction#getTargetClass() */ @Override public String getTargetClass() { return goalUse.getClassName(); } /* (non-Javadoc) * @see org.evosuite.testcase.TestFitnessFunction#getTargetMethod() */ @Override public String getTargetMethod() { return goalUse.getMethodName(); } private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { DefUsePairType type = (DefUsePairType) ois.readObject(); Integer useId = (Integer) ois.readObject(); Integer defId = (Integer) ois.readObject(); Use use = DefUsePool.getUseByUseId(useId); //TODO: Need to find a better solution. if(use == null) return; if (type == DefUsePairType.PARAMETER) { initParameterUse(use); } else { Definition def = DefUsePool.getDefinitionByDefId(defId); initRegularDefUse(def, use, type); } } /** * Serialize, but need to abstract classloader away * * @param oos * @throws IOException */ private void writeObject(ObjectOutputStream oos) throws IOException { oos.writeObject(type); oos.writeObject(Integer.valueOf(goalUse.useId)); if (goalDefinition != null) oos.writeObject(Integer.valueOf(goalDefinition.defId)); else oos.writeObject(0); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy