From 06a7af64ca69aa630da31e1add66dff32c9f3d39 Mon Sep 17 00:00:00 2001 From: Jendrik Johannes Date: Fri, 31 Oct 2025 18:03:47 +0100 Subject: [PATCH] Fix: sourcesUnderTest can be reconfigured --- .../testing/JavaModuleTestingExtension.java | 8 +++-- .../javamodule/testing/TaskLockService.java | 2 ++ .../testing/WhiteboxJvmTestSuite.java | 2 ++ .../testing/internal/ModuleInfoParser.java | 5 ++++ .../internal/ModuleInfoRequiresParser.java | 2 ++ .../bridges/JavaModuleDependenciesBridge.java | 4 +++ .../WhiteboxTestCompileArgumentProvider.java | 16 ++++++---- .../WhiteboxTestRuntimeArgumentProvider.java | 23 +++++++++----- .../testing/test/CustomizationTest.java | 30 +++++++++++++++++++ .../testing/test/fixture/GradleBuild.java | 8 ++--- 10 files changed, 78 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/gradlex/javamodule/testing/JavaModuleTestingExtension.java b/src/main/java/org/gradlex/javamodule/testing/JavaModuleTestingExtension.java index 75fbaf5..86c175f 100644 --- a/src/main/java/org/gradlex/javamodule/testing/JavaModuleTestingExtension.java +++ b/src/main/java/org/gradlex/javamodule/testing/JavaModuleTestingExtension.java @@ -30,8 +30,10 @@ import org.gradlex.javamodule.testing.internal.bridges.JavaModuleDependenciesBridge; import org.gradlex.javamodule.testing.internal.provider.WhiteboxTestCompileArgumentProvider; import org.gradlex.javamodule.testing.internal.provider.WhiteboxTestRuntimeArgumentProvider; +import org.jspecify.annotations.NullMarked; @SuppressWarnings("UnstableApiUsage") +@NullMarked public abstract class JavaModuleTestingExtension { private static final Action NO_OP_ACTION = c -> {}; @@ -251,7 +253,6 @@ private void configureJvmTestSuiteForWhitebox( .orElseGet(() -> { WhiteboxTestCompileArgumentProvider newProvider = new WhiteboxTestCompileArgumentProvider( - sourcesUnderTest.getJava().getSrcDirs(), testSources.getJava().getSrcDirs(), moduleInfoParser, project.getObjects()); @@ -263,6 +264,7 @@ private void configureJvmTestSuiteForWhitebox( project.getObjects().newInstance(JavaCompileSetModulePathAction.class)); return newProvider; }); + argumentProvider.setMainSourceFolders(sourcesUnderTest.getJava().getSrcDirs()); argumentProvider.testRequires( JavaModuleDependenciesBridge.getCompileClasspathModules(project, testSources)); argumentProvider.testRequires(whiteboxJvmTestSuite.getRequires()); @@ -289,15 +291,15 @@ private void configureJvmTestSuiteForWhitebox( .orElseGet(() -> { WhiteboxTestRuntimeArgumentProvider newProvider = new WhiteboxTestRuntimeArgumentProvider( - sourcesUnderTest.getJava().getSrcDirs(), testSources.getJava().getClassesDirectory(), - sourcesUnderTest.getOutput().getResourcesDir(), testSources.getOutput().getResourcesDir(), moduleInfoParser, project.getObjects()); test.getJvmArgumentProviders().add(newProvider); return newProvider; }); + argumentProvider.setMainSourceFolders(sourcesUnderTest.getJava().getSrcDirs()); + argumentProvider.setResourcesUnderTest(sourcesUnderTest.getOutput().getResourcesDir()); argumentProvider.testRequires( JavaModuleDependenciesBridge.getRuntimeClasspathModules(project, testSources)); argumentProvider.testRequires(whiteboxJvmTestSuite.getRequires()); diff --git a/src/main/java/org/gradlex/javamodule/testing/TaskLockService.java b/src/main/java/org/gradlex/javamodule/testing/TaskLockService.java index 3f7c583..30610e4 100644 --- a/src/main/java/org/gradlex/javamodule/testing/TaskLockService.java +++ b/src/main/java/org/gradlex/javamodule/testing/TaskLockService.java @@ -3,11 +3,13 @@ import org.gradle.api.services.BuildService; import org.gradle.api.services.BuildServiceParameters; +import org.jspecify.annotations.NullMarked; /** * No-op service that can serve as 'lock' to prevent multiple test tasks from running in parallel: * usesService(gradle.sharedServices.registerIfAbsent(TaskLockService.NAME, TaskLockService::class) { maxParallelUsages = 1 }) */ +@NullMarked public abstract class TaskLockService implements BuildService { public static String NAME = "taskLock"; } diff --git a/src/main/java/org/gradlex/javamodule/testing/WhiteboxJvmTestSuite.java b/src/main/java/org/gradlex/javamodule/testing/WhiteboxJvmTestSuite.java index 83fd5b0..e51a513 100644 --- a/src/main/java/org/gradlex/javamodule/testing/WhiteboxJvmTestSuite.java +++ b/src/main/java/org/gradlex/javamodule/testing/WhiteboxJvmTestSuite.java @@ -4,7 +4,9 @@ import org.gradle.api.provider.ListProperty; import org.gradle.api.provider.Property; import org.gradle.api.tasks.SourceSet; +import org.jspecify.annotations.NullMarked; +@NullMarked public interface WhiteboxJvmTestSuite { /** diff --git a/src/main/java/org/gradlex/javamodule/testing/internal/ModuleInfoParser.java b/src/main/java/org/gradlex/javamodule/testing/internal/ModuleInfoParser.java index be9764b..7123ea7 100644 --- a/src/main/java/org/gradlex/javamodule/testing/internal/ModuleInfoParser.java +++ b/src/main/java/org/gradlex/javamodule/testing/internal/ModuleInfoParser.java @@ -9,7 +9,10 @@ import org.gradle.api.file.RegularFile; import org.gradle.api.provider.Provider; import org.gradle.api.provider.ProviderFactory; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +@NullMarked public class ModuleInfoParser { private final ProjectLayout layout; @@ -20,6 +23,7 @@ public ModuleInfoParser(ProjectLayout layout, ProviderFactory providers) { this.providers = providers; } + @Nullable public String moduleName(Set sourceFolders) { for (File folder : sourceFolders) { Provider moduleInfoFile = @@ -33,6 +37,7 @@ public String moduleName(Set sourceFolders) { return null; } + @Nullable static String moduleName(String moduleInfoFileContent) { boolean inComment = false; boolean moduleKeywordFound = false; diff --git a/src/main/java/org/gradlex/javamodule/testing/internal/ModuleInfoRequiresParser.java b/src/main/java/org/gradlex/javamodule/testing/internal/ModuleInfoRequiresParser.java index d15e364..3eeeb90 100644 --- a/src/main/java/org/gradlex/javamodule/testing/internal/ModuleInfoRequiresParser.java +++ b/src/main/java/org/gradlex/javamodule/testing/internal/ModuleInfoRequiresParser.java @@ -4,7 +4,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import org.jspecify.annotations.NullMarked; +@NullMarked public class ModuleInfoRequiresParser { private static final String RUNTIME_KEYWORD = "/*runtime*/"; diff --git a/src/main/java/org/gradlex/javamodule/testing/internal/bridges/JavaModuleDependenciesBridge.java b/src/main/java/org/gradlex/javamodule/testing/internal/bridges/JavaModuleDependenciesBridge.java index 22f5f1f..0096997 100644 --- a/src/main/java/org/gradlex/javamodule/testing/internal/bridges/JavaModuleDependenciesBridge.java +++ b/src/main/java/org/gradlex/javamodule/testing/internal/bridges/JavaModuleDependenciesBridge.java @@ -7,9 +7,13 @@ import org.gradle.api.Project; import org.gradle.api.provider.Provider; import org.gradle.api.tasks.SourceSet; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +@NullMarked public class JavaModuleDependenciesBridge { + @Nullable public static Provider create(Project project, String moduleName, SourceSet sourceSetWithModuleInfo) { Object javaModuleDependencies = project.getExtensions().findByName("javaModuleDependencies"); if (javaModuleDependencies == null) { diff --git a/src/main/java/org/gradlex/javamodule/testing/internal/provider/WhiteboxTestCompileArgumentProvider.java b/src/main/java/org/gradlex/javamodule/testing/internal/provider/WhiteboxTestCompileArgumentProvider.java index 4303ab9..fab395a 100644 --- a/src/main/java/org/gradlex/javamodule/testing/internal/provider/WhiteboxTestCompileArgumentProvider.java +++ b/src/main/java/org/gradlex/javamodule/testing/internal/provider/WhiteboxTestCompileArgumentProvider.java @@ -11,25 +11,29 @@ import org.gradle.api.provider.Provider; import org.gradle.process.CommandLineArgumentProvider; import org.gradlex.javamodule.testing.internal.ModuleInfoParser; +import org.jspecify.annotations.NullMarked; +@NullMarked public class WhiteboxTestCompileArgumentProvider implements CommandLineArgumentProvider { - private final Set mainSourceFolders; private final Set testSourceFolders; private final ModuleInfoParser moduleInfoParser; + @SuppressWarnings("NotNullFieldNotInitialized") + private Set mainSourceFolders; + private final ListProperty allTestRequires; public WhiteboxTestCompileArgumentProvider( - Set mainSourceFolders, - Set testSourceFolders, - ModuleInfoParser moduleInfoParser, - ObjectFactory objects) { - this.mainSourceFolders = mainSourceFolders; + Set testSourceFolders, ModuleInfoParser moduleInfoParser, ObjectFactory objects) { this.testSourceFolders = testSourceFolders; this.moduleInfoParser = moduleInfoParser; this.allTestRequires = objects.listProperty(String.class); } + public void setMainSourceFolders(Set mainSourceFolders) { + this.mainSourceFolders = mainSourceFolders; + } + public void testRequires(Provider> testRequires) { allTestRequires.addAll(testRequires); } diff --git a/src/main/java/org/gradlex/javamodule/testing/internal/provider/WhiteboxTestRuntimeArgumentProvider.java b/src/main/java/org/gradlex/javamodule/testing/internal/provider/WhiteboxTestRuntimeArgumentProvider.java index 760db6a..06ff595 100644 --- a/src/main/java/org/gradlex/javamodule/testing/internal/provider/WhiteboxTestRuntimeArgumentProvider.java +++ b/src/main/java/org/gradlex/javamodule/testing/internal/provider/WhiteboxTestRuntimeArgumentProvider.java @@ -12,29 +12,30 @@ import org.gradle.api.provider.Provider; import org.gradle.process.CommandLineArgumentProvider; import org.gradlex.javamodule.testing.internal.ModuleInfoParser; +import org.jspecify.annotations.NullMarked; +@NullMarked public class WhiteboxTestRuntimeArgumentProvider implements CommandLineArgumentProvider { - private final Set mainSourceFolders; private final Provider testClassesFolders; - private final File resourcesUnderTest; private final File testResources; private final ModuleInfoParser moduleInfoParser; + @SuppressWarnings("NotNullFieldNotInitialized") + private Set mainSourceFolders; + + @SuppressWarnings("NotNullFieldNotInitialized") + private File resourcesUnderTest; + private final ListProperty allTestRequires; private final ListProperty allTestOpensTo; private final ListProperty allTestExportsTo; public WhiteboxTestRuntimeArgumentProvider( - Set mainSourceFolders, Provider testClassesFolders, - File resourcesUnderTest, File testResources, ModuleInfoParser moduleInfoParser, ObjectFactory objects) { - - this.mainSourceFolders = mainSourceFolders; this.testClassesFolders = testClassesFolders; - this.resourcesUnderTest = resourcesUnderTest; this.testResources = testResources; this.moduleInfoParser = moduleInfoParser; this.allTestRequires = objects.listProperty(String.class); @@ -42,6 +43,14 @@ public WhiteboxTestRuntimeArgumentProvider( this.allTestExportsTo = objects.listProperty(String.class); } + public void setMainSourceFolders(Set mainSourceFolders) { + this.mainSourceFolders = mainSourceFolders; + } + + public void setResourcesUnderTest(File resourcesUnderTest) { + this.resourcesUnderTest = resourcesUnderTest; + } + public void testRequires(Provider> testRequires) { allTestRequires.addAll(testRequires); } diff --git a/src/test/java/org/gradlex/javamodule/testing/test/CustomizationTest.java b/src/test/java/org/gradlex/javamodule/testing/test/CustomizationTest.java index 0cc7b94..729877e 100644 --- a/src/test/java/org/gradlex/javamodule/testing/test/CustomizationTest.java +++ b/src/test/java/org/gradlex/javamodule/testing/test/CustomizationTest.java @@ -36,6 +36,36 @@ void can_customize_whitebox_test_suites_in_multiple_steps() { assertThat(testResult.getOutcome()).isEqualTo(TaskOutcome.SUCCESS); } + @Test + void can_change_sourcesUnderTest_of_whitebox_test_suite() { + build.useTestFixturesPlugin(); + build.file("app/src/testFixtures/java/module-info.java") + .writeText(""" + module org.example.fixtures { + } + """); + build.file("app/src/testFixtures/java/org/example/app/Main.java") + .writeText(""" + package org.example.app; + public class Main {} + """); + build.appBuildFile.appendText( + """ + javaModuleTesting.whitebox(testing.suites["test"]) { + sourcesUnderTest.set(sourceSets.testFixtures); + requires.add("org.junit.jupiter.api") + } + """); + + var result = build.runTests(); + var testResult = result.task(":app:test"); + + assertThat(result.getOutput()).contains("Main Module: org.example.fixtures"); + assertThat(result.getOutput()).contains("Test Module: org.example.fixtures"); + assertThat(testResult).isNotNull(); + assertThat(testResult.getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + } + @Test void can_define_whitebox_test_suite_requires_in_moduleinfo_file() { build.appModuleInfoFile.writeText(""" diff --git a/src/test/java/org/gradlex/javamodule/testing/test/fixture/GradleBuild.java b/src/test/java/org/gradlex/javamodule/testing/test/fixture/GradleBuild.java index 76d85a1..93986d0 100644 --- a/src/test/java/org/gradlex/javamodule/testing/test/fixture/GradleBuild.java +++ b/src/test/java/org/gradlex/javamodule/testing/test/fixture/GradleBuild.java @@ -74,7 +74,7 @@ public GradleBuild(Path dir) { testLogging.showStandardStreams = true } tasks.withType().configureEach { options.release.set(11) } - """ + """ .formatted(launcherDependency)); file("app/src/main/java/org/example/app/Main.java") .writeText( @@ -151,15 +151,11 @@ public BuildResult fail() { } public GradleRunner runner(String... args) { - return runner(true, args); - } - - public GradleRunner runner(boolean projectIsolation, String... args) { boolean debugMode = ManagementFactory.getRuntimeMXBean() .getInputArguments() .toString() .contains("-agentlib:jdwp"); - List latestFeaturesArgs = GRADLE_VERSION_UNDER_TEST != null || !projectIsolation + List latestFeaturesArgs = GRADLE_VERSION_UNDER_TEST != null || debugMode ? List.of() : List.of( "--configuration-cache",