-
Notifications
You must be signed in to change notification settings - Fork 54
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #71 from thejohnfreeman/master
Support coverage calculated from PIT mutation tests
- Loading branch information
Showing
9 changed files
with
344 additions
and
3 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
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
90 changes: 90 additions & 0 deletions
90
src/main/groovy/org/kt3k/gradle/plugin/coveralls/domain/PITSourceReportFactory.groovy
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,90 @@ | ||
package org.kt3k.gradle.plugin.coveralls.domain | ||
|
||
import org.gradle.api.Project | ||
import org.gradle.api.plugins.JavaPlugin | ||
|
||
/** | ||
* Factory class for SourceReport for PIT report file. | ||
*/ | ||
class PITSourceReportFactory implements SourceReportFactory { | ||
|
||
@Override | ||
List<SourceReport> createReportList(Project project, File reportFile) { | ||
// Build a PATH of source directories. | ||
List<File> sourceDirectories = project.extensions.coveralls.sourceDirs | ||
|
||
project.plugins.withType(JavaPlugin) { | ||
sourceDirectories += project.sourceSets.main.java.srcDirs | ||
} | ||
|
||
return createReportList(sourceDirectories, reportFile) | ||
} | ||
|
||
// This method has been separated for testing. | ||
static List<SourceReport> createReportList( | ||
List<File> sourceDirectories, File reportFile) | ||
{ | ||
def mutations = new XmlSlurper().parse(reportFile) | ||
|
||
// mapping of [filename] => [line] => [hits] | ||
Map<String, Map<Integer, Integer>> hitsPerLineMapPerFile = [:] | ||
|
||
mutations.mutation.each() { mutation -> | ||
// PIT reports only the source file's base name, which might not be | ||
// unique. Assume the source file's directory can be derived from | ||
// the package name. | ||
// This pattern matches more than valid package names, | ||
// but we're assuming the name is valid if it compiled. | ||
def matcher = (mutation.mutatedClass.text() =~ /(?:[a-zA-Z0-9_]+\.)*/) | ||
if (!matcher.find()) { | ||
// Cannot parse the class name. | ||
// TODO: Give a warning to the user at least. | ||
return | ||
} | ||
def packageName = matcher.group(0) | ||
def filename = packageName.replace('.', File.separator) + mutation.sourceFile.text() | ||
def hitsPerLine = hitsPerLineMapPerFile.get(filename, [:]) | ||
Integer lineNumber = mutation.lineNumber.text().toInteger() - 1 | ||
Integer hits = hitsPerLine.get(lineNumber, 0) | ||
hitsPerLine[lineNumber] = hits + 1 | ||
} | ||
|
||
List<SourceReport> reports = new ArrayList<SourceReport>() | ||
|
||
hitsPerLineMapPerFile.each { String filename, Map<Integer, Integer> hitsPerLine -> | ||
|
||
// find actual source file from directory candidates | ||
String sourceFilename = findSourceFile(sourceDirectories, filename) | ||
|
||
if (sourceFilename == null) { | ||
// if sourceFilename is not found then ignore the entry | ||
return | ||
} | ||
|
||
File sourceFile = new File(sourceFilename) | ||
String sourceText = sourceFile.text | ||
|
||
// create hits per line list | ||
List<Integer> hitsArray = [null] * sourceText.readLines().size() | ||
|
||
hitsPerLine.each { Integer line, Integer hits -> | ||
hitsArray[line] = hits | ||
} | ||
|
||
reports.add new SourceReport(sourceFilename, sourceText, hitsArray) | ||
} | ||
|
||
return reports | ||
} | ||
|
||
/** | ||
* Finds the actual source file path and returns File object | ||
* | ||
* @param sourceDirs the list of candidate source dirs | ||
* @param filename the file name to search | ||
* @return found File object | ||
*/ | ||
private static String findSourceFile(List<File> sourceDirs, String filename) { | ||
return sourceDirs.collect { new File(it, filename) }.find { it.exists() } | ||
} | ||
} |
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,91 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<mutations> | ||
<mutation detected="true" status="KILLED"> | ||
<sourceFile>BankAccount.java</sourceFile> | ||
<mutatedClass>org.kt3k.bankaccount.BankAccount</mutatedClass> | ||
<mutatedMethod>decrease</mutatedMethod> | ||
<methodDescription>(Ljava/lang/Integer;)V</methodDescription> | ||
<lineNumber>19</lineNumber> | ||
<mutator>org.pitest.mutationtest.engine.gregor.mutators.MathMutator</mutator> | ||
<index>11</index> | ||
<killingTest>org.kt3k.bankaccount.TransferContextTest.testTransfer(org.kt3k.bankaccount.TransferContextTest)</killingTest> | ||
<description>Replaced integer subtraction with addition</description> | ||
</mutation> | ||
<mutation detected="true" status="KILLED"> | ||
<sourceFile>BankAccount.java</sourceFile> | ||
<mutatedClass>org.kt3k.bankaccount.BankAccount</mutatedClass> | ||
<mutatedMethod>getBalance</mutatedMethod> | ||
<methodDescription>()Ljava/lang/Integer;</methodDescription> | ||
<lineNumber>23</lineNumber> | ||
<mutator>org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator</mutator> | ||
<index>5</index> | ||
<killingTest>org.kt3k.bankaccount.TransferContextTest.testTransfer(org.kt3k.bankaccount.TransferContextTest)</killingTest> | ||
<description>mutated return of Object value for org/kt3k/bankaccount/BankAccount::getBalance to ( if (x != null) null else throw new RuntimeException )</description> | ||
</mutation> | ||
<mutation detected="false" status="NO_COVERAGE"> | ||
<sourceFile>BankAccount.java</sourceFile> | ||
<mutatedClass>org.kt3k.bankaccount.BankAccount</mutatedClass> | ||
<mutatedMethod>getId</mutatedMethod> | ||
<methodDescription>()Ljava/lang/String;</methodDescription> | ||
<lineNumber>27</lineNumber> | ||
<mutator>org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator</mutator> | ||
<index>5</index> | ||
<killingTest/> | ||
<description>mutated return of Object value for org/kt3k/bankaccount/BankAccount::getId to ( if (x != null) null else throw new RuntimeException )</description> | ||
</mutation> | ||
<mutation detected="true" status="KILLED"> | ||
<sourceFile>BankAccount.java</sourceFile> | ||
<mutatedClass>org.kt3k.bankaccount.BankAccount</mutatedClass> | ||
<mutatedMethod>increase</mutatedMethod> | ||
<methodDescription>(Ljava/lang/Integer;)V</methodDescription> | ||
<lineNumber>15</lineNumber> | ||
<mutator>org.pitest.mutationtest.engine.gregor.mutators.MathMutator</mutator> | ||
<index>11</index> | ||
<killingTest>org.kt3k.bankaccount.TransferContextTest.testTransfer(org.kt3k.bankaccount.TransferContextTest)</killingTest> | ||
<description>Replaced integer addition with subtraction</description> | ||
</mutation> | ||
<mutation detected="true" status="KILLED"> | ||
<sourceFile>TransferContext.java</sourceFile> | ||
<mutatedClass>org.kt3k.bankaccount.TransferContext$BankAccountSender</mutatedClass> | ||
<mutatedMethod>send</mutatedMethod> | ||
<methodDescription>(Ljava/lang/Integer;Lorg/kt3k/bankaccount/TransferContext$BankAccountReceiver;)V</methodDescription> | ||
<lineNumber>22</lineNumber> | ||
<mutator>org.pitest.mutationtest.engine.gregor.mutators.VoidMethodCallMutator</mutator> | ||
<index>6</index> | ||
<killingTest>org.kt3k.bankaccount.TransferContextTest.testTransfer(org.kt3k.bankaccount.TransferContextTest)</killingTest> | ||
<description>removed call to org/kt3k/bankaccount/BankAccount::decrease</description> | ||
</mutation> | ||
<mutation detected="true" status="KILLED"> | ||
<sourceFile>TransferContext.java</sourceFile> | ||
<mutatedClass>org.kt3k.bankaccount.TransferContext$BankAccountSender</mutatedClass> | ||
<mutatedMethod>send</mutatedMethod> | ||
<methodDescription>(Ljava/lang/Integer;Lorg/kt3k/bankaccount/TransferContext$BankAccountReceiver;)V</methodDescription> | ||
<lineNumber>24</lineNumber> | ||
<mutator>org.pitest.mutationtest.engine.gregor.mutators.VoidMethodCallMutator</mutator> | ||
<index>11</index> | ||
<killingTest>org.kt3k.bankaccount.TransferContextTest.testTransfer(org.kt3k.bankaccount.TransferContextTest)</killingTest> | ||
<description>removed call to org/kt3k/bankaccount/TransferContext$BankAccountReceiver::onReceive</description> | ||
</mutation> | ||
<mutation detected="true" status="KILLED"> | ||
<sourceFile>TransferContext.java</sourceFile> | ||
<mutatedClass>org.kt3k.bankaccount.TransferContext</mutatedClass> | ||
<mutatedMethod>transfer</mutatedMethod> | ||
<methodDescription>(Ljava/lang/Integer;)V</methodDescription> | ||
<lineNumber>42</lineNumber> | ||
<mutator>org.pitest.mutationtest.engine.gregor.mutators.VoidMethodCallMutator</mutator> | ||
<index>8</index> | ||
<killingTest>org.kt3k.bankaccount.TransferContextTest.testTransfer(org.kt3k.bankaccount.TransferContextTest)</killingTest> | ||
<description>removed call to org/kt3k/bankaccount/TransferContext$BankAccountSender::send</description> | ||
</mutation> | ||
<mutation detected="true" status="KILLED"> | ||
<sourceFile>TransferContext.java</sourceFile> | ||
<mutatedClass>org.kt3k.bankaccount.TransferContext$BankAccountReceiver</mutatedClass> | ||
<mutatedMethod>onReceive</mutatedMethod> | ||
<methodDescription>(Ljava/lang/Integer;)V</methodDescription> | ||
<lineNumber>37</lineNumber> | ||
<mutator>org.pitest.mutationtest.engine.gregor.mutators.VoidMethodCallMutator</mutator> | ||
<index>6</index> | ||
<killingTest>org.kt3k.bankaccount.TransferContextTest.testTransfer(org.kt3k.bankaccount.TransferContextTest)</killingTest> | ||
<description>removed call to org/kt3k/bankaccount/BankAccount::increase</description> | ||
</mutation> | ||
</mutations> |
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,30 @@ | ||
package org.kt3k.bankaccount; | ||
|
||
public class BankAccount { | ||
|
||
private String id; | ||
private Integer balance; | ||
|
||
public BankAccount(String id, Integer balance) { | ||
this.id = id; | ||
this.balance = balance; | ||
} | ||
|
||
|
||
public void increase(Integer money) { | ||
this.balance += money; | ||
} | ||
|
||
public void decrease(Integer money) { | ||
this.balance -= money; | ||
} | ||
|
||
public Integer getBalance() { | ||
return this.balance; | ||
} | ||
|
||
public String getId() { | ||
return this.id; | ||
} | ||
|
||
} |
45 changes: 45 additions & 0 deletions
45
src/test/fixture/org/kt3k/bankaccount/TransferContext.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,45 @@ | ||
package org.kt3k.bankaccount; | ||
|
||
public class TransferContext { | ||
|
||
private BankAccountSender sender; | ||
private BankAccountReceiver receiver; | ||
|
||
public TransferContext(BankAccount sender, BankAccount receiver) { | ||
this.sender = new BankAccountSender(sender); | ||
this.receiver = new BankAccountReceiver(receiver); | ||
} | ||
|
||
static private class BankAccountSender { | ||
|
||
private BankAccount actor; | ||
|
||
public BankAccountSender(BankAccount actor) { | ||
this.actor = actor; | ||
} | ||
|
||
public void send(Integer money, BankAccountReceiver receiver) { | ||
this.actor.decrease(money); | ||
|
||
receiver.onReceive(money); | ||
} | ||
} | ||
|
||
static private class BankAccountReceiver { | ||
|
||
private BankAccount actor; | ||
|
||
public BankAccountReceiver(BankAccount actor) { | ||
this.actor = actor; | ||
} | ||
|
||
public void onReceive(Integer money) { | ||
this.actor.increase(money); | ||
} | ||
} | ||
|
||
public void transfer(Integer money) { | ||
this.sender.send(money, this.receiver); | ||
} | ||
|
||
} |
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
42 changes: 42 additions & 0 deletions
42
src/test/groovy/org/kt3k/gradle/plugin/coveralls/domain/PITSourceReportFactoryTest.groovy
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,42 @@ | ||
package org.kt3k.gradle.plugin.coveralls.domain | ||
|
||
import org.gradle.api.Project | ||
import org.gradle.testfixtures.ProjectBuilder | ||
import org.junit.Before | ||
import org.junit.Test | ||
import static org.junit.Assert.* | ||
import org.kt3k.gradle.plugin.CoverallsPluginExtension | ||
|
||
class PITSourceReportFactoryTest { | ||
|
||
Project project | ||
|
||
@Before | ||
public void setUp() { | ||
|
||
// fake a project | ||
project = ProjectBuilder.builder().build() | ||
|
||
// create coveralls extension | ||
project.extensions.create('coveralls', CoverallsPluginExtension) | ||
} | ||
|
||
@Test | ||
public void testCreateFromMutationsXML() { | ||
|
||
List<SourceReport> reports = PITSourceReportFactory.createReportList( | ||
[new File('src/test/fixture')], | ||
new File ('src/test/fixture/mutations.xml')) | ||
|
||
assertNotNull reports | ||
assertEquals 2, reports.size() | ||
|
||
assertEquals 'src/test/fixture/org/kt3k/bankaccount/BankAccount.java', reports[0].name | ||
assertEquals 30, reports[0].coverage.size() | ||
assertEquals 4, reports[0].coverage.findAll{ it != null }.sum() | ||
assertEquals 'src/test/fixture/org/kt3k/bankaccount/TransferContext.java', reports[1].name | ||
assertEquals 45, reports[1].coverage.size() | ||
assertEquals 4, reports[1].coverage.findAll{ it != null }.sum() | ||
} | ||
|
||
} |