Skip to content

Commit

Permalink
add Flacoco as fault localization engine (#220)
Browse files Browse the repository at this point in the history
  • Loading branch information
andre15silva authored Nov 18, 2021
1 parent f77a01a commit 1bbca81
Show file tree
Hide file tree
Showing 9 changed files with 283 additions and 26 deletions.
31 changes: 21 additions & 10 deletions nopol/pom.xml
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>fr.inria.gforge.spirals</groupId>
<artifactId>nopol</artifactId>
<groupId>fr.inria.gforge.spirals</groupId> <artifactId>nopol</artifactId>
<version>0.2-SNAPSHOT</version>
<name>Nopol</name>
<description>Java Program Repair via Conditional Expression Replacement</description>
Expand Down Expand Up @@ -44,17 +42,22 @@
<maven-jar-plugin.version>2.4</maven-jar-plugin.version>
<maven-release-plugin.version>2.5.1</maven-release-plugin.version>
<maven-resources-plugin.version>2.6</maven-resources-plugin.version>
<maven-jacoco-plugin.version>0.8.3</maven-jacoco-plugin.version>
<maven-jacoco-plugin.version>0.8.7</maven-jacoco-plugin.version>
<maven-coveralls-plugin.version>4.0.0</maven-coveralls-plugin.version>

<github.global.server>github</github.global.server>
</properties>

<dependencies>
<dependency>
<groupId>com.github.spoonlabs</groupId>
<artifactId>flacoco</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<version>4.13.2</version>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
Expand Down Expand Up @@ -108,7 +111,7 @@
<dependency>
<groupId>fr.inria.gforge.spoon</groupId>
<artifactId>spoon-core</artifactId>
<version>7.5.0-SNAPSHOT</version>
<version>9.1.0</version>
</dependency>
<dependency>
<groupId>org.smtlib</groupId>
Expand Down Expand Up @@ -276,7 +279,7 @@
<artifactId>maven-surefire-plugin</artifactId>
<version>2.14.1</version>
<configuration>
<argLine>${argLine}</argLine>
<argLine>-Xms2048m -Xmx2048m</argLine>
</configuration>
</plugin>
<plugin>
Expand Down Expand Up @@ -397,17 +400,25 @@
<url>http://sachaproject.gforge.inria.fr/repositories/releases/</url>
<snapshots/>
</repository>

<repository>
<id>gforge.inria.fr-snapshot</id>
<name>Maven Repository for Spoon Snapshot</name>
<url>http://maven.inria.fr/artifactory/spoon-public-snapshot/</url>
<id>spoon-snapshot</id>
<name>Maven Repository for Spoon Snapshots</name>
<url>https://repository.ow2.org/nexus/content/repositories/snapshots/</url>
<snapshots/>
</repository>

<repository>
<id>tdurieux.github.io/maven-repository/snapshots/</id>
<name>tdurieux.github.io maven-repository</name>
<url>https://tdurieux.github.io/maven-repository/snapshots/</url>
</repository>
<repository>
<id>snapshots-repo</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases><enabled>false</enabled></releases>
<snapshots><enabled>true</enabled></snapshots>
</repository>
</repositories>

<distributionManagement>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package fr.inria.lille.localization;

import fr.inria.lille.localization.metric.Metric;
import fr.inria.lille.localization.metric.Ochiai;
import fr.inria.lille.repair.common.config.NopolContext;
import fr.inria.lille.repair.nopol.SourceLocation;
import fr.spoonlabs.flacoco.api.result.Location;
import fr.spoonlabs.flacoco.core.config.FlacocoConfig;
import fr.spoonlabs.flacoco.core.coverage.CoverageMatrix;
import fr.spoonlabs.flacoco.core.coverage.CoverageRunner;
import fr.spoonlabs.flacoco.core.coverage.framework.JUnit4Strategy;
import fr.spoonlabs.flacoco.core.coverage.framework.JUnit5Strategy;
import fr.spoonlabs.flacoco.core.test.TestContext;
import fr.spoonlabs.flacoco.core.test.TestDetector;
import fr.spoonlabs.flacoco.core.test.method.TestMethod;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import spoon.Launcher;
import spoon.reflect.CtModel;
import spoon.reflect.declaration.CtTypeInformation;
import xxl.java.junit.TestCase;

import java.io.File;
import java.net.URL;
import java.util.*;
import java.util.stream.Collectors;

public class FlacocoFaultLocalizer implements FaultLocalizer {

private Map<SourceLocation, List<TestResult>> testListPerStatement = new HashMap<>();

private List<StatementSourceLocation> statementSourceLocations = new ArrayList<>();

public FlacocoFaultLocalizer(NopolContext nopolContext, Metric metric) {
runFlacoco(nopolContext, metric);
}

public FlacocoFaultLocalizer(NopolContext nopolContext) {
this(nopolContext, new Ochiai());
}

private void runFlacoco(NopolContext nopolContext, Metric metric) {
FlacocoConfig config = new FlacocoConfig();

Launcher spoon = new Launcher();
List<String> javaSources = new ArrayList<>();
for (File file : nopolContext.getProjectSources()) {
spoon.addInputResource(file.getAbsolutePath());
javaSources.add(file.getAbsolutePath());
}
CtModel model = spoon.buildModel();

List<String> javaBin = new ArrayList<>();

// Init FlacocoConfig
config.setClasspath(Arrays.stream(nopolContext.getProjectClasspath()).map(URL::getPath)
.reduce((x, y) -> x + File.pathSeparator + y).orElse(""));
config.setJacocoIncludes(
model.getAllTypes().stream().map(CtTypeInformation::getQualifiedName).collect(Collectors.toSet()));
config.setComplianceLevel(nopolContext.getComplianceLevel());
config.setTestRunnerJVMArgs("-Xms2048m -Xmx2048m");
config.setSrcJavaDir(javaSources);

System.out.println(nopolContext);

// Set tests
TestDetector testDetector = new TestDetector(config);
List<TestContext> tests = testDetector.getTests();

for (TestContext testContext : tests) {
if (testContext.getTestFrameworkStrategy() instanceof JUnit4Strategy) {
config.setjUnit4Tests(
testContext.getTestMethods().stream()
.filter(x -> Arrays.asList(nopolContext.getProjectTests())
.contains(x.getFullyQualifiedClassName()))
.map(TestMethod::getFullyQualifiedMethodName)
.collect(Collectors.toSet())
);
}
if (testContext.getTestFrameworkStrategy() instanceof JUnit5Strategy) {
config.setjUnit5Tests(
testContext.getTestMethods().stream()
.filter(x -> Arrays.asList(nopolContext.getProjectTests())
.contains(x.getFullyQualifiedClassName()))
.map(TestMethod::getFullyQualifiedMethodName)
.collect(Collectors.toSet())
);
}
}

// Get CoverageMatrix
CoverageRunner coverageRunner = new CoverageRunner(config);
CoverageMatrix coverageMatrix = coverageRunner.getCoverageMatrix(new TestDetector(config).getTests());

for (Location location : coverageMatrix.getResultExecution().keySet()) {
SourceLocation sourceLocation = new SourceLocation(
location.getClassName(),
location.getLineNumber()
);
StatementSourceLocation statementSourceLocation = new StatementSourceLocation(metric, sourceLocation);
int ef = 0;
int ep = 0;
int nf = 0;
int np = 0;
for (TestMethod testMethod : coverageMatrix.getTests().keySet()) {
boolean iTestPassing = coverageMatrix.getTests().get(testMethod);
boolean nrExecuted = coverageMatrix.getResultExecution().get(location).contains(testMethod);
if (iTestPassing && nrExecuted) {
ep++;
} else if (!iTestPassing && nrExecuted) {
ef++;
} else if (iTestPassing && !nrExecuted) {
np++;
} else if (!iTestPassing && !nrExecuted) {
nf++;
}
}
statementSourceLocation.setEp(ep);
statementSourceLocation.setEf(ef);
statementSourceLocation.setNf(nf);
statementSourceLocation.setNp(np);

statementSourceLocations.add(statementSourceLocation);
testListPerStatement.put(
sourceLocation,
coverageMatrix.getResultExecution().get(location).stream()
.map(x -> new TestResultImpl(TestCase.from(x.getFullyQualifiedMethodName()), coverageMatrix.getTests().get(x)))
.collect(Collectors.toList())
);
}

statementSourceLocations.sort(Comparator.comparing(x -> x.getLocation().getContainingClassName()));
statementSourceLocations.sort((o1, o2) -> Integer.compare(o2.getLocation().getLineNumber(), o1.getLocation().getLineNumber()));
statementSourceLocations.sort((o1, o2) -> Double.compare(o2.getSuspiciousness(), o1.getSuspiciousness()));

LinkedHashMap<SourceLocation, List<fr.inria.lille.localization.TestResult>> map = new LinkedHashMap<>();
for (StatementSourceLocation source : statementSourceLocations) {
map.put(source.getLocation(), testListPerStatement.get(source.getLocation()));
}
testListPerStatement = map;
}

@Override
public Map<SourceLocation, List<TestResult>> getTestListPerStatement() {
return testListPerStatement;
}

@Override
public List<? extends StatementSourceLocation> getStatements() {
return statementSourceLocations;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,12 @@ public StatementSourceLocation(Metric metric, SourceLocation location) {
public SourceLocation getLocation() {
return location;
}

@Override
public String toString() {
return "StatementSourceLocation{" +
"suspiciousness=" + getSuspiciousness() +
", location=" + location +
'}';
}
}
7 changes: 5 additions & 2 deletions nopol/src/main/java/fr/inria/lille/repair/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,11 @@ private static NopolContext.NopolLocalizer strToLocalizer(String str) {
return NopolContext.NopolLocalizer.GZOLTAR;
} else if (str.equals("dumb")) {
return NopolContext.NopolLocalizer.DUMB;
} else
} else if (str.equals("cocospoon")) {
return NopolContext.NopolLocalizer.COCOSPOON;
} else /* it can only be flacoco */{
return NopolContext.NopolLocalizer.FLACOCO;
}
}

private void initJSAP() throws JSAPException {
Expand Down Expand Up @@ -365,7 +368,7 @@ private void initJSAP() throws JSAPException {
faultLocalization.setAllowMultipleDeclarations(false);
faultLocalization.setLongFlag("flocal");
faultLocalization.setShortFlag('z');
faultLocalization.setUsageName(" cocospoon|dumb|gzoltar");//TODO ADD PARAMETIZED FAULT LOCALIZER
faultLocalization.setUsageName("cocospoon|dumb|gzoltar|flacoco");//TODO ADD PARAMETIZED FAULT LOCALIZER
faultLocalization.setStringParser(JSAP.STRING_PARSER);
faultLocalization.setDefault(NopolContext.DEFAULT_FAULT_LOCALIZER.name().toLowerCase());
faultLocalization.setHelp("Define the fault localizer to be used.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ public enum NopolSolver {
public enum NopolLocalizer {
DUMB,
GZOLTAR,
COCOSPOON
COCOSPOON,
FLACOCO
}

private final String filename = "default-nopol-config.ini";
Expand Down Expand Up @@ -102,7 +103,7 @@ public enum NopolLocalizer {
private NopolSynthesis synthesis = NopolSynthesis.SMT;
private NopolOracle oracle = NopolOracle.ANGELIC;
private NopolSolver solver = NopolSolver.Z3;
public final static NopolLocalizer DEFAULT_FAULT_LOCALIZER = NopolLocalizer.GZOLTAR;
public final static NopolLocalizer DEFAULT_FAULT_LOCALIZER = NopolLocalizer.FLACOCO;
private NopolLocalizer localizer = DEFAULT_FAULT_LOCALIZER;


Expand Down
9 changes: 3 additions & 6 deletions nopol/src/main/java/fr/inria/lille/repair/nopol/NoPol.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,7 @@
import fr.inria.lille.commons.spoon.SpoonedProject;
import fr.inria.lille.commons.synthesis.ConstraintBasedSynthesis;
import fr.inria.lille.commons.synthesis.operator.Operator;
import fr.inria.lille.localization.CocoSpoonBasedSpectrumBasedFaultLocalizer;
import fr.inria.lille.localization.DumbFaultLocalizerImpl;
import fr.inria.lille.localization.FaultLocalizer;
import fr.inria.lille.localization.GZoltarFaultLocalizer;
import fr.inria.lille.localization.TestResult;
import fr.inria.lille.localization.*;
import fr.inria.lille.localization.metric.Ochiai;
import fr.inria.lille.repair.common.BottomTopURLClassLoader;
import fr.inria.lille.repair.common.config.NopolContext;
Expand Down Expand Up @@ -180,8 +176,9 @@ private FaultLocalizer createLocalizer() {
return new DumbFaultLocalizerImpl(this.nopolContext);
case COCOSPOON: // default
return new CocoSpoonBasedSpectrumBasedFaultLocalizer(this.nopolContext, new Ochiai());
case FLACOCO:
default:
return GZoltarFaultLocalizer.createInstance(this.nopolContext);
return new FlacocoFaultLocalizer(this.nopolContext);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package fr.inria.lille.localization;

import fr.inria.lille.localization.metric.Ochiai;
import fr.inria.lille.repair.common.config.NopolContext;
import fr.inria.lille.repair.nopol.SourceLocation;
import org.junit.Test;

import java.io.File;
import java.net.URL;
import java.util.List;
import java.util.Map;

import static gov.nasa.jpf.util.test.TestJPF.assertEquals;
import static gov.nasa.jpf.util.test.TestJPF.assertTrue;

public class FlacocoLocalizerTest {

@Test
public void testOchiaiFlacocoLocalizer() throws Exception {

/* test OchiaiCoCoSpoonLocalizer : the SourceLocation must be sorted following the Ochiai metric */

File[] sources = new File[]{new File("../test-projects/src/main/java/nopol_examples/nopol_example_1/NopolExample.java")};
URL[] classpath = new URL[]{
new File("../test-projects/target/classes").toURI().toURL(),
new File("../test-projects/target/test-classes").toURI().toURL()
};
String[] testClasses = new String[]{"nopol_examples.nopol_example_1.NopolExampleTest"};
FlacocoFaultLocalizer localizer = new FlacocoFaultLocalizer(new NopolContext(sources, classpath, testClasses), new Ochiai());

Map<SourceLocation, List<TestResult>> executedSourceLocationPerTest = localizer.getTestListPerStatement();
assertEquals(10, executedSourceLocationPerTest.keySet().size());

for (StatementSourceLocation sourceLocation : localizer.getStatements()) {
System.out.println(sourceLocation);
}

SourceLocation sourceLocation1 = new SourceLocation("nopol_examples.nopol_example_1.NopolExample", 27);
SourceLocation sourceLocation2 = new SourceLocation("nopol_examples.nopol_example_1.NopolExample", 16);
SourceLocation sourceLocation3 = new SourceLocation("nopol_examples.nopol_example_1.NopolExample", 15);
SourceLocation sourceLocation4 = new SourceLocation("nopol_examples.nopol_example_1.NopolExample", 18);
SourceLocation sourceLocation5 = new SourceLocation("nopol_examples.nopol_example_1.NopolExample", 12);
SourceLocation sourceLocation6 = new SourceLocation("nopol_examples.nopol_example_1.NopolExample", 23);
SourceLocation sourceLocation7 = new SourceLocation("nopol_examples.nopol_example_1.NopolExample", 25);
SourceLocation sourceLocation8 = new SourceLocation("nopol_examples.nopol_example_1.NopolExample", 13);
SourceLocation sourceLocation9 = new SourceLocation("nopol_examples.nopol_example_1.NopolExample", 24);
SourceLocation sourceLocation10 = new SourceLocation("nopol_examples.nopol_example_1.NopolExample", 21);

assertTrue(executedSourceLocationPerTest.keySet().contains(sourceLocation1));
assertTrue(executedSourceLocationPerTest.keySet().contains(sourceLocation2));
assertTrue(executedSourceLocationPerTest.keySet().contains(sourceLocation3));
assertTrue(executedSourceLocationPerTest.keySet().contains(sourceLocation4));
assertTrue(executedSourceLocationPerTest.keySet().contains(sourceLocation5));
assertTrue(executedSourceLocationPerTest.keySet().contains(sourceLocation6));
assertTrue(executedSourceLocationPerTest.keySet().contains(sourceLocation7));
assertTrue(executedSourceLocationPerTest.keySet().contains(sourceLocation8));
assertTrue(executedSourceLocationPerTest.keySet().contains(sourceLocation9));
assertTrue(executedSourceLocationPerTest.keySet().contains(sourceLocation10));

List<? extends StatementSourceLocation> sortedStatements = localizer.getStatements();

assertEquals(0.534, sortedStatements.get(0).getSuspiciousness(), 10E-3);
assertEquals(0.5, sortedStatements.get(1).getSuspiciousness(), 10E-3);
assertEquals(0.471, sortedStatements.get(2).getSuspiciousness(), 10E-3);
assertEquals(0.471, sortedStatements.get(3).getSuspiciousness(), 10E-3);
assertEquals(0.471, sortedStatements.get(4).getSuspiciousness(), 10E-3);
assertEquals(0.471, sortedStatements.get(5).getSuspiciousness(), 10E-3);
assertEquals(0.471, sortedStatements.get(6).getSuspiciousness(), 10E-3);
assertEquals(0.471, sortedStatements.get(7).getSuspiciousness(), 10E-3);
assertEquals(0.0, sortedStatements.get(8).getSuspiciousness(), 10E-3);
assertEquals(0.0, sortedStatements.get(9).getSuspiciousness(), 10E-3);

assertEquals(sourceLocation2, sortedStatements.get(0).getLocation());
}
}
Loading

0 comments on commit 1bbca81

Please sign in to comment.