-
-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add Flacoco as fault localization engine (#220)
- Loading branch information
1 parent
f77a01a
commit 1bbca81
Showing
9 changed files
with
283 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
153 changes: 153 additions & 0 deletions
153
nopol/src/main/java/fr/inria/lille/localization/FlacocoFaultLocalizer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
nopol/src/test/java/fr/inria/lille/localization/FlacocoLocalizerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()); | ||
} | ||
} |
Oops, something went wrong.