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

org.evosuite.symbolic.solver.avm.StringAVM 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.symbolic.solver.avm;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import org.evosuite.symbolic.expr.Constraint;
import org.evosuite.symbolic.expr.ExpressionEvaluator;
import org.evosuite.symbolic.expr.StringConstraint;
import org.evosuite.symbolic.expr.str.StringValue;
import org.evosuite.symbolic.expr.str.StringVariable;
import org.evosuite.symbolic.expr.token.HasMoreTokensExpr;
import org.evosuite.symbolic.solver.DistanceEstimator;
import org.evosuite.symbolic.solver.SolverTimeoutException;
import org.evosuite.utils.Randomness;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

final class StringAVM extends VariableAVM {

	public StringAVM(StringVariable strVar, Collection> cnstr, long start_time, long timeout) {
		super(cnstr, start_time, timeout);
		this.strVar = strVar;
	}

	static Logger log = LoggerFactory.getLogger(StringAVM.class);

	private double checkpointDistance = Double.MAX_VALUE;

	private String checkpointStringValue;

	private final StringVariable strVar;

	/**
	 * 

* strLocalSearch *

* * @return a boolean. */ public boolean applyAVM() throws SolverTimeoutException { ExpressionEvaluator exprExecutor = new ExpressionEvaluator(); // try to remove each log.debug("Trying to remove characters"); boolean improvement = false; checkpointVar(DistanceEstimator.getDistance(cnstr)); // First chop characters from the back until distance doesn't improve String oldString = strVar.getConcreteValue(); boolean improved = true; while (improved && oldString.length() > 0 ) { if (isFinished()) { throw new SolverTimeoutException(); } String newStr = oldString.substring(0, oldString.length() - 1); strVar.setConcreteValue(newStr); log.debug("Current attempt: " + newStr); improved = false; double newDist = DistanceEstimator.getDistance(cnstr); // if (distImpr(newDist)) { if (newDist <= checkpointDistance) { log.debug("Distance improved or did not increase, keeping change"); checkpointVar(newDist); improvement = true; improved = true; oldString = newStr; if (newDist == 0) { return true; } } else { log.debug("Distance did not improve, reverting change"); restoreVar(); } } // next try to replace each character using AVM log.debug("Trying to replace characters"); // Backup is done internally if (doStringAVM(oldString)) { improvement = true; oldString = strVar.getConcreteValue(); } if (checkpointDistance == 0.0) { return true; } // try to add at the end log.debug("Trying to add characters"); checkpointVar(DistanceEstimator.getDistance(cnstr)); // Finally add new characters at the end of the string improved = true; while (improved) { if (isFinished()) { throw new SolverTimeoutException(); } improved = false; char charToInsert = Randomness.nextChar(); String newStr = oldString + charToInsert; strVar.setConcreteValue(newStr); double newDist = DistanceEstimator.getDistance(cnstr); log.debug("Adding: " + newStr + ": " + newDist); if (distImpr(newDist)) { improvement = true; improved = true; checkpointVar(newDist); if (checkpointDistance == 0.0) { log.debug("Search seems successful, stopping at " + checkpointDistance + "/" + newDist); return true; } doCharacterAVM(newStr.length() - 1); oldString = strVar.getConcreteValue(); } else { restoreVar(); } } // try to insert delimiters (if any) Set delimiters = getTokenDelimiters(cnstr); for (StringValue delimiter : delimiters) { if (isFinished()) { throw new SolverTimeoutException(); } improved = true; String delimiterStr = (String) delimiter.accept(exprExecutor, null); while (improved) { if (isFinished()) { throw new SolverTimeoutException(); } improved = false; char charToInsert = Randomness.nextChar(); String newStr = oldString + delimiterStr + charToInsert; strVar.setConcreteValue(newStr); double newDist = DistanceEstimator.getDistance(cnstr); log.debug("Adding: " + newStr + ": " + newDist); if (distImpr(newDist)) { improvement = true; improved = true; checkpointVar(newDist); if (checkpointDistance == 0.0) { log.debug("Search seems successful, stopping at " + checkpointDistance + "/" + newDist); return true; } doCharacterAVM(newStr.length() - 1); oldString = strVar.getConcreteValue(); } else { restoreVar(); } } } return improvement; } private void checkpointVar(double newDist) { checkpointStringValue = strVar.getConcreteValue(); checkpointDistance = newDist; } private boolean distImpr(double newDistance) { return newDistance < checkpointDistance; } private void restoreVar() { strVar.setConcreteValue(checkpointStringValue); } /** * Apply AVM to an individual character within a string * * @param position * @param varsToChange * * @return */ private boolean doCharacterAVM(int position) throws SolverTimeoutException { checkpointVar(DistanceEstimator.getDistance(cnstr)); boolean done = false; boolean hasImproved = false; while (!done) { if (isFinished()) { throw new SolverTimeoutException(); } done = true; String origString = strVar.getConcreteValue(); char oldChar = origString.charAt(position); char[] characters = origString.toCharArray(); // Try +1 char replacement = oldChar; replacement = nextChar(replacement, 1); characters[position] = replacement; String newString = new String(characters); strVar.setConcreteValue(newString); double newDist = DistanceEstimator.getDistance(cnstr); log.debug("Probing increment " + position + ": " + newString + ": " + newDist + " replacement = " + (int) replacement); if (distImpr(newDist)) { checkpointVar(newDist); if (newDist == 0.0) return true; done = false; hasImproved = true; iterateCharacterAVM(position, 2); } else { replacement = nextChar(replacement, -2); characters[position] = replacement; newString = new String(characters); strVar.setConcreteValue(newString); newDist = DistanceEstimator.getDistance(cnstr); log.debug("Probing decrement " + position + ": " + newString + ": " + newDist + " replacement = " + (int) replacement); if (distImpr(newDist)) { checkpointVar(newDist); if (newDist == 0.0) return true; done = false; hasImproved = true; iterateCharacterAVM(position, -2); } else { // Try +32 replacement = (char) (oldChar + 32); characters[position] = replacement; newString = new String(characters); strVar.setConcreteValue(newString); newDist = DistanceEstimator.getDistance(cnstr); log.debug("Probing increment [32] " + position + ": " + newString + ": " + newDist + " replacement = " + (int) replacement); if (distImpr(newDist)) { checkpointVar(newDist); done = false; hasImproved = true; // Now try +/-1 as usual break; } else { // Try -32 replacement = (char) (oldChar + 32); characters[position] = replacement; newString = new String(characters); strVar.setConcreteValue(newString); newDist = DistanceEstimator.getDistance(cnstr); log.debug("Probing increment [32] " + position + ": " + newString + ": " + newDist + " replacement = " + (int) replacement); if (distImpr(newDist)) { checkpointVar(newDist); done = false; hasImproved = true; // Now try +/-1 as usual } else { restoreVar(); } } if (done) log.debug("Search finished " + position + ": " + newString + ": " + newDist); else log.debug("Going for another iteration at position " + position); } } } return hasImproved; } /** * Apply AVM to all characters in a string * * @param oldString * @param varsToChange * * @return */ private boolean doStringAVM(String oldString) throws SolverTimeoutException { boolean improvement = false; for (int i = 0; i < oldString.length(); i++) { if (isFinished()) { throw new SolverTimeoutException(); } log.info("Current character: " + i); if (doCharacterAVM(i)) improvement = true; } return improvement; } private boolean iterateCharacterAVM(int position, int delta) throws SolverTimeoutException { boolean improvement = false; String oldString = strVar.getConcreteValue(); log.debug("Trying increment " + delta + " of " + oldString); char oldChar = oldString.charAt(position); log.info(" -> Character " + position + ": " + oldChar); char[] characters = oldString.toCharArray(); char replacement = oldChar; replacement = nextChar(replacement, delta); characters[position] = replacement; String newString = new String(characters); strVar.setConcreteValue(newString); double newDist = DistanceEstimator.getDistance(cnstr); while (distImpr(newDist)) { if (isFinished()) { throw new SolverTimeoutException(); } checkpointVar(newDist); if (newDist == 0.0) return true; oldString = newString; improvement = true; delta = 2 * delta; replacement = nextChar(replacement, delta); log.info("Current delta: " + delta + " -> " + replacement); characters[position] = replacement; newString = new String(characters); log.info(" " + position + " " + oldString + "/" + oldString.length() + " -> " + newString + "/" + newString.length()); strVar.setConcreteValue(newString); newDist = DistanceEstimator.getDistance(cnstr); } log.debug("No improvement on " + oldString); restoreVar(); // strVar.setMinValue(oldString); log.debug("Final value of this iteration: " + oldString); return improvement; } /** * This method avoids overflow when computing the next char. * * @param oldChar * @param delta * @return */ private char nextChar(char oldChar, int delta) { char nextChar = (char) (oldChar + delta); if (delta >= 0) { if (nextChar < oldChar) { nextChar = Character.MAX_VALUE; } } else { if (nextChar > oldChar) { nextChar = Character.MIN_VALUE; } } return nextChar; } private static Set getTokenDelimiters(Collection> constraints) { Set delimiters = new HashSet(); for (Constraint constraint : constraints) { if (constraint instanceof StringConstraint) { StringConstraint stringConstraint = (StringConstraint) constraint; if (stringConstraint.getLeftOperand() instanceof HasMoreTokensExpr) { HasMoreTokensExpr hasMoreTokensExpr = (HasMoreTokensExpr) stringConstraint.getLeftOperand(); StringValue delimiter = hasMoreTokensExpr.getTokenizerExpr().getDelimiter(); delimiters.add(delimiter); } } } return delimiters; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy