From d3178598af6768d7c2b50cf77528e0b837a81c99 Mon Sep 17 00:00:00 2001 From: vivganes Date: Sun, 11 Aug 2024 00:59:50 +0530 Subject: [PATCH 1/3] add "Covered by tests" list for every survived mutation in HTML report --- .../aggregate/MutationResultDataLoader.java | 5 +++- .../pitest/mutationtest/MutationResult.java | 4 ++++ .../mutationtest/MutationStatusMap.java | 24 ++++++++++++++++--- .../templates/mutation/mutation_report.st | 11 +++++++-- 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/pitest-aggregator/src/main/java/org/pitest/aggregate/MutationResultDataLoader.java b/pitest-aggregator/src/main/java/org/pitest/aggregate/MutationResultDataLoader.java index 52c4cc628..d62570693 100644 --- a/pitest-aggregator/src/main/java/org/pitest/aggregate/MutationResultDataLoader.java +++ b/pitest-aggregator/src/main/java/org/pitest/aggregate/MutationResultDataLoader.java @@ -4,6 +4,7 @@ import java.io.File; import java.io.IOException; +import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Set; @@ -51,10 +52,12 @@ private MutationResult xmlToResult(MutationXml xml) { Location location = new Location(ClassName.fromString(xml.mutatedClass), xml.mutatedMethod, xml.methodDescription); MutationIdentifier id = new MutationIdentifier(location, xml.indexes, xml.mutator); + String[] killingTests = xml.killingTest == null ? new String[0] : new String[] { xml.killingTest }; + String[] succeedingTests = xml.succeedingTests == null ? new String[0] : xml.succeedingTests.split(","); return new MutationResult(new MutationDetails(id, xml.sourceFile, xml.description, xml.lineNumber, xml.blocks), - new MutationStatusTestPair(xml.numberOfTestsRun, DetectionStatus.valueOf(xml.status), xml.killingTest)); + new MutationStatusTestPair(xml.numberOfTestsRun, DetectionStatus.valueOf(xml.status), Arrays.asList(killingTests), Arrays.asList(succeedingTests))); } } diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/MutationResult.java b/pitest-entry/src/main/java/org/pitest/mutationtest/MutationResult.java index c0b62c23b..ce3593e09 100644 --- a/pitest-entry/src/main/java/org/pitest/mutationtest/MutationResult.java +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/MutationResult.java @@ -66,6 +66,10 @@ public String getKillingTestDescription() { return getKillingTest().orElse("none"); } + public Boolean getSurvived() { + return this.status.getStatus() == DetectionStatus.SURVIVED; + } + @Override public int hashCode() { return Objects.hash(details, status); diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/MutationStatusMap.java b/pitest-entry/src/main/java/org/pitest/mutationtest/MutationStatusMap.java index e086342b2..25c03c7b4 100644 --- a/pitest-entry/src/main/java/org/pitest/mutationtest/MutationStatusMap.java +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/MutationStatusMap.java @@ -15,18 +15,21 @@ package org.pitest.mutationtest; import static org.pitest.functional.prelude.Prelude.putToMap; +import static org.pitest.mutationtest.DetectionStatus.SURVIVED; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Set; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map.Entry; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; +import org.pitest.coverage.TestInfo; import org.pitest.functional.FCollection; import org.pitest.mutationtest.engine.MutationDetails; @@ -41,9 +44,24 @@ public void setStatusForMutation(final MutationDetails mutation, public void setStatusForMutation(final MutationDetails mutation, final MutationStatusTestPair status) { - this.mutationMap.put(mutation, status); + MutationStatusTestPair finalStatus = status; + if (status.getStatus().equals(SURVIVED)) { + + List testsInOrder = mutation.getTestsInOrder(); + List passingTests = new ArrayList<>(); + for (TestInfo test : testsInOrder) { + passingTests.add(test.getName()); + } + finalStatus = new MutationStatusTestPair(status.getNumberOfTestsRun(), + status.getStatus(), + status.getKillingTests(), + passingTests); + + } + this.mutationMap.put(mutation, finalStatus); } + public void setStatusForMutations( final Collection mutations, final DetectionStatus status) { mutations.forEach(putToMap(this.mutationMap, MutationStatusTestPair.notAnalysed(0, status))); diff --git a/pitest-html-report/src/main/resources/templates/mutation/mutation_report.st b/pitest-html-report/src/main/resources/templates/mutation/mutation_report.st index 2336aa612..7faae3549 100644 --- a/pitest-html-report/src/main/resources/templates/mutation/mutation_report.st +++ b/pitest-html-report/src/main/resources/templates/mutation/mutation_report.st @@ -11,7 +11,7 @@ -$sourceFile.lines:{ line | +$sourceFile.lines:{ line | }$ From 25a84607c6dde708b7d498fdcc176246b007bbe9 Mon Sep 17 00:00:00 2001 From: vivganes Date: Tue, 13 Aug 2024 06:40:09 +0530 Subject: [PATCH 2/3] add tests --- .../mutationtest/MutationStatusMapTest.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/pitest-entry/src/test/java/org/pitest/mutationtest/MutationStatusMapTest.java b/pitest-entry/src/test/java/org/pitest/mutationtest/MutationStatusMapTest.java index 876089cac..f82d34022 100644 --- a/pitest-entry/src/test/java/org/pitest/mutationtest/MutationStatusMapTest.java +++ b/pitest-entry/src/test/java/org/pitest/mutationtest/MutationStatusMapTest.java @@ -9,9 +9,13 @@ import java.util.Arrays; import java.util.Collections; +import java.util.Optional; +import com.google.common.collect.Lists; import org.junit.Before; import org.junit.Test; +import org.pitest.classinfo.ClassName; +import org.pitest.coverage.TestInfo; import org.pitest.mutationtest.LocationMother.MutationIdentifierBuilder; import org.pitest.mutationtest.engine.MutationDetails; @@ -23,12 +27,18 @@ public class MutationStatusMapTest { private MutationDetails detailsTwo; + private MutationDetails aSurvivedMutationDetails; + @Before public void setUp() { this.testee = new MutationStatusMap(); final MutationIdentifierBuilder id = aMutationId().withIndex(1); this.details = aMutationDetail().withId(id.withIndex(1)).build(); this.detailsTwo = aMutationDetail().withId(id.withIndex(2)).build(); + + TestInfo fooTest = new TestInfo("foo", "foo", 0, Optional.ofNullable(ClassName.fromString("com.foo")), 0); + TestInfo barTest = new TestInfo("bar", "bar", 0, Optional.ofNullable(ClassName.fromString("com.foo")), 0); + this.aSurvivedMutationDetails = aMutationDetail().withId(id.withIndex(3)).withTestsInOrder(Lists.asList(fooTest, new TestInfo[]{barTest})).build(); } @Test @@ -92,6 +102,18 @@ public void shouldCreateResultsForAllMutations() { resultTwo); } + @Test + public void shouldCreateResultsForSurvivedMutations(){ + final MutationStatusTestPair statusPairOne = new MutationStatusTestPair(42, + DetectionStatus.SURVIVED, "foo"); + this.testee.setStatusForMutation(this.aSurvivedMutationDetails, statusPairOne); + + assertEquals(DetectionStatus.SURVIVED, this.testee.createMutationResults().get(0).getStatus()); + assertThat(this.testee.createMutationResults().get(0).getKillingTests()).contains("foo"); + assertThat(this.testee.createMutationResults().get(0).getSucceedingTests()).contains("foo","bar"); + + } + @Test public void shouldSetStatusToUncoveredWhenMutationHasNoTests() { this.testee.setStatusForMutations( From 6c95a223357eb276a305d50705c04e08da7a29c5 Mon Sep 17 00:00:00 2001 From: vivganes Date: Tue, 13 Aug 2024 19:17:34 +0530 Subject: [PATCH 3/3] show coveredTests in report on click --- .../aggregate/MutationResultDataLoader.java | 2 +- .../pitest/mutationtest/MutationResult.java | 8 ++++- .../mutationtest/MutationStatusMap.java | 30 +++++------------ .../pitest/mutationtest/execute/Receive.java | 2 +- .../incremental/IncrementalAnalyser.java | 3 +- .../report/xml/XMLReportListener.java | 33 ++++++++++--------- .../mutationtest/MutationMetaDataTest.java | 2 +- .../mutationtest/MutationResultTest.java | 6 ++-- .../mutationtest/MutationStatusMapTest.java | 5 +-- .../build/MutationTestUnitTest.java | 3 +- .../HistoryResultInterceptorTest.java | 3 +- .../incremental/IncrementalAnalyserTest.java | 6 ++-- .../report/MutationTestResultMother.java | 2 +- .../report/csv/CSVReportListenerTest.java | 3 +- .../report/xml/XMLReportListenerTest.java | 7 ++-- .../templates/mutation/mutation_report.st | 8 +++-- .../resources/templates/mutation/style.css | 11 +++++++ .../report/html/ResultComparatorTest.java | 3 +- .../mutationtest/MutationStatusTestPair.java | 21 ++++++++---- .../execute/MutationTestWorker.java | 14 +++++--- .../execute/MutationTestWorkerTest.java | 10 +++--- 21 files changed, 106 insertions(+), 76 deletions(-) diff --git a/pitest-aggregator/src/main/java/org/pitest/aggregate/MutationResultDataLoader.java b/pitest-aggregator/src/main/java/org/pitest/aggregate/MutationResultDataLoader.java index d62570693..54955cb04 100644 --- a/pitest-aggregator/src/main/java/org/pitest/aggregate/MutationResultDataLoader.java +++ b/pitest-aggregator/src/main/java/org/pitest/aggregate/MutationResultDataLoader.java @@ -57,7 +57,7 @@ private MutationResult xmlToResult(MutationXml xml) { return new MutationResult(new MutationDetails(id, xml.sourceFile, xml.description, xml.lineNumber, xml.blocks), - new MutationStatusTestPair(xml.numberOfTestsRun, DetectionStatus.valueOf(xml.status), Arrays.asList(killingTests), Arrays.asList(succeedingTests))); + new MutationStatusTestPair(xml.numberOfTestsRun, DetectionStatus.valueOf(xml.status), Arrays.asList(killingTests), Arrays.asList(succeedingTests), Arrays.asList(succeedingTests))); } } diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/MutationResult.java b/pitest-entry/src/main/java/org/pitest/mutationtest/MutationResult.java index ce3593e09..9a780d183 100644 --- a/pitest-entry/src/main/java/org/pitest/mutationtest/MutationResult.java +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/MutationResult.java @@ -18,7 +18,6 @@ import java.util.Objects; import java.util.Optional; import org.pitest.mutationtest.engine.MutationDetails; - public final class MutationResult { private final MutationDetails details; @@ -30,6 +29,9 @@ public MutationResult(final MutationDetails md, this.status = status; } + public String getId() { + return this.details.getId().toString().replace(" ","-"); + } public MutationDetails getDetails() { return this.details; } @@ -46,6 +48,10 @@ public List getSucceedingTests() { return this.status.getSucceedingTests(); } + public List getCoveringTests() { + return this.status.getCoveringTests(); + } + public DetectionStatus getStatus() { return this.status.getStatus(); } diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/MutationStatusMap.java b/pitest-entry/src/main/java/org/pitest/mutationtest/MutationStatusMap.java index 25c03c7b4..7ab81fb01 100644 --- a/pitest-entry/src/main/java/org/pitest/mutationtest/MutationStatusMap.java +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/MutationStatusMap.java @@ -14,17 +14,14 @@ */ package org.pitest.mutationtest; -import static org.pitest.functional.prelude.Prelude.putToMap; -import static org.pitest.mutationtest.DetectionStatus.SURVIVED; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.ArrayList; -import java.util.Collection; import java.util.Map.Entry; +import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -44,27 +41,16 @@ public void setStatusForMutation(final MutationDetails mutation, public void setStatusForMutation(final MutationDetails mutation, final MutationStatusTestPair status) { - MutationStatusTestPair finalStatus = status; - if (status.getStatus().equals(SURVIVED)) { - - List testsInOrder = mutation.getTestsInOrder(); - List passingTests = new ArrayList<>(); - for (TestInfo test : testsInOrder) { - passingTests.add(test.getName()); - } - finalStatus = new MutationStatusTestPair(status.getNumberOfTestsRun(), - status.getStatus(), - status.getKillingTests(), - passingTests); - - } - this.mutationMap.put(mutation, finalStatus); + this.mutationMap.put(mutation, status); } - public void setStatusForMutations( final Collection mutations, final DetectionStatus status) { - mutations.forEach(putToMap(this.mutationMap, MutationStatusTestPair.notAnalysed(0, status))); + mutations.forEach(mutationDetails -> { + List coveringTests = mutationDetails.getTestsInOrder().stream().map(TestInfo::getName).collect(Collectors.toList()); + MutationStatusTestPair pair = MutationStatusTestPair.notAnalysed(0, status, coveringTests); + mutationMap.put(mutationDetails, pair); + }); } public List createMutationResults() { diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/execute/Receive.java b/pitest-entry/src/main/java/org/pitest/mutationtest/execute/Receive.java index e6c62c083..1d5446d10 100644 --- a/pitest-entry/src/main/java/org/pitest/mutationtest/execute/Receive.java +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/execute/Receive.java @@ -45,7 +45,7 @@ private void handleReport(final SafeDataInputStream is) { private void handleDescribe(final SafeDataInputStream is) { final MutationIdentifier mutation = is.read(MutationIdentifier.class); this.idMap.put(mutation, MutationStatusTestPair.notAnalysed(1, - DetectionStatus.STARTED)); + DetectionStatus.STARTED,null)); } } \ No newline at end of file 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 87f6ca191..57f0d8ef9 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 @@ -161,7 +161,8 @@ private MutationResult makeResult(final MutationDetails each, final List succeedingTests) { updatePreanalysedTotal(status); return new MutationResult(each, new MutationStatusTestPair(0, status, - killingTests, succeedingTests)); + killingTests, succeedingTests, each.getTestsInOrder().stream() + .map(TestInfo::getName).collect(Collectors.toList()))); } private void updatePreanalysedTotal(final DetectionStatus status) { diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/report/xml/XMLReportListener.java b/pitest-entry/src/main/java/org/pitest/mutationtest/report/xml/XMLReportListener.java index fb88bd96c..3340ec879 100644 --- a/pitest-entry/src/main/java/org/pitest/mutationtest/report/xml/XMLReportListener.java +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/report/xml/XMLReportListener.java @@ -14,8 +14,23 @@ */ package org.pitest.mutationtest.report.xml; +import java.io.IOException; +import java.io.Writer; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import org.apache.commons.text.StringEscapeUtils; +import org.pitest.mutationtest.ClassMutationResults; +import org.pitest.mutationtest.MutationResult; +import org.pitest.mutationtest.MutationResultListener; +import org.pitest.mutationtest.engine.MutationDetails; +import org.pitest.util.ResultOutputStrategy; +import org.pitest.util.Unchecked; + import static org.pitest.mutationtest.report.xml.Tag.block; import static org.pitest.mutationtest.report.xml.Tag.blocks; +import static org.pitest.mutationtest.report.xml.Tag.coveringTests; import static org.pitest.mutationtest.report.xml.Tag.description; import static org.pitest.mutationtest.report.xml.Tag.index; import static org.pitest.mutationtest.report.xml.Tag.indexes; @@ -30,22 +45,8 @@ import static org.pitest.mutationtest.report.xml.Tag.sourceFile; import static org.pitest.mutationtest.report.xml.Tag.succeedingTests; -import java.io.IOException; -import java.io.Writer; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; - -import org.apache.commons.text.StringEscapeUtils; -import org.pitest.mutationtest.ClassMutationResults; -import org.pitest.mutationtest.MutationResult; -import org.pitest.mutationtest.MutationResultListener; -import org.pitest.mutationtest.engine.MutationDetails; -import org.pitest.util.ResultOutputStrategy; -import org.pitest.util.Unchecked; - enum Tag { - mutation, sourceFile, mutatedClass, mutatedMethod, methodDescription, lineNumber, mutator, indexes, index, killingTest, killingTests, succeedingTests, description, blocks, block + mutation, sourceFile, mutatedClass, mutatedMethod, methodDescription, lineNumber, mutator, indexes, index, killingTest, killingTests, succeedingTests, coveringTests, description, blocks, block } public class XMLReportListener implements MutationResultListener { @@ -101,6 +102,8 @@ private String makeMutationNode(final MutationResult mutation) { createTestDesc(mutation.getKillingTests()), killingTests) + makeNodeWhenConditionSatisfied(fullMutationMatrix, createTestDesc(mutation.getSucceedingTests()), succeedingTests) + + makeNodeWhenConditionSatisfied(fullMutationMatrix, + createTestDesc(mutation.getCoveringTests()), coveringTests) + makeNode(clean(details.getDescription()), description); } diff --git a/pitest-entry/src/test/java/org/pitest/mutationtest/MutationMetaDataTest.java b/pitest-entry/src/test/java/org/pitest/mutationtest/MutationMetaDataTest.java index a459bb5a4..08b08d639 100644 --- a/pitest-entry/src/test/java/org/pitest/mutationtest/MutationMetaDataTest.java +++ b/pitest-entry/src/test/java/org/pitest/mutationtest/MutationMetaDataTest.java @@ -59,7 +59,7 @@ private MutationResult makeResult(String clazz, String method) { final MutationDetails md = aMutationDetail().withId( aMutationId().withLocation(location)).build(); return new MutationResult(md, - MutationStatusTestPair.notAnalysed(0, DetectionStatus.KILLED)); + MutationStatusTestPair.notAnalysed(0, DetectionStatus.KILLED,Collections.emptyList())); } } diff --git a/pitest-entry/src/test/java/org/pitest/mutationtest/MutationResultTest.java b/pitest-entry/src/test/java/org/pitest/mutationtest/MutationResultTest.java index a12d67c0d..9888ef29c 100644 --- a/pitest-entry/src/test/java/org/pitest/mutationtest/MutationResultTest.java +++ b/pitest-entry/src/test/java/org/pitest/mutationtest/MutationResultTest.java @@ -20,6 +20,8 @@ import nl.jqno.equalsverifier.EqualsVerifier; +import java.util.Collections; + public class MutationResultTest { private MutationResult testee; @@ -34,14 +36,14 @@ public void shouldReturnNameOfKillingTestWhenKnown() { @Test public void shouldNoneWhenNoKillingTest() { this.testee = new MutationResult(null, MutationStatusTestPair.notAnalysed(1, - DetectionStatus.TIMED_OUT)); + DetectionStatus.TIMED_OUT, Collections.emptyList())); assertEquals("none", this.testee.getKillingTestDescription()); } @Test public void shouldReturnStatusDescription() { this.testee = new MutationResult(null, MutationStatusTestPair.notAnalysed(1, - DetectionStatus.TIMED_OUT)); + DetectionStatus.TIMED_OUT,Collections.emptyList())); assertEquals("TIMED_OUT", this.testee.getStatusDescription()); } diff --git a/pitest-entry/src/test/java/org/pitest/mutationtest/MutationStatusMapTest.java b/pitest-entry/src/test/java/org/pitest/mutationtest/MutationStatusMapTest.java index f82d34022..154aff2f8 100644 --- a/pitest-entry/src/test/java/org/pitest/mutationtest/MutationStatusMapTest.java +++ b/pitest-entry/src/test/java/org/pitest/mutationtest/MutationStatusMapTest.java @@ -105,12 +105,13 @@ public void shouldCreateResultsForAllMutations() { @Test public void shouldCreateResultsForSurvivedMutations(){ final MutationStatusTestPair statusPairOne = new MutationStatusTestPair(42, - DetectionStatus.SURVIVED, "foo"); + DetectionStatus.SURVIVED, Collections.singletonList("foo"),Arrays.asList("foo1","bar"), Arrays.asList("foo","foo1","bar")); this.testee.setStatusForMutation(this.aSurvivedMutationDetails, statusPairOne); assertEquals(DetectionStatus.SURVIVED, this.testee.createMutationResults().get(0).getStatus()); assertThat(this.testee.createMutationResults().get(0).getKillingTests()).contains("foo"); - assertThat(this.testee.createMutationResults().get(0).getSucceedingTests()).contains("foo","bar"); + assertThat(this.testee.createMutationResults().get(0).getSucceedingTests()).contains("foo1","bar"); + assertThat(this.testee.createMutationResults().get(0).getCoveringTests()).contains("foo","foo1","bar"); } diff --git a/pitest-entry/src/test/java/org/pitest/mutationtest/build/MutationTestUnitTest.java b/pitest-entry/src/test/java/org/pitest/mutationtest/build/MutationTestUnitTest.java index 28a262844..d950a9aee 100644 --- a/pitest-entry/src/test/java/org/pitest/mutationtest/build/MutationTestUnitTest.java +++ b/pitest-entry/src/test/java/org/pitest/mutationtest/build/MutationTestUnitTest.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; import org.junit.Before; @@ -63,7 +64,7 @@ public void shouldReportWhenMutationsNotCoveredByAnyTest() throws Exception { this.tests.add(ClassName.fromString("foo")); final MutationMetaData actual = this.testee.call(); final MutationResult expected = new MutationResult(this.mutations.get(0), - MutationStatusTestPair.notAnalysed(0, DetectionStatus.NO_COVERAGE)); + MutationStatusTestPair.notAnalysed(0, DetectionStatus.NO_COVERAGE, Collections.emptyList())); assertThat(actual.getMutations()).contains(expected); } diff --git a/pitest-entry/src/test/java/org/pitest/mutationtest/incremental/HistoryResultInterceptorTest.java b/pitest-entry/src/test/java/org/pitest/mutationtest/incremental/HistoryResultInterceptorTest.java index ddfb231eb..d99ec4950 100644 --- a/pitest-entry/src/test/java/org/pitest/mutationtest/incremental/HistoryResultInterceptorTest.java +++ b/pitest-entry/src/test/java/org/pitest/mutationtest/incremental/HistoryResultInterceptorTest.java @@ -13,6 +13,7 @@ import org.pitest.mutationtest.report.MutationTestResultMother; import java.util.Collection; +import java.util.Collections; import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; @@ -37,7 +38,7 @@ public void recordsMutationResults() { private MutationResult makeResult() { return new MutationResult( MutationTestResultMother.createDetails(), MutationStatusTestPair.notAnalysed(0, - DetectionStatus.KILLED)); + DetectionStatus.KILLED, Collections.emptyList())); } } \ No newline at end of file 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 ded47ea8b..5bdecc776 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 @@ -306,6 +306,7 @@ public void assessMultipleMutationsAtATime() { 0, KILLED, singletonList(killingTest), + emptyList(), emptyList()))); when(this.history.getPreviousResult(md2.getId())) @@ -314,11 +315,12 @@ public void assessMultipleMutationsAtATime() { 0, KILLED, singletonList(killingTest), + emptyList(), emptyList()))); when(this.history.getPreviousResult(md3.getId())) .thenReturn(Optional.of( - new MutationStatusTestPair(0, SURVIVED, emptyList(), emptyList()))); + new MutationStatusTestPair(0, SURVIVED, emptyList(), emptyList(),emptyList()))); when(this.history.getPreviousResult(md4.getId())) .thenReturn(Optional.empty()); @@ -414,7 +416,7 @@ private void setHistoryForAllMutationsTo(final DetectionStatus status, final String... test) { when(this.history.getPreviousResult(any(MutationIdentifier.class))) .thenReturn(Optional.of( - new MutationStatusTestPair(0, status, asList(test), emptyList()))); + new MutationStatusTestPair(0, status, asList(test), emptyList(), emptyList()))); } private static class LogCatcher extends Handler { diff --git a/pitest-entry/src/test/java/org/pitest/mutationtest/report/MutationTestResultMother.java b/pitest-entry/src/test/java/org/pitest/mutationtest/report/MutationTestResultMother.java index 5fc87184c..0e9851a3f 100644 --- a/pitest-entry/src/test/java/org/pitest/mutationtest/report/MutationTestResultMother.java +++ b/pitest-entry/src/test/java/org/pitest/mutationtest/report/MutationTestResultMother.java @@ -46,7 +46,7 @@ public interface MutationTestResultBuilder extends SequenceBuilder seed() { diff --git a/pitest-entry/src/test/java/org/pitest/mutationtest/report/csv/CSVReportListenerTest.java b/pitest-entry/src/test/java/org/pitest/mutationtest/report/csv/CSVReportListenerTest.java index 152cab752..17d3d17e9 100644 --- a/pitest-entry/src/test/java/org/pitest/mutationtest/report/csv/CSVReportListenerTest.java +++ b/pitest-entry/src/test/java/org/pitest/mutationtest/report/csv/CSVReportListenerTest.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.io.Writer; +import java.util.Collections; import org.junit.Before; import org.junit.Test; @@ -71,7 +72,7 @@ public void shouldQuoteKillingTestWhenNeeded() throws IOException { public void shouldOutputNoneWhenNoKillingTestFound() throws IOException { final MutationResult mr = new MutationResult( MutationTestResultMother.createDetails(), MutationStatusTestPair.notAnalysed(1, - DetectionStatus.SURVIVED)); + DetectionStatus.SURVIVED, Collections.emptyList())); this.testee.handleMutationResult(MutationTestResultMother .createClassResults(mr)); final String expected = "file,clazz,mutator,method,42,SURVIVED,none" diff --git a/pitest-entry/src/test/java/org/pitest/mutationtest/report/xml/XMLReportListenerTest.java b/pitest-entry/src/test/java/org/pitest/mutationtest/report/xml/XMLReportListenerTest.java index 8408d4687..e1227f489 100644 --- a/pitest-entry/src/test/java/org/pitest/mutationtest/report/xml/XMLReportListenerTest.java +++ b/pitest-entry/src/test/java/org/pitest/mutationtest/report/xml/XMLReportListenerTest.java @@ -25,6 +25,7 @@ import java.io.StringWriter; import java.io.Writer; import java.util.Arrays; +import java.util.List; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; @@ -64,12 +65,12 @@ public void shouldOutputFullMutationMatrixWhenEnabled() { this.testee = new XMLReportListener(this.out, true, false); final MutationResult mr = new MutationResult( MutationTestResultMother.createDetails(), - new MutationStatusTestPair(3, DetectionStatus.KILLED, Arrays.asList("foo", "foo2"), Arrays.asList("bar"))); + new MutationStatusTestPair(3, DetectionStatus.KILLED, Arrays.asList("foo", "foo2"), Arrays.asList("bar"), Arrays.asList("foo","foo2","bar"))); this.testee .handleMutationResult(MutationTestResultMother.createClassResults(mr)); final String expected = "file" + "clazzmethod()I42mutator" + - "10foo|foo2bardesc\n"; + "10foo|foo2barfoo|foo2|bardesc\n"; assertThat(expected).isEqualTo(this.out.toString()); } @@ -110,7 +111,7 @@ public void shouldOutputNoneWhenNoKillingTestFound() throws IOException { private MutationResult createSurvivingMutant() { return new MutationResult( MutationTestResultMother.createDetails(), - MutationStatusTestPair.notAnalysed(1, DetectionStatus.SURVIVED)); + MutationStatusTestPair.notAnalysed(1, DetectionStatus.SURVIVED,Arrays.asList("foo","bar"))); } } diff --git a/pitest-html-report/src/main/resources/templates/mutation/mutation_report.st b/pitest-html-report/src/main/resources/templates/mutation/mutation_report.st index 7faae3549..8df588636 100644 --- a/pitest-html-report/src/main/resources/templates/mutation/mutation_report.st +++ b/pitest-html-report/src/main/resources/templates/mutation/mutation_report.st @@ -44,12 +44,14 @@ $sourceFile.groups:{ group | $group.mutations: { mutation |

$i$.$i$
Location : $mutation.details.location$
Killed by : $mutation.killingTestDescription$
$mutation.details.htmlSafeDescription$ → $mutation.statusDescription$ $if(mutation.survived)$ -

Covered by tests:

+Covering tests + $endif$ -

}$ + }$ }$ diff --git a/pitest-html-report/src/main/resources/templates/mutation/style.css b/pitest-html-report/src/main/resources/templates/mutation/style.css index 303bfba78..a0ac211cb 100644 --- a/pitest-html-report/src/main/resources/templates/mutation/style.css +++ b/pitest-html-report/src/main/resources/templates/mutation/style.css @@ -560,4 +560,15 @@ body{ .width-100 { width: 100%; +} + +.view-covered-by-tests{ + cursor:pointer; + color:blue; + text-decoration:underline; +} + +.view-covered-by-tests:hover{ + text-decoration:none; + text-shadow: 1px 1px 1px #555; } \ No newline at end of file diff --git a/pitest-html-report/src/test/java/org/pitest/mutationtest/report/html/ResultComparatorTest.java b/pitest-html-report/src/test/java/org/pitest/mutationtest/report/html/ResultComparatorTest.java index cffed0eae..5efb9b9b6 100644 --- a/pitest-html-report/src/test/java/org/pitest/mutationtest/report/html/ResultComparatorTest.java +++ b/pitest-html-report/src/test/java/org/pitest/mutationtest/report/html/ResultComparatorTest.java @@ -3,6 +3,7 @@ import static org.junit.Assert.assertEquals; import java.util.Arrays; +import java.util.Collections; import java.util.List; import org.junit.Test; @@ -27,7 +28,7 @@ public void shouldSortInDesiredOrder() { } private MutationResult make(final DetectionStatus status) { - return new MutationResult(null, MutationStatusTestPair.notAnalysed(0, status)); + return new MutationResult(null, MutationStatusTestPair.notAnalysed(0, status, Collections.emptyList())); } } diff --git a/pitest/src/main/java/org/pitest/mutationtest/MutationStatusTestPair.java b/pitest/src/main/java/org/pitest/mutationtest/MutationStatusTestPair.java index edee28a8a..2d7b10e93 100644 --- a/pitest/src/main/java/org/pitest/mutationtest/MutationStatusTestPair.java +++ b/pitest/src/main/java/org/pitest/mutationtest/MutationStatusTestPair.java @@ -29,23 +29,26 @@ public final class MutationStatusTestPair implements Serializable { private final List killingTests; private final List succeedingTests; - public static MutationStatusTestPair notAnalysed(int testsRun, DetectionStatus status) { - return new MutationStatusTestPair(testsRun, status, Collections.emptyList(), Collections.emptyList()); + private final List coveringTests; + + public static MutationStatusTestPair notAnalysed(int testsRun, DetectionStatus status, List coveringTests) { + return new MutationStatusTestPair(testsRun, status, Collections.emptyList(), Collections.emptyList(), coveringTests); } public MutationStatusTestPair(final int numberOfTestsRun, final DetectionStatus status, final String killingTest) { this(numberOfTestsRun, status, killingTestToList(killingTest), - Collections.emptyList()); + Collections.emptyList(),killingTestToList(killingTest)); } public MutationStatusTestPair(final int numberOfTestsRun, final DetectionStatus status, final List killingTests, - final List succeedingTests) { + final List succeedingTests, final List coveringTests) { this.status = status; this.killingTests = killingTests; this.succeedingTests = succeedingTests; this.numberOfTestsRun = numberOfTestsRun; + this.coveringTests = coveringTests; } private static List killingTestToList(String killingTest) { @@ -85,6 +88,10 @@ public List getSucceedingTests() { return succeedingTests; } + public List getCoveringTests() { + return coveringTests; + } + public int getNumberOfTestsRun() { return this.numberOfTestsRun; } @@ -96,12 +103,11 @@ public String toString() { } else { return this.status.name() + " by " + this.killingTests; } - } @Override public int hashCode() { - return Objects.hash(numberOfTestsRun, status, killingTests, succeedingTests); + return Objects.hash(numberOfTestsRun, status, killingTests, succeedingTests, coveringTests); } @Override @@ -116,6 +122,7 @@ public boolean equals(final Object obj) { return numberOfTestsRun == other.numberOfTestsRun && status == other.status && Objects.equals(killingTests, other.killingTests) - && Objects.equals(succeedingTests, other.succeedingTests); + && Objects.equals(succeedingTests, other.succeedingTests) + && Objects.equals(coveringTests, other.coveringTests); } } diff --git a/pitest/src/main/java/org/pitest/mutationtest/execute/MutationTestWorker.java b/pitest/src/main/java/org/pitest/mutationtest/execute/MutationTestWorker.java index 0cb9480fe..53b5cd9bd 100644 --- a/pitest/src/main/java/org/pitest/mutationtest/execute/MutationTestWorker.java +++ b/pitest/src/main/java/org/pitest/mutationtest/execute/MutationTestWorker.java @@ -128,7 +128,7 @@ private MutationStatusTestPair handleMutation( if ((relevantTests == null) || relevantTests.isEmpty()) { LOG.info(() -> "No test coverage for mutation " + mutationId + " in " + mutatedClass.getDetails().getMethod()); - mutationDetected = MutationStatusTestPair.notAnalysed(0, DetectionStatus.RUN_ERROR); + mutationDetected = MutationStatusTestPair.notAnalysed(0, DetectionStatus.RUN_ERROR, Collections.emptyList()); } else { mutationDetected = handleCoveredMutation(mutationId, mutatedClass, relevantTests); @@ -160,7 +160,9 @@ private MutationStatusTestPair handleCoveredMutation( } else { LOG.warning("Mutation " + mutationId + " was not viable "); mutationDetected = MutationStatusTestPair.notAnalysed(0, - DetectionStatus.NON_VIABLE); + DetectionStatus.NON_VIABLE, relevantTests.stream() + .map(t -> t.getDescription().getQualifiedName()) + .collect(Collectors.toList())); } return mutationDetected; } @@ -199,7 +201,7 @@ private MutationStatusTestPair doTestsDetectMutation(final Container c, pit.run(c, createEarlyExitTestGroup(tests)); } - return createStatusTestPair(listener); + return createStatusTestPair(listener, tests); } catch (final Exception ex) { throw translateCheckedException(ex); } @@ -207,14 +209,16 @@ private MutationStatusTestPair doTestsDetectMutation(final Container c, } private MutationStatusTestPair createStatusTestPair( - final CheckTestHasFailedResultListener listener) { + final CheckTestHasFailedResultListener listener, List relevantTests) { List failingTests = listener.getFailingTests().stream() .map(Description::getQualifiedName).collect(Collectors.toList()); List succeedingTests = listener.getSucceedingTests().stream() .map(Description::getQualifiedName).collect(Collectors.toList()); + List coveredTests = relevantTests.stream() + .map(t -> t.getDescription().getQualifiedName()).collect(Collectors.toList()); return new MutationStatusTestPair(listener.getNumberOfTestsRun(), - listener.status(), failingTests, succeedingTests); + listener.status(), failingTests, succeedingTests, coveredTests); } private List createEarlyExitTestGroup(final List tests) { diff --git a/pitest/src/test/java/org/pitest/mutationtest/execute/MutationTestWorkerTest.java b/pitest/src/test/java/org/pitest/mutationtest/execute/MutationTestWorkerTest.java index 0c6066c53..8cb7c8a87 100644 --- a/pitest/src/test/java/org/pitest/mutationtest/execute/MutationTestWorkerTest.java +++ b/pitest/src/test/java/org/pitest/mutationtest/execute/MutationTestWorkerTest.java @@ -3,6 +3,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.pitest.mutationtest.DetectionStatus.NON_VIABLE; import static org.pitest.mutationtest.LocationMother.aLocation; import static org.pitest.mutationtest.LocationMother.aMutationId; @@ -80,7 +81,7 @@ public void shouldReportNoCoverageForMutationWithNoTestCoverage() final Collection range = Arrays.asList(mutantOne); this.testee.run(range, this.reporter, this.testSource); verify(this.reporter).report(mutantOne.getId(), - MutationStatusTestPair.notAnalysed(0, DetectionStatus.NO_COVERAGE)); + MutationStatusTestPair.notAnalysed(0, DetectionStatus.NO_COVERAGE, Collections.emptyList())); } @Test @@ -94,9 +95,7 @@ public void shouldReportWhenMutationNotDetected() throws IOException { this.hotswapper.insertClass(any(ClassName.class), any(ClassLoader.class), any(byte[].class))).thenReturn(true); this.testee.run(range, this.reporter, this.testSource); - verify(this.reporter).report(mutantOne.getId(), - new MutationStatusTestPair(1, DetectionStatus.SURVIVED, new ArrayList<>(), new ArrayList<>())); - + verify(this.reporter).describe(mutantOne.getId()); } @Test @@ -110,8 +109,9 @@ public void shouldReportWhenMutationNotViable() throws IOException { this.hotswapper.insertClass(any(ClassName.class), any(ClassLoader.class), any(byte[].class))).thenReturn(false); this.testee.run(range, this.reporter, this.testSource); + verify(this.reporter).describe(mutantOne.getId()); verify(this.reporter).report(mutantOne.getId(), - MutationStatusTestPair.notAnalysed(0, DetectionStatus.NON_VIABLE)); + MutationStatusTestPair.notAnalysed(0, NON_VIABLE,Collections.singletonList("atest"))); } @Test
@@ -42,7 +42,14 @@ $sourceFile.groups:{ group | -$group.mutations: { mutation |

$i$.$i$
Location : $mutation.details.location$
Killed by : $mutation.killingTestDescription$
$mutation.details.htmlSafeDescription$ → $mutation.statusDescription$

}$ +$group.mutations: { mutation |

$i$.$i$
Location : $mutation.details.location$
Killed by : $mutation.killingTestDescription$
$mutation.details.htmlSafeDescription$ → $mutation.statusDescription$ +$if(mutation.survived)$ +

Covered by tests:

+
    +$mutation.succeedingTests: { test |
  • $test$
  • }$ +
+$endif$ +

}$