info.solidsoft.gradle.pitest.PitestTask.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-pitest-plugin Show documentation
Show all versions of gradle-pitest-plugin Show documentation
Gradle plugin for PIT Mutation Testing in Android projects
/* Copyright (c) 2012 Marcin Zajączkowski
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package info.solidsoft.gradle.pitest
import groovy.transform.CompileStatic
import groovy.transform.PackageScope
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.JavaExec
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.OutputFile
/**
* Gradle task implementation for Pitest.
*/
@CompileStatic
class PitestTask extends JavaExec {
@OutputDirectory
File reportDir
@Input
Set targetClasses
@Input
@Optional
Set targetTests
@Input
@Optional
Integer dependencyDistance
@Input
@Optional
Integer threads
@Input
@Optional
Boolean mutateStaticInits
@Input
@Optional
Boolean includeJarFiles
@Input
@Optional
Set mutators
@Input
@Optional
Set excludedMethods
@Input
@Optional
Set excludedClasses
@Input
@Optional
Set avoidCallsTo
@Input
@Optional
Boolean verbose
@Input
@Optional
BigDecimal timeoutFactor
@Input
@Optional
Integer timeoutConstInMillis
@Input
@Optional
Integer maxMutationsPerClass
@Input
@Optional
List childProcessJvmArgs
@Input
@Optional
Set outputFormats
@Input
@Optional
Boolean failWhenNoMutations
@Input
@Optional
Set includedGroups
@Input
@Optional
Set excludedGroups
@InputFiles
Set sourceDirs
@Input
@Optional
Boolean detectInlinedCode
@Input
@Optional
Boolean timestampedReports
@InputFiles
FileCollection additionalClasspath //"classpath" is already defined internally in ExecTask
@Input
Boolean useAdditionalClasspathFile
@Input
@OutputFile
File additionalClasspathFile
@InputFiles
Set mutableCodePaths
@Input
@Optional
File historyInputLocation
@OutputFile
@Optional
File historyOutputLocation
@Input
@Optional
Boolean enableDefaultIncrementalAnalysis
@Input
File defaultFileForHistoryData
@Input
@Optional
Integer mutationThreshold
@Input
@Optional
Integer coverageThreshold
@Input
@Optional
String mutationEngine
@Input
@Optional
Boolean exportLineCoverage
@Input
@Optional
File jvmPath
@Input
@Optional
List mainProcessJvmArgs
@Input
FileCollection launchClasspath
@Input
@Optional
Map pluginConfiguration
@Input
@Optional
Integer maxSurviving
@Input
@Optional
List features
@Override
void exec() {
//Workaround for compatibility with Gradle <4.0 due to setArgs(List) and setJvmArgs(List) added in Gradle 4.0
args = createListOfAllArgumentsForPit()
jvmArgs = (getMainProcessJvmArgs() ?: getJvmArgs())
main = "org.pitest.mutationtest.commandline.MutationCoverageReport"
classpath = getLaunchClasspath()
super.exec()
}
private List createListOfAllArgumentsForPit() {
Map taskArgumentsMap = createTaskArgumentMap()
List argsAsList = createArgumentsListFromMap(taskArgumentsMap)
List multiValueArgsAsList = createMultiValueArgsAsList()
return concatenateTwoLists(argsAsList, multiValueArgsAsList)
}
@PackageScope //visible for testing
Map createTaskArgumentMap() {
Map map = [:]
map['sourceDirs'] = (getSourceDirs()*.path)?.join(',')
map['reportDir'] = getReportDir().toString()
map['targetClasses'] = getTargetClasses().join(',')
map['targetTests'] = getTargetTests()?.join(',')
map['dependencyDistance'] = getDependencyDistance()?.toString()
map['threads'] = getThreads()?.toString()
map['mutateStaticInits'] = getMutateStaticInits()?.toString()
map['includeJarFiles'] = getIncludeJarFiles()?.toString()
map["mutators"] = getMutators()?.join(',')
map['excludedMethods'] = getExcludedMethods()?.join(',')
map['excludedClasses'] = getExcludedClasses()?.join(',')
map['avoidCallsTo'] = getAvoidCallsTo()?.join(',')
map['verbose'] = getVerbose()?.toString()
map['timeoutFactor'] = getTimeoutFactor()?.toString()
map['timeoutConst'] = getTimeoutConstInMillis()?.toString()
map['maxMutationsPerClass'] = getMaxMutationsPerClass()?.toString()
map['jvmArgs'] = getChildProcessJvmArgs()?.join(',')
map['outputFormats'] = getOutputFormats()?.join(',')
map['failWhenNoMutations'] = getFailWhenNoMutations()?.toString()
map['mutableCodePaths'] = (getMutableCodePaths()*.path)?.join(',')
map['includedGroups'] = getIncludedGroups()?.join(',')
map['excludedGroups'] = getExcludedGroups()?.join(',')
map['detectInlinedCode'] = getDetectInlinedCode()?.toString()
map['timestampedReports'] = getTimestampedReports()?.toString()
map['mutationThreshold'] = getMutationThreshold()?.toString()
map['coverageThreshold'] = getCoverageThreshold()?.toString()
map['mutationEngine'] = getMutationEngine()
map['exportLineCoverage'] = getExportLineCoverage()?.toString()
map['includeLaunchClasspath'] = Boolean.FALSE.toString() //code to analyse is passed via classPath
map['jvmPath'] = getJvmPath()?.path
map['maxSurviving'] = getMaxSurviving()?.toString()
map['features'] = getFeatures()?.join(',')
map.putAll(prepareMapWithClasspathConfiguration())
map.putAll(prepareMapWithIncrementalAnalysisConfiguration())
return removeEntriesWithNullValue(map)
}
private Map prepareMapWithClasspathConfiguration() {
if (getUseAdditionalClasspathFile()) {
fillAdditionalClasspathFileWithClasspathElements()
return [classPathFile: getAdditionalClasspathFile().absolutePath]
} else {
return [classPath: getAdditionalClasspath().files.join(',')]
}
}
private void fillAdditionalClasspathFileWithClasspathElements() {
String classpathElementsAsFileContent = getAdditionalClasspath().files.collect { it.getAbsolutePath() }.join(System.lineSeparator())
//"withWriter" as "file << content" works in append mode (instead of overwrite one)
getAdditionalClasspathFile().withWriter() {
it << classpathElementsAsFileContent
}
}
private Map prepareMapWithIncrementalAnalysisConfiguration() {
if (getEnableDefaultIncrementalAnalysis()) {
return [historyInputLocation : getHistoryInputLocation()?.path ?: getDefaultFileForHistoryData().path,
historyOutputLocation: getHistoryOutputLocation()?.path ?: getDefaultFileForHistoryData().path]
} else {
return [historyInputLocation: getHistoryInputLocation()?.path,
historyOutputLocation: getHistoryOutputLocation()?.path]
}
}
private Map removeEntriesWithNullValue(Map map) {
return map.findAll { it.value != null }
}
private List createArgumentsListFromMap(Map taskArgumentsMap) {
return taskArgumentsMap.collect { k, v ->
"--$k=$v".toString()
}
}
@PackageScope //visible for testing
List createMultiValueArgsAsList() {
//It is a duplication/special case handling, but a PoC implementation with emulated multimap was also quite ugly and in addition error prone
return getPluginConfiguration()?.collect { k, v ->
"$k=$v".toString()
}?.collect {
"--pluginConfiguration=$it".toString()
} ?: [] as List
}
//Workaround to keep compatibility with Gradle <2.8
//[] + [] is compiled in Groovy 2.4.x as "List plus(List left, Collection right)" which is unavailable in Groovy 2.3 and fails with Gradle <2.8
private List concatenateTwoLists(List argsAsList, List multiValueArgsAsList) {
List allArgs = []
allArgs.addAll(argsAsList)
allArgs.addAll(multiValueArgsAsList)
return allArgs
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy