Skip to content

Commit

Permalink
Test with ProGuard (#591)
Browse files Browse the repository at this point in the history
  • Loading branch information
JakeWharton authored Jan 8, 2025
1 parent aaf44d6 commit 9f634c5
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 2 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ allprojects {
testLogging {
if (System.getenv('CI') == 'true') {
events = ['started', 'failed', 'skipped', 'passed']
showStandardStreams = true
}
exceptionFormat 'full'
}
Expand Down
60 changes: 58 additions & 2 deletions mosaic-terminal/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget

import static co.touchlab.cklib.gradle.CompileToBitcode.Language.C
import static org.gradle.language.base.plugins.LifecycleBasePlugin.BUILD_GROUP
import static org.gradle.language.base.plugins.LifecycleBasePlugin.VERIFICATION_GROUP
import static org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.MAIN_COMPILATION_NAME
import static org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.TEST_COMPILATION_NAME
Expand All @@ -13,6 +14,14 @@ apply plugin: 'co.touchlab.cklib'
apply plugin: 'com.jakewharton.cite'
apply plugin: 'dev.drewhamilton.poko'

configurations {
proGuard
}

dependencies {
proGuard 'com.guardsquare:proguard-base:7.6.1'
}

kotlin {
explicitApi()

Expand All @@ -32,7 +41,10 @@ kotlin {
}

targets.withType(KotlinJvmTarget).configureEach { target ->
target.compilations.named(MAIN_COMPILATION_NAME).configure { main ->
def mainCompilation = target.compilations.named(MAIN_COMPILATION_NAME)
def testCompilation = target.compilations.named(TEST_COMPILATION_NAME)

mainCompilation.configure { main ->
tasks.named(main.processResourcesTaskName).configure {
doFirst {
def jniDir = file("src/${target.name}Main/resources/jni")
Expand Down Expand Up @@ -70,9 +82,53 @@ kotlin {
}
}

def dependencyFiles = testCompilation.map { it.runtimeDependencyFiles }
def proGuardJar = base.archivesName.flatMap { archivesName ->
layout.buildDirectory.file("libs/$archivesName-tests-${target.name}-$version-ProGuard.jar")
}
def proGuardTask = tasks.register("${target.name}TestJarProGuard", JavaExec) {
group = BUILD_GROUP
description = 'Assembles an archive containing the test classes run through ProGuard.'

inputs.files(configurations.proGuard)
inputs.files(dependencyFiles)
outputs.file(proGuardJar.get())

classpath(configurations.proGuard)
mainClass = 'proguard.ProGuard'
args = [
'-libraryjars', '<java.home>/jmods/java.base.jmod(!**.jar;!module-info.class)',
// TODO These should be pulled from the jars, but for now this unblocks us.
'@src/jvmMain/resources/META-INF/proguard/com.jakewharton.mosaic-terminal.pro',
'@src/jvmTest/resources/META-INF/proguard/com.jakewharton.mosaic-terminal-test.pro',
]

doFirst {
// Defer resolving this until execution time since JavaExec lacks provider-based args.
args += '-injars'
args += dependencyFiles.get().files.join(File.pathSeparator)
// These do not need deferred, but since it must come after -injars it has to go here.
args += '-outjars'
args += proGuardJar.get().asFile.toString()
}
}

target.testRuns.create("ProGuard") { run ->
allJvmTests.configure {
it.dependsOn(run.executionTask)
}
run.executionTask.configure {
dependsOn(proGuardTask)
}
run.setExecutionSourceFrom(
project.files(proGuardJar.get()),
dependencyFiles.get().filter { it.isDirectory() },
)
}

// Adding additional test runs somehow removes the configuration capabilities which allow
// automatic resolution of the junit test dependency. Add it explicitly instead.
target.compilations.named(TEST_COMPILATION_NAME).configure {
testCompilation.configure {
dependencies {
implementation(libs.kotlin.test.junit)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
-keep class **.*Test {
public <init>();
@org.junit.Test public void *(...);
}

# Gradle does A LOT of reflection to invoke JUnit. Just keep it all.
-keep class org.junit.** {
*** *(...);
}

# Keep @Test, @Ignore annotations, etc.
-keepattributes RuntimeVisibleAnnotations, AnnotationDefault

# Temporarily work around a ProGuard bug. https://github.com/Guardsquare/proguard/issues/460
-optimizations !method/specialization/parametertype

# TODO These should be pulled from the jars, but for now this unblocks us.
-dontwarn kotlinx.coroutines.debug.internal.AgentPremain*
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
-dontwarn assertk.assertions.AnyJVMKt*

# ServiceLoader support
-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
-keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}

# Most of volatile fields are updated with AFU and should not be mangled
-keepclassmembers class kotlinx.coroutines.** {
volatile <fields>;
}

# Same story for the standard library's SafeContinuation that also uses AtomicReferenceFieldUpdater
-keepclassmembers class kotlin.coroutines.SafeContinuation {
volatile <fields>;
}

0 comments on commit 9f634c5

Please sign in to comment.