diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/incremental/IncrementalAnalyser.java b/pitest-entry/src/main/java/org/pitest/mutationtest/incremental/IncrementalAnalyser.java index 02a129b70..3b13ebd2e 100644 --- a/pitest-entry/src/main/java/org/pitest/mutationtest/incremental/IncrementalAnalyser.java +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/incremental/IncrementalAnalyser.java @@ -43,8 +43,7 @@ public IncrementalAnalyser(CodeHistory history, CoverageDatabase coverage, boole } @Override - public Collection analyse( - final Collection mutation) { + public Collection analyse(Collection mutation) { final List mrs = new ArrayList<>( mutation.size()); @@ -81,12 +80,14 @@ private void logTotals() { LOG.info("Incremental analysis reduced number of mutations by " + numberOfReducedMutations ); } - private MutationResult analyseFromHistory(final MutationDetails each, - final MutationStatusTestPair mutationStatusTestPair) { + private MutationResult analyseFromHistory(MutationDetails each, MutationStatusTestPair mutationStatusTestPair) { final ClassName clazz = each.getClassName(); if (this.history.hasClassChanged(clazz)) { + if (mutationStatusTestPair.getKillingTest().isPresent()) { + return prioritiseLastTest(each, mutationStatusTestPair.getKillingTest().get()); + } return analyseFromScratch(each); } @@ -103,6 +104,10 @@ private MutationResult analyseFromHistory(final MutationDetails each, DetectionStatus.KILLED, killingTestNames, mutationStatusTestPair.getSucceedingTests()); + } else { + if (mutationStatusTestPair.getKillingTest().isPresent()) { + return prioritiseLastTest(each, mutationStatusTestPair.getKillingTest().get()); + } } } @@ -114,7 +119,6 @@ private MutationResult analyseFromHistory(final MutationDetails each, return analyseFromScratch(each); } - private List filterUnchangedKillingTests(final MutationDetails each, final MutationStatusTestPair mutationStatusTestPair) { @@ -134,6 +138,25 @@ private static Predicate isAKillingTestFor(final MutationStatusTestPai return a -> killingTestNames.contains(a.getName()); } + private MutationResult prioritiseLastTest(MutationDetails mutation, String killingTestName) { + List mutableOrderedTestList = mutation.getTestsInOrder(); + + Optional maybeKillingTest = mutation.getTestsInOrder().stream() + .filter(ti -> ti.getName().equals(killingTestName)) + .findFirst(); + + // last killing test is no longer available + if (!maybeKillingTest.isPresent()) { + return analyseFromScratch(mutation); + } + + // hack the ordered list to put the killing test at the front + mutableOrderedTestList.remove(maybeKillingTest.get()); + mutableOrderedTestList.add(0, maybeKillingTest.get()); + + return analyseFromScratch(mutation); + } + private MutationResult analyseFromScratch(final MutationDetails mutation) { return makeResult(mutation, DetectionStatus.NOT_STARTED); } diff --git a/pitest-entry/src/test/java/org/pitest/mutationtest/incremental/IncrementalAnalyserTest.java b/pitest-entry/src/test/java/org/pitest/mutationtest/incremental/IncrementalAnalyserTest.java index 573a845db..401774ad3 100644 --- a/pitest-entry/src/test/java/org/pitest/mutationtest/incremental/IncrementalAnalyserTest.java +++ b/pitest-entry/src/test/java/org/pitest/mutationtest/incremental/IncrementalAnalyserTest.java @@ -19,6 +19,7 @@ import java.math.BigInteger; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Optional; @@ -29,6 +30,7 @@ import org.hamcrest.Description; import org.hamcrest.Matcher; +import org.hamcrest.Matchers; import org.hamcrest.TypeSafeDiagnosingMatcher; import org.junit.After; import org.junit.Before; @@ -241,6 +243,54 @@ public void shouldStartPreviousKilledMutationsAtAStatusOfNotStartedWhenTestHasCh )); } + @Test + public void prioritisesLastKillingTestWhenClassHasChanged() { + + final String killingTest = "fooTest"; + setHistoryForAllMutationsTo(DetectionStatus.KILLED, killingTest); + Collection tests = Arrays.asList(testNamed("one"), testNamed("two"), testNamed(killingTest), testNamed("three")); + + final MutationDetails md = makeMutation("foo"); + md.addTestsInOrder(tests); + + when(this.coverage.getTestsForClass(any(ClassName.class))) + .thenReturn(tests); + when(this.history.hasClassChanged(ClassName.fromString("clazz"))).thenReturn( + true); + when(this.history.hasClassChanged(ClassName.fromString("TEST_CLASS"))) + .thenReturn(false); + + MutationResult actual = this.testee.analyse(singletonList(md)).stream() + .findFirst().get(); + + assertThat(actual.getDetails().getTestsInOrder().get(0), Matchers.equalTo(testNamed(killingTest))); + assertThat(actual.getDetails().getTestsInOrder(), Matchers.hasSize(4)); + } + + @Test + public void prioritisesLastKillingTestWhenTestHasChanged() { + + final String killingTest = "fooTest"; + setHistoryForAllMutationsTo(DetectionStatus.KILLED, killingTest); + Collection tests = Arrays.asList(testNamed("one"), testNamed("two"), testNamed(killingTest), testNamed("three")); + + final MutationDetails md = makeMutation("foo"); + md.addTestsInOrder(tests); + + when(this.coverage.getTestsForClass(any(ClassName.class))) + .thenReturn(tests); + when(this.history.hasClassChanged(ClassName.fromString("clazz"))).thenReturn( + false); + when(this.history.hasClassChanged(ClassName.fromString("TEST_CLASS"))) + .thenReturn(true); + + MutationResult actual = this.testee.analyse(singletonList(md)).stream() + .findFirst().get(); + + assertThat(actual.getDetails().getTestsInOrder().get(0), Matchers.equalTo(testNamed(killingTest))); + assertThat(actual.getDetails().getTestsInOrder(), Matchers.hasSize(4)); + } + @Test public void assessMultipleMutationsAtATime() { final MutationDetails md1 = makeMutation("foo"); @@ -299,6 +349,11 @@ public void assessMultipleMutationsAtATime() { )); } + private TestInfo testNamed(String name) { + return new TestInfo( + "TEST_CLASS", name, 0, Optional.empty(), 0); + } + private Matcher withStatus(final DetectionStatus status) { return new TypeSafeDiagnosingMatcher() {