Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
0ded027
First approach with random selection
FerrumBrain Jul 23, 2024
581b36a
fix
FerrumBrain Jul 23, 2024
f91ecc9
basic idea of state splitting
FerrumBrain Jul 25, 2024
747be24
basic clause selector version
FerrumBrain Jul 26, 2024
07e827e
clause selection based on min uncovered distance
FerrumBrain Jul 29, 2024
8b56a6e
collecting all tests
FerrumBrain Jul 29, 2024
607890a
minor fixes
FerrumBrain Jul 29, 2024
cf7757d
added timeout for test generation
FerrumBrain Jul 29, 2024
f655da4
fixed loop condition
FerrumBrain Jul 30, 2024
b9b3ea7
changed to a mutation
FerrumBrain Jul 31, 2024
b68945d
fixed
FerrumBrain Aug 2, 2024
00dbbd1
adjustments
FerrumBrain Aug 5, 2024
daf40bb
new logs?
FerrumBrain Aug 7, 2024
bfa74bf
small fixes
FerrumBrain Aug 9, 2024
0da1f09
counting irreversible
FerrumBrain Aug 12, 2024
ba3d469
fixes + new logs
FerrumBrain Aug 21, 2024
acdaff7
new logs
FerrumBrain Aug 23, 2024
4e05f61
added null handling
FerrumBrain Aug 23, 2024
6e6dba8
fixed null handling and added enum handling
FerrumBrain Aug 29, 2024
3757185
finished enum handling
FerrumBrain Aug 30, 2024
69c7d1e
fixes + added arm support for running experiments
FerrumBrain Sep 3, 2024
fdce016
fixes + new logs + new condition for clause selection
FerrumBrain Sep 12, 2024
349fec0
logged kex calls
FerrumBrain Sep 13, 2024
88da7e3
rewrote data flow analysis
FerrumBrain Sep 18, 2024
b482829
rewrote data flow analysis to transformer
FerrumBrain Sep 20, 2024
8f17fbf
changed ArrayLengthTerm analysis approach
FerrumBrain Sep 20, 2024
195373e
changed approach to the PathClauses
FerrumBrain Sep 20, 2024
00356a6
added stesgaard
FerrumBrain Sep 21, 2024
c13a248
added pointer check to stensgaard
FerrumBrain Sep 21, 2024
09ccab9
added must(?) alias analysis
FerrumBrain Sep 21, 2024
44fc1d2
hided must(?) alias analysis
FerrumBrain Sep 24, 2024
6d402da
restored alias analysis
FerrumBrain Sep 24, 2024
2e629a3
concolic mutations on plateaus
FerrumBrain Sep 25, 2024
91f4dd4
new statistics collection notebook
FerrumBrain Sep 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions client/src/main/java/org/evosuite/Properties.java
Original file line number Diff line number Diff line change
Expand Up @@ -1277,10 +1277,9 @@ public enum ArchiveType {
@Parameter(key = "seed_dir", group = "Output", description = "Directory name where the best chromosomes are saved")
public static String SEED_DIR = "evosuite-seeds";

@Parameter(key = "concolic_mutation", description = "Deprecated. Probability of using concolic mutation operator")
@Parameter(key = "concolic_mutation", description = "Probability of using concolic mutation operator")
@DoubleValue(min = 0.0, max = 1.0)
@Deprecated
public static double CONCOLIC_MUTATION = 0.0;
public static double CONCOLIC_MUTATION = 0.5;

@Parameter(key = "constraint_solution_attempts", description = "Number of attempts to solve constraints related to one code branch")
public static int CONSTRAINT_SOLUTION_ATTEMPTS = 3;
Expand Down
106 changes: 35 additions & 71 deletions client/src/main/java/org/evosuite/ga/metaheuristics/mosa/DynaMOSA.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,18 @@
*/
package org.evosuite.ga.metaheuristics.mosa;

import kotlin.jvm.functions.Function0;
import org.evosuite.Properties;
import org.evosuite.coverage.line.LineCoverageTestFitness;
import org.evosuite.ga.ChromosomeFactory;
import org.evosuite.ga.comparators.OnlyCrowdingComparator;
import org.evosuite.ga.metaheuristics.mosa.structural.MultiCriteriaManager;
import org.evosuite.ga.operators.ranking.CrowdingDistance;
import org.evosuite.kex.KexTestGenerator;
import org.evosuite.testcase.TestCase;
import org.evosuite.testcase.TestChromosome;
import org.evosuite.testcase.*;
import org.evosuite.utils.LoggingUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.*;

/**
* Implementation of the DynaMOSA (Many Objective Sorting Algorithm) described in the paper
Expand All @@ -56,13 +51,9 @@ public class DynaMOSA extends AbstractMOSA {

protected CrowdingDistance<TestChromosome> distance = new CrowdingDistance<>();

private boolean wasTargeted;
private int stallLen;
private int maxStallLen = 32;
private boolean wasTargeted;
private final int maxGenerateTests = 5;
private final long kexExecutionTimeout = 5000;
private final long kexGenerationTimeout = 5000;
private KexTestGenerator kexTestGenerator;

/**
* Constructor based on the abstract class {@link AbstractMOSA}.
Expand All @@ -76,72 +67,42 @@ public DynaMOSA(ChromosomeFactory<TestChromosome> factory) {
/** {@inheritDoc} */
@Override
protected void evolve() {
List<TestChromosome> additional = Collections.emptyList();
if (stallLen > maxStallLen) {
logger.info("Run test generation using kex");
stallLen = 0;
wasTargeted = true;

additional = new ArrayList<>();

logger.info("Constraints collection");
long startTime = System.currentTimeMillis();
List<TestChromosome> solutions = getSolutions();
statLogger.debug("Current solutions: {}", solutions.size());
// statLogger.debug("-----------------------");
// for (TestChromosome solution : solutions) {
// statLogger.debug(solution.toString());
// statLogger.debug("-----------------------");
// }
kexTestGenerator.collectTraces(
solutions,
() -> System.currentTimeMillis() - startTime > kexExecutionTimeout
);
long endExecutionTime = System.currentTimeMillis();

logger.info("Start generation");
Function0<Boolean> stoppingCondition =
() -> System.currentTimeMillis() - endExecutionTime > kexGenerationTimeout;
int i = 0;
while (maxGenerateTests == -1 || i < maxGenerateTests) {
TestCase testCase = kexTestGenerator.generateTest(stoppingCondition);
if (testCase == null) {
break;
}
TestChromosome test = new TestChromosome();
test.setTestCase(testCase);
additional.add(test);
calculateFitness(test);
logger.debug("Covered goals: {}", testCase.getCoveredGoals().size());
i++;
}
long endTime = System.currentTimeMillis();
statLogger.debug("Test cases generated: {}", additional.size());
// statLogger.debug("---------------------");
// for (TestChromosome test: additional) {
// statLogger.debug(test.toString());
// statLogger.debug("----------------------");
// }

statLogger.debug("Kex generation time: {}", endTime - endExecutionTime);
statLogger.debug("Kex execution time: {}", endExecutionTime - startTime);
statLogger.debug("Kex iteration time: {}", endTime - startTime);

if (additional.isEmpty()) {
return;
}

List<TestChromosome> temp = additional;
additional = this.population;
this.population = temp;
TestChromosome.enableConcolic = true;
} else {
TestChromosome.enableConcolic = false;
}

// Generate offspring, compute their fitness, update the archive and coverage goals.
TestChromosome.reset();
List<TestChromosome> offspringPopulation = this.breedNextGeneration();
statLogger.debug("Concolic mutation: ================== {} ==================", this.getAge());
statLogger.debug("Concolic mutation: Number of total mutations: {}", TestChromosome.numberOfMutations);
statLogger.debug("Concolic mutation: Number of collected tests before concolic mutations: {}", TestChromosome.numberOfCollected);
statLogger.debug("Concolic mutation: Number of concolic mutations: {}", TestChromosome.numberOfConcolic);
statLogger.debug("Concolic mutation: Number of success concolic mutations: {}", TestChromosome.numberOfSuccessConcolic);
statLogger.debug("Concolic mutation: Number of timeout for concolic mutation: {}", TestChromosome.numberOfTimeouts);
statLogger.debug("Concolic mutation: Total time for concolic mutation: {}", TestChromosome.totalAmountOfTimeConcolic);
statLogger.debug("Concolic mutation: Number of irreversible for concolic mutation: {}", TestChromosome.numberOfIrreversibleConcolic);
statLogger.debug("Concolic mutation: Number of unsupported tests for concolic mutation (mocks): {}", TestChromosome.numberOfUnsupported[0]);
statLogger.debug("Concolic mutation: Number of unsupported tests for concolic mutation (EnviromentDataStatement): {}", TestChromosome.numberOfUnsupported[1]);
statLogger.debug("Concolic mutation: Number of covered tests before concolic mutation: {}", TestChromosome.numberOfCovered);
statLogger.debug("Concolic mutation: Number of unsats concolic mutation: {}", TestChromosome.numberOfUnsat);
statLogger.debug("Concolic mutation: Number of sats concolic mutation: {}", TestChromosome.numberOfSat);
statLogger.debug("Concolic mutation: Total time for of unsats concolic mutation: {}", TestChromosome.timeOfUnsat);
statLogger.debug("Concolic mutation: Total time for of sats concolic mutation: {}", TestChromosome.timeOfSat);
statLogger.debug("Concolic mutation: Number of Kex calls: {}", TestChromosome.numberOfKexCalls);

long currentTime = System.currentTimeMillis();
KexTestGenerator.INSTANCE.collectTraces(
offspringPopulation,
() -> System.currentTimeMillis() - currentTime > KexTestGenerator.KEX_EXECUTION_TIMEOUT
);

// Create the union of parents and offspring
List<TestChromosome> union = new ArrayList<>(additional.size() + this.population.size() + offspringPopulation.size());
union.addAll(additional);
List<TestChromosome> union = new ArrayList<>(this.population.size() + offspringPopulation.size());
union.addAll(this.population);
union.addAll(offspringPopulation);

Expand Down Expand Up @@ -227,6 +188,11 @@ public void generateSolution() {
// Initialize the population by creating solutions at random.
this.initializePopulation();
}
long currentTime = System.currentTimeMillis();
KexTestGenerator.INSTANCE.collectTraces(
this.population,
() -> System.currentTimeMillis() - currentTime > KexTestGenerator.KEX_EXECUTION_TIMEOUT
);

// Compute the fitness for each population member, update the coverage information and the
// set of goals to cover. Finally, update the archive.
Expand All @@ -247,7 +213,6 @@ public void generateSolution() {
int iterations = 0;
int kexIterations = 0;
int kexImproveIterations = 0;
kexTestGenerator = new KexTestGenerator();
while (!isFinished() && getNumberOfUncoveredGoals() > 0) {
wasTargeted = false;
long oldCoverage = getLineCoverage();
Expand All @@ -274,7 +239,6 @@ public void generateSolution() {

if (oldCoverage == newCoverage) {
if (wasTargeted) {
// maxGenerateTests *= 2;
maxStallLen *= 2;
} else {
stallLen++;
Expand Down
80 changes: 46 additions & 34 deletions client/src/main/java/org/evosuite/testcase/TestChromosome.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,16 @@
*/
package org.evosuite.testcase;

import kotlin.jvm.functions.Function0;
import org.evosuite.Properties;
import org.evosuite.coverage.mutation.Mutation;
import org.evosuite.coverage.mutation.MutationExecutionResult;
import org.evosuite.ga.ConstructionFailedException;
import org.evosuite.ga.SecondaryObjective;
import org.evosuite.ga.localsearch.LocalSearchObjective;
import org.evosuite.ga.operators.mutation.MutationHistory;
import org.evosuite.kex.KexTestGenerator;
import org.evosuite.runtime.util.AtMostOnceLogger;
import org.evosuite.setup.TestCluster;
import org.evosuite.symbolic.BranchCondition;
import org.evosuite.symbolic.ConcolicExecution;
import org.evosuite.symbolic.ConcolicMutation;
import org.evosuite.testcase.execution.ExecutionResult;
import org.evosuite.testcase.localsearch.TestCaseLocalSearch;
import org.evosuite.testcase.statements.FunctionalMockStatement;
Expand All @@ -41,7 +39,6 @@
import org.evosuite.testsuite.TestSuiteChromosome;
import org.evosuite.testsuite.TestSuiteFitnessFunction;
import org.evosuite.utils.Randomness;
import org.evosuite.utils.generic.GenericAccessibleObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -55,8 +52,6 @@
import java.util.stream.IntStream;
import java.util.stream.Stream;

import static java.util.stream.Collectors.toCollection;

/**
* Chromosome representation of test cases
*
Expand All @@ -65,6 +60,38 @@
*/
public final class TestChromosome extends AbstractTestChromosome<TestChromosome> {

public static int numberOfMutations = 0;
public static int numberOfCollected = 0;
public static int numberOfTimeouts = 0;
public static int numberOfConcolic = 0;
public static int numberOfSuccessConcolic = 0;
public static int totalAmountOfTimeConcolic = 0;
public static int numberOfIrreversibleConcolic = 0;
public static int numberOfCovered = 0;
public static int[] numberOfUnsupported = {0, 0};
public static int numberOfUnsat = 0;
public static int numberOfSat = 0;
public static int timeOfUnsat = 0;
public static int timeOfSat = 0;
public static int numberOfKexCalls = 0;
public static boolean enableConcolic = false;
public static void reset() {
numberOfCovered = 0;
numberOfCollected = 0;
numberOfTimeouts = 0;
numberOfMutations = 0;
numberOfConcolic = 0;
numberOfSuccessConcolic = 0;
totalAmountOfTimeConcolic = 0;
numberOfIrreversibleConcolic = 0;
numberOfKexCalls = 0;
numberOfUnsupported = new int[]{0, 0};
numberOfUnsat = 0;
numberOfSat = 0;
timeOfUnsat = 0;
timeOfSat = 0;
}

private static final long serialVersionUID = 7532366007973252782L;

private static final Logger logger = LoggerFactory.getLogger(TestChromosome.class);
Expand Down Expand Up @@ -284,6 +311,8 @@ public boolean localSearch(LocalSearchObjective<TestChromosome> objective) {
*/
@Override
public void mutate() {
numberOfMutations += 1;

boolean changed = false;
mutationHistory.clear();

Expand Down Expand Up @@ -462,13 +491,17 @@ private boolean mutationChange() {
double pl = 1d / (lastMutatableStatement + 1);
TestFactory testFactory = TestFactory.getInstance();

if (Randomness.nextDouble() < Properties.CONCOLIC_MUTATION) {
if (Randomness.nextDouble() < Properties.CONCOLIC_MUTATION && enableConcolic) {
numberOfConcolic += 1;
long time = System.currentTimeMillis();
try {
changed = mutationConcolic();
} catch (Exception exc) {
logger.warn("Encountered exception when trying to use concolic mutation: {}", exc.getMessage());
logger.debug("Detailed exception trace: ", exc);
}
totalAmountOfTimeConcolic += System.currentTimeMillis() - time;
numberOfSuccessConcolic += changed ? 1 : 0;
}

if (!changed) {
Expand Down Expand Up @@ -548,32 +581,11 @@ public boolean mutationInsert() {
*/
private boolean mutationConcolic() {
logger.info("Applying DSE mutation");
// concolicExecution = new ConcolicExecution();

// Apply DSE to gather constraints
List<BranchCondition> branches = ConcolicExecution.getSymbolicPath(this);
logger.debug("Conditions: " + branches);
if (branches.isEmpty())
return false;

boolean mutated = false;

List<BranchCondition> targetBranches = branches.stream()
.filter(b -> TestCluster.isTargetClassName(b.getClassName()))
.collect(toCollection(ArrayList::new));

// Select random branch
List<BranchCondition> bs = targetBranches.isEmpty() ? branches : targetBranches;
BranchCondition branch = Randomness.choice(bs);

logger.debug("Trying to negate branch " + branch.getInstructionIndex()
+ " - have " + targetBranches.size() + "/" + branches.size()
+ " target branches");

// Try to solve negated constraint
TestCase newTest = ConcolicMutation.negateCondition(branches, branch, test);
long currentTime = System.currentTimeMillis();
Function0<Boolean> stoppingCondition = () -> System.currentTimeMillis() - currentTime >
KexTestGenerator.KEX_GENERATION_TIMEOUT;

// If successful, add resulting test to test suite
TestCase newTest = KexTestGenerator.INSTANCE.generateTest(this, stoppingCondition);
if (newTest != null) {
logger.debug("CONCOLIC: Created new test");
// logger.info(newTest.toCode());
Expand All @@ -586,7 +598,7 @@ private boolean mutationConcolic() {
logger.debug("CONCOLIC: Did not create new test");
}

return mutated;
return newTest != null;
}

/**
Expand Down
18 changes: 18 additions & 0 deletions client/src/main/kotlin/org/evosuite/kex/ClauseSelector.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.evosuite.kex

import org.vorpal.research.kex.asm.analysis.util.SuspendableIterator
import org.vorpal.research.kex.trace.symbolic.Clause
import org.vorpal.research.kex.trace.symbolic.PathClause
import org.vorpal.research.kfg.ir.Method
import org.vorpal.research.kfg.ir.value.instruction.Instruction

interface ClauseSelector : SuspendableIterator<Pair<List<Clause>?, List<PathClause>?>> {
val targets: Set<Method>

suspend fun isEmpty(): Boolean
suspend fun addExecutionTrace(
trace: List<Instruction>
)

fun reverse(pathClause: PathClause): PathClause?
}
Loading