Skip to content

Commit

Permalink
Merge pull request #1542 from TNG/feature/separate-plugin-config-and-…
Browse files Browse the repository at this point in the history
…execution

Feature/separate plugin config and execution
  • Loading branch information
l-1squared authored Feb 29, 2024
2 parents ca6476c + 9be2e78 commit e699d4f
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 98 deletions.
72 changes: 39 additions & 33 deletions CHANGELOG.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,25 @@
import com.tngtech.jgiven.gradle.internal.JGivenHtmlReportImpl;
import com.tngtech.jgiven.impl.Config;
import com.tngtech.jgiven.impl.util.WordUtil;
import java.io.File;
import java.util.Objects;
import java.util.concurrent.Callable;
import org.gradle.api.Action;
import org.gradle.api.NonNullApi;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.internal.ConventionMapping;
import org.gradle.api.internal.IConventionAware;
import org.gradle.api.*;
import org.gradle.api.file.Directory;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.plugins.ReportingBasePlugin;
import org.gradle.api.provider.Provider;
import org.gradle.api.reporting.Report;
import org.gradle.api.reporting.ReportingExtension;
import org.gradle.api.tasks.testing.Test;

import javax.inject.Inject;
import java.util.Objects;

@SuppressWarnings("unused")
@NonNullApi
public class JGivenPlugin implements Plugin<Project> {
public abstract class JGivenPlugin implements Plugin<Project> {

@Inject
protected abstract ObjectFactory getObjects();

@Override
public void apply(final Project project) {
project.getPluginManager().apply(ReportingBasePlugin.class);
Expand All @@ -35,64 +37,60 @@ private void addTaskExtension(Project project) {

private void applyTo(Test test) {
final String testName = test.getName();
final JGivenTaskExtension extension = test.getExtensions().create("jgiven", JGivenTaskExtension.class);
final Project project = test.getProject();
((IConventionAware) extension).getConventionMapping().map("resultsDir",
(Callable<File>) () -> project.file(project.getBuildDir() + "/jgiven-results/" + testName));

File resultsDir = extension.getResultsDir();
if (resultsDir != null) {
test.getOutputs().dir(resultsDir).withPropertyName("jgiven.resultsDir");
}
final JGivenTaskExtension extension = getObjects().newInstance(JGivenTaskExtension.class);
test.getExtensions().add("jgiven", extension);
extension.getResultsDir().convention(project.getLayout().getBuildDirectory().dir("jgiven-results/" + testName));
Provider<Directory> resultsDir = extension.getResultsDir();
test.getOutputs().dir(resultsDir).withPropertyName("jgiven.resultsDir");

/* Java lambda classes are created at runtime with a non-deterministic classname.
* Therefore, the class name does not identify the implementation of the lambda,
* and changes between different Gradle runs.
* See: https://docs.gradle.org/current/userguide/more_about_tasks.html#sec:how_does_it_work
*/
//noinspection Convert2Lambda
test.prependParallelSafeAction(new Action<Task>() {
test.doFirst(new Action<>() {
@Override
public void execute(Task task) {
((Test) task).systemProperty(Config.JGIVEN_REPORT_DIR, extension.getResultsDir().getAbsolutePath());
((Test) task).systemProperty(Config.JGIVEN_REPORT_DIR,
extension.getResultsDir().get().getAsFile().getAbsolutePath());
}
});
}

private void configureJGivenReportDefaults(Project project) {
project.getTasks()
.withType(JGivenReportTask.class).forEach(reportTask ->
reportTask.getReports().all((Action<Report>) report ->
report.getRequired().convention(report.getName().equals(JGivenHtmlReportImpl.NAME))
));
.withType(JGivenReportTask.class).configureEach(reportTask ->
reportTask.getReports().all((Action<Report>) report ->
report.getRequired().convention(report.getName().equals(JGivenHtmlReportImpl.NAME))
));
}

private void addDefaultReports(final Project project) {
final ReportingExtension reportingExtension = Objects.requireNonNull(
project.getExtensions().findByType(ReportingExtension.class));

project.getTasks().withType(Test.class).forEach(test -> project.getTasks()
.register("jgiven" + WordUtil.capitalize(test.getName()) + "Report", JGivenReportTask.class)
.configure(reportTask -> configureDefaultReportTask(test, reportTask, reportingExtension))
.register("jgiven" + WordUtil.capitalize(test.getName()) + "Report", JGivenReportTask.class)
.configure(reportTask -> configureDefaultReportTask(test, reportTask, reportingExtension))
);
}

private void configureDefaultReportTask(final Test test, JGivenReportTask reportTask,
final ReportingExtension reportingExtension) {
reportTask.mustRunAfter(test);

ConventionMapping mapping = ((IConventionAware) reportTask).getConventionMapping();
Callable<File> getResultsDirectory = () -> test.getExtensions()
Provider<Directory> resultsDirectory = test.getExtensions()
.getByType(JGivenTaskExtension.class)
.getResultsDir();
mapping.map("results", getResultsDirectory);

Objects.requireNonNull(mapping.getConventionValue(reportTask.getReports(), "reports", false))
.all(report -> {
ConventionMapping reportMapping = ((IConventionAware) report).getConventionMapping();
String relativeFilePath = "jgiven" + "/" + test.getName() + "/" + report.getName();
Callable<File> getDestination = () -> reportingExtension.file(relativeFilePath);
reportMapping.map("destination", getDestination);
});

reportTask.getResults().convention(resultsDirectory);

String relativeFilePath = "jgiven" + "/" + test.getName() + "/";
Provider<Directory> reportOutputLocation = reportingExtension.getBaseDirectory().dir(relativeFilePath);

reportTask.getReports().configureEach(report -> {
report.getOutputLocation().set(reportOutputLocation.map(d -> d.dir(report.getName())));
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import org.gradle.api.Action;
import org.gradle.api.DefaultTask;
import org.gradle.api.NonNullApi;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.reporting.Reporting;
import org.gradle.api.tasks.CacheableTask;
import org.gradle.api.tasks.InputDirectory;
Expand All @@ -20,29 +22,20 @@

@CacheableTask
@NonNullApi
public class JGivenReportTask extends DefaultTask implements Reporting<JGivenReportsContainer> {
public abstract class JGivenReportTask extends DefaultTask implements Reporting<JGivenReportsContainer> {
private final JGivenReportsContainer reports;
private File results;

public JGivenReportTask() {
reports = getInstantiator().newInstance(JGivenReportsContainerImpl.class, this);
reports = getObjects().newInstance(JGivenReportsContainerImpl.class, this);
}

@Inject
protected Instantiator getInstantiator() {
throw new UnsupportedOperationException();
}
protected abstract ObjectFactory getObjects();

@InputDirectory
@SkipWhenEmpty
@PathSensitive(PathSensitivity.NONE)
public File getResults() {
return results;
}

public void setResults(File results) {
this.results = results;
}
public abstract DirectoryProperty getResults();

@TaskAction
public void generate() {
Expand All @@ -53,7 +46,7 @@ public void generate() {

private void generateReport(JGivenReport report) {
AbstractReportGenerator generator = report.createGenerator();
generator.config.setSourceDir(getResults());
generator.config.setSourceDir(getResults().get().getAsFile());
generator.loadReportModel();
try {
generator.generate();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
package com.tngtech.jgiven.gradle;

import java.io.File;
import org.gradle.api.file.DirectoryProperty;

public class JGivenTaskExtension {
private File resultsDir;
public interface JGivenTaskExtension {
DirectoryProperty getResultsDir();

public File getResultsDir() {
return resultsDir;
}

public void setResultsDir( File resultsDir ) {
this.resultsDir = resultsDir;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
import org.gradle.api.Task;
import org.gradle.api.reporting.internal.TaskReportContainer;

import javax.inject.Inject;

import static org.gradle.api.internal.CollectionCallbackActionDecorator.NOOP;

public class JGivenReportsContainerImpl extends TaskReportContainer<JGivenReport> implements JGivenReportsContainer {

@Inject
public JGivenReportsContainerImpl( Task task ) {
super( JGivenReport.class, task, NOOP);
add(JGivenHtmlReportImpl.class, task);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,37 @@ class JGivenPluginShould extends Specification {
buildFile = new File(testProjectDir,'build.gradle')
}

def "configuration is cacheable"() {
given:
buildFile << """
plugins {
id 'java'
id 'com.tngtech.jgiven.gradle-plugin'
}
repositories { mavenCentral() }
dependencies {
testImplementation 'com.tngtech.jgiven:jgiven-junit:1.2.5'
testImplementation 'junit:junit:4.13.2'
}
"""

new File(testProjectDir,"src/test/java").mkdirs()
File scenario = new File(testProjectDir,"src/test/java/SimpleScenario.java")
scenario << Resources.toByteArray(Resources.getResource("SimpleScenario.java"))

when:
def result = GradleRunner.create()
.withProjectDir(testProjectDir)
.withArguments("--configuration-cache", "test", "jgivenTestReport", "-S", "--info"/*, "-Dorg.gradle.debug=true"*/ )
.withPluginClasspath()
.build()

then:
result.task(":test").outcome == SUCCESS
result.task(":jgivenTestReport").outcome == SUCCESS
}

def "test is cacheable"() {
given:
buildFile << """
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@
import com.tngtech.jgiven.annotation.ScenarioState;
import com.tngtech.jgiven.junit5.JGivenExtension;
import com.tngtech.jgiven.junit5.ScenarioTest;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.BuildTask;
import org.gradle.testkit.runner.GradleRunner;
Expand Down Expand Up @@ -162,14 +165,40 @@ void no_jgiven_results_no_report() throws IOException {
.and().there_are_JGiven_tests();

when()
.a_build().with()
.a_build().with().the_argument("-x test").and()
.the_task("jgivenTestReport").is_successful();

then().the_JGiven_reports_are_not_written_to("build/reports/jgiven/test/html");

}

@Test
void no_report_task_no_report() throws IOException {

given()
.the_plugin_is_applied()
.and().there_are_JGiven_tests();

when()
.a_build().with()
.the_task("test").is_successful();

then()
.the_JGiven_reports_are_not_written_to("build/reports/jgiven/test/html");

}

@Test
void jgiven_reports_can_be_attached_to_test_tasks() throws IOException {
given().the_plugin_is_applied()
.and().there_are_JGiven_tests()
.and().test_tasks_are_finalized_by_JGiven();

when().the_task("test").is_successful();

then().the_JGiven_html_reports_are_written_to("build/reports/jgiven/test/html");
}

@SuppressWarnings("UnusedReturnValue")
static class Given extends Stage<Given> {
@ExpectedScenarioState
Expand Down Expand Up @@ -209,6 +238,11 @@ Given the_jgiven_report_is_configured_by(String configuration) throws IOExceptio
buildFile.write("jgivenTestReport { " + configuration + " } ");
return self();
}

Given test_tasks_are_finalized_by_JGiven() throws IOException{
buildFile.write("test.finalizedBy jgivenTestReport\n");
return self();
}
}

@SuppressWarnings("UnusedReturnValue")
Expand All @@ -229,6 +263,11 @@ When a_build() {
return self();
}

When the_argument(String argument){
tasks.addAll(Arrays.asList(argument.split(" ")));
return self();
}

When is_successful() {
result = GradleRunner.create()
.withProjectDir(testProjectDir.get())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public void generate() {
copyCustomFile( specializedConfig.getCustomCss(), new File( specializedConfig.getTargetDir(), "css" ), "custom.css" );
copyCustomFile( specializedConfig.getCustomJs(), new File( specializedConfig.getTargetDir(), "js" ), "custom.js" );
} catch( IOException e ) {
throw Throwables.propagate( e );
throw new RuntimeException(e);
}
}

Expand Down

0 comments on commit e699d4f

Please sign in to comment.