Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add Flacoco as fault localization engine #220

Merged
merged 23 commits into from
Nov 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
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
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