Skip to content

Commit

Permalink
Issue #71, #140, #172 (#180)
Browse files Browse the repository at this point in the history
* issue #140: Support gradle test fixtures
* issue #71: Consider transitive dependencies when resolving TestEngine
* issue #172: TestNG has the wrong module name for versions 7.0.0 and above
  • Loading branch information
siordache authored Mar 28, 2021
1 parent 8cbe1c1 commit 9b233dc
Show file tree
Hide file tree
Showing 37 changed files with 406 additions and 108 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[![Build Status](https://img.shields.io/github/workflow/status/javamodularity/gradle-modules-plugin/Build)](https://github.com/javamodularity/gradle-modules-plugin/actions?query=workflow%3A%22Build%22)
[![Build Status](https://img.shields.io/github/workflow/status/java9-modularity/gradle-modules-plugin/Build)](https://github.com/java9-modularity/gradle-modules-plugin/actions?query=workflow%3A%22Build%22)


Introduction
Expand Down Expand Up @@ -45,6 +45,7 @@ For this guide we assume the following directory structure:
├── greeter.javaexec
├── greeter.provider
├── greeter.provider.test
├── greeter.provider.testfixture
├── greeter.runner
├── greeter.startscripts
└── settings.gradle
Expand All @@ -54,6 +55,7 @@ For this guide we assume the following directory structure:
* greeter.javaexec: Applications that can be started with `ModularJavaExec` tasks
* greeter.provider: Provides a service implementation for the interface provided by `greeter.api`
* greeter.provider.test: Blackbox module test for `greeter.provider`
* greeter.provider.testfixture: Blackbox module test with test fixtures for `greeter.provider`
* greeter.runner: Main class that uses the `Greeter` service, that can be started/packaged with the `application plugin`
* greeter.startscripts: Applications with start scripts generated by `ModularCreateStartScripts` tasks

Expand Down Expand Up @@ -650,7 +652,7 @@ Requirements
This plugin requires JDK 11 or newer to be used when running Gradle.

The minimum Gradle version supported by this plugin is 5.1.
However, we strongly recommend to use at least Gradle 5.6, because there are a few special cases that cannot be handled correctly when using older versions.
However, we strongly recommend to use at least Gradle 6.0, because there are a few special cases that cannot be handled correctly when using older versions.

Contributing
===
Expand Down
11 changes: 6 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@ dependencies {
plugin 'com.github.javaparser:javaparser-symbol-solver-core:3.13.5'

testImplementation gradleTestKit()
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.1'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.4.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.4.1'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.4.1' // required when testing in Eclipse
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.1'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.1'
testImplementation 'org.junit-pioneer:junit-pioneer:1.3.8'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.1'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.7.1' // required when testing in Eclipse
}

shadowJar {
Expand Down Expand Up @@ -106,7 +107,7 @@ pluginBundle {

publishing { // used for publishing to local maven repository
publications {
maven(MavenPublication) {
pluginMaven(MavenPublication) {
groupId = 'org.javamodularity'
artifactId = 'moduleplugin'
version = project.version
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.4-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
* Generic helper for Gradle {@link Project} API that is modular and has {@link JavaPlugin} applied.
*/
public final class JavaProjectHelper {
public static final String COMPILE_TEST_FIXTURES_JAVA_TASK_NAME = "compileTestFixturesJava";
public static final String COMPILE_TEST_FIXTURES_KOTLIN_TASK_NAME = "compileTestFixturesKotlin";
public static final String COMPILE_TEST_FIXTURES_GROOVY_TASK_NAME = "compileTestFixturesGroovy";

public static final String TEST_FIXTURES_SOURCE_SET_NAME = "testFixtures";

private final Project project;

Expand Down Expand Up @@ -44,8 +49,8 @@ public String moduleName() {
}

public boolean shouldFixEffectiveArguments() {
return /*GradleVersion.current().compareTo(GradleVersion.version("6.3")) <= 0
&& */ modularityExtension().optionContainer().isEffectiveArgumentsAdjustmentEnabled();
return GradleVersion.current().compareTo(GradleVersion.version("6.6")) < 0
&& modularityExtension().optionContainer().isEffectiveArgumentsAdjustmentEnabled();
}

//region SOURCE SETS
Expand All @@ -64,7 +69,15 @@ public SourceSet mainSourceSet() {
public SourceSet testSourceSet() {
return sourceSet(SourceSet.TEST_SOURCE_SET_NAME);
}
//endregion

public Optional<SourceSet> findSourceSet(String sourceSetName) {
return Optional.ofNullable(sourceSets().findByName(sourceSetName));
}

public Optional<SourceSet> findTestFixturesSourceSet() {
return findSourceSet(TEST_FIXTURES_SOURCE_SET_NAME);
}
//endregion

//region TASKS
public Task task(String taskName) {
Expand Down
50 changes: 32 additions & 18 deletions src/main/java/org/javamodularity/moduleplugin/TestEngine.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
package org.javamodularity.moduleplugin;

import org.gradle.api.Project;
import org.gradle.api.artifacts.*;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.javamodularity.moduleplugin.internal.TaskOption;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public enum TestEngine {

JUNIT_4("junit", "junit", "junit", "junit"),
JUNIT_5_API("org.junit.jupiter", "junit-jupiter-api", "org.junit.jupiter.api", "org.junit.platform.commons"),
JUNIT_5("org.junit.jupiter", "junit-jupiter", "org.junit.jupiter.api", "org.junit.jupiter.api"),
TESTNG("org.testng", "testng", "testng", "testng"),
JUNIT_5_API("org.junit.jupiter", ".*", "org.junit.jupiter.api", "org.junit.platform.commons"),
JUNIT_5("org.junit.jupiter", ".*", "org.junit.jupiter.api", "org.junit.jupiter.api"),
JUNIT_PLATFORM_COMMONS("org.junit.jupiter", ".*", "org.junit.platform.commons", "ALL-UNNAMED",
new TaskOption("--add-exports", "org.junit.platform.commons/org.junit.platform.commons.util=ALL-UNNAMED"),
new TaskOption("--add-exports", "org.junit.platform.commons/org.junit.platform.commons.logging=ALL-UNNAMED"),
new TaskOption("--add-exports", "org.junit.platform.engine/org.junit.platform.engine.support.filter=org.junit.jupiter.engine,ALL-UNNAMED")
),
TESTNG("org.testng", "testng", "org.testng", "org.testng"),
ASSERTJ("org.assertj", "assertj-core", "org.assertj.core", "org.assertj.core"),
MOCKITO("org.mockito", "mockito-core", "org.mockito", "org.mockito"),
EASYMOCK("org.easymock", "easymock", "org.easymock", "org.easymock"),
Expand All @@ -24,6 +29,8 @@ public enum TestEngine {
new TaskOption("--add-exports", "org.junit.platform.engine/org.junit.platform.engine.support.filter=org.junit.jupiter.engine,ALL-UNNAMED")
);

private static final Logger LOGGER = Logging.getLogger(TestEngine.class);

private final String groupId;
private final String artifactId;

Expand All @@ -39,19 +46,26 @@ public enum TestEngine {
this.additionalTaskOptions = Arrays.asList(additionalTaskOptions);
}

public static List<TestEngine> selectMultiple(Project project) {
public static Collection<TestEngine> selectMultiple(Project project) {
var configurations = project.getConfigurations();
var testImplementation = configurations.getByName("testImplementation").getDependencies().stream();
var testCompile = configurations.getByName("testCompile").getDependencies().stream();
return Stream.concat(testImplementation, testCompile)
.map(d -> TestEngine.select(d.getGroup(), d.getName()))
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
}
var engines = List.of(
"compileClasspath", "compileOnly", "implementation", "runtimeClasspath", "runtimeOnly",
"testImplementation", "testCompile", "testRuntime", "testRuntimeOnly",
"testFixturesApi", "testFixturesCompile", "testFixturesImplementation", "testFixturesRuntime", "testFixturesRuntimeOnly")
.stream()
.map(configurations::findByName)
.filter(Objects::nonNull)
.map(Configuration::getDependencies)
.flatMap(DependencySet::stream)
.flatMap(d -> TestEngine.select(d.getGroup(), d.getName()))
.collect(Collectors.toSet());
LOGGER.info("Selected test engines: " + engines);
return engines;

private static Optional<TestEngine> select(String groupId, String artifactId) {
return Arrays.stream(TestEngine.values()).filter(engine -> engine.groupId.equals(groupId) && engine.artifactId.equals(artifactId)).findAny();
}

private static Stream<TestEngine> select(String groupId, String artifactId) {
return Arrays.stream(TestEngine.values())
.filter(engine -> groupId.matches(engine.groupId) && artifactId.matches(engine.artifactId));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.javamodularity.moduleplugin.extensions.CompileModuleOptions;
import org.javamodularity.moduleplugin.internal.CompileModuleInfoHelper;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;

Expand Down Expand Up @@ -53,7 +54,18 @@ public void execute(Task task) {
}
});

project.getTasks().withType(Jar.class).configureEach(jar -> jar.from(helper().getModuleInfoDir()));
project.getTasks().withType(Jar.class).configureEach(jar -> {
File moduleInfoDir = helper().getModuleInfoDir();
jar.from(moduleInfoDir);
jar.doFirst(task -> {
File classesDir = helper().mainSourceSet().getJava().getOutputDir();
File mainModuleInfoFile = new File(classesDir, "module-info.class");
File customModuleInfoFile = new File(moduleInfoDir, "module-info.class");
if(mainModuleInfoFile.isFile() && customModuleInfoFile.isFile()) {
mainModuleInfoFile.delete();
}
});
});
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.gradle.api.logging.Logging;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.tasks.compile.JavaCompile;
import org.javamodularity.moduleplugin.JavaProjectHelper;
import org.javamodularity.moduleplugin.TestEngine;
import org.javamodularity.moduleplugin.extensions.CompileTestModuleOptions;
import org.javamodularity.moduleplugin.extensions.PatchModuleContainer;
Expand All @@ -26,6 +27,10 @@ public CompileTestTask(Project project) {
public void configureCompileTestJava() {
helper().findTask(JavaPlugin.COMPILE_TEST_JAVA_TASK_NAME, JavaCompile.class)
.ifPresent(this::configureCompileTestJava);
project.afterEvaluate(p -> {
helper().findTask(JavaProjectHelper.COMPILE_TEST_FIXTURES_JAVA_TASK_NAME, JavaCompile.class)
.ifPresent(task -> task.exclude("module-info.java"));
});
}

private void configureCompileTestJava(JavaCompile compileTestJava) {
Expand Down Expand Up @@ -55,7 +60,12 @@ private List<String> buildCompilerArgs(
var patchModuleContainer = PatchModuleContainer.copyOf(
helper().modularityExtension().optionContainer().getPatchModuleContainer());
FileCollection testSourceDirs = helper().testSourceSet().getJava().getSourceDirectories();
testSourceDirs.forEach(dir -> patchModuleContainer.addDir(moduleName, dir.getAbsolutePath()));
FileCollection testFixturesSourceDirs = helper().findTestFixturesSourceSet()
.map(sourceSet -> sourceSet.getJava().getSourceDirectories())
.orElse(project.files());
FileCollection allTestSourceDirs = testSourceDirs.plus(testFixturesSourceDirs);

allTestSourceDirs.forEach(dir -> patchModuleContainer.addDir(moduleName, dir.getAbsolutePath()));
patchModuleContainer.buildModulePathOption(classpath).ifPresent(option -> option.mutateArgs(compilerArgs));

TestEngine.selectMultiple(project).forEach(testEngine -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

import org.gradle.api.Project;
import org.gradle.api.file.FileCollection;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.tasks.Sync;
import org.gradle.api.tasks.compile.AbstractCompile;
import org.gradle.api.tasks.compile.JavaCompile;
import org.gradle.jvm.tasks.Jar;
import org.javamodularity.moduleplugin.JavaProjectHelper;
import org.javamodularity.moduleplugin.extensions.CompileModuleOptions;
import org.javamodularity.moduleplugin.internal.StreamHelper;
Expand All @@ -18,8 +21,10 @@
import java.util.stream.Stream;

public class MergeClassesHelper {
private static final Logger LOGGER = Logging.getLogger(MergeClassesHelper.class);

public static final String MERGE_CLASSES_TASK_NAME = "mergeClasses";
public static final List<String> PRE_JAVA_COMPILE_TASK_NAMES = List.of("compileKotlin");
public static final List<String> PRE_JAVA_COMPILE_TASK_NAMES = List.of("compileKotlin", JavaProjectHelper.COMPILE_TEST_FIXTURES_KOTLIN_TASK_NAME);
public static final List<String> POST_JAVA_COMPILE_TASK_NAMES = List.of("compileGroovy");

private final Project project;
Expand Down Expand Up @@ -63,7 +68,15 @@ public Sync createMergeClassesTask() {
}

public FileCollection getMergeAdjustedClasspath(FileCollection classpath) {
if (!isMergeRequired()) {
File testFixturesJar = helper().findTask("testFixturesJar", Jar.class)
.map(task -> task.getArchiveFile().get().getAsFile())
.orElse(null);
if(testFixturesJar != null) {
classpath = classpath.minus(project.files(testFixturesJar));
}

boolean mergeRequired = isMergeRequired();
if (!mergeRequired) {
return classpath;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
package org.javamodularity.moduleplugin.tasks;

import org.gradle.api.Project;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.gradle.api.plugins.ApplicationPlugin;
import org.gradle.api.plugins.JavaPlugin;
import org.javamodularity.moduleplugin.JavaProjectHelper;
import org.javamodularity.moduleplugin.extensions.CompileModuleOptions;

import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

public class MergeClassesTask extends AbstractModulePluginTask {
private static final Logger LOGGER = Logging.getLogger(MergeClassesTask.class);

public MergeClassesTask(Project project) {
super(project);
}
Expand All @@ -17,19 +24,21 @@ public void configureMergeClasses() {
}

public void configureMergeClassesAfterEvaluate() {
if (!mergeClassesHelper().isMergeRequired()) {
return;
}

var mergeClasses = mergeClassesHelper().createMergeClassesTask();

mergeClassesHelper().allCompileTaskStream().forEach(task -> {
mergeClasses.from(task.getDestinationDir());
List<String> modularTasks = List.of(JavaPlugin.COMPILE_JAVA_TASK_NAME, CompileModuleOptions.COMPILE_MODULE_INFO_TASK_NAME);
if(modularTasks.contains(task.getName())) {
mergeClasses.from(task.getDestinationDir());
} else {
mergeClasses.from(task.getDestinationDir(), copySpec -> copySpec.exclude("**/module-info.class"));
}
mergeClasses.dependsOn(task);
});
mergeClasses.into(helper().getMergedDir());
mergeClasses.onlyIf(task -> mergeClassesHelper().isMergeRequired());

Stream.of(ApplicationPlugin.TASK_RUN_NAME, JavaPlugin.TEST_TASK_NAME)
Stream.of(ApplicationPlugin.TASK_RUN_NAME, JavaPlugin.TEST_TASK_NAME, JavaProjectHelper.COMPILE_TEST_FIXTURES_JAVA_TASK_NAME)
.map(helper()::findTask)
.flatMap(Optional::stream)
.forEach(task -> task.dependsOn(mergeClasses));
Expand Down
16 changes: 13 additions & 3 deletions src/main/java/org/javamodularity/moduleplugin/tasks/TestTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,21 @@ private List<String> buildJvmArgs(Test testJava, TestModuleOptions testModuleOpt
}

private Stream<Path> buildPatchModulePathStream() {
SourceSet testSourceSet = helper().testSourceSet();
SourceSet mainSourceSet = helper().mainSourceSet();
SourceSet testSourceSet = helper().testSourceSet();
Optional<SourceSet> testFixturesSourceSet = helper().findTestFixturesSourceSet();

var classesSourceSets = new ArrayList<SourceSet>();
classesSourceSets.add(testSourceSet);
testFixturesSourceSet.ifPresent(classesSourceSets::add);

var sourceSets = new ArrayList<SourceSet>();
sourceSets.add(mainSourceSet);
sourceSets.addAll(classesSourceSets);

Stream<File> classesFileStream = testSourceSet.getOutput().getClassesDirs().getFiles().stream();
Stream<File> resourceFileStream = Stream.of(mainSourceSet, testSourceSet)
Stream<File> classesFileStream = classesSourceSets.stream()
.flatMap(sourceSet -> sourceSet.getOutput().getClassesDirs().getFiles().stream());
Stream<File> resourceFileStream = sourceSets.stream()
.map(sourceSet -> sourceSet.getOutput().getResourcesDir());

return Stream.concat(classesFileStream, resourceFileStream).map(File::toPath);
Expand Down
Loading

0 comments on commit 9b233dc

Please sign in to comment.