Skip to content

Commit

Permalink
AndroidLibrarySupport: Add functional tests for Kotlin Android librar…
Browse files Browse the repository at this point in the history
…ies (#102)


Fixes: #94

Co-authored-by: Baris Basturk <realbarisbasturk@gmail.com>
  • Loading branch information
qwwdfsad and realbarisbasturk committed Oct 20, 2022
1 parent 89c1b22 commit 3f37b63
Show file tree
Hide file tree
Showing 12 changed files with 375 additions and 2 deletions.
4 changes: 4 additions & 0 deletions build.gradle.kts
Expand Up @@ -13,6 +13,7 @@ plugins {
repositories {
mavenCentral()
gradlePluginPortal()
google()
}

sourceSets {
Expand Down Expand Up @@ -63,6 +64,7 @@ val createClasspathManifest = tasks.register("createClasspathManifest") {
}

val kotlinVersion: String by project
val androidGradlePluginVersion: String = "7.2.2"

configurations.implementation {
exclude(group = "org.jetbrains.kotlin", module = "kotlin-stdlib")
Expand All @@ -77,10 +79,12 @@ dependencies {
implementation("org.ow2.asm:asm-tree:9.2")
implementation("com.googlecode.java-diff-utils:diffutils:1.3.0")
compileOnly("org.jetbrains.kotlin.multiplatform:org.jetbrains.kotlin.multiplatform.gradle.plugin:1.6.0")
compileOnly("com.android.tools.build:gradle:${androidGradlePluginVersion}")

// The test needs the full kotlin multiplatform plugin loaded as it has no visibility of previously loaded plugins,
// unlike the regular way gradle loads plugins.
add(testPluginRuntimeConfiguration.name, "org.jetbrains.kotlin.multiplatform:org.jetbrains.kotlin.multiplatform.gradle.plugin:$kotlinVersion")
add(testPluginRuntimeConfiguration.name, "com.android.tools.build:gradle:${androidGradlePluginVersion}")

testImplementation(kotlin("test-junit"))
"functionalTestImplementation"(files(createClasspathManifest))
Expand Down
12 changes: 12 additions & 0 deletions src/functionalTest/kotlin/kotlinx/validation/api/TestDsl.kt
Expand Up @@ -47,6 +47,18 @@ internal fun FileContainer.kotlin(classFileName: String, sourceSet:String = "mai
file(fileName, fn)
}

/**
* same as [file][FileContainer.file], but prepends "src/${sourceSet}/java" before given `classFileName`
*/
internal fun FileContainer.java(classFileName: String, sourceSet:String = "main", fn: AppendableScope.() -> Unit) {
require(classFileName.endsWith(".java")) {
"ClassFileName must end with '.java'"
}

val fileName = "src/${sourceSet}/java/$classFileName"
file(fileName, fn)
}

/**
* Shortcut for creating a `build.gradle.kts` by using [file][FileContainer.file]
*/
Expand Down
@@ -0,0 +1,130 @@
/*
* Copyright 2016-2022 JetBrains s.r.o.
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
*/

package kotlinx.validation.test

import kotlinx.validation.api.*
import org.junit.Assume
import org.junit.Test
import java.io.File

internal class AndroidLibraryTest : BaseKotlinGradleTest() {

// region Kotlin Android Library

@Test
fun `Given a Kotlin Android Library, when api is dumped, then task should be successful`() {
assumeHasAndroid()
val runner = test {
createProjectWithSubModules()
runner {
arguments.add(":kotlin-library:apiDump")
arguments.add("--full-stacktrace")
}
}

runner.build().apply {
assertTaskSuccess(":kotlin-library:apiDump")
}
}

@Test
fun `Given a Kotlin Android Library, when api is checked, then it should match the expected`() {
assumeHasAndroid()
test {
createProjectWithSubModules()
runner {
arguments.add(":kotlin-library:apiCheck")
}
}.build().apply {
assertTaskSuccess(":kotlin-library:apiCheck")
}
}

//endregion

//region Java Android Library

@Test
fun `Given a Java Android Library, when api is dumped, then task should be successful`() {
assumeHasAndroid()
val runner = test {
createProjectWithSubModules()
runner {
arguments.add(":java-library:apiDump")
arguments.add("--full-stacktrace")
}
}

runner.build().apply {
assertTaskSuccess(":java-library:apiDump")
}
}

@Test
fun `Given a Java Android Library, when api is checked, then it should match the expected`() {
assumeHasAndroid()
test {
createProjectWithSubModules()
runner {
arguments.add(":java-library:apiCheck")
}
}.build().apply {
assertTaskSuccess(":java-library:apiCheck")
}
}

//endregion

/**
* Creates a single project with 2 (Kotlin and Java Android Library) modules, applies
* the plugin on the root project.
*/
private fun BaseKotlinScope.createProjectWithSubModules() {
settingsGradleKts {
resolve("examples/gradle/settings/settings-android-project.gradle.kts")
}
buildGradleKts {
resolve("examples/gradle/base/androidProjectRoot.gradle.kts")
}
initLocalProperties()

dir("kotlin-library") {
buildGradleKts {
resolve("examples/gradle/base/androidKotlinLibrary.gradle.kts")
}
kotlin("KotlinLib.kt") {
resolve("examples/classes/KotlinLib.kt")
}
apiFile(projectName = "kotlin-library") {
resolve("examples/classes/KotlinLib.dump")
}
}
dir("java-library") {
buildGradleKts {
resolve("examples/gradle/base/androidJavaLibrary.gradle.kts")
}
java("JavaLib.java") {
resolve("examples/classes/JavaLib.java")
}
apiFile(projectName = "java-library") {
resolve("examples/classes/JavaLib.dump")
}
}
}

private fun initLocalProperties() {
val home = System.getenv("ANDROID_HOME") ?: System.getenv("HOME")
File(rootProjectDir, "local.properties").apply {
writeText("sdk.dir=$home/Android/Sdk")
}
}

// We do not have ANDROID_HOME on CI, and this functionality is not critical, so we are disabling these
// tests on CI
private fun assumeHasAndroid() {
Assume.assumeFalse(System.getenv("ANDROID_HOME").isNullOrEmpty())
}
}
12 changes: 12 additions & 0 deletions src/functionalTest/resources/examples/classes/JavaLib.dump
@@ -0,0 +1,12 @@
public final class examples/classes/JavaLib {
public fun <init> ()V
public fun foo ()Ljava/lang/String;
}

public final class org/jetbrains/kotlinx/android/java/library/BuildConfig {
public static final field BUILD_TYPE Ljava/lang/String;
public static final field DEBUG Z
public static final field LIBRARY_PACKAGE_NAME Ljava/lang/String;
public fun <init> ()V
}

18 changes: 18 additions & 0 deletions src/functionalTest/resources/examples/classes/JavaLib.java
@@ -0,0 +1,18 @@
/*
* Copyright 2016-2022 JetBrains s.r.o.
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
*/

package examples.classes;

public final class JavaLib {

public String foo() {
return "foo";
}

private String bar() {
return "bar";
}

}
12 changes: 12 additions & 0 deletions src/functionalTest/resources/examples/classes/KotlinLib.dump
@@ -0,0 +1,12 @@
public final class examples/classes/KotlinLib {
public fun <init> ()V
public final fun foo ()Ljava/lang/String;
}

public final class org/jetbrains/kotlinx/android/kotlin/library/BuildConfig {
public static final field BUILD_TYPE Ljava/lang/String;
public static final field DEBUG Z
public static final field LIBRARY_PACKAGE_NAME Ljava/lang/String;
public fun <init> ()V
}

13 changes: 13 additions & 0 deletions src/functionalTest/resources/examples/classes/KotlinLib.kt
@@ -0,0 +1,13 @@
/*
* Copyright 2016-2022 JetBrains s.r.o.
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
*/

package examples.classes

class KotlinLib {

fun foo(): String = "foo"
internal fun bar(): String = "bar"

}
@@ -0,0 +1,39 @@
/*
* Copyright 2016-2022 JetBrains s.r.o.
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
*/

plugins {
id("com.android.library")
id("org.jetbrains.kotlinx.binary-compatibility-validator")
}

android {

namespace = "org.jetbrains.kotlinx.android.java.library"

compileSdk = 32

defaultConfig {
minSdk = 31
targetSdk = 32

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}

buildTypes {
release {
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}

}

dependencies {
// no dependencies required
}
@@ -0,0 +1,40 @@
/*
* Copyright 2016-2022 JetBrains s.r.o.
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
*/

plugins {
id("com.android.library")
id("kotlin-android")
id("org.jetbrains.kotlinx.binary-compatibility-validator")
}

android {

namespace = "org.jetbrains.kotlinx.android.kotlin.library"

compileSdk = 32

defaultConfig {
minSdk = 31
targetSdk = 32

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}

buildTypes {
release {
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}

}

dependencies {
// no dependencies required
}
@@ -0,0 +1,10 @@
plugins {
id("com.android.application").version("7.2.2").apply(false)
id("com.android.library").version("7.2.2").apply(false)
id("org.jetbrains.kotlin.android").version("1.7.10").apply(false)
id("org.jetbrains.kotlinx.binary-compatibility-validator").apply(false)
}

tasks.register("clean", Delete::class) {
delete(rootProject.buildDir)
}
@@ -0,0 +1,20 @@
pluginManagement {
repositories {
mavenLocal()
gradlePluginPortal()
google()
mavenCentral()
}
}

dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}

rootProject.name = "android-project"
include(":kotlin-library")
include(":java-library")

0 comments on commit 3f37b63

Please sign in to comment.