diff --git a/nopol/pom.xml b/nopol/pom.xml index b193347b..a6803ba4 100644 --- a/nopol/pom.xml +++ b/nopol/pom.xml @@ -1,9 +1,7 @@ 4.0.0 - - fr.inria.gforge.spirals - nopol +fr.inria.gforge.spirals nopol 0.2-SNAPSHOT Nopol Java Program Repair via Conditional Expression Replacement @@ -44,17 +42,22 @@ 2.4 2.5.1 2.6 - 0.8.3 + 0.8.7 4.0.0 github + + com.github.spoonlabs + flacoco + 1.0.1 + junit junit - 4.13.1 + 4.13.2 org.reflections @@ -108,7 +111,7 @@ fr.inria.gforge.spoon spoon-core - 7.5.0-SNAPSHOT + 9.1.0 org.smtlib @@ -276,7 +279,7 @@ maven-surefire-plugin 2.14.1 - ${argLine} + -Xms2048m -Xmx2048m @@ -397,17 +400,25 @@ http://sachaproject.gforge.inria.fr/repositories/releases/ + - gforge.inria.fr-snapshot - Maven Repository for Spoon Snapshot - http://maven.inria.fr/artifactory/spoon-public-snapshot/ + spoon-snapshot + Maven Repository for Spoon Snapshots + https://repository.ow2.org/nexus/content/repositories/snapshots/ + tdurieux.github.io/maven-repository/snapshots/ tdurieux.github.io maven-repository https://tdurieux.github.io/maven-repository/snapshots/ + + snapshots-repo + https://oss.sonatype.org/content/repositories/snapshots + false + true + diff --git a/nopol/src/main/java/fr/inria/lille/localization/FlacocoFaultLocalizer.java b/nopol/src/main/java/fr/inria/lille/localization/FlacocoFaultLocalizer.java new file mode 100644 index 00000000..7b68e479 --- /dev/null +++ b/nopol/src/main/java/fr/inria/lille/localization/FlacocoFaultLocalizer.java @@ -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> testListPerStatement = new HashMap<>(); + + private List 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 javaSources = new ArrayList<>(); + for (File file : nopolContext.getProjectSources()) { + spoon.addInputResource(file.getAbsolutePath()); + javaSources.add(file.getAbsolutePath()); + } + CtModel model = spoon.buildModel(); + + List 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 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> map = new LinkedHashMap<>(); + for (StatementSourceLocation source : statementSourceLocations) { + map.put(source.getLocation(), testListPerStatement.get(source.getLocation())); + } + testListPerStatement = map; + } + + @Override + public Map> getTestListPerStatement() { + return testListPerStatement; + } + + @Override + public List getStatements() { + return statementSourceLocations; + } + +} diff --git a/nopol/src/main/java/fr/inria/lille/localization/StatementSourceLocation.java b/nopol/src/main/java/fr/inria/lille/localization/StatementSourceLocation.java index 052049e8..3dc89645 100644 --- a/nopol/src/main/java/fr/inria/lille/localization/StatementSourceLocation.java +++ b/nopol/src/main/java/fr/inria/lille/localization/StatementSourceLocation.java @@ -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 + + '}'; + } } diff --git a/nopol/src/main/java/fr/inria/lille/repair/Main.java b/nopol/src/main/java/fr/inria/lille/repair/Main.java index 5f224bfb..60e388b8 100644 --- a/nopol/src/main/java/fr/inria/lille/repair/Main.java +++ b/nopol/src/main/java/fr/inria/lille/repair/Main.java @@ -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 { @@ -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."); diff --git a/nopol/src/main/java/fr/inria/lille/repair/common/config/NopolContext.java b/nopol/src/main/java/fr/inria/lille/repair/common/config/NopolContext.java index fff825b6..17897f95 100644 --- a/nopol/src/main/java/fr/inria/lille/repair/common/config/NopolContext.java +++ b/nopol/src/main/java/fr/inria/lille/repair/common/config/NopolContext.java @@ -53,7 +53,8 @@ public enum NopolSolver { public enum NopolLocalizer { DUMB, GZOLTAR, - COCOSPOON + COCOSPOON, + FLACOCO } private final String filename = "default-nopol-config.ini"; @@ -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; diff --git a/nopol/src/main/java/fr/inria/lille/repair/nopol/NoPol.java b/nopol/src/main/java/fr/inria/lille/repair/nopol/NoPol.java index 0523a910..98965d69 100644 --- a/nopol/src/main/java/fr/inria/lille/repair/nopol/NoPol.java +++ b/nopol/src/main/java/fr/inria/lille/repair/nopol/NoPol.java @@ -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; @@ -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); } } diff --git a/nopol/src/test/java/fr/inria/lille/localization/FlacocoLocalizerTest.java b/nopol/src/test/java/fr/inria/lille/localization/FlacocoLocalizerTest.java new file mode 100644 index 00000000..4857243d --- /dev/null +++ b/nopol/src/test/java/fr/inria/lille/localization/FlacocoLocalizerTest.java @@ -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> 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 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()); + } +} diff --git a/nopol/src/test/java/fr/inria/lille/repair/nopol/NopolTest.java b/nopol/src/test/java/fr/inria/lille/repair/nopol/NopolTest.java index 828f7abd..cb34759a 100644 --- a/nopol/src/test/java/fr/inria/lille/repair/nopol/NopolTest.java +++ b/nopol/src/test/java/fr/inria/lille/repair/nopol/NopolTest.java @@ -132,7 +132,8 @@ public void example7Fix() { "(intermediaire == 0) && (2 < a)", "(intermediaire == 0) && ((a) != (2))", "((2) != (a)) && (intermediaire == 0)", - "(intermediaire == 0) && (3 < a)" + "(intermediaire == 0) && (3 < a)", + "(((2) != (a)) && (!(0 < intermediaire))) || (2 == intermediaire)" ); } diff --git a/nopol/src/test/java/fr/inria/lille/repair/nopol/TseEvaluationTest.java b/nopol/src/test/java/fr/inria/lille/repair/nopol/TseEvaluationTest.java index d053088c..a6fa5514 100644 --- a/nopol/src/test/java/fr/inria/lille/repair/nopol/TseEvaluationTest.java +++ b/nopol/src/test/java/fr/inria/lille/repair/nopol/TseEvaluationTest.java @@ -6,6 +6,7 @@ import fr.inria.lille.repair.common.synth.RepairType; import org.json.JSONObject; import org.json.JSONTokener; +import org.junit.Ignore; import org.junit.Test; import java.io.File; @@ -24,7 +25,11 @@ public boolean testShouldBeRun() { return true; } - public void testTSEBug(String bug_id) throws Exception { + public void testTSEBug(String bud_id) throws Exception { + testTSEBug(bud_id, NopolContext.NopolLocalizer.FLACOCO); + } + + public void testTSEBug(String bug_id, NopolContext.NopolLocalizer localizer) throws Exception { String folder = "unknown"; if (bug_id.startsWith("cm") || bug_id.startsWith("pm")) { folder = "math"; @@ -64,12 +69,12 @@ public void testTSEBug(String bug_id) throws Exception { } nopolContext.setProjectClasspath(cp); - //nopolContext.setLocalizer(NopolContext.NopolLocalizer.COCOSPOON); nopolContext.setType(RepairType.PRECONDITION); if ("condition".equals(root.getString("type"))) { nopolContext.setType(RepairType.CONDITIONAL); } SolverFactory.setSolver("z3", TestUtility.solverPath); + nopolContext.setLocalizer(localizer); NoPol nopol = new NoPol(nopolContext); NopolResult result = nopol.build(); @@ -96,11 +101,14 @@ public void test_cm4() throws Exception { if (testShouldBeRun()) testTSEBug("cm4"); } + /** + * Ignored due to issue with patch synthesis (see https://github.com/SpoonLabs/nopol/pull/220#issuecomment-925976387) + */ + @Ignore @Test(timeout = TIMEOUT) public void test_cm5() throws Exception { - // ignored, there is a regression in Gzoltar which crashes with NPE - // if (testShouldBeRun()) - // testTSEBug("cm5"); + if (testShouldBeRun()) + testTSEBug("cm5"); } @Test(timeout = TIMEOUT)