diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 30b5f19a8..61d015c9a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,12 +29,18 @@ Shadow has multiple test suites to ensure code quality: #### Running Specific Tests -To speed up local development, you can run specific test classes or methods: +To speed up local development, you can run specific test suites or individual tests: -- Run a specific unit test: `./gradlew test --tests "com.example.YourTestClass"` -- Run functional tests against a specific Gradle version: `./gradlew functionalTest -PtestGradleVersion=9.1.0` (useful +- **Run a specific test suite**: `./gradlew test --tests "*ShadowPropertiesTest*"` +- **Run an individual test within a suite**: TestBalloon uses the `↘` hierarchical separator instead of the standard `Class.method` format: + - `./gradlew functionalTest --tests "*CachingTest*↘disableCacheIfAnyTransformerIsNotCacheable"` + - `./gradlew documentTest --tests "*DocCodeSnippetTest*↘*groovy*"` +- **Run functional tests against a specific Gradle version**: `./gradlew functionalTest -PtestGradleVersion=9.1.0` (useful to verify compatibility locally with the minimum or a custom Gradle version) +> [!NOTE] +> When running individual tests via IntelliJ IDEA run configurations, if `--tests` filtering encounters issues, you can set the `TESTBALLOON_INCLUDE_PATTERNS` environment variable instead (e.g. `TESTBALLOON_INCLUDE_PATTERNS="*CachingTest*↘disableCacheIfAnyTransformerIsNotCacheable"`). + Make sure all tests pass before submitting your changes. ### API Compatibility diff --git a/build.gradle.kts b/build.gradle.kts index c34ad4623..9295d3fa3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -21,6 +21,7 @@ plugins { alias(libs.plugins.pluginPublish) alias(libs.plugins.spotless) alias(libs.plugins.buildConfig) + alias(libs.plugins.testBalloon) } version = providers.gradleProperty("VERSION_NAME").get() @@ -137,6 +138,7 @@ dependencies { testKitImplementation(gradleTestKit()) testKitImplementation(libs.assertk) + testKitImplementation(libs.testBalloon.framework.core) testPluginClasspath(libs.foojayResolver) testPluginClasspath(libs.pluginPublish) @@ -153,14 +155,6 @@ testing.suites { register("documentTest") { targets.configureEach { testTask { - systemProperty("junit.jupiter.execution.parallel.enabled", "true") - systemProperty("junit.jupiter.execution.parallel.mode.default", "concurrent") - systemProperty("junit.jupiter.execution.parallel.config.strategy", "fixed") - // Each snippet runs a nested Gradle build. Two-way parallelism performed better than - // four-way by avoiding excessive CPU, memory, and disk contention. - systemProperty("junit.jupiter.execution.parallel.config.fixed.parallelism", "2") - systemProperty("junit.jupiter.execution.parallel.config.fixed.max-pool-size", "2") - inputs.files( fileTree(docsDir) { // Changelog file doesn't contain code snippet to run. @@ -201,10 +195,10 @@ testing.suites { } withType().configureEach { - useJUnitJupiter(libs.junit.bom.map { checkNotNull(it.version) }) dependencies { implementation(testKit.get().output) implementation(libs.assertk) + implementation(libs.testBalloon.framework.core) } targets.configureEach { testTask { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index aedbd8ab6..ab380970b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,6 +3,8 @@ minGradle = "9.4.0" kotlin = "2.4.10" moshi = "1.15.2" pluginPublish = "2.1.1" +testBalloon = "1.1.0-RC" + [libraries] apache-ant = "org.apache.ant:ant:1.10.17" @@ -28,8 +30,9 @@ androidx-gradlePluginLints = "androidx.lint:lint-gradle:1.0.0" ktfmt = "com.facebook:ktfmt:0.64" r8 = "com.android.tools:r8:9.4.14" -junit-bom = "org.junit:junit-bom:6.1.3" assertk = "com.willowtreeapps.assertk:assertk:0.28.1" +testBalloon-framework-core = { module = "de.infix.testBalloon:testBalloon-framework-core", version.ref = "testBalloon" } + [plugins] kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } @@ -39,3 +42,4 @@ mavenPublish = "com.vanniktech.maven.publish:0.37.0" pluginPublish = { id = "com.gradle.plugin-publish", version.ref = "pluginPublish" } spotless = "com.diffplug.spotless:8.9.0" buildConfig = "com.github.gmazzo.buildconfig:6.0.10" +testBalloon = { id = "de.infix.testBalloon", version.ref = "testBalloon" } diff --git a/src/documentTest/kotlin/com/github/jengelman/gradle/plugins/shadow/DocCodeSnippetTest.kt b/src/documentTest/kotlin/com/github/jengelman/gradle/plugins/shadow/DocCodeSnippetTest.kt index 08a9c6ae3..556bcdd99 100644 --- a/src/documentTest/kotlin/com/github/jengelman/gradle/plugins/shadow/DocCodeSnippetTest.kt +++ b/src/documentTest/kotlin/com/github/jengelman/gradle/plugins/shadow/DocCodeSnippetTest.kt @@ -1,34 +1,33 @@ package com.github.jengelman.gradle.plugins.shadow -import java.nio.file.Path -import org.junit.jupiter.api.Named.named -import org.junit.jupiter.api.io.TempDir -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.Arguments.arguments -import org.junit.jupiter.params.provider.MethodSource +import com.github.jengelman.gradle.plugins.shadow.testkit.tempDirFixture +import de.infix.testBalloon.framework.core.TestConfig +import de.infix.testBalloon.framework.core.coroutineContext +import de.infix.testBalloon.framework.core.invocation +import de.infix.testBalloon.framework.core.testScope +import de.infix.testBalloon.framework.core.testSuite +import kotlinx.coroutines.Dispatchers -class DocCodeSnippetTest { +val DocCodeSnippetTest by + testSuite( + testConfig = + TestConfig.invocation(TestConfig.Invocation.Concurrent) + // Each snippet runs a nested Gradle build. Two-way parallelism performed better than + // four-way by avoiding excessive CPU, memory, and disk contention. + .coroutineContext(Dispatchers.Default.limitedParallelism(2)) + .testScope(isEnabled = false) + ) { + val langExecutables = DslLang.entries.map(DslLang::extractCodeSnippets) - @ParameterizedTest(name = "{0}") - @MethodSource("snippets") - fun test(executable: SnippetExecutable, @TempDir tempDir: Path) { - executable.execute(tempDir) - } - - private companion object { - @JvmStatic - fun snippets(): List { - val langExecutables = DslLang.entries.map(DslLang::extractCodeSnippets) - - check(langExecutables.sumOf { it.size } > 0) { "No code snippets found." } - check(langExecutables.map { it.size }.distinct().size == 1) { - "All languages must have the same number of code snippets." - } + check(langExecutables.sumOf { it.size } > 0) { "No code snippets found." } + check(langExecutables.map { it.size }.distinct().size == 1) { + "All languages must have the same number of code snippets." + } - return langExecutables.flatten().map { executable -> - arguments(named(executable.displayName, executable)) + tempDirFixture() asParameterForEach + { + for (executable in langExecutables.flatten()) { + test(executable.displayName) { testDir -> executable.execute(testDir) } + } } - } } -} diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/ApplicationPluginTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/ApplicationPluginTest.kt index f1716cb88..f64e016ac 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/ApplicationPluginTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/ApplicationPluginTest.kt @@ -13,8 +13,10 @@ import com.github.jengelman.gradle.plugins.shadow.testkit.JarPath import com.github.jengelman.gradle.plugins.shadow.testkit.containsAtLeast import com.github.jengelman.gradle.plugins.shadow.testkit.getContent import com.github.jengelman.gradle.plugins.shadow.testkit.getMainAttr +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests import com.github.jengelman.gradle.plugins.shadow.util.isWindows import com.github.jengelman.gradle.plugins.shadow.util.runProcess +import de.infix.testBalloon.framework.core.testSuite import java.nio.file.Path import java.util.zip.ZipFile import kotlin.io.path.appendText @@ -24,12 +26,14 @@ import kotlin.io.path.readText import kotlin.io.path.relativeTo import kotlin.io.path.walk import kotlin.io.path.writeText -import org.junit.jupiter.api.Test -class ApplicationPluginTest : BasePluginTest() { +val ApplicationPluginTests by testSuite { + runTests(::ApplicationPluginTest) +} + +private class ApplicationPluginTest : BasePluginTest() { private lateinit var mainClass: String - @Test fun integrationWithApplicationPluginAndJavaToolchains() { prepare( mainClassWithImports = true, @@ -67,7 +71,6 @@ class ApplicationPluginTest : BasePluginTest() { ) } - @Test fun installShadowOutputs() { prepare( mainClassWithImports = true, @@ -116,7 +119,6 @@ class ApplicationPluginTest : BasePluginTest() { .contains("Hello, World! (bar) from Main", "Refs: junit.framework.Test") } - @Test fun installShadowDoesNotExecuteDependentShadowTask() { prepare() @@ -125,7 +127,7 @@ class ApplicationPluginTest : BasePluginTest() { commonAssertions(jarPath("build/install/myapp-shadow/lib/myapp-1.0-all.jar")) } - @Test // #613 + // #613 fun overrideMainClassAttrInManifestBlock() { val main2ClassEntry = writeClass(className = "Main2") prepare( @@ -170,7 +172,6 @@ class ApplicationPluginTest : BasePluginTest() { assertions(result.output, "bar") } - @Test fun overrideMainClassFromApplicationPlugin() { prepare() projectScript.appendText( @@ -189,7 +190,6 @@ class ApplicationPluginTest : BasePluginTest() { } } - @Test fun errorWhenMainClassNotSet() { prepare(mainClassBlock = "") @@ -198,7 +198,6 @@ class ApplicationPluginTest : BasePluginTest() { assertThat(result.output).contains("no main manifest attribute, in") } - @Test fun addExtraFilesIntoDistribution() { path("extra/echo.sh").writeText("echo 'Hello, World!'") path("some/dir/hello.txt").writeText("'Hello, World!'") @@ -239,7 +238,6 @@ class ApplicationPluginTest : BasePluginTest() { } } - @Test fun includeSrcDistByDefault() { path("src/dist/echo.sh").writeText("echo 'Hello, World!'") prepare() @@ -260,7 +258,6 @@ class ApplicationPluginTest : BasePluginTest() { } } - @Test fun honorApplicationExtensionProperties() { val applicationNames = "new" to "new" val executableDirs = "sbin" to "sbin" @@ -344,7 +341,7 @@ class ApplicationPluginTest : BasePluginTest() { } } - private companion object { + companion object { fun Path.walkEntries(includeDirs: Boolean = false): Sequence = walk() .filter { includeDirs || it.isRegularFile() } diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/BasePluginTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/BasePluginTest.kt index 0e11c26f4..40aee9183 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/BasePluginTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/BasePluginTest.kt @@ -36,29 +36,66 @@ import kotlin.io.path.writeText import org.gradle.testkit.runner.BuildResult import org.gradle.testkit.runner.GradleRunner import org.gradle.testkit.runner.TaskOutcome -import org.junit.jupiter.api.AfterAll -import org.junit.jupiter.api.AfterEach -import org.junit.jupiter.api.BeforeAll -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.TestInstance -import org.junit.jupiter.api.io.TempDir import org.vafer.jdeb.shaded.objectweb.asm.ClassWriter import org.vafer.jdeb.shaded.objectweb.asm.Opcodes -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -abstract class BasePluginTest { - @TempDir - lateinit var projectRoot: Path - private set - - lateinit var localRepo: AppendableMavenRepository - private set - - lateinit var artifactAJar: Path - private set +val sharedLocalRepo: AppendableMavenRepository by lazy { + val repoTempDir = createTempDirectory() + val repoRoot = repoTempDir.resolve("local-maven-repo").createDirectories() + Runtime.getRuntime() + .addShutdownHook( + Thread { + @OptIn(ExperimentalPathApi::class) repoTempDir.deleteRecursively() + } + ) + AppendableMavenRepository(root = repoRoot) + .apply { + jarModule("junit", "junit", "3.8.2") { useJar(BasePluginTest.junitJar) } + val a = + jarModule("my", "a", "1.0") { + buildJar { + insert("a.properties", "a") + insert("a2.properties", "a2") + } + } + val b = jarModule("my", "b", "1.0") { buildJar { insert("b.properties", "b") } } + val c = jarModule("my", "c", "1.0") { buildJar { insert("c.properties", "c") } } + val d = + jarModule("my", "d", "1.0") { + buildJar { insert("d.properties", "d") } + // Depends on c but c does not depend on d. + addDependency(c) + } + val e = + jarModule("my", "e", "1.0") { + buildJar { insert("e.properties", "e") } + // Circular dependency with f. + addDependency("my:f:1.0") + } + val f = + jarModule("my", "f", "1.0") { + buildJar { insert("f.properties", "f") } + // Circular dependency with e. + addDependency(e) + } + bomModule("my", "bom", "1.0") { + addDependency(a) + addDependency(b) + addDependency(c) + addDependency(d) + addDependency(e) + addDependency(f) + } + } + .also { it.publish() } +} - lateinit var artifactBJar: Path - private set +abstract class BasePluginTest( + val projectRoot: Path = createTempDirectory(), + val localRepo: AppendableMavenRepository = sharedLocalRepo, +) { + val artifactAJar: Path = localRepo.root.resolve("my/a/1.0/a-1.0.jar") + val artifactBJar: Path = localRepo.root.resolve("my/b/1.0/b-1.0.jar") val projectScript: Path get() = path("build.gradle") @@ -75,72 +112,11 @@ abstract class BasePluginTest { val outputServerShadowedJar: JarPath get() = jarPath("server/build/libs/server-1.0-all.jar") - @BeforeAll - fun beforeAll() { - localRepo = - AppendableMavenRepository( - root = createTempDirectory().resolve("local-maven-repo").createDirectories() - ) - .apply { - jarModule("junit", "junit", "3.8.2") { useJar(junitJar) } - val a = - jarModule("my", "a", "1.0") { - buildJar { - insert("a.properties", "a") - insert("a2.properties", "a2") - } - } - val b = jarModule("my", "b", "1.0") { buildJar { insert("b.properties", "b") } } - val c = jarModule("my", "c", "1.0") { buildJar { insert("c.properties", "c") } } - val d = - jarModule("my", "d", "1.0") { - buildJar { insert("d.properties", "d") } - // Depends on c but c does not depend on d. - addDependency(c) - } - val e = - jarModule("my", "e", "1.0") { - buildJar { insert("e.properties", "e") } - // Circular dependency with f. - addDependency("my:f:1.0") - } - val f = - jarModule("my", "f", "1.0") { - buildJar { insert("f.properties", "f") } - // Circular dependency with e. - addDependency(e) - } - bomModule("my", "bom", "1.0") { - addDependency(a) - addDependency(b) - addDependency(c) - addDependency(d) - addDependency(e) - addDependency(f) - } - } - localRepo.publish() - - artifactAJar = path("my/a/1.0/a-1.0.jar", parent = localRepo.root) - artifactBJar = path("my/b/1.0/b-1.0.jar", parent = localRepo.root) - } - - @BeforeEach - open fun beforeEach() { + init { projectScript.writeText(getDefaultProjectBuildScript()) settingsScript.writeText(getDefaultSettingsBuildScript()) } - @AfterEach - fun afterEach() { - println(projectScript.readText()) - } - - @AfterAll - fun afterAll() { - @OptIn(ExperimentalPathApi::class) localRepo.root.deleteRecursively() - } - fun getDefaultProjectBuildScript( plugin: String = "java", withGroup: Boolean = true, @@ -164,9 +140,9 @@ abstract class BasePluginTest { fun getDefaultSettingsBuildScript( startBlock: String = "", // Use a test-specific build cache directory. This ensures that we'll only use cached outputs - // generated during - // this test, and we won't accidentally use cached outputs from a different test or a different - // build. + // generated during this test, and we won't accidentally use cached outputs from a different + // test + // or a different build. // https://docs.gradle.org/current/userguide/build_cache.html#sec:build_cache_configure_local buildCacheBlock: String = "local { directory = file('build-cache') }", endBlock: String = "rootProject.name = 'my'", diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/CachingTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/CachingTest.kt index 08a5bfc61..db13d9a2d 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/CachingTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/CachingTest.kt @@ -8,8 +8,10 @@ import com.github.jengelman.gradle.plugins.shadow.internal.mainClassAttributeKey import com.github.jengelman.gradle.plugins.shadow.testkit.JarPath import com.github.jengelman.gradle.plugins.shadow.testkit.containsOnly import com.github.jengelman.gradle.plugins.shadow.testkit.getMainAttr +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests import com.github.jengelman.gradle.plugins.shadow.transformers.ResourceTransformer import com.github.jengelman.gradle.plugins.shadow.transformers.ServiceFileTransformer +import de.infix.testBalloon.framework.core.testSuite import kotlin.io.path.appendText import kotlin.io.path.isDirectory import kotlin.io.path.name @@ -18,12 +20,14 @@ import kotlin.io.path.walk import kotlin.io.path.writeText import org.gradle.api.file.DuplicatesStrategy import org.gradle.testkit.runner.TaskOutcome -import org.junit.jupiter.api.Test -class CachingTest : BasePluginTest() { +val CachingTests by testSuite { + runTests(::CachingTest) +} + +private class CachingTest : BasePluginTest() { private var taskPath: String = shadowJarPath - @Test fun dependenciesChanged() { projectScript.appendText( """ @@ -43,7 +47,6 @@ class CachingTest : BasePluginTest() { assertCompositeExecutions { containsOnly(*entriesInA, *manifestEntries) } } - @Test fun outputFileChanged() { projectScript.appendText( """ @@ -72,7 +75,6 @@ class CachingTest : BasePluginTest() { } } - @Test fun duplicatesStrategyChanged() { listOf(DuplicatesStrategy.EXCLUDE, DuplicatesStrategy.INCLUDE, DuplicatesStrategy.WARN) .forEach { strategy -> @@ -90,7 +92,6 @@ class CachingTest : BasePluginTest() { } } - @Test fun manifestAttrsChanged() { projectScript.appendText( """ @@ -133,7 +134,6 @@ class CachingTest : BasePluginTest() { assertions("Foo3", "Bar3") } - @Test fun kotlinMainRunChanged() { val mainClassName = "my.Main" val main2ClassName = "my.Main2" @@ -158,7 +158,6 @@ class CachingTest : BasePluginTest() { assertCompositeExecutions { getMainAttr(mainClassAttributeKey).isEqualTo(main2ClassName) } } - @Test fun applicationChanged() { val mainClassName = "my.Main" val main2ClassName = "my.Main2" @@ -181,7 +180,7 @@ class CachingTest : BasePluginTest() { assertCompositeExecutions { getMainAttr(mainClassAttributeKey).isEqualTo(main2ClassName) } } - @Test // #717 + // #717 fun jarIncludesExcludesChanged() { val mainClassEntry = writeClass(className = "Main") val main2ClassEntry = writeClass(className = "Main2") @@ -240,7 +239,6 @@ class CachingTest : BasePluginTest() { } } - @Test fun dependenciesIncludesExcludesChanged() { val mainClassEntry = writeClass(withImports = true) projectScript.appendText( @@ -270,7 +268,6 @@ class CachingTest : BasePluginTest() { assertCompositeExecutions { containsOnly("my/", mainClassEntry, *manifestEntries) } } - @Test fun minimizeChanged() { taskPath = serverShadowJarPath @@ -312,7 +309,6 @@ class CachingTest : BasePluginTest() { } } - @Test fun r8KeepRuleFileChanged() { val previousTaskPath = taskPath taskPath = serverShadowJarPath @@ -352,7 +348,6 @@ class CachingTest : BasePluginTest() { } } - @Test fun r8ClasspathRuleChanged() { val previousTaskPath = taskPath taskPath = serverShadowJarPath @@ -394,7 +389,6 @@ class CachingTest : BasePluginTest() { } } - @Test fun relocatorChanged() { projectScript.appendText( """ @@ -426,7 +420,7 @@ class CachingTest : BasePluginTest() { } } - @Test // #1932 + // #1932 fun relocatorPatternChanged() { projectScript.appendText( """ @@ -458,7 +452,6 @@ class CachingTest : BasePluginTest() { } } - @Test fun serviceFileTransformerPropsChanged() { val mainClassEntry = writeClass() val assertions = { @@ -485,7 +478,6 @@ class CachingTest : BasePluginTest() { assertions() } - @Test fun disableCacheIfAnyTransformerIsNotCacheable() { projectScript.appendText( """ diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/FilteringTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/FilteringTest.kt index ccb6fbad8..1f93c0bbd 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/FilteringTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/FilteringTest.kt @@ -2,17 +2,17 @@ package com.github.jengelman.gradle.plugins.shadow import assertk.assertThat import com.github.jengelman.gradle.plugins.shadow.testkit.containsOnly +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests +import de.infix.testBalloon.framework.core.testSuite import kotlin.io.path.appendText import kotlin.io.path.writeText -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.ValueSource - -class FilteringTest : BasePluginTest() { - @BeforeEach - override fun beforeEach() { - super.beforeEach() + +val FilteringTests by testSuite { + runTests(::FilteringTest) +} + +private class FilteringTest : BasePluginTest() { + init { projectScript.appendText( """ |dependencies { @@ -24,14 +24,12 @@ class FilteringTest : BasePluginTest() { ) } - @Test fun includeAllDependencies() { runWithSuccess(shadowJarPath) assertThat(outputShadowedJar).useAll { containsOnly(*entriesInAB, *manifestEntries) } } - @Test fun excludeFiles() { projectScript.appendText( """ @@ -49,8 +47,6 @@ class FilteringTest : BasePluginTest() { } } - @ParameterizedTest - @ValueSource(booleans = [false, true]) fun excludeDependency(useAccessor: Boolean) { settingsScript.appendText( """ @@ -82,7 +78,6 @@ class FilteringTest : BasePluginTest() { commonAssertions() } - @Test fun includeDependencyAndExcludeOthers() { projectScript.appendText( """ @@ -113,8 +108,6 @@ class FilteringTest : BasePluginTest() { } } - @ParameterizedTest - @ValueSource(booleans = [false, true]) fun filterProjectDependencies(useAccessor: Boolean) { val clientProject = if (useAccessor) "project(projects.client)" else "project(':client')" writeClientAndServerModules( @@ -134,7 +127,7 @@ class FilteringTest : BasePluginTest() { } } - @Test // #671 + // #671 fun filterProjectThatVersionContainsPlus() { writeClientAndServerModules( serverShadowBlock = @@ -154,7 +147,6 @@ class FilteringTest : BasePluginTest() { } } - @Test fun excludeTransitiveProjectDependency() { writeClientAndServerModules( serverShadowBlock = @@ -179,7 +171,6 @@ class FilteringTest : BasePluginTest() { } } - @Test fun verifyExcludePrecedenceOverInclude() { projectScript.appendText( """ @@ -199,7 +190,6 @@ class FilteringTest : BasePluginTest() { } } - @Test fun handleExcludeWithCircularDependency() { val dependency = "'my:e:1.0'" projectScript.appendText( diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/FindResourceInClasspathTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/FindResourceInClasspathTest.kt index 23533615f..23d251048 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/FindResourceInClasspathTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/FindResourceInClasspathTest.kt @@ -5,12 +5,16 @@ import assertk.assertThat import assertk.assertions.contains import assertk.assertions.doesNotContain import com.github.jengelman.gradle.plugins.shadow.tasks.FindResourceInClasspath +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests import com.github.jengelman.gradle.plugins.shadow.testkit.variantSeparatorsPathString +import de.infix.testBalloon.framework.core.testSuite import kotlin.io.path.appendText -import org.junit.jupiter.api.Test -class FindResourceInClasspathTest : BasePluginTest() { - @Test +val FindResourceInClasspathTests by testSuite { + runTests(::FindResourceInClasspathTest) +} + +private class FindResourceInClasspathTest : BasePluginTest() { fun findResourceInClasspath() { val taskClassName = FindResourceInClasspath::class.java.name projectScript.appendText( diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/JavaPluginsTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/JavaPluginsTest.kt index cd32e258c..be7a326d5 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/JavaPluginsTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/JavaPluginsTest.kt @@ -23,33 +23,84 @@ import com.github.jengelman.gradle.plugins.shadow.testkit.containsOnly import com.github.jengelman.gradle.plugins.shadow.testkit.getContent import com.github.jengelman.gradle.plugins.shadow.testkit.getMainAttr import com.github.jengelman.gradle.plugins.shadow.testkit.getStream +import com.github.jengelman.gradle.plugins.shadow.testkit.runTest +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests +import com.github.jengelman.gradle.plugins.shadow.util.AppendableMavenRepository import com.github.jengelman.gradle.plugins.shadow.util.prependText import com.github.jengelman.gradle.plugins.shadow.util.runProcess +import de.infix.testBalloon.framework.core.testSuite import kotlin.io.path.appendText import kotlin.io.path.deleteExisting import kotlin.io.path.invariantSeparatorsPathString import kotlin.io.path.name import kotlin.io.path.outputStream +import kotlin.io.path.readText import kotlin.io.path.writeText import kotlin.reflect.full.declaredFunctions import kotlin.reflect.jvm.javaMethod import org.gradle.api.JavaVersion -import org.gradle.api.plugins.JavaPlugin.API_CONFIGURATION_NAME import org.gradle.api.plugins.JavaPlugin.COMPILE_ONLY_API_CONFIGURATION_NAME -import org.gradle.api.plugins.JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME import org.gradle.api.plugins.JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME import org.gradle.api.tasks.bundling.ZipEntryCompression import org.gradle.language.base.plugins.LifecycleBasePlugin.ASSEMBLE_TASK_NAME import org.gradle.testkit.runner.TaskOutcome.SUCCESS -import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.EnumSource -import org.junit.jupiter.params.provider.MethodSource -import org.junit.jupiter.params.provider.ValueSource - -class JavaPluginsTest : BasePluginTest() { - @Test // #1766 + +val JavaPluginsTests by testSuite { + runTests(::JavaPluginsTest) + + for (configuration in + listOf(ShadowBasePlugin.CONFIGURATION_NAME, IMPLEMENTATION_CONFIGURATION_NAME)) { + runTest( + "addShadowConfigurationToClassPathInManifest_configuration_$configuration", + ::JavaPluginsTest, + ) { + addShadowConfigurationToClassPathInManifest(configuration) + } + } + + for (method in ZipEntryCompression.entries) { + runTest("supportZipCompressions_method_$method", ::JavaPluginsTest) { + supportZipCompressions(method) + } + } + + for (configuration in listOf("implementation", "api")) { + runTest("doNotReAddSuppressedGradleApi_configuration_$configuration", ::JavaPluginsTest) { + doNotReAddSuppressedGradleApi(configuration) + } + } + + val fallbackByPropertyCases = + listOf( + Triple( + "my.Main", + "my.Main", + "Adding $mainClassAttributeKey attribute to the manifest with value", + ), + Triple( + "", + null, + "Skipping adding $mainClassAttributeKey attribute to the manifest as it is empty.", + ), + ) + for ((index, case) in fallbackByPropertyCases.withIndex()) { + val (input, expected, message) = case + runTest("fallbackMainClassByProperty_$index", ::JavaPluginsTest) { + fallbackMainClassByProperty(input, expected, message) + } + } + + val fallbackByCliCases = listOf("my.Main" to "my.Main", "" to null) + for ((index, case) in fallbackByCliCases.withIndex()) { + val (input, expected) = case + runTest("fallbackMainClassByCliOption_$index", ::JavaPluginsTest) { + fallbackMainClassByCliOption(input, expected) + } + } +} + +private class JavaPluginsTest : BasePluginTest() { + // #1766 fun makeAssembleDependOnShadowJarEvenIfAddedLater() { val kFunction = ShadowJar.Companion::class.declaredFunctions.single { it.name == "registerShadowJarCommon" } @@ -90,7 +141,7 @@ class JavaPluginsTest : BasePluginTest() { assertThat(result.output).contains("task dependencies: $SHADOW_JAR_TASK_NAME") } - @Test // #1908 + // #1908 fun shadowJarNotAddedToAssembleWhenDisabled() { projectScript.appendText( """ @@ -110,7 +161,6 @@ class JavaPluginsTest : BasePluginTest() { assertThat(result.task(shadowJarPath)).isNull() } - @Test fun shadowJarCliOptions() { val result = runWithSuccess("help", "--task", shadowJarPath) @@ -131,7 +181,6 @@ class JavaPluginsTest : BasePluginTest() { ) } - @Test fun includeProjectDependencies() { writeClientAndServerModules() @@ -149,7 +198,6 @@ class JavaPluginsTest : BasePluginTest() { } } - @Test fun dependOnProjectShadowJar() { writeClientAndServerModules(clientShadowed = true) @@ -164,7 +212,6 @@ class JavaPluginsTest : BasePluginTest() { } } - @Test fun shadowProjectShadowJar() { writeClientAndServerModules(clientShadowed = true) val relocatedEntries = @@ -189,7 +236,7 @@ class JavaPluginsTest : BasePluginTest() { } } - @Test // #1893 + // #1893 fun consumeShadowedProjectViaApiElementsAndRuntimeElements() { settingsScript.appendText( """ @@ -267,7 +314,7 @@ class JavaPluginsTest : BasePluginTest() { } } - @Test // #1893 + // #1893 fun excludeRulesPreventBundledDepsOnConsumerClasspath() { settingsScript.appendText("include 'foo', 'consumer'\n") projectScript.writeText("") @@ -323,7 +370,7 @@ class JavaPluginsTest : BasePluginTest() { } } - @Test // #1606 + // #1606 fun shadowExposedCustomSourceSetOutput() { writeClientAndServerModules() path("client/build.gradle") @@ -373,8 +420,7 @@ class JavaPluginsTest : BasePluginTest() { } } - @ParameterizedTest // #449 - @ValueSource(booleans = [false, true]) + // #449 fun containsMultiReleaseAttrIfAnyDependencyContainsIt(addAttribute: Boolean) { writeClientAndServerModules() path("client/build.gradle") @@ -413,8 +459,6 @@ class JavaPluginsTest : BasePluginTest() { .isEqualTo(if (addAttribute) "true" else null) } - @ParameterizedTest - @ValueSource(booleans = [false, true]) fun containsMultiReleaseAttrByCliOption(enable: Boolean) { writeClientAndServerModules() path("client/build.gradle") @@ -445,7 +489,7 @@ class JavaPluginsTest : BasePluginTest() { .isEqualTo(if (enable) "true" else null) } - @Test // #352, #729 + // #352, #729 fun excludeSomeResourcesByDefault() { val resJar = buildJar("meta-inf.jar") { @@ -473,7 +517,6 @@ class JavaPluginsTest : BasePluginTest() { assertThat(outputShadowedJar).useAll { containsOnly("META-INF/a.properties", *manifestEntries) } } - @Test fun includeRuntimeConfigurationByDefault() { projectScript.appendText( """ @@ -491,10 +534,9 @@ class JavaPluginsTest : BasePluginTest() { assertThat(outputShadowedJar).useAll { containsOnly(*entriesInA, *manifestEntries) } } - @Test fun includeJavaLibraryConfigurationsByDefault() { - localRepo - .apply { + val customRepo = + AppendableMavenRepository(root = path("custom-local-maven-repo/")).apply { jarModule("my", "api", "1.0") { buildJar { insert("api.properties", "api") } } jarModule("my", "implementation", "1.0") { buildJar { insert("implementation.properties", "implementation") } @@ -504,7 +546,16 @@ class JavaPluginsTest : BasePluginTest() { buildJar { insert("runtime-only.properties", "runtime-only") } } } - .publish() + customRepo.publish() + + settingsScript.writeText( + settingsScript + .readText() + .replace( + "repositories {", + "repositories {\n maven { url = '${customRepo.root.toUri()}' }", + ) + ) projectScript.writeText( """ @@ -531,7 +582,6 @@ class JavaPluginsTest : BasePluginTest() { } } - @Test fun classPathInManifestNotAddedIfEmpty() { projectScript.appendText( """ @@ -550,8 +600,7 @@ class JavaPluginsTest : BasePluginTest() { } } - @ParameterizedTest // #65 - @ValueSource(strings = [ShadowBasePlugin.CONFIGURATION_NAME, IMPLEMENTATION_CONFIGURATION_NAME]) + // #65 fun addShadowConfigurationToClassPathInManifest(configuration: String) { projectScript.appendText( """ @@ -578,7 +627,7 @@ class JavaPluginsTest : BasePluginTest() { assertThat(actual).isEqualTo(expected) } - @Test // #92 + // #92 fun doNotIncludeNullValueInClassPathWhenJarFileDoesNotContainClassPath() { projectScript.appendText( """ @@ -595,8 +644,7 @@ class JavaPluginsTest : BasePluginTest() { assertThat(value).isEqualTo("junit-3.8.2.jar") } - @ParameterizedTest // #203 - @EnumSource(ZipEntryCompression::class) + // #203 fun supportZipCompressions(method: ZipEntryCompression) { projectScript.appendText( """ @@ -616,7 +664,7 @@ class JavaPluginsTest : BasePluginTest() { assertThat(outputShadowedJar).useAll { containsOnly(*junitEntries, *manifestEntries) } } - @Test // #459, #852 + // #459, #852 fun excludeGradleApiByDefault() { writeGradlePluginModule() projectScript.appendText( @@ -653,7 +701,7 @@ class JavaPluginsTest : BasePluginTest() { } } - @Test // #1422 + // #1422 fun moveLocalGradleApiToCompileOnly() { projectScript.writeText(getDefaultProjectBuildScript("java-gradle-plugin")) @@ -663,8 +711,7 @@ class JavaPluginsTest : BasePluginTest() { assertThat(outputCompileOnlyApi).contains("unspecified") } - @ParameterizedTest // #1422 - @ValueSource(strings = [COMPILE_ONLY_CONFIGURATION_NAME, API_CONFIGURATION_NAME]) + // #1422 fun doNotReAddSuppressedGradleApi(configuration: String) { projectScript.writeText(getDefaultProjectBuildScript("java-gradle-plugin")) @@ -679,7 +726,7 @@ class JavaPluginsTest : BasePluginTest() { assertThat(output).doesNotContain("unspecified") } - @Test // #1070 + // #1070 fun registerCustomShadowJarTask() { val mainClassEntry = writeClass(sourceSet = "test", withImports = true) val testShadowJarTask = "testShadowJar" @@ -714,7 +761,7 @@ class JavaPluginsTest : BasePluginTest() { .contains("Hello, World! (foo) from Main", "Refs: junit.framework.Test") } - @Test // #1784 + // #1784 fun registerShadowJarTaskWithoutShadowPluginApplied() { val mainClassEntry = writeClass(sourceSet = "test", withImports = true) val testShadowJarTask = "testShadowJar" @@ -758,7 +805,7 @@ class JavaPluginsTest : BasePluginTest() { .contains("Hello, World! (foo) from Main", "Refs: junit.framework.Test") } - @Test // #443 + // #443 fun registerCustomShadowJarThatContainsDependenciesOnly() { val mainClassEntry = writeClass() val dependencyShadowJar = "dependencyShadowJar" @@ -789,7 +836,6 @@ class JavaPluginsTest : BasePluginTest() { } } - @Test fun registerCustomShadowJarWithoutShadowR8Configuration() { val customShadowJar = "customShadowJar" projectScript.writeText( @@ -812,7 +858,7 @@ class JavaPluginsTest : BasePluginTest() { ) } - @Test // #1975 + // #1975 fun skipNonExistentDependencyDirectory() { val nonExistentDir = projectRoot.resolve("non-existent-dir") @@ -830,7 +876,7 @@ class JavaPluginsTest : BasePluginTest() { assertThat(result.task(shadowJarPath)).isNotNull().transform { it.outcome }.isEqualTo(SUCCESS) } - @Test // #915 + // #915 fun failBuildIfProcessingBadJar() { val badJarPath = path("bad.jar").apply { writeText("A bad jar.") } @@ -848,7 +894,6 @@ class JavaPluginsTest : BasePluginTest() { assertThat(result.output).containsMatch("Cannot expand ZIP '.*bad\\.jar'".toRegex()) } - @Test fun failBuildIfProcessingAar() { val fooAarPath = buildJar("foo.aar") { insert("AndroidManifest.xml", "") } @@ -867,7 +912,6 @@ class JavaPluginsTest : BasePluginTest() { .contains("Shadowing AAR file is not supported.", "Please exclude dependency artifact:") } - @Test fun addExtraFilesViaFrom() { val mainClassEntry = writeClass() path("Foo").writeText("Foo") @@ -912,7 +956,6 @@ class JavaPluginsTest : BasePluginTest() { assertThat(jarPath(unzipped.name)).useAll { containsOnly(*entriesInA) } } - @Test fun addDependenciesViaCustomConfigurationWithoutUnzipping() { projectScript.appendText( """ @@ -935,7 +978,7 @@ class JavaPluginsTest : BasePluginTest() { } } - @Test // #520 + // #520 fun onlyKeepFilesFromProjectWhenDuplicatesStrategyIsExclude() { val fooJar = buildJar("foo.jar") { insert("module-info.class", "module myModuleName {}") } val mainClassEntry = writeClass() @@ -966,7 +1009,7 @@ class JavaPluginsTest : BasePluginTest() { } } - @Test // #1441 + // #1441 fun includeFilesInTaskOutputDirectory() { // Create a build that has a task with jars in the output directory projectScript.appendText( @@ -1002,7 +1045,6 @@ class JavaPluginsTest : BasePluginTest() { assertThat(outputShadowedJar).useAll { containsOnly(*entriesInAB, *manifestEntries) } } - @Test fun integrateWithDevelocityBuildScan() { writeClientAndServerModules() settingsScript.prependText( @@ -1029,8 +1071,6 @@ class JavaPluginsTest : BasePluginTest() { } } - @ParameterizedTest - @ValueSource(booleans = [false, true]) fun failBuildIfDuplicateEntries(enable: Boolean) { path("src/main/resources/a.properties").writeText("invalid a") projectScript.appendText( @@ -1057,8 +1097,6 @@ class JavaPluginsTest : BasePluginTest() { .contains("Duplicate entries found in the shadowed JAR:", "a.properties (2 times)") } - @ParameterizedTest - @ValueSource(booleans = [false, true]) fun failBuildIfDuplicateEntriesByCliOption(enable: Boolean) { path("src/main/resources/a.properties").writeText("project a") projectScript.appendText( @@ -1084,8 +1122,6 @@ class JavaPluginsTest : BasePluginTest() { .contains("Duplicate entries found in the shadowed JAR:", "a.properties (2 times)") } - @ParameterizedTest - @MethodSource("fallbackMainClassProvider") fun fallbackMainClassByProperty(input: String, expected: String?, message: String) { projectScript.appendText( """ @@ -1102,8 +1138,6 @@ class JavaPluginsTest : BasePluginTest() { assertThat(outputShadowedJar).useAll { getMainAttr(mainClassAttributeKey).isEqualTo(expected) } } - @ParameterizedTest - @MethodSource("fallbackMainClassProvider") fun fallbackMainClassByCliOption(input: String, expected: String?) { if (input.isEmpty()) { runWithSuccess(shadowJarPath) @@ -1114,7 +1148,7 @@ class JavaPluginsTest : BasePluginTest() { assertThat(outputShadowedJar).useAll { getMainAttr(mainClassAttributeKey).isEqualTo(expected) } } - @Test // #882 + // #882 fun compatGradleArtifactTransform() { settingsScript.writeText("include('app', 'lib')\n") path("lib/build.gradle") @@ -1218,7 +1252,7 @@ class JavaPluginsTest : BasePluginTest() { } } - @Test // #2086 + // #2086 fun useToolchainWithoutTargetCompatibilityInKts() { projectScript.deleteExisting() path("build.gradle.kts") @@ -1240,7 +1274,7 @@ class JavaPluginsTest : BasePluginTest() { assertThat(result.task(shadowJarPath)).isNotNull().transform { it.outcome }.isEqualTo(SUCCESS) } - @Test // #2099 + // #2099 fun doNotResolveR8WhenLockingAllConfigurations() { projectScript.appendText( """ @@ -1276,21 +1310,4 @@ class JavaPluginsTest : BasePluginTest() { private fun dependencies(configuration: String, vararg flags: String): String { return runWithSuccess("dependencies", "--configuration", configuration, *flags).output } - - private companion object { - @JvmStatic - fun fallbackMainClassProvider() = - listOf( - Arguments.of( - "my.Main", - "my.Main", - "Adding $mainClassAttributeKey attribute to the manifest with value", - ), - Arguments.of( - "", - null, - "Skipping adding $mainClassAttributeKey attribute to the manifest as it is empty.", - ), - ) - } } diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/KotlinPluginsTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/KotlinPluginsTest.kt index c9dbb7ebd..184b291a1 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/KotlinPluginsTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/KotlinPluginsTest.kt @@ -8,25 +8,23 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar.Companion.SHAD import com.github.jengelman.gradle.plugins.shadow.testkit.containsAtLeast import com.github.jengelman.gradle.plugins.shadow.testkit.containsOnly import com.github.jengelman.gradle.plugins.shadow.testkit.getMainAttr +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests import com.github.jengelman.gradle.plugins.shadow.util.JvmLang +import de.infix.testBalloon.framework.core.testSuite import kotlin.io.path.appendText import kotlin.io.path.writeText -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.ValueSource -class KotlinPluginsTest : BasePluginTest() { - @BeforeEach - override fun beforeEach() { - super.beforeEach() +val KotlinPluginsTests by testSuite { + runTests(::KotlinPluginsTest) +} + +private class KotlinPluginsTest : BasePluginTest() { + init { projectScript.writeText( getDefaultProjectBuildScript(plugin = "org.jetbrains.kotlin.multiplatform") ) } - @ParameterizedTest - @ValueSource(booleans = [false, true]) fun compatKotlinJvmPlugin(excludeStdlib: Boolean) { val stdlib = compileOnlyStdlib(excludeStdlib) @@ -61,8 +59,6 @@ class KotlinPluginsTest : BasePluginTest() { } } - @ParameterizedTest - @ValueSource(booleans = [false, true]) fun compatKmpJvmTarget(excludeStdlib: Boolean) { val stdlib = compileOnlyStdlib(excludeStdlib) @@ -108,7 +104,7 @@ class KotlinPluginsTest : BasePluginTest() { } } - @Test // #1377 + // #1377 fun compatKmpForOtherNamedJvmTarget() { val jvmTargetName = "newJvm" val jvmTargetMain = "${jvmTargetName}Main" @@ -144,7 +140,7 @@ class KotlinPluginsTest : BasePluginTest() { } } - @Test // #1377 + // #1377 fun doNotCreateJvmTargetEagerly() { projectScript.appendText( """ @@ -163,8 +159,6 @@ class KotlinPluginsTest : BasePluginTest() { ) } - @ParameterizedTest - @ValueSource(booleans = [false, true]) fun setMainClassAttributeFromMainRun(useShadowAttr: Boolean) { val mainClassName = "my.Main" val main2ClassName = "my.Main2" @@ -194,8 +188,6 @@ class KotlinPluginsTest : BasePluginTest() { } } - @ParameterizedTest - @ValueSource(booleans = [false, true]) fun setManifestAttrsFromJvmTargetJar(useShadowAttr: Boolean) { val mainClassName = "my.Main" val main2ClassName = "my.Main2" @@ -228,7 +220,6 @@ class KotlinPluginsTest : BasePluginTest() { } } - @Test fun registerShadowJarForFirstJvmTarget() { val jvmTargetName = "newJvm" projectScript.appendText( diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/MinimizeTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/MinimizeTest.kt index 772c8184b..704c76032 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/MinimizeTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/MinimizeTest.kt @@ -11,17 +11,20 @@ import com.github.jengelman.gradle.plugins.shadow.testkit.containsNone import com.github.jengelman.gradle.plugins.shadow.testkit.containsOnly import com.github.jengelman.gradle.plugins.shadow.testkit.getContent import com.github.jengelman.gradle.plugins.shadow.testkit.invariantEolString +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests +import de.infix.testBalloon.framework.core.testSuite import java.net.URLClassLoader import java.util.ServiceLoader import kotlin.io.path.appendText import kotlin.io.path.readText import kotlin.io.path.writeText import org.gradle.api.JavaVersion -import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.ValueSource -class MinimizeTest : BasePluginTest() { +val MinimizeTests by testSuite { + runTests(::MinimizeTest) +} + +private class MinimizeTest : BasePluginTest() { private val outputImplShadowedJar: JarPath get() = jarPath("impl/build/libs/impl-1.0-all.jar") @@ -30,7 +33,6 @@ class MinimizeTest : BasePluginTest() { * shall remove 'junit', but not 'api'. Unused classes of 'api' and theirs dependencies also * shouldn't be removed. */ - @Test fun useMinimizeWithDependenciesWithApiScope() { writeApiLibAndImplModules() @@ -54,7 +56,6 @@ class MinimizeTest : BasePluginTest() { * 'api' used as api for 'impl', and 'lib' used as api for 'api'. Unused classes of 'api' and * 'lib' shouldn't be removed. */ - @Test fun useMinimizeWithTransitiveDependenciesWithApiScope() { writeApiLibAndImplModules() path("api/build.gradle") @@ -88,7 +89,6 @@ class MinimizeTest : BasePluginTest() { } /** 'Server' depends on 'Client'. 'junit' is independent. The minimize shall remove 'junit'. */ - @Test fun minimizeByKeepingOnlyTransitiveDependencies() { writeClientAndServerModules( serverShadowBlock = @@ -122,7 +122,6 @@ class MinimizeTest : BasePluginTest() { * 'Client', 'Server' and 'junit' are independent. 'junit' is excluded from the minimize step. The * minimize step shall remove 'Client' but not 'junit'. */ - @Test fun excludeDependencyFromMinimize() { writeClientAndServerModules( serverShadowBlock = @@ -146,7 +145,7 @@ class MinimizeTest : BasePluginTest() { * 'Client', 'Server' and 'junit' are independent. Unused classes of 'client' and theirs * dependencies shouldn't be removed. */ - @Test // #744 + // #744 fun excludeProjectFromMinimize() { writeClientAndServerModules( serverShadowBlock = @@ -176,7 +175,6 @@ class MinimizeTest : BasePluginTest() { * 'Client', 'Server' and 'junit' are independent. Unused classes of 'client' and theirs * dependencies shouldn't be removed. */ - @Test fun excludeProjectFromMinimizeShallNotExcludeTransitiveDependenciesThatAreUsedInSubproject() { writeClientAndServerModules( serverShadowBlock = @@ -220,7 +218,7 @@ class MinimizeTest : BasePluginTest() { } } - @Test // #1610 + // #1610 fun excludeCircularDependencies() { val dependency = "'my:e:1.0'" projectScript.appendText( @@ -244,8 +242,6 @@ class MinimizeTest : BasePluginTest() { } } - @ParameterizedTest - @ValueSource(booleans = [false, true]) fun enableMinimizationByCliOption(enable: Boolean) { writeClientAndServerModules() @@ -272,7 +268,7 @@ class MinimizeTest : BasePluginTest() { } } - @Test // #1636 + // #1636 fun minimizeBomDependency() { writeApiLibAndImplModules() path("impl/build.gradle") @@ -301,7 +297,6 @@ class MinimizeTest : BasePluginTest() { } } - @Test fun minimizeWithR8ShrinksUnusedDependencyClasses() { writeR8Repository() writeR8ClientAndServerModules( @@ -340,7 +335,6 @@ class MinimizeTest : BasePluginTest() { ) } - @Test fun minimizeWithR8KeepsServiceProviders() { writeR8Repository() writeR8ServiceModules() @@ -367,7 +361,6 @@ class MinimizeTest : BasePluginTest() { } } - @Test fun minimizeWithR8HonorsCustomProguardRules() { writeR8Repository() writeR8ClientAndServerModules( @@ -411,7 +404,6 @@ class MinimizeTest : BasePluginTest() { ) } - @Test fun minimizeWithR8GeneratesReportsRelativeToConfigurationFile() { writeR8Repository() writeR8ClientAndServerModules( @@ -456,7 +448,6 @@ class MinimizeTest : BasePluginTest() { .contains("client.Reflective", "client.Unused") } - @Test fun minimizeWithR8UsesClasspathRules() { writeR8Repository() writeR8ClientAndServerModules( @@ -505,7 +496,6 @@ class MinimizeTest : BasePluginTest() { ) } - @Test fun minimizeWithR8PreservesRepeatedLinesInClasspathRules() { writeR8Repository() writeR8ClientAndServerModules( @@ -547,7 +537,6 @@ class MinimizeTest : BasePluginTest() { } } - @Test fun minimizeWithR8CanEnableObfuscation() { writeR8Repository() writeR8ClientAndServerModules( @@ -575,7 +564,6 @@ class MinimizeTest : BasePluginTest() { } } - @Test fun minimizeWithR8CanEnableOptimization() { writeR8Repository() writeR8ClientAndServerModules( @@ -601,7 +589,6 @@ class MinimizeTest : BasePluginTest() { } } - @Test fun minimizeWithR8HonorsDependencyExcludes() { writeR8Repository() writeR8ClientAndServerModules( @@ -630,7 +617,6 @@ class MinimizeTest : BasePluginTest() { } } - @Test fun minimizeWithR8UsesJavaToolchain() { writeR8Repository() writeR8ClientAndServerModules( diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/PublishingTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/PublishingTest.kt index 2f8aa4b6c..aa9fedb47 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/PublishingTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/PublishingTest.kt @@ -16,14 +16,17 @@ import com.github.jengelman.gradle.plugins.shadow.testkit.containsAtLeast import com.github.jengelman.gradle.plugins.shadow.testkit.containsNone import com.github.jengelman.gradle.plugins.shadow.testkit.containsOnly import com.github.jengelman.gradle.plugins.shadow.testkit.getMainAttr +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests import com.github.jengelman.gradle.plugins.shadow.util.GradleModuleMetadata import com.github.jengelman.gradle.plugins.shadow.util.coordinate import com.github.jengelman.gradle.plugins.shadow.util.prependText import com.squareup.moshi.JsonAdapter import com.squareup.moshi.Moshi import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory +import de.infix.testBalloon.framework.core.testSuite import java.nio.file.Path import kotlin.io.path.appendText +import kotlin.io.path.createTempDirectory import kotlin.io.path.exists import kotlin.io.path.inputStream import kotlin.io.path.listDirectoryEntries @@ -41,22 +44,18 @@ import org.gradle.api.attributes.java.TargetJvmVersion import org.gradle.api.plugins.JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME import org.gradle.api.plugins.JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME import org.gradle.testkit.runner.BuildResult -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.io.TempDir -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.ValueSource - -class PublishingTest : BasePluginTest() { - @TempDir lateinit var remoteRepoPath: Path - - @BeforeEach - override fun beforeEach() { - super.beforeEach() + +val PublishingTests by testSuite { + runTests(::PublishingTest) +} + +private class PublishingTest : BasePluginTest() { + val remoteRepoPath: Path = createTempDirectory() + + init { settingsScript.appendText("rootProject.name = 'maven'\n") } - @Test fun publishShadowJarWithCorrectTargetJvm() { projectScript.appendText( publishConfiguration( @@ -137,7 +136,7 @@ class PublishingTest : BasePluginTest() { assertions(attrsWithoutTargetJvm + targetJvmAttr8) } - @Test // #1665 + // #1665 fun dontInjectTargetJvmVersionWhenAutoTargetJvmDisabled() { projectScript.appendText( publishConfiguration( @@ -172,7 +171,6 @@ class PublishingTest : BasePluginTest() { ) } - @Test fun dontInjectTargetJvmVersionWhenOptingOut() { projectScript.appendText( publishConfiguration( @@ -207,7 +205,6 @@ class PublishingTest : BasePluginTest() { ) } - @Test fun overrideBundlingAttrInGradleMetadata() { projectScript.appendText( publishConfiguration( @@ -240,7 +237,6 @@ class PublishingTest : BasePluginTest() { ) } - @Test fun publishShadowJarInsteadOfJar() { projectScript.appendText( publishConfiguration( @@ -285,7 +281,6 @@ class PublishingTest : BasePluginTest() { assertShadowVariantCommon(gmmAdapter.fromJson(repoPath("$artifactRoot/maven-1.0.module"))) } - @Test fun publishCustomShadowJar() { projectScript.appendText( publishConfiguration( @@ -321,7 +316,6 @@ class PublishingTest : BasePluginTest() { } } - @Test fun publishShadowedGradlePlugin() { writeGradlePluginModule() projectScript.appendText( @@ -365,7 +359,7 @@ class PublishingTest : BasePluginTest() { ) } - @Test // #614, #860, #945 + // #614, #860, #945 fun publishShadowJarWithCustomArtifactName() { projectScript.appendText( publishConfiguration( @@ -420,7 +414,6 @@ class PublishingTest : BasePluginTest() { assertShadowVariantCommon(gmmAdapter.fromJson(repoPath("$artifactRoot/my-artifact-2.0.module"))) } - @Test fun publishJarAndShadowJarWithGradleMetadata() { projectScript.appendText( publishConfiguration( @@ -533,8 +526,7 @@ class PublishingTest : BasePluginTest() { } } - @ParameterizedTest // #651 - @ValueSource(booleans = [false, true]) + // #651 fun publishShadowVariantJar(addShadowVariant: Boolean) { projectScript.appendText( publishingBlock( @@ -730,7 +722,7 @@ class PublishingTest : BasePluginTest() { } } - private companion object { + companion object { val gmmAdapter: JsonAdapter = Moshi.Builder() .add(KotlinJsonAdapterFactory()) diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/RelocationTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/RelocationTest.kt index ddaa6fc1d..9d83db6af 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/RelocationTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/RelocationTest.kt @@ -10,25 +10,41 @@ import assertk.assertions.isNotEqualTo import assertk.fail import com.github.jengelman.gradle.plugins.shadow.internal.mainClassAttributeKey import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar.Companion.CONSTANT_TIME_FOR_ZIP_ENTRIES +import com.github.jengelman.gradle.plugins.shadow.testkit.Arguments import com.github.jengelman.gradle.plugins.shadow.testkit.containsOnly import com.github.jengelman.gradle.plugins.shadow.testkit.getBytes import com.github.jengelman.gradle.plugins.shadow.testkit.requireResourceAsPath +import com.github.jengelman.gradle.plugins.shadow.testkit.runTest +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests import com.github.jengelman.gradle.plugins.shadow.util.runProcess +import de.infix.testBalloon.framework.core.testSuite import java.net.URLClassLoader import kotlin.io.path.appendText import kotlin.io.path.readBytes import kotlin.io.path.writeText import kotlin.time.Duration.Companion.seconds -import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.MethodSource -import org.junit.jupiter.params.provider.ValueSource import org.opentest4j.AssertionFailedError -class RelocationTest : BasePluginTest() { - @ParameterizedTest - @ValueSource(strings = ["foo", "new.pkg", "new/path"]) +val RelocationTests by testSuite { + runTests(::RelocationTest) + + for (relocationPrefix in listOf("foo", "new.pkg", "new/path")) { + runTest("autoRelocation_$relocationPrefix", ::RelocationTest) { + autoRelocation(relocationPrefix) + } + } + + for ((enable: Boolean, relocationPrefix: String) in RelocationTest.relocationCliOptionProvider) { + runTest( + "enableAutoRelocationByCliOption_${enable}_${relocationPrefix}", + ::RelocationTest, + ) { + enableAutoRelocationByCliOption(enable, relocationPrefix) + } + } +} + +private class RelocationTest : BasePluginTest() { fun autoRelocation(relocationPrefix: String) { val mainClassEntry = writeClass() projectScript.appendText( @@ -67,8 +83,6 @@ class RelocationTest : BasePluginTest() { assertThat(result.output).contains("Relocator count: 6.") } - @ParameterizedTest - @MethodSource("relocationCliOptionProvider") fun enableAutoRelocationByCliOption(enable: Boolean, relocationPrefix: String) { val mainClassEntry = writeClass() projectScript.appendText( @@ -109,7 +123,7 @@ class RelocationTest : BasePluginTest() { } } - @Test // #58 + // #58 fun relocateDependencyFiles() { val mainClassEntry = writeClass() projectScript.appendText( @@ -150,7 +164,6 @@ class RelocationTest : BasePluginTest() { } } - @Test fun relocateDependencyFilesWithFiltering() { val mainClassEntry = writeClass() projectScript.appendText( @@ -199,7 +212,7 @@ class RelocationTest : BasePluginTest() { } } - @Test // #53, #55 + // #53, #55 fun remapClassNamesForRelocatedFilesInProjectSource() { projectScript.appendText( """ @@ -249,7 +262,7 @@ class RelocationTest : BasePluginTest() { } } - @Test // #93, #114 + // #93, #114 fun relocateResourceFiles() { val depJar = buildJar("foo.jar") { insert("foo/dep.properties", "c") } writeClass(packageName = "foo", className = "Foo") @@ -280,8 +293,6 @@ class RelocationTest : BasePluginTest() { } } - @ParameterizedTest - @MethodSource("preserveLastModifiedProvider") fun preserveLastModifiedCorrectly( enableAutoRelocation: Boolean, preserveFileTimestamps: Boolean, @@ -372,7 +383,7 @@ class RelocationTest : BasePluginTest() { } } - @Test // #295, #562, #884 + // #295, #562, #884 fun excludeKotlinBuiltinsFromRelocation() { val kotlinJar = buildJar("kotlin.jar") { @@ -399,8 +410,6 @@ class RelocationTest : BasePluginTest() { } } - @ParameterizedTest - @ValueSource(booleans = [false, true]) fun relocateAllPackagesButCertainOne(exclude: Boolean) { val relocateConfig = if (exclude) { @@ -437,7 +446,6 @@ class RelocationTest : BasePluginTest() { } } - @Test fun relocateProjectResourcesOnly() { val mainClassEntry = writeClass() projectScript.appendText( @@ -460,7 +468,6 @@ class RelocationTest : BasePluginTest() { } } - @Test fun relocateStringConstantsByDefault() { writeClassWithStringRef() projectScript.appendText( @@ -481,8 +488,7 @@ class RelocationTest : BasePluginTest() { assertThat(result).contains("shadow.foo.Foo", "shadow.foo.Bar") } - @ParameterizedTest // #232, #606 - @ValueSource(booleans = [false, true]) + // #232, #606 fun disableStringConstantsRelocation(skipStringConstants: Boolean) { writeClassWithStringRef() projectScript.appendText( @@ -509,7 +515,7 @@ class RelocationTest : BasePluginTest() { } } - @Test // #1403 + // #1403 fun relocateMultiClassSignatureStringConstants() { writeClass { """ @@ -548,7 +554,6 @@ class RelocationTest : BasePluginTest() { ) } - @Test fun classBytesUnchangedIfPossible() { val mainClassEntry = writeClass() projectScript.appendText( @@ -570,8 +575,7 @@ class RelocationTest : BasePluginTest() { assertThat(relocatedBytes).isEqualTo(originalBytes) } - @ParameterizedTest // #843 - @ValueSource(booleans = [false, true]) + // #843 fun relocateKotlinModuleFiles(enableKotlinModuleRemapping: Boolean) { val originalModuleFilePath = "META-INF/kotlin-stdlib.kotlin_module" val originalModuleFileBytes = requireResourceAsPath(originalModuleFilePath).readBytes() @@ -627,7 +631,6 @@ class RelocationTest : BasePluginTest() { } } - @Test fun relocateWithR8() { writeClass(packageName = "my", withImports = false) { """ @@ -679,18 +682,8 @@ class RelocationTest : BasePluginTest() { } } - private companion object { - @JvmStatic - fun preserveLastModifiedProvider() = - listOf( - Arguments.of(false, false), - Arguments.of(true, false), - Arguments.of(false, true), - Arguments.of(true, true), - ) - - @JvmStatic - fun relocationCliOptionProvider() = + companion object { + val relocationCliOptionProvider = listOf( Arguments.of(false, "foo"), Arguments.of(false, "bar"), diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/AppendingTransformerTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/AppendingTransformerTest.kt index 979efcc2f..6e0393db1 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/AppendingTransformerTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/AppendingTransformerTest.kt @@ -3,11 +3,15 @@ package com.github.jengelman.gradle.plugins.shadow.transformers import assertk.assertThat import assertk.assertions.isEqualTo import com.github.jengelman.gradle.plugins.shadow.testkit.getContent +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests +import de.infix.testBalloon.framework.core.testSuite import kotlin.io.path.appendText -import org.junit.jupiter.api.Test -class AppendingTransformerTest : BaseTransformerTest() { - @Test +val AppendingTransformerTests by testSuite { + runTests(::AppendingTransformerTest) +} + +private class AppendingTransformerTest : BaseTransformerTest() { fun appendTestProperties() { val one = buildJarOne { insert(ENTRY_TEST_PROPERTIES, CONTENT_ONE) } val two = buildJarTwo { insert(ENTRY_TEST_PROPERTIES, CONTENT_TWO) } diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/BaseTransformerTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/BaseTransformerTest.kt index 2d173523c..77a512044 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/BaseTransformerTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/BaseTransformerTest.kt @@ -4,12 +4,9 @@ import com.github.jengelman.gradle.plugins.shadow.BasePluginTest import com.github.jengelman.gradle.plugins.shadow.util.JarBuilder import java.nio.file.Path import kotlin.io.path.appendText -import org.junit.jupiter.api.BeforeEach abstract class BaseTransformerTest : BasePluginTest() { - @BeforeEach - override fun beforeEach() { - super.beforeEach() + init { projectScript.appendText( """ |$shadowJarTask { diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/GroovyExtensionModuleTransformerTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/GroovyExtensionModuleTransformerTest.kt index 365963ebb..d34296147 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/GroovyExtensionModuleTransformerTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/GroovyExtensionModuleTransformerTest.kt @@ -4,6 +4,7 @@ import assertk.assertThat import assertk.assertions.isEqualTo import com.github.jengelman.gradle.plugins.shadow.testkit.JarPath import com.github.jengelman.gradle.plugins.shadow.testkit.getContent +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests import com.github.jengelman.gradle.plugins.shadow.transformers.GroovyExtensionModuleTransformer.Companion.KEY_EXTENSION_CLASSES import com.github.jengelman.gradle.plugins.shadow.transformers.GroovyExtensionModuleTransformer.Companion.KEY_MODULE_NAME import com.github.jengelman.gradle.plugins.shadow.transformers.GroovyExtensionModuleTransformer.Companion.KEY_MODULE_VERSION @@ -11,12 +12,15 @@ import com.github.jengelman.gradle.plugins.shadow.transformers.GroovyExtensionMo import com.github.jengelman.gradle.plugins.shadow.transformers.GroovyExtensionModuleTransformer.Companion.MERGED_MODULE_NAME import com.github.jengelman.gradle.plugins.shadow.transformers.GroovyExtensionModuleTransformer.Companion.MERGED_MODULE_VERSION import com.github.jengelman.gradle.plugins.shadow.transformers.GroovyExtensionModuleTransformer.Companion.PATH_GROOVY_EXTENSION_MODULE_DESCRIPTOR +import de.infix.testBalloon.framework.core.testSuite import java.nio.file.Path import kotlin.io.path.appendText -import org.junit.jupiter.api.Test -class GroovyExtensionModuleTransformerTest : BaseTransformerTest() { - @Test +val GroovyExtensionModuleTransformerTests by testSuite { + runTests(::GroovyExtensionModuleTransformerTest) +} + +private class GroovyExtensionModuleTransformerTest : BaseTransformerTest() { fun groovyExtensionModuleTransformer() { projectScript.appendText( """ @@ -70,7 +74,7 @@ class GroovyExtensionModuleTransformerTest : BaseTransformerTest() { ) } - private companion object { + companion object { const val EXTENSION_CLASSES_FOO = "com.acme.foo.FooExtension,com.acme.foo.BarExtension" const val EXTENSION_CLASSES_BAR = "com.acme.bar.SomeExtension,com.acme.bar.AnotherExtension" const val STATIC_EXTENSION_CLASSES_FOO = "com.acme.foo.FooStaticExtension" diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerTest.kt index 59a63382f..9eb4c1c96 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerTest.kt @@ -4,14 +4,18 @@ import assertk.assertThat import assertk.assertions.contains import assertk.assertions.isEqualTo import com.github.jengelman.gradle.plugins.shadow.testkit.getContent +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests +import de.infix.testBalloon.framework.core.testSuite import kotlin.io.path.appendText import kotlin.io.path.invariantSeparatorsPathString import kotlin.io.path.writeText -import org.junit.jupiter.api.Test -class PropertiesFileTransformerTest : BaseTransformerTest() { +val PropertiesFileTransformerTests by testSuite { + runTests(::PropertiesFileTransformerTest) +} + +private class PropertiesFileTransformerTest : BaseTransformerTest() { - @Test fun configureComplexTransformerProperties() { val propertiesEntry = "META-INF/test.properties" val one = buildJarOne { diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ServiceFileTransformerTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ServiceFileTransformerTest.kt index 5dba0720a..91839ba77 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ServiceFileTransformerTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ServiceFileTransformerTest.kt @@ -4,8 +4,12 @@ import assertk.assertThat import assertk.assertions.contains import assertk.assertions.containsMatch import assertk.assertions.isEqualTo +import com.github.jengelman.gradle.plugins.shadow.testkit.Arguments import com.github.jengelman.gradle.plugins.shadow.testkit.containsOnly import com.github.jengelman.gradle.plugins.shadow.testkit.getContent +import com.github.jengelman.gradle.plugins.shadow.testkit.runTest +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests +import de.infix.testBalloon.framework.core.testSuite import kotlin.io.path.appendText import kotlin.io.path.writeText import org.gradle.api.file.DuplicatesStrategy @@ -14,13 +18,35 @@ import org.gradle.api.file.DuplicatesStrategy.FAIL import org.gradle.api.file.DuplicatesStrategy.INCLUDE import org.gradle.api.file.DuplicatesStrategy.INHERIT import org.gradle.api.file.DuplicatesStrategy.WARN -import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.MethodSource -class ServiceFileTransformerTest : BaseTransformerTest() { - @Test +val ServiceFileTransformerTests by testSuite { + runTests(::ServiceFileTransformerTest) + + for ((strategy, outputRegex) in ServiceFileTransformerTest.withThrowingProvider) { + runTest("honorDuplicatesStrategyWithThrowing_$strategy", ::ServiceFileTransformerTest) { + honorDuplicatesStrategyWithThrowing(strategy, outputRegex) + } + } + + for ((strategy: DuplicatesStrategy, firstValue: String, secondValue: String) in + ServiceFileTransformerTest.withoutThrowingProvider) { + runTest("honorDuplicatesStrategyWithoutThrowing_$strategy", ::ServiceFileTransformerTest) { + honorDuplicatesStrategyWithoutThrowing(strategy, firstValue, secondValue) + } + } + + for ((default: DuplicatesStrategy, override: DuplicatesStrategy, matchPath: String) in + ServiceFileTransformerTest.eachFileStrategyProvider) { + runTest( + "strategyCanBeOverriddenByEachFile_${default}_${override}", + ::ServiceFileTransformerTest, + ) { + strategyCanBeOverriddenByEachFile(default, override, matchPath) + } + } +} + +private class ServiceFileTransformerTest : BaseTransformerTest() { fun serviceResourceTransformerAlternatePath() { val one = buildJarOne { insert(ENTRY_FOO_SHADE, CONTENT_ONE) } val two = buildJarTwo { insert(ENTRY_FOO_SHADE, CONTENT_TWO) } @@ -42,7 +68,6 @@ class ServiceFileTransformerTest : BaseTransformerTest() { assertThat(content).isEqualTo(CONTENT_ONE_TWO) } - @Test fun serviceResourceTransformerWithRelocation() { val one = buildJarOne { insert("com/example/Driver.class", createEmptyClassBytes("com/example/Driver")) @@ -102,7 +127,6 @@ class ServiceFileTransformerTest : BaseTransformerTest() { } } - @Test fun serviceResourceTransformerWithR8Relocation() { val one = buildJarOne { insert("com/example/Driver.class", createEmptyClassBytes("com/example/Driver")) @@ -167,7 +191,7 @@ class ServiceFileTransformerTest : BaseTransformerTest() { } } - @Test // #70, #71 + // #70, #71 fun transformProjectResources() { val servicesBarEntry = "META-INF/services/foo.Bar" val one = buildJarOne { insert(servicesBarEntry, CONTENT_ONE) } @@ -191,8 +215,6 @@ class ServiceFileTransformerTest : BaseTransformerTest() { assertThat(content).isEqualTo("$CONTENT_THREE\n$CONTENT_ONE_TWO") } - @ParameterizedTest - @MethodSource("withThrowingProvider") fun honorDuplicatesStrategyWithThrowing(strategy: DuplicatesStrategy, outputRegex: String) { writeDuplicatesStrategy(strategy) @@ -201,8 +223,6 @@ class ServiceFileTransformerTest : BaseTransformerTest() { assertThat(result.output).containsMatch(outputRegex.toRegex()) } - @ParameterizedTest - @MethodSource("withoutThrowingProvider") fun honorDuplicatesStrategyWithoutThrowing( strategy: DuplicatesStrategy, firstValue: String, @@ -226,7 +246,6 @@ class ServiceFileTransformerTest : BaseTransformerTest() { } } - @Test fun strategyCanBeOverriddenByFilesMatching() { writeDuplicatesStrategy(EXCLUDE) projectScript.appendText( @@ -248,7 +267,6 @@ class ServiceFileTransformerTest : BaseTransformerTest() { } } - @Test fun strategyCanBeOverriddenByFilesNotMatching() { writeDuplicatesStrategy(INCLUDE) projectScript.appendText( @@ -270,8 +288,6 @@ class ServiceFileTransformerTest : BaseTransformerTest() { } } - @ParameterizedTest - @MethodSource("eachFileStrategyProvider") fun strategyCanBeOverriddenByEachFile( default: DuplicatesStrategy, override: DuplicatesStrategy, @@ -315,30 +331,21 @@ class ServiceFileTransformerTest : BaseTransformerTest() { ) } - private companion object { - @JvmStatic - fun withThrowingProvider() = + companion object { + val withThrowingProvider = listOf( - Arguments.of( - FAIL, - "Cannot copy zip entry .* to .* because zip entry .* has already been copied there", - ), - Arguments.of( - INHERIT, - "Entry .* is a duplicate but no duplicate handling strategy has been set", - ), + FAIL to "Cannot copy zip entry .* to .* because zip entry .* has already been copied there", + INHERIT to "Entry .* is a duplicate but no duplicate handling strategy has been set", ) - @JvmStatic - fun withoutThrowingProvider() = + val withoutThrowingProvider = listOf( Arguments.of(EXCLUDE, CONTENT_ONE, "one"), Arguments.of(INCLUDE, CONTENT_ONE_TWO, "one\ntwo"), Arguments.of(WARN, CONTENT_ONE_TWO, "one\ntwo"), ) - @JvmStatic - fun eachFileStrategyProvider() = + val eachFileStrategyProvider = listOf( Arguments.of(EXCLUDE, INCLUDE, ENTRY_SERVICES_SHADE), Arguments.of(INCLUDE, EXCLUDE, ENTRY_SERVICES_FOO), diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/TransformersTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/TransformersTest.kt index 99ce25538..1b53656b1 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/TransformersTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/TransformersTest.kt @@ -11,16 +11,20 @@ import com.github.jengelman.gradle.plugins.shadow.testkit.containsOnly import com.github.jengelman.gradle.plugins.shadow.testkit.getContent import com.github.jengelman.gradle.plugins.shadow.testkit.getStream import com.github.jengelman.gradle.plugins.shadow.testkit.requireResourceAsPath +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests +import de.infix.testBalloon.framework.core.testSuite import java.util.jar.Attributes as JarAttribute import kotlin.io.path.appendText import kotlin.io.path.readText import kotlin.io.path.writeText import org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor.PLUGIN_CACHE_FILE -import org.junit.jupiter.api.Test -class TransformersTest : BaseTransformerTest() { +val TransformersTests by testSuite { + runTests(::TransformersTest) +} + +private class TransformersTest : BaseTransformerTest() { - @Test fun manifestRetained() { writeClass() projectScript.appendText( @@ -43,7 +47,6 @@ class TransformersTest : BaseTransformerTest() { } } - @Test fun manifestTransformed() { writeClass() @@ -54,7 +57,7 @@ class TransformersTest : BaseTransformerTest() { commonAssertions() } - @Test // #427 + // #427 fun mergeLog4j2PluginCacheFiles() { val content = requireResourceAsPath(PLUGIN_CACHE_FILE).readText() val one = buildJarOne { insert(PLUGIN_CACHE_FILE, content) } @@ -77,7 +80,6 @@ class TransformersTest : BaseTransformerTest() { } } - @Test fun preserveFirstFoundResource() { path("src/main/resources/foo/bar").writeText("bar1") path("src/main/resources/foo/baz").writeText("baz1") @@ -105,7 +107,6 @@ class TransformersTest : BaseTransformerTest() { } } - @Test fun useCustomTransformer() { projectScript.appendText( """ @@ -138,7 +139,7 @@ class TransformersTest : BaseTransformerTest() { mainAttributesBlock(mf.mainAttributes) } - private companion object { + companion object { const val NEW_ENTRY_ATTR_KEY = "New-Entry" const val TEST_ENTRY_ATTR_KEY = "Test-Entry" diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowPropertiesTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowPropertiesTest.kt index 91c70e5ab..92c33e265 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowPropertiesTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/ShadowPropertiesTest.kt @@ -23,6 +23,8 @@ import com.github.jengelman.gradle.plugins.shadow.internal.runtimeConfiguration import com.github.jengelman.gradle.plugins.shadow.legacy.LegacyShadowPlugin import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar.Companion.SHADOW_JAR_TASK_NAME import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar.Companion.shadowJar +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests +import de.infix.testBalloon.framework.core.testSuite import org.gradle.api.Named import org.gradle.api.Project import org.gradle.api.Task @@ -41,22 +43,18 @@ import org.gradle.language.base.plugins.LifecycleBasePlugin import org.gradle.language.base.plugins.LifecycleBasePlugin.ASSEMBLE_TASK_NAME import org.gradle.plugin.devel.plugins.JavaGradlePluginPlugin import org.gradle.testfixtures.ProjectBuilder -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -class ShadowPropertiesTest { - private lateinit var project: Project +val ShadowPropertiesTests by testSuite { + runTests(::ShadowPropertiesTest) +} - @BeforeEach - fun beforeEach() { - project = - ProjectBuilder.builder().withName(PROJECT_NAME).build().also { - it.version = VERSION - it.plugins.apply(ShadowPlugin::class.java) - } - } +private class ShadowPropertiesTest { + private val project: Project = + ProjectBuilder.builder().withName(PROJECT_NAME).build().also { + it.version = VERSION + it.plugins.apply(ShadowPlugin::class.java) + } - @Test fun misc() = with(project) { assertThat(plugins.hasPlugin(ShadowPlugin::class.java)).isTrue() @@ -71,7 +69,6 @@ class ShadowPropertiesTest { } } - @Test fun inheritManifestAttrsFromJars() = with(project) { plugins.apply(JavaPlugin::class.java) @@ -96,7 +93,6 @@ class ShadowPropertiesTest { ) } - @Test fun inheritManifestMainClassFromJar() = with(project) { plugins.apply(JavaPlugin::class.java) @@ -108,7 +104,6 @@ class ShadowPropertiesTest { .containsOnly("Manifest-Version" to "1.0", mainClassAttributeKey to "Main") } - @Test fun applyJavaPlugin() = with(project) { plugins.apply(JavaPlugin::class.java) @@ -165,7 +160,6 @@ class ShadowPropertiesTest { } } - @Test fun applyApplicationPlugin() = with(project) { plugins.apply(ApplicationPlugin::class.java) @@ -257,7 +251,6 @@ class ShadowPropertiesTest { } } - @Test fun applyJavaGradlePlugin() = with(project) { plugins.apply(JavaGradlePluginPlugin::class.java) @@ -270,7 +263,7 @@ class ShadowPropertiesTest { assertThat(compileOnlyApi.dependencies).containsOnly(gradleApi) } - private companion object { + companion object { const val PROJECT_NAME = "my-project" const val VERSION = "1.0.0" diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/BytecodeRemappingTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/BytecodeRemappingTest.kt index 9bbb3c7d6..133623086 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/BytecodeRemappingTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/BytecodeRemappingTest.kt @@ -1,3 +1,5 @@ +@file:OptIn(kotlin.io.path.ExperimentalPathApi::class) + package com.github.jengelman.gradle.plugins.shadow.internal import assertk.assertFailure @@ -9,18 +11,18 @@ import assertk.assertions.isEqualTo import assertk.assertions.isInstanceOf import com.github.jengelman.gradle.plugins.shadow.relocation.SimpleRelocator import com.github.jengelman.gradle.plugins.shadow.testkit.requireResourceAsPath +import com.github.jengelman.gradle.plugins.shadow.testkit.runTest +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests import com.github.jengelman.gradle.plugins.shadow.util.noOpDelegate +import de.infix.testBalloon.framework.core.testSuite import java.io.File import java.nio.file.Path import kotlin.io.path.copyTo import kotlin.io.path.createParentDirectories +import kotlin.io.path.createTempDirectory import kotlin.reflect.KClass import org.gradle.api.GradleException import org.gradle.api.file.FileCopyDetails -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.io.TempDir -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.ValueSource import org.vafer.jdeb.shaded.objectweb.asm.AnnotationVisitor import org.vafer.jdeb.shaded.objectweb.asm.ClassReader import org.vafer.jdeb.shaded.objectweb.asm.ClassVisitor @@ -31,15 +33,23 @@ import org.vafer.jdeb.shaded.objectweb.asm.MethodVisitor import org.vafer.jdeb.shaded.objectweb.asm.ModuleVisitor import org.vafer.jdeb.shaded.objectweb.asm.Opcodes +val BytecodeRemappingTests by testSuite { + runTests(::BytecodeRemappingTest) + + for (primitiveDescriptor in listOf('B', 'C', 'D', 'F', 'I', 'J', 'S', 'Z')) { + runTest("primitivePlusClassMethodIsRelocated_$primitiveDescriptor", ::BytecodeRemappingTest) { + primitivePlusClassMethodIsRelocated(primitiveDescriptor) + } + } +} + /** * The cases reflect the cases in * [com.github.jengelman.gradle.plugins.shadow.relocation.RelocatorsTest], but operate on the * bytecode level to verify that the remapper correctly transforms class names in all relevant * bytecode structures. */ -class BytecodeRemappingTest { - @TempDir lateinit var tempDir: Path - +private class BytecodeRemappingTest(val tempDir: Path = createTempDirectory()) { // Relocator used across all relocation tests: moves the test package to a distinct target. private val relocators = setOf( @@ -55,7 +65,6 @@ class BytecodeRemappingTest { private val fixtureSubjectDetails get() = FixtureSubject::class.toFileCopyDetails() - @Test fun classNotModified() { val details = fixtureSubjectDetails // Relocator pattern does not match – original bytes must be returned as-is. @@ -66,7 +75,6 @@ class BytecodeRemappingTest { assertThat(result).isEqualTo(details.file.readBytes()) } - @Test fun asmFailureIsWrappedWithClassPath() { val path = "broken/Example.class" val file = tempDir.resolve("broken.class").toFile().apply { writeText("not bytecode") } @@ -82,7 +90,6 @@ class BytecodeRemappingTest { .hasMessage("Error in ASM processing class $path") } - @Test fun classNameIsRelocated() { val result = fixtureSubjectDetails.remapClass(relocators) @@ -90,7 +97,6 @@ class BytecodeRemappingTest { .isEqualTo($$"com/example/relocated/BytecodeRemappingTest$FixtureSubject") } - @Test fun annotationIsRelocated() { val result = fixtureSubjectDetails.remapClass(relocators) @@ -98,7 +104,6 @@ class BytecodeRemappingTest { .contains($$"Lcom/example/relocated/BytecodeRemappingTest$FixtureAnnotation;") } - @Test fun baseClassNameIsRelocated() { // Verify relocation also works on a simple class (FixtureBase has no fields/methods // referencing the target package beyond its own class name). @@ -109,35 +114,30 @@ class BytecodeRemappingTest { assertThat(ClassReader(result).className).isEqualTo(relocatedFixtureBase) } - @Test fun superclassIsRelocated() { val result = fixtureSubjectDetails.remapClass(relocators) assertThat(ClassReader(result).superName).isEqualTo(relocatedFixtureBase) } - @Test fun fieldDescriptorIsRelocated() { val result = fixtureSubjectDetails.remapClass(relocators) assertThat(result.classInfo().fieldDescriptors).contains("L$relocatedFixtureBase;") } - @Test fun arrayFieldDescriptorIsRelocated() { val result = fixtureSubjectDetails.remapClass(relocators) assertThat(result.classInfo().fieldDescriptors).contains("[L$relocatedFixtureBase;") } - @Test fun array2dFieldDescriptorIsRelocated() { val result = fixtureSubjectDetails.remapClass(relocators) assertThat(result.classInfo().fieldDescriptors).contains("[[L$relocatedFixtureBase;") } - @Test fun methodDescriptorIsRelocated() { val result = fixtureSubjectDetails.remapClass(relocators) @@ -145,7 +145,6 @@ class BytecodeRemappingTest { .contains("(L$relocatedFixtureBase;)L$relocatedFixtureBase;") } - @Test fun methodMultipleArgsIsRelocated() { val result = fixtureSubjectDetails.remapClass(relocators) @@ -153,8 +152,6 @@ class BytecodeRemappingTest { .contains("(L$relocatedFixtureBase;L$relocatedFixtureBase;)L$relocatedFixtureBase;") } - @ParameterizedTest - @ValueSource(chars = ['B', 'C', 'D', 'F', 'I', 'J', 'S', 'Z']) fun primitivePlusClassMethodIsRelocated(primitiveDescriptor: Char) { val result = fixtureSubjectDetails.remapClass(relocators) @@ -162,7 +159,6 @@ class BytecodeRemappingTest { .contains("(${primitiveDescriptor}L$relocatedFixtureBase;)L$relocatedFixtureBase;") } - @Test fun stringConstantIsRelocated() { val result = fixtureSubjectDetails.remapClass(relocators) @@ -170,7 +166,6 @@ class BytecodeRemappingTest { .contains($$"com.example.relocated.BytecodeRemappingTest$FixtureBase") } - @Test fun stringConstantNotRelocatedWhenSkipEnabled() { val skipRelocators = setOf( @@ -186,7 +181,6 @@ class BytecodeRemappingTest { .doesNotContain($$"com.example.relocated.BytecodeRemappingTest$FixtureBase") } - @Test fun multiClassDescriptorStringConstantIsRelocated() { val result = fixtureSubjectDetails.remapClass(relocators) @@ -198,7 +192,6 @@ class BytecodeRemappingTest { ) } - @Test fun interfaceIsRelocated() { val result = fixtureSubjectDetails.remapClass(relocators) @@ -206,7 +199,6 @@ class BytecodeRemappingTest { .contains($$"com/example/relocated/BytecodeRemappingTest$FixtureInterface") } - @Test fun signatureIsRelocated() { val result = fixtureSubjectDetails.remapClass(relocators) @@ -214,7 +206,6 @@ class BytecodeRemappingTest { assertThat(checkNotNull(method.signature)).contains("L$relocatedFixtureBase;") } - @Test fun nestedClassSignatureIsRelocated() { val result = fixtureSubjectDetails.remapClass(relocators) @@ -225,7 +216,6 @@ class BytecodeRemappingTest { ) } - @Test fun moduleMainClassIsRelocated() { val originalMainClass = $$"com/github/jengelman/gradle/plugins/shadow/internal/BytecodeRemappingTest$FixtureBase" @@ -264,7 +254,6 @@ class BytecodeRemappingTest { assertThat(remappedMainClass).isEqualTo(relocatedFixtureBase) } - @Test fun localVariableIsRelocated() { val result = fixtureSubjectDetails.remapClass(relocators) @@ -272,7 +261,6 @@ class BytecodeRemappingTest { assertThat(method.localVarDescriptors).contains("L$relocatedFixtureBase;") } - @Test fun instructionIsRelocated() { val result = fixtureSubjectDetails.remapClass(relocators) diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/DefaultDependencyFilterTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/DefaultDependencyFilterTest.kt index 3d756a4e9..7c10c7485 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/DefaultDependencyFilterTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/DefaultDependencyFilterTest.kt @@ -7,19 +7,37 @@ import assertk.assertions.isEqualTo import assertk.assertions.isInstanceOf import assertk.assertions.isTrue import assertk.assertions.messageContains +import com.github.jengelman.gradle.plugins.shadow.testkit.Arguments +import com.github.jengelman.gradle.plugins.shadow.testkit.runTest +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests import com.github.jengelman.gradle.plugins.shadow.util.noOpDelegate +import de.infix.testBalloon.framework.core.testSuite import org.gradle.api.artifacts.ResolvedDependency import org.gradle.testfixtures.ProjectBuilder -import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.MethodSource -class DefaultDependencyFilterTest { +val DefaultDependencyFilterTests by testSuite { + runTests(::DefaultDependencyFilterTest) + + for ((notation: Any, group: String, name: String, version: String, expected: Boolean) in + DefaultDependencyFilterTest.dependencyNotationProvider) { + runTest( + "matchesDependencyNotation_${notation}_${group}_${name}_$version", + ::DefaultDependencyFilterTest, + ) { + matchesDependencyNotation(notation, group, name, version, expected) + } + } + + for (notation in DefaultDependencyFilterTest.projectNotationProvider) { + runTest("matchesProjectNotation_${notation}", ::DefaultDependencyFilterTest) { + matchesProjectNotation(notation) + } + } +} + +private class DefaultDependencyFilterTest { private val filter = DefaultDependencyFilter(project) - @ParameterizedTest - @MethodSource("dependencyNotationProvider") fun matchesDependencyNotation( notation: Any, group: String, @@ -33,8 +51,6 @@ class DefaultDependencyFilterTest { assertThat(spec.isSatisfiedBy(dep)).isEqualTo(expected) } - @ParameterizedTest - @MethodSource("projectNotationProvider") fun matchesProjectNotation(notation: Any) { val spec = filter.project(notation) val dep = @@ -47,14 +63,13 @@ class DefaultDependencyFilterTest { assertThat(spec.isSatisfiedBy(dep)).isTrue() } - @Test fun rejectsUnsupportedProjectNotation() { assertFailure { filter.project(42) } .isInstanceOf() .messageContains("Unsupported notation type: class java.lang.Integer") } - private companion object { + companion object { val project = ProjectBuilder.builder().build() val subproject = ProjectBuilder.builder().withName("subproject").withParent(project).build() val projectDependency = project.dependencies.project(mapOf("path" to subproject.path)) @@ -94,15 +109,14 @@ class DefaultDependencyFilterTest { Arguments.of(mapOf("name" to "bar"), "any.group", "bar", "1.0", true), ) - @JvmStatic fun dependencyNotationProvider() = stringNotations + providerNotations + mapNotations + val dependencyNotationProvider = stringNotations + providerNotations + mapNotations - @JvmStatic - fun projectNotationProvider() = + val projectNotationProvider = listOf( - Arguments.of(subproject.path), - Arguments.of(project.provider { subproject.path }), - Arguments.of(mapOf("path" to subproject.path)), - Arguments.of(projectDependency), + subproject.path, + project.provider { subproject.path }, + mapOf("path" to subproject.path), + projectDependency, ) } } diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/DuplicatesStrategyCheckerTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/DuplicatesStrategyCheckerTest.kt index c91845708..ed8c22d8e 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/DuplicatesStrategyCheckerTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/DuplicatesStrategyCheckerTest.kt @@ -1,14 +1,19 @@ +@file:OptIn(kotlin.io.path.ExperimentalPathApi::class) + package com.github.jengelman.gradle.plugins.shadow.internal import assertk.assertThat import assertk.assertions.isEqualTo +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests import com.github.jengelman.gradle.plugins.shadow.transformers.BaseTransformerTest.Companion.canTransformResource import com.github.jengelman.gradle.plugins.shadow.transformers.ResourceTransformer import com.github.jengelman.gradle.plugins.shadow.transformers.ResourceTransformer.Companion.create import com.github.jengelman.gradle.plugins.shadow.util.testObjectFactory +import de.infix.testBalloon.framework.core.testSuite import java.io.File import java.net.JarURLConnection import java.nio.file.Path +import kotlin.io.path.createTempDirectory import kotlin.io.path.createTempFile import kotlin.io.path.exists import kotlin.io.path.extension @@ -16,13 +21,12 @@ import kotlin.io.path.isRegularFile import kotlin.io.path.toPath import kotlin.io.path.walk import kotlin.reflect.full.isSubclassOf -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.io.TempDir -class DuplicatesStrategyCheckerTest { - @TempDir lateinit var tempDir: Path +val DuplicatesStrategyCheckerTests by testSuite { + runTests(::DuplicatesStrategyCheckerTest) +} - @Test +private class DuplicatesStrategyCheckerTest(val tempDir: Path = createTempDirectory()) { fun checkDupStrategyInvocationCount() { val allResourceTransformers = getTransformerClasses().map { diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/MinimizeSpecsTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/MinimizeSpecsTest.kt index 0c3b5d006..95046a1e5 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/MinimizeSpecsTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/MinimizeSpecsTest.kt @@ -9,20 +9,23 @@ import assertk.assertions.isNull import assertk.assertions.isSameInstanceAs import assertk.assertions.isTrue import com.github.jengelman.gradle.plugins.shadow.tasks.MinimizeTool +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests +import de.infix.testBalloon.framework.core.testSuite import org.gradle.testfixtures.ProjectBuilder -import org.junit.jupiter.api.Test -class MinimizeSpecsTest { +val MinimizeSpecsTests by testSuite { + runTests(::MinimizeSpecsTest) +} + +private class MinimizeSpecsTest { private val project = ProjectBuilder.builder().build() - @Test fun defaultMinimizeSpecUsesDependencyAnalyzer() = with(project.objects.newInstance(DefaultMinimizeSpec::class.java, project)) { assertThat(tool.get()).isEqualTo(MinimizeTool.DEPENDENCY_ANALYZER) assertThat(r8SpecForInputs).isNull() } - @Test fun r8ConfiguresToolAndExposesSameSpecAsInput() = with(project.objects.newInstance(DefaultMinimizeSpec::class.java, project)) { lateinit var configured: Any @@ -33,7 +36,6 @@ class MinimizeSpecsTest { assertThat(r8Spec).isSameInstanceAs(configured) } - @Test fun defaultR8SpecIsShrinkOnly() = with(project.objects.newInstance(DefaultR8Spec::class.java)) { assertThat(args.get()).containsExactly(DefaultR8Spec.NO_MINIFICATION_ARG) @@ -47,7 +49,6 @@ class MinimizeSpecsTest { ) } - @Test fun enablingObfuscationRemovesDefaultArgument() = with(project.objects.newInstance(DefaultR8Spec::class.java)) { enableObfuscation() @@ -57,7 +58,6 @@ class MinimizeSpecsTest { assertThat(optimizationEnabled.get()).isFalse() } - @Test fun enablingOptimizationOnlyChangesOptimizationFlag() = with(project.objects.newInstance(DefaultR8Spec::class.java)) { enableOptimization() @@ -67,7 +67,6 @@ class MinimizeSpecsTest { assertThat(optimizationEnabled.get()).isTrue() } - @Test fun explicitArgumentsTakePrecedenceOverChangedDefaults() = with(project.objects.newInstance(DefaultR8Spec::class.java)) { args.set(listOf("--debug")) diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/R8MinimizerTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/R8MinimizerTest.kt index af5b2bd5d..c3096294e 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/R8MinimizerTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/R8MinimizerTest.kt @@ -1,18 +1,24 @@ +@file:OptIn(kotlin.io.path.ExperimentalPathApi::class) + package com.github.jengelman.gradle.plugins.shadow.internal import assertk.assertThat import assertk.assertions.isEqualTo +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests import com.github.jengelman.gradle.plugins.shadow.util.zipOutputStream +import de.infix.testBalloon.framework.core.testSuite import java.nio.file.Path +import kotlin.io.path.createTempDirectory import org.apache.tools.zip.UnixStat import org.apache.tools.zip.ZipFile import org.gradle.api.tasks.bundling.ZipEntryCompression -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.io.TempDir -class R8MinimizerTest { - @Test - fun normalizeJarPreservesUnixPermissions(@TempDir tempDir: Path) { +val R8MinimizerTests by testSuite { + runTests(::R8MinimizerTest) +} + +private class R8MinimizerTest(val tempDir: Path = createTempDirectory()) { + fun normalizeJarPreservesUnixPermissions() { val inputJar = tempDir.resolve("input.jar") val outputJar = tempDir.resolve("output.jar") val expectedExecutableMode = UnixStat.FILE_FLAG or 493 // 0755 octal diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/ReproduciblePropertiesTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/ReproduciblePropertiesTest.kt index f9ae183ab..582ce8c6a 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/ReproduciblePropertiesTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/ReproduciblePropertiesTest.kt @@ -3,22 +3,31 @@ package com.github.jengelman.gradle.plugins.shadow.internal import assertk.assertThat import assertk.assertions.isEqualTo import com.github.jengelman.gradle.plugins.shadow.testkit.invariantEolString +import de.infix.testBalloon.framework.core.testSuite import java.io.ByteArrayOutputStream import java.nio.charset.Charset -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.MethodSource -class ReproduciblePropertiesTest { - @ParameterizedTest - @MethodSource("generalCharsetsProvider") +val ReproduciblePropertiesTests by testSuite { + val subject = ReproduciblePropertiesTest() + + for (charset in ReproduciblePropertiesTest.generalCharsetsProvider) { + test("emptyProperties_${charset.name()}") { subject.emptyProperties(charset) } + test("asciiProps_${charset.name()}") { subject.asciiProps(charset) } + test("escapesSpecialCharacters_${charset.name()}") { subject.escapesSpecialCharacters(charset) } + } + + for (charset in ReproduciblePropertiesTest.utfCharsetsProvider) { + test("utfProps_${charset.name()}") { subject.utfProps(charset) } + } +} + +private class ReproduciblePropertiesTest { fun emptyProperties(charset: Charset) { val output = ReproducibleProperties().writeToString(charset) assertThat(output).isEqualTo("") } - @ParameterizedTest - @MethodSource("generalCharsetsProvider") fun asciiProps(charset: Charset) { val output = ReproducibleProperties() @@ -50,8 +59,6 @@ class ReproduciblePropertiesTest { ) } - @ParameterizedTest - @MethodSource("utfCharsetsProvider") fun utfProps(charset: Charset) { val output = ReproducibleProperties() @@ -75,8 +82,6 @@ class ReproduciblePropertiesTest { ) } - @ParameterizedTest - @MethodSource("generalCharsetsProvider") fun escapesSpecialCharacters(charset: Charset) { val output = ReproducibleProperties() @@ -94,14 +99,13 @@ class ReproduciblePropertiesTest { ) } - private companion object Companion { - @JvmStatic - fun generalCharsetsProvider() = - listOf(Charsets.ISO_8859_1, Charsets.US_ASCII) + utfCharsetsProvider() + companion object Companion { + val utfCharsetsProvider = listOf(Charsets.UTF_8, Charsets.UTF_16) - @JvmStatic fun utfCharsetsProvider() = listOf(Charsets.UTF_8, Charsets.UTF_16) + val generalCharsetsProvider = + listOf(Charsets.ISO_8859_1, Charsets.US_ASCII) + utfCharsetsProvider - fun ReproducibleProperties.writeToString(charset: Charset): String { + internal fun ReproducibleProperties.writeToString(charset: Charset): String { return ByteArrayOutputStream() .also { writeWithoutComments(charset, it) } .toString(charset.name()) diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/ZipEntryValidationTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/ZipEntryValidationTest.kt index 6112e3734..78d0a9465 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/ZipEntryValidationTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/ZipEntryValidationTest.kt @@ -1,3 +1,5 @@ +@file:OptIn(kotlin.io.path.ExperimentalPathApi::class) + package com.github.jengelman.gradle.plugins.shadow.internal import assertk.assertFailure @@ -6,28 +8,31 @@ import assertk.assertions.hasMessage import assertk.assertions.isEqualTo import assertk.assertions.isInstanceOf import assertk.assertions.isTrue +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests import com.github.jengelman.gradle.plugins.shadow.util.zipOutputStream +import de.infix.testBalloon.framework.core.testSuite import java.io.ByteArrayOutputStream import java.nio.file.Path import java.util.Properties import java.util.zip.ZipInputStream +import kotlin.io.path.createTempDirectory import org.apache.tools.zip.UnixStat import org.apache.tools.zip.ZipFile import org.apache.tools.zip.ZipOutputStream import org.gradle.api.GradleException -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.io.TempDir -class ZipEntryValidationTest { +val ZipEntryValidationTests by testSuite { + runTests(::ZipEntryValidationTest) +} + +private class ZipEntryValidationTest(val tempDir: Path = createTempDirectory()) { - @Test fun parentDirectoryEntriesAreOrderedFromRootToLeaf() { assertThat("foo/bar/baz.txt".parentDirectoryEntries()).isEqualTo(listOf("foo/", "foo/bar/")) assertThat("file.txt".parentDirectoryEntries()).isEqualTo(emptyList()) } - @Test - fun writeEntryUsesRequestedOrReproducibleTimestampAndAppliesUnixMode(@TempDir tempDir: Path) { + fun writeEntryUsesRequestedOrReproducibleTimestampAndAppliesUnixMode() { val requestedTimestamp = 1_700_000_000_000 val archive = tempDir.resolve("output.jar").toFile() ZipOutputStream(archive).use { output -> @@ -57,7 +62,6 @@ class ZipEntryValidationTest { } } - @Test fun propertiesInputStreamUsesRequestedCharsetAndComments() { val properties = Properties().apply { setProperty("greeting", "你好") } @@ -70,7 +74,6 @@ class ZipEntryValidationTest { assertThat(loaded.getProperty("greeting")).isEqualTo("你好") } - @Test fun validZipEntryNamesDoNotThrow() { val validNames = listOf( @@ -101,7 +104,6 @@ class ZipEntryValidationTest { assertThat(names).isEqualTo(validNames.toSet()) } - @Test fun maliciousZipEntryNamesWithPathTraversalThrowException() { val maliciousNames = listOf( diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/RelocatorsTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/RelocatorsTest.kt index 55f8c48b7..fb3196710 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/RelocatorsTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/RelocatorsTest.kt @@ -3,14 +3,14 @@ package com.github.jengelman.gradle.plugins.shadow.relocation import assertk.assertThat import assertk.assertions.isEqualTo import com.github.jengelman.gradle.plugins.shadow.internal.mapName -import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.MethodSource +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests +import de.infix.testBalloon.framework.core.testSuite -class RelocatorsTest { - @ParameterizedTest - @MethodSource("signaturePatternsProvider") +val RelocatorsTests by testSuite { + runTests(::RelocatorsTest) +} + +private class RelocatorsTest { fun relocateSignaturePatterns(input: String, expected: String) { val actual = setOf(SimpleRelocator("org.package", "shadow.org.package")).mapName(name = input) assertThat(actual).isEqualTo(expected) @@ -20,7 +20,6 @@ class RelocatorsTest { * Verifies that a relocator with [Relocator.skipStringConstants] = true is skipped individually * when mapping literals, rather than short-circuiting the entire set of relocators. */ - @Test fun skipStringConstantsIsPerRelocator() { val skippingRelocator = SimpleRelocator("org.package", "shadow.org.package", skipStringConstants = true) @@ -40,68 +39,45 @@ class RelocatorsTest { .isEqualTo("shadow.org.package.Bar") } - private companion object { + companion object { val primitiveTypes = setOf('B', 'C', 'D', 'F', 'I', 'J', 'S', 'Z') val primitiveTypePatterns = primitiveTypes.map { // Methods like `void method(boolean arg1, org.package.ClassA arg2)` - Arguments.of("(${it}Lorg/package/ClassA;)V", "(${it}Lshadow/org/package/ClassA;)V") + "(${it}Lorg/package/ClassA;)V" to "(${it}Lshadow/org/package/ClassA;)V" } - @JvmStatic - fun signaturePatternsProvider() = + val signaturePatternsProvider = listOf( // Normal class: `org.package.ClassA` - Arguments.of("Lorg/package/ClassA;", "Lshadow/org/package/ClassA;"), + "Lorg/package/ClassA;" to "Lshadow/org/package/ClassA;", // Array class: `org.package.ClassA[]` - Arguments.of("[Lorg/package/ClassA;", "[Lshadow/org/package/ClassA;"), + "[Lorg/package/ClassA;" to "[Lshadow/org/package/ClassA;", // Multidimensional array of class: `org.package.ClassA[][]` - Arguments.of("[[Lorg/package/ClassA;", "[[Lshadow/org/package/ClassA;"), + "[[Lorg/package/ClassA;" to "[[Lshadow/org/package/ClassA;", // Multiple classes: `org.package.ClassA org.package.ClassB` - Arguments.of( - "Lorg/package/ClassA;Lorg/package/ClassB;", + "Lorg/package/ClassA;Lorg/package/ClassB;" to "Lshadow/org/package/ClassA;Lshadow/org/package/ClassB;", - ), // Multiple classes: `java.lang.Object org.package.ClassB` - Arguments.of( - "Ljava/lang/Object;Lorg/package/ClassB;", - "Ljava/lang/Object;Lshadow/org/package/ClassB;", - ), + "Ljava/lang/Object;Lorg/package/ClassB;" to "Ljava/lang/Object;Lshadow/org/package/ClassB;", // Single method argument: `void method(org.package.ClassA arg);` - Arguments.of("(Lorg/package/ClassA;)", "(Lshadow/org/package/ClassA;)"), + "(Lorg/package/ClassA;)" to "(Lshadow/org/package/ClassA;)", // Method arguments: `void method(org.package.ClassA arg1, org.package.ClassB arg2);` - Arguments.of( - "(Lorg/package/ClassA;Lorg/package/ClassB;)", + "(Lorg/package/ClassA;Lorg/package/ClassB;)" to "(Lshadow/org/package/ClassA;Lshadow/org/package/ClassB;)", - ), // Example from issue 1403. - Arguments.of( - "()Lorg/package/ClassA;Lorg/package/ClassB;", + "()Lorg/package/ClassA;Lorg/package/ClassB;" to "()Lshadow/org/package/ClassA;Lshadow/org/package/ClassB;", - ), // Class name in slashy format (used in capturing class, impl class, and functional // interface class of SerializedLambda) - Arguments.of( - "org/package/ClassA", - "shadow/org/package/ClassA", - ), + "org/package/ClassA" to "shadow/org/package/ClassA", // Method descriptor formats found in lambda deserialization metadata - Arguments.of( - "(Lorg/package/ClassA;)Ljava/lang/String;", + "(Lorg/package/ClassA;)Ljava/lang/String;" to "(Lshadow/org/package/ClassA;)Ljava/lang/String;", - ), - Arguments.of( - "(Lorg/package/ClassA;I)V", - "(Lshadow/org/package/ClassA;I)V", - ), - Arguments.of( - "(ILorg/package/ClassA;)V", - "(ILshadow/org/package/ClassA;)V", - ), - Arguments.of( - "(Lorg/package/ClassA;Lorg/package/ClassB;)Lorg/package/ClassA;", + "(Lorg/package/ClassA;I)V" to "(Lshadow/org/package/ClassA;I)V", + "(ILorg/package/ClassA;)V" to "(ILshadow/org/package/ClassA;)V", + "(Lorg/package/ClassA;Lorg/package/ClassB;)Lorg/package/ClassA;" to "(Lshadow/org/package/ClassA;Lshadow/org/package/ClassB;)Lshadow/org/package/ClassA;", - ), ) + primitiveTypePatterns } } diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocatorTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocatorTest.kt index 4a88226aa..c509c843e 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocatorTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocatorTest.kt @@ -4,15 +4,19 @@ import assertk.assertThat import assertk.assertions.isEqualTo import assertk.assertions.isFalse import assertk.assertions.isTrue -import org.junit.jupiter.api.Test +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests +import de.infix.testBalloon.framework.core.testSuite + +val SimpleRelocatorTests by testSuite { + runTests(::SimpleRelocatorTest) +} /** * Modified from * [org.apache.maven.plugins.shade.relocation.SimpleRelocatorTest.java](https://github.com/apache/maven-shade-plugin/blob/master/src/test/java/org/apache/maven/plugins/shade/relocation/SimpleRelocatorTest.java). */ -class SimpleRelocatorTest { +private class SimpleRelocatorTest { - @Test fun canRelocatePath() { var relocator = SimpleRelocator("org.foo") assertThat(relocator.canRelocatePath("org/foo/Class")).isTrue() @@ -82,7 +86,6 @@ class SimpleRelocatorTest { assertThat(relocator.canRelocatePath("foo/foobar")).isFalse() // File without extension. } - @Test fun canRelocatePathWithRegex() { // Include with Regex var relocator = SimpleRelocator("org.foo", includes = listOf("%regex[org/foo/R(\\$.*)?$]")) @@ -116,7 +119,6 @@ class SimpleRelocatorTest { assertThat(relocator.canRelocatePath("org/foo/R.class")).isFalse() } - @Test fun canRelocateClass() { var relocator = SimpleRelocator("org.foo") assertThat(relocator.canRelocateClass("org.foo.Class")).isTrue() @@ -152,7 +154,6 @@ class SimpleRelocatorTest { assertThat(relocator.canRelocateClass("org.foo.recurse.sub.Class")).isFalse() } - @Test fun canRelocateRawString() { var relocator = SimpleRelocator("org/foo", rawString = true) assertThat(relocator.canRelocatePath("(I)org/foo/bar/Class;")).isTrue() @@ -161,14 +162,12 @@ class SimpleRelocatorTest { assertThat(relocator.canRelocatePath("META-INF/org.foo.xml")).isTrue() } - @Test fun canRelocateAbsClassPath() { val relocator = SimpleRelocator("org.apache.velocity", "org.apache.momentum") assertThat(relocator.relocatePath("/org/apache/velocity/mass.properties")) .isEqualTo("/org/apache/momentum/mass.properties") } - @Test fun canRelocateAbsClassPathWithExcludes() { val relocator = SimpleRelocator( @@ -182,7 +181,6 @@ class SimpleRelocatorTest { assertThat(relocator.canRelocatePath("org/apache/velocity/excluded/mass.properties")).isFalse() } - @Test fun canRelocateAbsClassPathWithIncludes() { val relocator = SimpleRelocator( @@ -196,7 +194,6 @@ class SimpleRelocatorTest { assertThat(relocator.canRelocatePath("org/apache/velocity/included/mass.properties")).isTrue() } - @Test fun relocatePath() { var relocator = SimpleRelocator("org.foo") assertThat(relocator.relocatePath("org/foo/bar/Class.class")) @@ -210,7 +207,6 @@ class SimpleRelocatorTest { .isEqualTo("private/stuff/bar/Class.class") } - @Test fun relocateClass() { var relocator = SimpleRelocator("org.foo") assertThat(relocator.relocateClass("org.foo.bar.Class")).isEqualTo("hidden.org.foo.bar.Class") @@ -219,7 +215,6 @@ class SimpleRelocatorTest { assertThat(relocator.relocateClass("org.foo.bar.Class")).isEqualTo("private.stuff.bar.Class") } - @Test fun relocateRawString() { var relocator = SimpleRelocator("Lorg/foo", "Lhidden/org/foo", rawString = true) assertThat(relocator.relocatePath("(I)Lorg/foo/bar/Class;")) @@ -231,7 +226,6 @@ class SimpleRelocatorTest { .isEqualTo("META-INF/hidden.org.foo.xml") } - @Test fun relocateMavenFiles() { val relocator = SimpleRelocator( @@ -250,7 +244,6 @@ class SimpleRelocatorTest { assertThat(relocator.canRelocatePath("META-INF/maven/com-foo-bar/artifactId/pom.xml")).isTrue() } - @Test fun canRelocateExcludedSourceFile() { val relocator = SimpleRelocator( @@ -276,7 +269,6 @@ class SimpleRelocatorTest { assertThat(relocator.canRelocatePath("org/foo/Class.class")).isTrue() } - @Test fun canRelocateExcludedSourceFileWithRegex() { val relocator = SimpleRelocator( @@ -298,7 +290,6 @@ class SimpleRelocatorTest { assertThat(relocator.canRelocatePath("org/foo/Class.class")).isTrue() } - @Test fun canRelocateIncludedSourceFile() { val relocator = SimpleRelocator( @@ -323,7 +314,6 @@ class SimpleRelocatorTest { assertThat(relocator.canRelocatePath("org/foo/Class.class")).isFalse() } - @Test fun canRelocateIncludedSourceFileWithRegex() { val relocator = SimpleRelocator( @@ -344,7 +334,6 @@ class SimpleRelocatorTest { assertThat(relocator.canRelocatePath("org/foo/Class.class")).isFalse() } - @Test fun relocateSourceWithExcludesRaw() { val relocator = SimpleRelocator( @@ -357,7 +346,6 @@ class SimpleRelocatorTest { assertThat(relocator.applyToSourceContent(sourceFile)).isEqualTo(sourceFile) } - @Test fun relocateSourceWithExcludes() { // Main relocator with in-/excludes val relocator = @@ -383,7 +371,7 @@ class SimpleRelocatorTest { .isEqualTo(relocatedFile) } - private companion object { + companion object { val sourceFile = """ |package org.apache.maven.hello; diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheLicenseResourceTransformerTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheLicenseResourceTransformerTest.kt index f48c65a8a..da0d5825a 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheLicenseResourceTransformerTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheLicenseResourceTransformerTest.kt @@ -3,20 +3,24 @@ package com.github.jengelman.gradle.plugins.shadow.transformers import assertk.assertThat import assertk.assertions.isFalse import assertk.assertions.isTrue -import org.junit.jupiter.api.Test +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests +import de.infix.testBalloon.framework.core.testSuite + +val ApacheLicenseResourceTransformerTests by testSuite { + runTests(::ApacheLicenseResourceTransformerTest) +} /** * Modified from * [org.apache.maven.plugins.shade.resource.ApacheLicenseResourceTransformerTest.java](https://github.com/apache/maven-shade-plugin/blob/master/src/test/java/org/apache/maven/plugins/shade/resource/ApacheLicenseResourceTransformerTest.java). */ -class ApacheLicenseResourceTransformerTest : +private class ApacheLicenseResourceTransformerTest : BaseTransformerTest() { init { setupTurkishLocale() } - @Test fun canTransformResource() = with(transformer) { assertThat(canTransformResource("META-INF/LICENSE")).isTrue() @@ -27,7 +31,6 @@ class ApacheLicenseResourceTransformerTest : assertThat(canTransformResource("META-INF/MANIFEST.MF")).isFalse() } - @Test fun canTransformByPattern() = with(transformer) { exclude("META-INF/LICENSE.txt") diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformerTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformerTest.kt index e694649b7..33435f580 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformerTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ApacheNoticeResourceTransformerTest.kt @@ -6,23 +6,28 @@ import assertk.assertions.isEqualTo import assertk.assertions.isFalse import assertk.assertions.isTrue import com.github.jengelman.gradle.plugins.shadow.testkit.getContent +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests +import de.infix.testBalloon.framework.core.testSuite import java.io.ByteArrayOutputStream import java.nio.charset.Charset import java.util.zip.ZipInputStream import org.apache.tools.zip.ZipOutputStream -import org.junit.jupiter.api.Test + +val ApacheNoticeResourceTransformerTests by testSuite { + runTests(::ApacheNoticeResourceTransformerTest) +} /** * Modified from * [org.apache.maven.plugins.shade.resource.ApacheNoticeResourceTransformerTest.java](https://github.com/apache/maven-shade-plugin/blob/master/src/test/java/org/apache/maven/plugins/shade/resource/ApacheNoticeResourceTransformerTest.java). */ -class ApacheNoticeResourceTransformerTest : BaseTransformerTest() { +private class ApacheNoticeResourceTransformerTest : + BaseTransformerTest() { init { setupTurkishLocale() } - @Test fun canTransformResource() = with(transformer) { assertThat(canTransformResource("META-INF/NOTICE")).isTrue() @@ -33,7 +38,6 @@ class ApacheNoticeResourceTransformerTest : BaseTransformerTest() { +private class AppendingTransformerTest : BaseTransformerTest() { init { setupTurkishLocale() } - @Test fun canTransformResource() = with(transformer) { resource.set("abcdefghijklmnopqrstuvwxyz") @@ -30,7 +34,6 @@ class AppendingTransformerTest : BaseTransformerTest() { assertThat(canTransformResource("META-INF/MANIFEST.MF")).isFalse() } - @Test fun appendResources() = with(transformer) { resource.set("test.properties") @@ -44,7 +47,6 @@ class AppendingTransformerTest : BaseTransformerTest() { assertThat(content).isEqualTo("foo=bar\nbaz=qux") } - @Test fun appendResourcesWithCustomSeparator() = with(transformer) { resource.set("application.yml") diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/BaseTransformerTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/BaseTransformerTest.kt index 1073f1310..36fcb161b 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/BaseTransformerTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/BaseTransformerTest.kt @@ -11,36 +11,29 @@ import java.lang.reflect.ParameterizedType import java.nio.file.Path import java.util.Locale import java.util.jar.JarFile.MANIFEST_NAME +import kotlin.io.path.createTempDirectory import kotlin.io.path.createTempFile import kotlin.io.path.outputStream import org.apache.tools.zip.ZipOutputStream import org.gradle.api.file.FileTreeElement import org.gradle.api.file.RelativePath -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.io.TempDir -abstract class BaseTransformerTest { - lateinit var transformer: T - private set +abstract class BaseTransformerTest( + val tempDir: Path = createTempDirectory() +) { + val transformer: T val manifestTransformerContext: TransformerContext get() = TransformerContext(MANIFEST_NAME, requireResourceAsStream(MANIFEST_NAME)) - @TempDir - lateinit var tempDir: Path - private set + val tempJar: Path = createTempFile(directory = tempDir, suffix = ".jar") - lateinit var tempJar: Path - private set - - @BeforeEach - open fun beforeEach() { + init { @Suppress("UNCHECKED_CAST") val clazz = (this::class.java.genericSuperclass as ParameterizedType).actualTypeArguments.single() as Class transformer = clazz.create(testObjectFactory) - tempJar = createTempFile(directory = tempDir, suffix = ".jar") } companion object { diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ComponentsXmlResourceTransformerTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ComponentsXmlResourceTransformerTest.kt index ee999d03b..b88f43a3e 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ComponentsXmlResourceTransformerTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ComponentsXmlResourceTransformerTest.kt @@ -3,17 +3,21 @@ package com.github.jengelman.gradle.plugins.shadow.transformers import assertk.assertThat import assertk.assertions.isTrue import com.github.jengelman.gradle.plugins.shadow.testkit.requireResourceAsPath +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests +import de.infix.testBalloon.framework.core.testSuite import kotlin.io.path.readText import org.custommonkey.xmlunit.XMLUnit -import org.junit.jupiter.api.Test + +val ComponentsXmlResourceTransformerTests by testSuite { + runTests(::ComponentsXmlResourceTransformerTest) +} /** * Modified from * [org.apache.maven.plugins.shade.resource.ComponentsXmlResourceTransformerTest.java](https://github.com/apache/maven-shade-plugin/blob/master/src/test/java/org/apache/maven/plugins/shade/resource/ComponentsXmlResourceTransformerTest.java). */ -class ComponentsXmlResourceTransformerTest : +private class ComponentsXmlResourceTransformerTest : BaseTransformerTest() { - @Test fun configurationMerging() = with(transformer) { XMLUnit.setNormalizeWhitespace(true) diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/DeduplicatingResourceTransformerTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/DeduplicatingResourceTransformerTest.kt index d129e5efe..a16734d26 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/DeduplicatingResourceTransformerTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/DeduplicatingResourceTransformerTest.kt @@ -9,30 +9,29 @@ import assertk.assertions.isEqualTo import assertk.assertions.isFalse import assertk.assertions.isInstanceOf import assertk.assertions.isTrue +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests import com.github.jengelman.gradle.plugins.shadow.transformers.DeduplicatingResourceTransformer.Companion.sha256Hex import com.github.jengelman.gradle.plugins.shadow.util.zipOutputStream +import de.infix.testBalloon.framework.core.testSuite import java.io.File import kotlin.io.path.writeText import org.gradle.api.GradleException -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.ValueSource -class DeduplicatingResourceTransformerTest : +val DeduplicatingResourceTransformerTests by testSuite { + runTests(::DeduplicatingResourceTransformerTest) +} + +private class DeduplicatingResourceTransformerTest : BaseTransformerTest() { - private lateinit var file1: File - private lateinit var file2: File - private lateinit var file3: File + private var file1: File + private var file2: File + private var file3: File private var hash1 = "" private var hash3 = "" - @BeforeEach - override fun beforeEach() { - super.beforeEach() - + init { val content1 = "content1" val content2 = "content2" file1 = tempDir.resolve("file1").apply { writeText(content1) }.toFile() @@ -42,7 +41,6 @@ class DeduplicatingResourceTransformerTest : hash3 = file3.sha256Hex() } - @Test fun sha256Hex() { val file = tempDir.resolve("sha256").apply { writeText("content") } @@ -50,8 +48,6 @@ class DeduplicatingResourceTransformerTest : .isEqualTo("ed7002b439e9ac845f22357d822bac1444730fbdb6016d3ec9432297b9ec9f73") } - @ParameterizedTest - @ValueSource(booleans = [false, true]) fun duplicateContent(exclusionCheck: Boolean) = with(transformer) { if (!exclusionCheck) { @@ -115,7 +111,6 @@ class DeduplicatingResourceTransformerTest : } } - @Test fun modifyOutputStreamReportsDuplicateContent() = with(transformer) { canTransformResource("differing-content", file1) diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/GroovyExtensionModuleTransformerTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/GroovyExtensionModuleTransformerTest.kt index 58d517b40..ce540efaa 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/GroovyExtensionModuleTransformerTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/GroovyExtensionModuleTransformerTest.kt @@ -5,8 +5,11 @@ import assertk.assertions.isEqualTo import assertk.assertions.isFalse import assertk.assertions.isTrue import com.github.jengelman.gradle.plugins.shadow.relocation.SimpleRelocator +import com.github.jengelman.gradle.plugins.shadow.testkit.Arguments import com.github.jengelman.gradle.plugins.shadow.testkit.JarPath import com.github.jengelman.gradle.plugins.shadow.testkit.getContent +import com.github.jengelman.gradle.plugins.shadow.testkit.runTest +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests import com.github.jengelman.gradle.plugins.shadow.transformers.GroovyExtensionModuleTransformer.Companion.KEY_EXTENSION_CLASSES import com.github.jengelman.gradle.plugins.shadow.transformers.GroovyExtensionModuleTransformer.Companion.KEY_MODULE_NAME import com.github.jengelman.gradle.plugins.shadow.transformers.GroovyExtensionModuleTransformer.Companion.KEY_MODULE_VERSION @@ -16,17 +19,24 @@ import com.github.jengelman.gradle.plugins.shadow.transformers.GroovyExtensionMo import com.github.jengelman.gradle.plugins.shadow.transformers.GroovyExtensionModuleTransformer.Companion.PATH_GROOVY_EXTENSION_MODULE_DESCRIPTOR import com.github.jengelman.gradle.plugins.shadow.transformers.GroovyExtensionModuleTransformer.Companion.PATH_LEGACY_GROOVY_EXTENSION_MODULE_DESCRIPTOR import com.github.jengelman.gradle.plugins.shadow.util.zipOutputStream +import de.infix.testBalloon.framework.core.testSuite import java.io.StringReader import java.util.Properties -import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.MethodSource -class GroovyExtensionModuleTransformerTest : +val GroovyExtensionModuleTransformerTests by testSuite { + runTests(::GroovyExtensionModuleTransformerTest) + + for ((fooEntry: String, barEntry: String) in + GroovyExtensionModuleTransformerTest.resourcePathProvider) { + runTest("mergeDescriptors_${fooEntry}_${barEntry}", ::GroovyExtensionModuleTransformerTest) { + mergeDescriptors(fooEntry, barEntry) + } + } +} + +private class GroovyExtensionModuleTransformerTest : BaseTransformerTest() { - @Test fun canTransformResource() = with(transformer) { assertThat(canTransformResource(PATH_LEGACY_GROOVY_EXTENSION_MODULE_DESCRIPTOR)).isTrue() @@ -34,8 +44,6 @@ class GroovyExtensionModuleTransformerTest : assertThat(canTransformResource("META-INF/MANIFEST.MF")).isFalse() } - @ParameterizedTest - @MethodSource("resourcePathProvider") fun mergeDescriptors(fooEntry: String, barEntry: String) = with(GroovyExtensionModuleTransformer()) { transform(textContext(fooEntry, FOO_DESCRIPTOR)) @@ -56,7 +64,6 @@ class GroovyExtensionModuleTransformerTest : .isEqualTo("$STATIC_EXTENSION_CLASSES_FOO,$STATIC_EXTENSION_CLASSES_BAR") } - @Test fun groovyExtensionModuleTransformerWithRelocation() = with(GroovyExtensionModuleTransformer()) { val relocator = SimpleRelocator("com.acme", "com.example.shaded.acme") @@ -83,7 +90,7 @@ class GroovyExtensionModuleTransformerTest : ) } - private companion object { + companion object { const val EXTENSION_CLASSES_FOO = "com.acme.foo.FooExtension,com.acme.foo.BarExtension" const val EXTENSION_CLASSES_BAR = "com.acme.bar.SomeExtension,com.acme.bar.AnotherExtension" const val STATIC_EXTENSION_CLASSES_FOO = "com.acme.foo.FooStaticExtension" @@ -109,8 +116,7 @@ class GroovyExtensionModuleTransformerTest : fun String.toProperties() = Properties().apply { load(StringReader(this@toProperties)) } - @JvmStatic - fun resourcePathProvider() = + val resourcePathProvider = listOf( Arguments.of( PATH_LEGACY_GROOVY_EXTENSION_MODULE_DESCRIPTOR, diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/KotlinModuleMetadataTransformerTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/KotlinModuleMetadataTransformerTest.kt index 08e44d04f..db15da4b1 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/KotlinModuleMetadataTransformerTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/KotlinModuleMetadataTransformerTest.kt @@ -12,15 +12,20 @@ import com.github.jengelman.gradle.plugins.shadow.relocation.SimpleRelocator import com.github.jengelman.gradle.plugins.shadow.testkit.JarPath import com.github.jengelman.gradle.plugins.shadow.testkit.getBytes import com.github.jengelman.gradle.plugins.shadow.testkit.requireResourceAsStream +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests import com.github.jengelman.gradle.plugins.shadow.util.zipOutputStream +import de.infix.testBalloon.framework.core.testSuite import kotlin.metadata.jvm.KotlinModuleMetadata import kotlin.metadata.jvm.UnstableMetadataApi -import org.junit.jupiter.api.Test + +val KotlinModuleMetadataTransformerTests by testSuite { + runTests(::KotlinModuleMetadataTransformerTest) +} @OptIn(UnstableMetadataApi::class) -class KotlinModuleMetadataTransformerTest : BaseTransformerTest() { +private class KotlinModuleMetadataTransformerTest : + BaseTransformerTest() { - @Test fun canTransformResource() = with(transformer) { assertThat(canTransformResource("META-INF/kotlin-stdlib.kotlin_module")).isTrue() @@ -28,7 +33,6 @@ class KotlinModuleMetadataTransformerTest : BaseTransformerTest() { - @Test fun canTransformResource() = with(transformer) { assertThat(canTransformResource("")).isFalse() @@ -45,7 +58,6 @@ class Log4j2PluginsCacheFileTransformerTest : assertThat(canTransformResource(PLUGIN_CACHE_FILE)).isTrue() } - @Test fun relocateClassesInsideDatFile() = with(transformer) { val relocator = SimpleRelocator("org.apache.logging", "new.location.org.apache.logging") @@ -56,8 +68,6 @@ class Log4j2PluginsCacheFileTransformerTest : modifyOutputStream(zos, true) } - // Extract the .dat file bytes to a temp file to avoid JarURLConnection locking tempJar on - // Windows val tempDat = createTempFile(directory = tempDir, suffix = ".dat") tempDat.writeBytes(JarPath(tempJar).use { it.getBytes(PLUGIN_CACHE_FILE) }) @@ -68,7 +78,7 @@ class Log4j2PluginsCacheFileTransformerTest : .isEqualTo("new.location.org.apache.logging.log4j.core.lookup.DateLookup") } - @Test // #427 + // #427 fun transformAndModifyOutputStream() = with(transformer) { assertThat(hasTransformedResource()).isFalse() @@ -87,7 +97,6 @@ class Log4j2PluginsCacheFileTransformerTest : fail("No expected resource in the output jar.") } else if (jarEntry.name == PLUGIN_CACHE_FILE) { assertThat(inputStream.readAllBytes().contentHashCode()).all { - // Hash of the original plugin cache file. isNotEqualTo(-2114104185) isEqualTo(1911442937) } @@ -97,8 +106,6 @@ class Log4j2PluginsCacheFileTransformerTest : } } - @ParameterizedTest - @MethodSource("relocationProvider") fun relocations(pattern: String, shadedPattern: String, expected: String) = with(transformer) { val aggregator = @@ -113,23 +120,20 @@ class Log4j2PluginsCacheFileTransformerTest : } } - private companion object { + companion object { val pluginCacheUrl: URL = requireResourceAsPath(PLUGIN_CACHE_FILE).toUri().toURL() fun context(vararg relocators: Relocator): TransformerContext { return resourceContext(PLUGIN_CACHE_FILE, relocators = relocators) } - @JvmStatic - fun relocationProvider() = + val relocationProvider = listOf( - // test with matching relocator Arguments.of( "org.apache.logging", "new.location.org.apache.logging", "new.location.org.apache.logging", ), - // test without matching relocator Arguments.of("com.apache.logging", "new.location.com.apache.logging", "org.apache.logging"), ) } diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ManifestAppenderTransformerTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ManifestAppenderTransformerTest.kt index a171c6a40..efe548420 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ManifestAppenderTransformerTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/ManifestAppenderTransformerTest.kt @@ -8,11 +8,15 @@ import assertk.assertions.isTrue import com.github.jengelman.gradle.plugins.shadow.testkit.getContent import com.github.jengelman.gradle.plugins.shadow.testkit.getStream import com.github.jengelman.gradle.plugins.shadow.testkit.requireResourceAsStream +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests +import de.infix.testBalloon.framework.core.testSuite import java.util.jar.JarFile.MANIFEST_NAME -import org.junit.jupiter.api.Test -class ManifestAppenderTransformerTest : BaseTransformerTest() { - @Test +val ManifestAppenderTransformerTests by testSuite { + runTests(::ManifestAppenderTransformerTest) +} + +private class ManifestAppenderTransformerTest : BaseTransformerTest() { fun canTransformResource() = with(transformer) { append("Name", "org/foo/bar/") @@ -22,7 +26,6 @@ class ManifestAppenderTransformerTest : BaseTransformerTest() { - @Test +val MergeLicenseResourceTransformerTests by testSuite { + runTests(::MergeLicenseResourceTransformerTest) +} + +private class MergeLicenseResourceTransformerTest : + BaseTransformerTest() { fun defaultIncludes() = with(transformer) { assertThat(canTransformResource("META-INF/LICENSE")).isTrue() @@ -22,7 +27,6 @@ class MergeLicenseResourceTransformerTest : BaseTransformerTest() { - @Test fun firstOccurrenceIsNotTransformed() = with(transformer) { include("foo/bar") @@ -17,7 +21,6 @@ class PreserveFirstFoundResourceTransformerTest : assertThat(canTransformResource("foo/bar")).isFalse() } - @Test fun subsequentOccurrencesAreTransformed() = with(transformer) { include("foo/bar") @@ -28,7 +31,6 @@ class PreserveFirstFoundResourceTransformerTest : assertThat(canTransformResource("foo/bar")).isTrue() } - @Test fun nonMatchingPathIsNotTransformed() = with(transformer) { include("foo/bar") diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerTest.kt index ec63cbbac..8360730f2 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerTest.kt @@ -9,22 +9,107 @@ import assertk.assertions.isFalse import assertk.assertions.isInstanceOf import assertk.assertions.isTrue import com.github.jengelman.gradle.plugins.shadow.internal.inputStream +import com.github.jengelman.gradle.plugins.shadow.testkit.Arguments import com.github.jengelman.gradle.plugins.shadow.testkit.JarPath import com.github.jengelman.gradle.plugins.shadow.testkit.getBytes import com.github.jengelman.gradle.plugins.shadow.testkit.getContent import com.github.jengelman.gradle.plugins.shadow.testkit.invariantEolString +import com.github.jengelman.gradle.plugins.shadow.testkit.runTest +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests import com.github.jengelman.gradle.plugins.shadow.transformers.PropertiesFileTransformer.MergeStrategy import com.github.jengelman.gradle.plugins.shadow.util.zipOutputStream +import de.infix.testBalloon.framework.core.testSuite import java.nio.charset.Charset import java.util.Properties import org.gradle.api.GradleException -import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.MethodSource -class PropertiesFileTransformerTest : BaseTransformerTest() { - @Test +val PropertiesFileTransformerTests by testSuite { + runTests(::PropertiesFileTransformerTest) + + for ((path: String, expected: Boolean) in PropertiesFileTransformerTest.pathProvider) { + runTest( + "canTransformResourceWithPaths_${path}_$expected", + ::PropertiesFileTransformerTest, + ) { + canTransformResourceWithPaths(path, expected) + } + } + + for (( + path: String, + mergeStrategy: String, + mergeSeparator: String, + input1: Map, + input2: Map, + expectedOutput: Map, + expectedConflicts: Map>) in + PropertiesFileTransformerTest.transformConfigProvider) { + runTest( + "exerciseAllTransformConfigurations_${path}_$mergeStrategy", + ::PropertiesFileTransformerTest, + ) { + exerciseAllTransformConfigurations( + path, + mergeStrategy, + mergeSeparator, + input1, + input2, + expectedOutput, + expectedConflicts, + ) + } + } + + for (( + path: String, + paths: List, + input1: Map, + input2: Map, + expectedOutput: Map) in + PropertiesFileTransformerTest.transformConfigWithPathsProvider) { + runTest( + "exerciseAllTransformConfigurationsWithPaths_${path}", + ::PropertiesFileTransformerTest, + ) { + exerciseAllTransformConfigurationsWithPaths(path, paths, input1, input2, expectedOutput) + } + } + + for (( + path: String, + mappings: Map>, + input1: Map, + input2: Map, + expectedOutput: Map) in + PropertiesFileTransformerTest.transformConfigWithMappingsProvider) { + runTest( + "exerciseAllTransformConfigurationsWithMappings_${path}", + ::PropertiesFileTransformerTest, + ) { + exerciseAllTransformConfigurationsWithMappings(path, mappings, input1, input2, expectedOutput) + } + } + + for (( + path: String, + keyTransformer: (String) -> String, + input1: Map, + input2: Map, + expectedOutput: Map) in PropertiesFileTransformerTest.keyTransformerProvider) { + runTest("appliesKeyTransformer_${path}", ::PropertiesFileTransformerTest) { + appliesKeyTransformer(path, keyTransformer, input1, input2, expectedOutput) + } + } + + for ((path: String, charset: String, input1: Map, input2: Map) in + PropertiesFileTransformerTest.charsetProvider) { + runTest("appliesCharset_${path}", ::PropertiesFileTransformerTest) { + appliesCharset(path, charset, input1, input2) + } + } +} + +private class PropertiesFileTransformerTest : BaseTransformerTest() { fun hasTransformedResource() = with(transformer) { assertThat(hasTransformedResource()).isFalse() @@ -34,14 +119,10 @@ class PropertiesFileTransformerTest : BaseTransformerTest, @@ -105,8 +183,6 @@ class PropertiesFileTransformerTest : BaseTransformerTest>, @@ -126,8 +202,6 @@ class PropertiesFileTransformerTest : BaseTransformerTest String, @@ -147,8 +221,6 @@ class PropertiesFileTransformerTest : BaseTransformerTest, @@ -199,8 +271,7 @@ class PropertiesFileTransformerTest : BaseTransformerTest() { - @ParameterizedTest - @MethodSource("resourceProvider") +private class ServiceFileTransformerTest : BaseTransformerTest() { fun canTransformResource(path: String, exclude: Boolean, expected: Boolean) = with(transformer) { if (exclude) { @@ -28,8 +44,6 @@ class ServiceFileTransformerTest : BaseTransformerTest() assertThat(canTransformResource(path)).isEqualTo(expected) } - @ParameterizedTest - @MethodSource("serviceFileProvider") fun transformServiceFile(path: String, input1: String, input2: String, output: String) = with(transformer) { if (canTransformResource(path)) { @@ -42,13 +56,11 @@ class ServiceFileTransformerTest : BaseTransformerTest() assertThat(entry).isEqualTo(output) } - @Test fun excludesGroovyExtensionModuleDescriptorFilesByDefault() { val element = "META-INF/services/org.codehaus.groovy.runtime.ExtensionModule" assertThat(transformer.canTransformResource(element)).isFalse() } - @Test fun canTransformAlternateResource() = with(transformer) { path = "foo/bar" @@ -56,49 +68,16 @@ class ServiceFileTransformerTest : BaseTransformerTest() assertThat(canTransformResource("META-INF/services/Zoo")).isFalse() } - @Test fun relocatedClasses() = - with(ServiceFileTransformer()) { - val relocator = SimpleRelocator("org.foo", "borg.foo", excludes = listOf("org.foo.exclude.*")) - val content = "org.foo.Service\norg.foo.exclude.OtherService\n" - val contentResource = "META-INF/services/org.foo.something.another" - val contentResourceShaded = "META-INF/services/borg.foo.something.another" - - transform(textContext(contentResource, content, relocator)) - - tempJar.zipOutputStream().use { zos -> - modifyOutputStream(zos, false) - } - - val transformedContent = JarPath(tempJar).use { it.getContent(contentResourceShaded) } - assertThat(transformedContent).isEqualTo("borg.foo.Service\norg.foo.exclude.OtherService") - } - - @Test - fun mergeRelocatedFiles() = - with(ServiceFileTransformer()) { - val relocator = SimpleRelocator("org.foo", "borg.foo", excludes = listOf("org.foo.exclude.*")) - val content = "org.foo.Service\norg.foo.exclude.OtherService\n" - val contentResource = "META-INF/services/org.foo.something.another" - val contentResourceShaded = "META-INF/services/borg.foo.something.another" + with(transformer) { + val relocator = SimpleRelocator("org.foo", "borg.foo") + var content = "org.foo.Service\n" + var contentResource = "META-INF/services/org.foo.something.another" transform(textContext(contentResource, content, relocator)) - transform(textContext(contentResourceShaded, content, relocator)) - tempJar.zipOutputStream().use { zos -> - modifyOutputStream(zos, false) - } - - val transformedContent = JarPath(tempJar).use { it.getContent(contentResourceShaded) } - assertThat(transformedContent).isEqualTo("borg.foo.Service\norg.foo.exclude.OtherService") - } - - @Test - fun concatenationAppliedMultipleTimes() = - with(ServiceFileTransformer()) { - val relocator = SimpleRelocator("org.eclipse", "org.eclipse1234") - val content = "org.eclipse.osgi.launch.EquinoxFactory\n" - val contentResource = "META-INF/services/org.osgi.framework.launch.FrameworkFactory" + content = "org.blah.Service\n" + contentResource = "META-INF/services/org.something.another" transform(textContext(contentResource, content, relocator)) @@ -107,15 +86,15 @@ class ServiceFileTransformerTest : BaseTransformerTest() } val transformedContent = JarPath(tempJar).use { it.getContent(contentResource) } - assertThat(transformedContent).isEqualTo("org.eclipse1234.osgi.launch.EquinoxFactory") + assertThat(transformedContent).isEqualTo("org.blah.Service") } - @Test - fun concatenation() = - with(ServiceFileTransformer()) { + fun serviceEntriesAreAppendedAndPreservedOrder() = + with(transformer) { val relocator = SimpleRelocator("org.foo", "borg.foo") var content = "org.foo.Service\n" var contentResource = "META-INF/services/org.something.another" + transform(textContext(contentResource, content, relocator)) content = "org.blah.Service\n" @@ -131,9 +110,8 @@ class ServiceFileTransformerTest : BaseTransformerTest() assertThat(transformedContent).isEqualTo("borg.foo.Service\norg.blah.Service") } - private companion object { - @JvmStatic - fun resourceProvider() = + companion object { + val resourceProvider = listOf( // path, exclude, expected Arguments.of("META-INF/services/java.sql.Driver", false, true), @@ -144,8 +122,7 @@ class ServiceFileTransformerTest : BaseTransformerTest() Arguments.of("foo.props", false, false), ) - @JvmStatic - fun serviceFileProvider() = + val serviceFileProvider = listOf( // path, input1, input2, output Arguments.of("META-INF/services/com.acme.Foo", "foo", "bar", "foo\nbar"), diff --git a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/XmlAppendingTransformerTest.kt b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/XmlAppendingTransformerTest.kt index 5b406fa1f..94479899d 100644 --- a/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/XmlAppendingTransformerTest.kt +++ b/src/test/kotlin/com/github/jengelman/gradle/plugins/shadow/transformers/XmlAppendingTransformerTest.kt @@ -6,16 +6,20 @@ import assertk.assertions.isFalse import assertk.assertions.isTrue import com.github.jengelman.gradle.plugins.shadow.testkit.JarPath import com.github.jengelman.gradle.plugins.shadow.testkit.getContent +import com.github.jengelman.gradle.plugins.shadow.testkit.runTests import com.github.jengelman.gradle.plugins.shadow.util.zipOutputStream -import org.junit.jupiter.api.Test +import de.infix.testBalloon.framework.core.testSuite -class XmlAppendingTransformerTest : BaseTransformerTest() { +val XmlAppendingTransformerTests by testSuite { + runTests(::XmlAppendingTransformerTest) +} + +private class XmlAppendingTransformerTest : BaseTransformerTest() { init { setupTurkishLocale() } - @Test fun canTransformResource() = with(transformer) { resource.set("abcdefghijklmnopqrstuvwxyz") @@ -25,7 +29,6 @@ class XmlAppendingTransformerTest : BaseTransformerTest assertThat(canTransformResource("META-INF/MANIFEST.MF")).isFalse() } - @Test fun appendXmlFiles() = with(transformer) { val xmlEntry = "properties.xml" @@ -61,7 +64,6 @@ class XmlAppendingTransformerTest : BaseTransformerTest ) } - @Test fun appendXmlFilesWithUnreachableDtd() = with(transformer) { val xmlEntry = "properties_invalid_dtd.xml" @@ -97,7 +99,7 @@ class XmlAppendingTransformerTest : BaseTransformerTest ) } - @Test // #168 + // #168 fun mergeNestedLevels() = with(transformer) { val xmlEntry = "META-INF/nested.xml" @@ -129,7 +131,7 @@ class XmlAppendingTransformerTest : BaseTransformerTest ) } - private companion object { + companion object { /** * Normalizes line breaks in XML content produced by [XmlAppendingTransformer]. * diff --git a/src/testKit/kotlin/com/github/jengelman/gradle/plugins/shadow/testkit/Arguments.kt b/src/testKit/kotlin/com/github/jengelman/gradle/plugins/shadow/testkit/Arguments.kt new file mode 100644 index 000000000..e813ccdce --- /dev/null +++ b/src/testKit/kotlin/com/github/jengelman/gradle/plugins/shadow/testkit/Arguments.kt @@ -0,0 +1,32 @@ +package com.github.jengelman.gradle.plugins.shadow.testkit + +@Suppress("UNCHECKED_CAST") +class Arguments private constructor(val list: List) { + operator fun get(index: Int): Any? = list[index] + + operator fun component1(): T = list[0] as T + + operator fun component2(): T = list[1] as T + + operator fun component3(): T = list[2] as T + + operator fun component4(): T = list[3] as T + + operator fun component5(): T = list[4] as T + + operator fun component6(): T = list[5] as T + + operator fun component7(): T = list[6] as T + + operator fun component8(): T = list[7] as T + + operator fun component9(): T = list[8] as T + + operator fun component10(): T = list[9] as T + + override fun toString(): String = list.joinToString(", ", prefix = "Arguments[", postfix = "]") + + companion object { + fun of(vararg arguments: Any?): Arguments = Arguments(arguments.toList()) + } +} diff --git a/src/testKit/kotlin/com/github/jengelman/gradle/plugins/shadow/testkit/TestSuiteScope.kt b/src/testKit/kotlin/com/github/jengelman/gradle/plugins/shadow/testkit/TestSuiteScope.kt new file mode 100644 index 000000000..6bfecb53a --- /dev/null +++ b/src/testKit/kotlin/com/github/jengelman/gradle/plugins/shadow/testkit/TestSuiteScope.kt @@ -0,0 +1,131 @@ +package com.github.jengelman.gradle.plugins.shadow.testkit + +import de.infix.testBalloon.framework.core.TestFixture +import de.infix.testBalloon.framework.core.TestSuiteScope +import java.lang.reflect.InvocationTargetException +import java.nio.file.Path +import kotlin.io.path.ExperimentalPathApi +import kotlin.io.path.createTempDirectory +import kotlin.io.path.deleteRecursively +import kotlin.io.path.exists +import kotlin.io.path.readText +import kotlin.reflect.KFunction1 +import kotlin.reflect.KVisibility +import kotlin.reflect.full.declaredMemberFunctions +import kotlin.reflect.full.declaredMemberProperties +import kotlin.reflect.jvm.isAccessible + +fun TestSuiteScope.tempDirFixture(): TestFixture = + testFixture { + createTempDirectory() + } closeWith { @OptIn(ExperimentalPathApi::class) deleteRecursively() } + +inline fun TestSuiteScope.runTests( + noinline factory: () -> T, + vararg functions: KFunction1, +) { + if (functions.isNotEmpty()) { + for (function in functions) { + runTest(function.name, factory, function) + } + } else { + val discovered = + T::class.declaredMemberFunctions.filter { it.visibility != KVisibility.PRIVATE } + for (function in discovered) { + function.isAccessible = true + val valueParams = function.parameters.drop(1) + when { + valueParams.isEmpty() -> { + runTest(function.name, factory) { + function.call(this) + } + } + + valueParams.all { it.type.classifier == Boolean::class } -> { + val combinations = + valueParams.fold(listOf(emptyList())) { acc, _ -> + acc.flatMap { list -> listOf(list + false, list + true) } + } + for (combo in combinations) { + val name = + "${function.name}_" + + valueParams.zip(combo).joinToString("_") { (param, value) -> + "${param.name}_$value" + } + runTest(name, factory) { + function.call(this, *combo.toTypedArray()) + } + } + } + } + } + } +} + +fun TestSuiteScope.runTest( + name: String, + factory: () -> T, + block: T.() -> Unit, +) { + test(name) { + val instance = factory() + try { + instance.block() + } catch (t: InvocationTargetException) { + logProjectScript(instance) + throw t.targetException ?: t + } catch (t: Throwable) { + logProjectScript(instance) + throw t + } finally { + cleanupInstance(instance) + } + } +} + +@PublishedApi +internal fun logProjectScript(instance: Any) { + try { + val scriptProp = + instance::class.declaredMemberProperties.firstOrNull { + it.name == "projectScript" && it.returnType.classifier == Path::class + } + if (scriptProp != null) { + scriptProp.isAccessible = true + val script = scriptProp.call(instance) as? Path + val rootProp = + instance::class.declaredMemberProperties.firstOrNull { + it.name == "projectRoot" && it.returnType.classifier == Path::class + } + rootProp?.isAccessible = true + val root = rootProp?.call(instance) as? Path + if (script != null && script.exists()) { + println("Project build script at $root:\n${script.readText()}") + } + } + } catch (_: Throwable) {} +} + +@OptIn(ExperimentalPathApi::class) +@PublishedApi +internal fun cleanupInstance(instance: Any) { + try { + if (instance is AutoCloseable) instance.close() + val rootProp = + instance::class.declaredMemberProperties.firstOrNull { + it.name == "projectRoot" && it.returnType.classifier == Path::class + } + if (rootProp != null) { + rootProp.isAccessible = true + (rootProp.call(instance) as? Path)?.deleteRecursively() + } + val tempDirProp = + instance::class.declaredMemberProperties.firstOrNull { + it.name == "tempDir" && it.returnType.classifier == Path::class + } + if (tempDirProp != null) { + tempDirProp.isAccessible = true + (tempDirProp.call(instance) as? Path)?.deleteRecursively() + } + } catch (_: Throwable) {} +}