Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 3 additions & 9 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -137,6 +138,7 @@ dependencies {

testKitImplementation(gradleTestKit())
testKitImplementation(libs.assertk)
testKitImplementation(libs.testBalloon.framework.core)

testPluginClasspath(libs.foojayResolver)
testPluginClasspath(libs.pluginPublish)
Expand All @@ -153,14 +155,6 @@ testing.suites {
register<JvmTestSuite>("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.
Expand Down Expand Up @@ -201,10 +195,10 @@ testing.suites {
}

withType<JvmTestSuite>().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 {
Expand Down
6 changes: 5 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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" }
Expand All @@ -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" }
Original file line number Diff line number Diff line change
@@ -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<Arguments> {
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) }
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand Down Expand Up @@ -67,7 +71,6 @@ class ApplicationPluginTest : BasePluginTest() {
)
}

@Test
fun installShadowOutputs() {
prepare(
mainClassWithImports = true,
Expand Down Expand Up @@ -116,7 +119,6 @@ class ApplicationPluginTest : BasePluginTest() {
.contains("Hello, World! (bar) from Main", "Refs: junit.framework.Test")
}

@Test
fun installShadowDoesNotExecuteDependentShadowTask() {
prepare()

Expand All @@ -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(
Expand Down Expand Up @@ -170,7 +172,6 @@ class ApplicationPluginTest : BasePluginTest() {
assertions(result.output, "bar")
}

@Test
fun overrideMainClassFromApplicationPlugin() {
prepare()
projectScript.appendText(
Expand All @@ -189,7 +190,6 @@ class ApplicationPluginTest : BasePluginTest() {
}
}

@Test
fun errorWhenMainClassNotSet() {
prepare(mainClassBlock = "")

Expand All @@ -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!'")
Expand Down Expand Up @@ -239,7 +238,6 @@ class ApplicationPluginTest : BasePluginTest() {
}
}

@Test
fun includeSrcDistByDefault() {
path("src/dist/echo.sh").writeText("echo 'Hello, World!'")
prepare()
Expand All @@ -260,7 +258,6 @@ class ApplicationPluginTest : BasePluginTest() {
}
}

@Test
fun honorApplicationExtensionProperties() {
val applicationNames = "new" to "new"
val executableDirs = "sbin" to "sbin"
Expand Down Expand Up @@ -344,7 +341,7 @@ class ApplicationPluginTest : BasePluginTest() {
}
}

private companion object {
companion object {
fun Path.walkEntries(includeDirs: Boolean = false): Sequence<String> =
walk()
.filter { includeDirs || it.isRegularFile() }
Expand Down
Loading