diff --git a/CHANGELOG.md b/CHANGELOG.md index e38e9ff7..401fa6d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 1.9.0 - Unreleased - PIT 1.9.4 by default + - Support for inputEncoding and outputEncoding - [#310](https://github.com/szpak/gradle-pitest-plugin/issues/310) - Add pitest dependencies only during configuration resolution - [#313](https://github.com/szpak/gradle-pitest-plugin/issues/313) - PR by [Ian O'Malley](https://github.com/omalleyian) - Improve build cache hit cache with relative path - [#315](https://github.com/szpak/gradle-pitest-plugin/issues/315) - PR by [Siddardha Bezawada](https://github.com/SidB3) diff --git a/src/main/groovy/info/solidsoft/gradle/pitest/AggregateReportGenerator.groovy b/src/main/groovy/info/solidsoft/gradle/pitest/AggregateReportGenerator.groovy index c8e507c7..f3e265c6 100644 --- a/src/main/groovy/info/solidsoft/gradle/pitest/AggregateReportGenerator.groovy +++ b/src/main/groovy/info/solidsoft/gradle/pitest/AggregateReportGenerator.groovy @@ -3,11 +3,14 @@ package info.solidsoft.gradle.pitest import groovy.transform.CompileStatic import groovy.util.logging.Slf4j import org.gradle.api.Incubating +import org.gradle.api.provider.Property import org.gradle.workers.WorkAction import org.pitest.aggregate.ReportAggregator import org.pitest.mutationtest.config.DirectoryResultOutputStrategy import org.pitest.mutationtest.config.UndatedReportDirCreationStrategy +import java.util.function.Consumer + @Slf4j @Incubating @CompileStatic @@ -23,6 +26,9 @@ abstract class AggregateReportGenerator implements WorkAction builder.addSourceCodeDirectory(file) } parameters.additionalClasspath.each { file -> builder.addCompiledCodeDirectory(file) } + consumeIfPropertyIsSet(parameters.inputCharset) { charset -> builder.inputCharSet(charset) } + consumeIfPropertyIsSet(parameters.outputCharset) { charset -> builder.outputCharset(charset) } + ReportAggregator aggregator = builder.resultOutputStrategy(new DirectoryResultOutputStrategy( parameters.reportDir.asFile.get().absolutePath, new UndatedReportDirCreationStrategy())) @@ -32,4 +38,10 @@ abstract class AggregateReportGenerator implements WorkAction void consumeIfPropertyIsSet(Property property, Consumer applyPropertyCode) { + if (property.isPresent()) { + applyPropertyCode.accept(property.get()) + } + } + } diff --git a/src/main/groovy/info/solidsoft/gradle/pitest/AggregateReportTask.groovy b/src/main/groovy/info/solidsoft/gradle/pitest/AggregateReportTask.groovy index b6966a34..743ea88d 100644 --- a/src/main/groovy/info/solidsoft/gradle/pitest/AggregateReportTask.groovy +++ b/src/main/groovy/info/solidsoft/gradle/pitest/AggregateReportTask.groovy @@ -7,8 +7,11 @@ import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.RegularFileProperty import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.Property import org.gradle.api.tasks.Classpath +import org.gradle.api.tasks.Input import org.gradle.api.tasks.InputFiles +import org.gradle.api.tasks.Optional import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.PathSensitive @@ -19,6 +22,7 @@ import org.gradle.workers.WorkQueue import org.gradle.workers.WorkerExecutor import javax.inject.Inject +import java.nio.charset.Charset /** * Task to aggregate pitest report @@ -60,6 +64,14 @@ abstract class AggregateReportTask extends DefaultTask { @Classpath abstract ConfigurableFileCollection getPitestReportClasspath() + @Input + @Optional + final Property inputCharset + + @Input + @Optional + final Property outputCharset + @Inject abstract WorkerExecutor getWorkerExecutor() @@ -71,6 +83,8 @@ abstract class AggregateReportTask extends DefaultTask { additionalClasspath = of.fileCollection() mutationFiles = of.fileCollection() lineCoverageFiles = of.fileCollection() + inputCharset = of.property(Charset) + outputCharset = of.property(Charset) } @TaskAction @@ -87,6 +101,8 @@ abstract class AggregateReportTask extends DefaultTask { parameters.additionalClasspath.from(additionalClasspath) parameters.mutationFiles.from(mutationFiles) parameters.lineCoverageFiles.from(lineCoverageFiles) + parameters.inputCharset.set(this.inputCharset) + parameters.outputCharset.set(this.outputCharset) } } diff --git a/src/main/groovy/info/solidsoft/gradle/pitest/AggregateReportWorkParameters.groovy b/src/main/groovy/info/solidsoft/gradle/pitest/AggregateReportWorkParameters.groovy index 08d63acd..2a44119d 100644 --- a/src/main/groovy/info/solidsoft/gradle/pitest/AggregateReportWorkParameters.groovy +++ b/src/main/groovy/info/solidsoft/gradle/pitest/AggregateReportWorkParameters.groovy @@ -4,8 +4,11 @@ import org.gradle.api.Incubating import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.Property import org.gradle.workers.WorkParameters +import java.nio.charset.Charset + @Incubating interface AggregateReportWorkParameters extends WorkParameters { @@ -15,5 +18,7 @@ interface AggregateReportWorkParameters extends WorkParameters { ConfigurableFileCollection getAdditionalClasspath() ConfigurableFileCollection getMutationFiles() ConfigurableFileCollection getLineCoverageFiles() + Property getInputCharset() + Property getOutputCharset() } diff --git a/src/main/groovy/info/solidsoft/gradle/pitest/PitestAggregatorPlugin.groovy b/src/main/groovy/info/solidsoft/gradle/pitest/PitestAggregatorPlugin.groovy index f1c980d7..67bc8b00 100644 --- a/src/main/groovy/info/solidsoft/gradle/pitest/PitestAggregatorPlugin.groovy +++ b/src/main/groovy/info/solidsoft/gradle/pitest/PitestAggregatorPlugin.groovy @@ -13,6 +13,7 @@ import org.gradle.api.provider.Provider import org.gradle.api.reporting.ReportingExtension import org.gradle.api.tasks.TaskCollection +import java.util.function.Consumer import java.util.stream.Collectors /** @@ -64,7 +65,7 @@ class PitestAggregatorPlugin implements Plugin { } private void configureTaskDefaults(AggregateReportTask aggregateReportTask) { - aggregateReportTask.with { + aggregateReportTask.with { task -> reportDir.set(new File(getReportBaseDirectory(), PitestPlugin.PITEST_REPORT_DIRECTORY_NAME)) reportFile.set(reportDir.file("index.html")) @@ -75,15 +76,17 @@ class PitestAggregatorPlugin implements Plugin { Set projectsWithPitest = getProjectsWithPitestPlugin() mutationFiles.from = collectMutationFiles(projectsWithPitest) lineCoverageFiles.from = collectLineCoverageFiles(projectsWithPitest) + + findPluginExtension().ifPresent({ PitestPluginExtension extension -> + inputCharset.set(extension.inputCharset) + outputCharset.set(extension.outputCharset) + } as Consumer) //Simplify with Groovy 3+ } } private void addPitAggregateReportDependency(Configuration pitestReportConfiguration) { pitestReportConfiguration.withDependencies { dependencies -> - Optional maybeExtension = Optional.ofNullable(project.extensions.findByType(PitestPluginExtension)) - .map { extension -> Optional.of(extension) } //Optional::of with Groovy 3 - .orElseGet { findPitestExtensionInSubprojects(project) } - String pitestVersion = maybeExtension + String pitestVersion = findPluginExtension() .map { extension -> extension.pitestVersion.get() } .orElse(PitestPlugin.DEFAULT_PITEST_VERSION) @@ -91,6 +94,12 @@ class PitestAggregatorPlugin implements Plugin { } } + private Optional findPluginExtension() { + return Optional.ofNullable(project.extensions.findByType(PitestPluginExtension)) + .map { extension -> Optional.of(extension) } //Optional::of with Groovy 3 + .orElseGet { findPitestExtensionInSubprojects(project) } + } + private File getReportBaseDirectory() { if (project.extensions.findByType(ReportingExtension)) { return project.extensions.getByType(ReportingExtension).baseDir diff --git a/src/main/groovy/info/solidsoft/gradle/pitest/PitestPlugin.groovy b/src/main/groovy/info/solidsoft/gradle/pitest/PitestPlugin.groovy index 5dd005e1..a978fba9 100644 --- a/src/main/groovy/info/solidsoft/gradle/pitest/PitestPlugin.groovy +++ b/src/main/groovy/info/solidsoft/gradle/pitest/PitestPlugin.groovy @@ -201,6 +201,8 @@ class PitestPlugin implements Plugin { task.pluginConfiguration.set(extension.pluginConfiguration) task.maxSurviving.set(extension.maxSurviving) task.useClasspathJar.set(extension.useClasspathJar) + task.inputEncoding.set(extension.inputCharset) + task.outputEncoding.set(extension.outputCharset) task.features.set(extension.features) } diff --git a/src/main/groovy/info/solidsoft/gradle/pitest/PitestPluginExtension.groovy b/src/main/groovy/info/solidsoft/gradle/pitest/PitestPluginExtension.groovy index e6e8dd04..0d7597a7 100644 --- a/src/main/groovy/info/solidsoft/gradle/pitest/PitestPluginExtension.groovy +++ b/src/main/groovy/info/solidsoft/gradle/pitest/PitestPluginExtension.groovy @@ -28,6 +28,8 @@ import org.gradle.api.provider.Provider import org.gradle.api.provider.SetProperty import org.gradle.api.tasks.SourceSet +import java.nio.charset.Charset + /** * Extension class with configurable parameters for Pitest plugin. * @@ -178,8 +180,11 @@ class PitestPluginExtension { @Incubating final Property useClasspathJar //new in PIT 1.4.2 (GPP 1.4.6) + final Property inputCharset //new in PIT 1.8.1 as inputEncoding (GPP 1.9.0) + final Property outputCharset //new in PIT 1.8.1 as outputEncoding (GPP 1.9.0) + /** - * Turnes on/off features in PIT itself and its plugins. + * Turns on/off features in PIT itself and its plugins. * * Some details: https://github.com/hcoles/pitest/releases/tag/pitest-parent-1.2.1 * @@ -263,6 +268,8 @@ class PitestPluginExtension { pluginConfiguration = nullMapPropertyOf(p, String, String) maxSurviving = of.property(Integer) useClasspathJar = of.property(Boolean) + inputCharset = of.property(Charset) + outputCharset = of.property(Charset) features = nullListPropertyOf(p, String) fileExtensionsToFilter = nullListPropertyOf(p, String) } @@ -296,6 +303,16 @@ class PitestPluginExtension { this.enableDefaultIncrementalAnalysis.set(withHistory) } + @Deprecated //Alias for inputCharset to keep naming compatibility with PIT + void setInputEncoding(Charset inputCharset) { + this.inputCharset.set(inputCharset) + } + + @Deprecated //Alias for outputCharset to keep naming compatibility with PIT + void setOutputEncoding(Charset outputCharset) { + this.outputCharset.set(outputCharset) + } + private static SetProperty nullSetPropertyOf(Project p, Class clazz) { return p.objects.setProperty(clazz).convention(p.providers.provider { null } as Provider) //coercion due to "red" warning in Idea } diff --git a/src/main/groovy/info/solidsoft/gradle/pitest/PitestTask.groovy b/src/main/groovy/info/solidsoft/gradle/pitest/PitestTask.groovy index 58201ea1..c2a2df2a 100644 --- a/src/main/groovy/info/solidsoft/gradle/pitest/PitestTask.groovy +++ b/src/main/groovy/info/solidsoft/gradle/pitest/PitestTask.groovy @@ -40,6 +40,8 @@ import org.gradle.api.tasks.PathSensitive import org.gradle.api.tasks.PathSensitivity import org.gradle.api.tasks.options.Option +import java.nio.charset.Charset + /** * Gradle task implementation for Pitest. */ @@ -223,6 +225,14 @@ class PitestTask extends JavaExec { @Optional final Property useClasspathJar + @Input + @Optional + final Property inputEncoding + + @Input + @Optional + final Property outputEncoding + @Input @Optional final ListProperty features @@ -285,6 +295,8 @@ class PitestTask extends JavaExec { pluginConfiguration = of.mapProperty(String, String) maxSurviving = of.property(Integer) useClasspathJar = of.property(Boolean) + inputEncoding = of.property(Charset) + outputEncoding = of.property(Charset) additionalClasspath = of.fileCollection() useAdditionalClasspathFile = of.property(Boolean) additionalClasspathFile = of.fileProperty() @@ -367,6 +379,8 @@ class PitestTask extends JavaExec { map['jvmPath'] = getJvmPath()?.getOrNull()?.asFile?.absolutePath map['maxSurviving'] = optionalPropertyAsString(maxSurviving) map['useClasspathJar'] = optionalPropertyAsString(useClasspathJar) + map['inputEncoding'] = optionalPropertyAsString(inputEncoding) + map['outputEncoding'] = optionalPropertyAsString(outputEncoding) map['features'] = (features.getOrElse([]) + (additionalFeatures ?: []))?.join(',') map.putAll(prepareMapWithClasspathConfiguration()) map.putAll(prepareMapWithIncrementalAnalysisConfiguration()) diff --git a/src/test/groovy/info/solidsoft/gradle/pitest/PitestAggregatorPluginTest.groovy b/src/test/groovy/info/solidsoft/gradle/pitest/PitestAggregatorPluginTest.groovy index c0a79c72..3631b4cb 100644 --- a/src/test/groovy/info/solidsoft/gradle/pitest/PitestAggregatorPluginTest.groovy +++ b/src/test/groovy/info/solidsoft/gradle/pitest/PitestAggregatorPluginTest.groovy @@ -49,6 +49,8 @@ class PitestAggregatorPluginTest extends Specification { // void "use pitest version from subproject project configuration"() {} //TODO: Can be implemented with ProjectBuilder? withParent()? +// void "use configured charset in aggregation"() {} //TODO: Can be tested in "unit" way? + private void assertThatTasksAreInGroup(List taskNames, String group) { taskNames.each { String taskName -> Task task = project.tasks[taskName] diff --git a/src/test/groovy/info/solidsoft/gradle/pitest/PitestTaskConfigurationSpec.groovy b/src/test/groovy/info/solidsoft/gradle/pitest/PitestTaskConfigurationSpec.groovy index 4d96de7d..80524e39 100644 --- a/src/test/groovy/info/solidsoft/gradle/pitest/PitestTaskConfigurationSpec.groovy +++ b/src/test/groovy/info/solidsoft/gradle/pitest/PitestTaskConfigurationSpec.groovy @@ -18,6 +18,8 @@ package info.solidsoft.gradle.pitest import groovy.transform.CompileDynamic import spock.lang.Issue +import java.nio.charset.Charset + //TODO: Think if task initialization with WithPitestTaskInitialization is not performed to early // (see PitestTaskTestPluginConfigurationSpec for corner case with login in PitestPlugin) @CompileDynamic @@ -56,6 +58,8 @@ class PitestTaskConfigurationSpec extends BasicProjectBuilderSpec implements Wit 'jvmPath', 'maxSurviving', 'useClasspathJar', + 'inputEncoding', + 'outputEncoding', 'features', 'historyInputLocation', 'historyOutputLocation', @@ -168,6 +172,9 @@ class PitestTaskConfigurationSpec extends BasicProjectBuilderSpec implements Wit //pluginConfiguration tested separately "maxSurviving" | 20 || "20" "useClasspathJar" | true || "true" + //inputCharset and outputCharset tested separately - they set inputEncoding and outputEncoding in PIT + "inputEncoding" | Charset.forName("ISO-8859-2") || "ISO-8859-2" + "outputEncoding" | Charset.forName("ISO-8859-1") || "ISO-8859-1" "features" | ["-FOO", "+BAR(a[1] a[2])"] || "-FOO,+BAR(a[1] a[2])" //fileExtensionsToFilter not passed to PIT, tested separately } @@ -249,6 +256,18 @@ class PitestTaskConfigurationSpec extends BasicProjectBuilderSpec implements Wit ] as Set } + void "should set input/output encoding in PIT for input/output charset"() { + given: + String inputEncodingAsString = "ISO-8859-2" + String outputEncodingAsString = "ISO-8859-1" + and: + project.pitest.inputCharset = Charset.forName(inputEncodingAsString) + project.pitest.outputCharset = Charset.forName(outputEncodingAsString) + expect: + task.taskArgumentMap()['inputEncoding'] == inputEncodingAsString + task.taskArgumentMap()['outputEncoding'] == outputEncodingAsString + } + private Set assembleMainSourceDirAsStringSet() { return ["resources", "java"].collect { String dirName -> new File(project.projectDir, "src/main/${dirName}")