Skip to content

Commit

Permalink
Optionally print a report URI when the Pitest task finishes
Browse files Browse the repository at this point in the history
Fixes szpak#296
  • Loading branch information
davidburstrom committed Sep 13, 2021
1 parent c54467b commit 085a53c
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,21 @@ abstract class AbstractPitestFunctionalSpec extends IntegrationSpec {
""".stripIndent()
}

protected void writeFailingPitTest(String packageDotted = 'gradle.pitest.test.hello', File baseDir = getProjectDir()) {
String path = 'src/test/java/' + packageDotted.replace('.', '/') + '/HelloPitTest.java'
File javaFile = createFile(path, baseDir)
javaFile << """package ${packageDotted};
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class HelloPitTest {
@Test public void shouldReturnInputNumber() {
assertEquals(1, new HelloPit().returnInputNumber(5));
}
}
""".stripIndent()
}

protected void assertStdOutOrStdErrContainsGivenText(ExecutionResult result, String textToContain) {
//TODO: Simplify if possible - standardOutput for Gradle <5 and standardError for Gradle 5+
assert result.standardOutput.contains(textToContain) || result.standardError.contains(textToContain)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,93 @@ class PitestPluginGeneralFunctionalSpec extends AbstractPitestFunctionalSpec {
historyOutputLocation.size()
}

void "report URI is not printed if test suite is not green"() {
given:
buildFile << getBasicGradlePitestConfig()
and:
writeHelloPitClass()
writeFailingPitTest()
when:
ExecutionResult result = runTasksWithFailure('pitest')
then:
result.wasExecuted(':pitest')
!result.getStandardOutput().contains('index.html')
}

void "timestamped report URI is printed if pitest run fails due to unmet thresholds"() {
given:
buildFile << getBasicGradlePitestConfig()
buildFile << """
pitest {
mutationThreshold = 101
}
""".stripIndent()
and:
writeHelloPitClass()
writeHelloPitTest()
when:
ExecutionResult result = runTasksWithFailure('pitest')
then:
result.wasExecuted(':pitest')
result.getStandardOutput().find(/pitest.[0-9]{12}.index\.html/)
}

void "timestamped report URI is not printed if turned off and pitest run fails due to unmet thresholds"() {
given:
buildFile << getBasicGradlePitestConfig()
buildFile << """
pitest {
mutationThreshold = 101
printReportUri = 'never'
}
""".stripIndent()
and:
writeHelloPitClass()
writeHelloPitTest()
when:
ExecutionResult result = runTasksWithFailure('pitest')
then:
result.wasExecuted(':pitest')
!result.getStandardOutput().find(/pitest.[0-9]{12}.index\.html/)
}

void "timestamped report URI is printed if always requested and pitest run passes"() {
given:
buildFile << getBasicGradlePitestConfig()
buildFile << """
pitest {
printReportUri = 'always'
}
""".stripIndent()
and:
writeHelloPitClass()
writeHelloPitTest()
when:
ExecutionResult result = runTasksSuccessfully('pitest')
then:
result.wasExecuted(':pitest')
result.getStandardOutput().find(/pitest.[0-9]{12}.index\.html/)
}

void "non-timestamped report URI is printed if always requested and pitest run passes"() {
given:
buildFile << getBasicGradlePitestConfig()
buildFile << """
pitest {
printReportUri = 'always'
timestampedReports = false
}
""".stripIndent()
and:
writeHelloPitClass()
writeHelloPitTest()
when:
ExecutionResult result = runTasksSuccessfully('pitest')
then:
result.wasExecuted(':pitest')
result.getStandardOutput().contains(quoteBackslashesInWindowsPath(new File('reports/pitest/index.html')))
}

void "pass additional configured parameters that cannot be test with ProjectBuilder"() {
given:
buildFile << getBasicGradlePitestConfig()
Expand Down Expand Up @@ -114,7 +201,7 @@ class PitestPluginGeneralFunctionalSpec extends AbstractPitestFunctionalSpec {

private String quoteBackslashesInWindowsPath(File file) {
//There is problem with backslash within '' or "" while running this test on Windows: "unexpected char"
return file.absolutePath.replaceAll('\\\\', '\\\\\\\\')
return file.toString().replaceAll('\\\\', '\\\\\\\\')
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ class PitestPlugin implements Plugin<Project> {
task.maxSurviving.set(extension.maxSurviving)
task.useClasspathJar.set(extension.useClasspathJar)
task.features.set(extension.features)
task.printReportUri.set(extension.printReportUri)

configurePropertiesWithProblematicTypesForGradle5(task)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,12 @@ class PitestPluginExtension {
@Incubating
final ListProperty<String> fileExtensionsToFilter

/**
* Controls when the report URI will be printed. Valid values are: 'never', 'on-failure' (default),
* or 'always'
*/
final Property<String> printReportUri

PitestPluginExtension(Project project) {
ObjectFactory of = project.objects
Project p = project
Expand Down Expand Up @@ -262,6 +268,7 @@ class PitestPluginExtension {
useClasspathJar = of.property(Boolean)
features = nullListPropertyOf(p, String)
fileExtensionsToFilter = nullListPropertyOf(p, String)
printReportUri = of.property(String)
}

void setReportDir(File reportDir) {
Expand Down
55 changes: 55 additions & 0 deletions src/main/groovy/info/solidsoft/gradle/pitest/PitestTask.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.PathSensitivity
import org.gradle.api.tasks.options.Option
import org.gradle.process.ExecResult

/**
* Gradle task implementation for Pitest.
Expand Down Expand Up @@ -241,6 +242,10 @@ class PitestTask extends JavaExec {
@Optional
List<String> overriddenTargetTests //should be Set<String> or SetProperty but it's not supported in Gradle as of 5.6.1

@Input
@Optional
final Property<String> printReportUri

PitestTask() {
//setting during execution doesn't work in 6.4+:
//The value for task ':pitest' property 'mainClass' is final and cannot be changed any further.
Expand Down Expand Up @@ -294,6 +299,7 @@ class PitestTask extends JavaExec {
useAdditionalClasspathFile = of.property(Boolean)
additionalClasspathFile = of.fileProperty()
features = of.listProperty(String)
printReportUri = of.property(String)
}

@Input
Expand All @@ -319,12 +325,61 @@ class PitestTask extends JavaExec {
return jvmPath.isPresent() ? jvmPath.asFile.get().absolutePath : null
}

@SuppressWarnings('UnnecessarySetter')
@Override
void exec() {
args = argumentsForPit()
jvmArgs = ((List<String>) getMainProcessJvmArgs().getOrNull() ?: getJvmArgs())
classpath = getLaunchClasspath()

/*
* As it's up to Pitest to write the report somewhere in the report dir if
* timestamped reports are allowed, it is necessary to figure out which one
* is the latest one.
*/
Set<File> previousReportDirs = []
if (timestampedReports.getOrElse(true)) {
previousReportDirs = listTimestampedReportDirs(getReportDir().asFile.get())
}

setIgnoreExitValue(true)
super.exec()
ExecResult execResult = getExecutionResult().get()

printReportUriIfNecessary(execResult.exitValue, previousReportDirs)

execResult.assertNormalExitValue()
}

private void printReportUriIfNecessary(int exitValue, Set<File> previousReportDirs) {
String printReportUri = this.printReportUri.getOrElse('on-failure')

if ((exitValue != 0 &&
printReportUri in ['on-failure', 'always'])
|| printReportUri in ['always']) {
File indexFile = resolveReportIndexFile(previousReportDirs)

if (indexFile.exists()) {
getLogger().warn('See the Pitest report at: ' +
new URI('file', '', indexFile.toURI().getPath(), (String) null, (String) null))
}
}
}

private File resolveReportIndexFile(Set<File> previousReportDirs) {
File actualReportDir

if (timestampedReports.getOrElse(true)) {
actualReportDir = (listTimestampedReportDirs(getReportDir().asFile.get()) - previousReportDirs).first()
} else {
actualReportDir = getReportDir().asFile.get()
}

return new File(actualReportDir, 'index.html')
}

private static Set<File> listTimestampedReportDirs(File reportDir) {
return reportDir.listFiles().findAll { file -> file.isDirectory() }.toSet()
}

private List<String> argumentsForPit() {
Expand Down

0 comments on commit 085a53c

Please sign in to comment.