Skip to content
Merged
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
2 changes: 2 additions & 0 deletions libs/processors/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ dependencies {
kapt "com.google.auto.service:auto-service:$googleAutoServiceVersion"
implementation "com.squareup:kotlinpoet:$squareupKotlinPoetVersion"

testImplementation "com.github.tschuchortdev:kotlin-compile-testing:1.5.0"
testImplementation "junit:junit:$junitVersion"
testImplementation "org.assertj:assertj-core:$assertjVersion"
testImplementation "org.jetbrains.kotlin:kotlin-reflect:$gradle.ext.kotlinVersion"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package org.wordpress.android.processor

import com.tschuchort.compiletesting.KotlinCompilation
import com.tschuchort.compiletesting.SourceFile
import org.assertj.core.api.Assertions.assertThat
import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.junit.Test

class RemoteConfigProcessorTest {
@Test
fun `given a class with features annotation, when compiling, generate expected configuration check`() {
// when
val result = compile(listOf(featureA))

// then
assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.OK)
assertThat(result.classLoader.loadClass("org.wordpress.android.util.config.RemoteFeatureConfigCheck"))
.hasDeclaredMethods("checkRemoteFields")
}

@Test
fun `given a class with remote field annotation, when compiling, generate expected config defaults class`() {
// given
val remoteFieldA = SourceFile.kotlin(
"RemoteField.kt", """
import org.wordpress.android.annotation.RemoteFieldDefaultGenerater
import org.wordpress.android.util.config.AppConfig

@RemoteFieldDefaultGenerater(remoteField = "remoteField", defaultValue = "default")
class RemoteFieldA
"""
)

// when
val result = compile(
listOf(
remoteFieldA,
featureA, /* adding a feature, as without it, annotation processor won't start */
)
)

// then
assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.OK)
val remoteFieldConfigDefaultsClass =
result.classLoader.loadClass("org.wordpress.android.util.config.RemoteFieldConfigDefaults")
val remoteFieldConfigDefaultsObject = remoteFieldConfigDefaultsClass.kotlin.objectInstance

assertThat(
remoteFieldConfigDefaultsClass.getDeclaredField("remoteFieldConfigDefaults")
.apply { isAccessible = true }
.get(remoteFieldConfigDefaultsObject)
.cast<Map<String, Any>>()
).containsEntry("remoteField", "default")
}

@Test
fun `given class with feature and experiment annotation, when compiling, generate config defaults class`() {
// given
val experiment = SourceFile.kotlin(
"Experiment.kt", """
import org.wordpress.android.annotation.Experiment
import org.wordpress.android.util.config.AppConfig

@Experiment("experimentFeature", "defaultVariant")
class Experiment
"""
)

// when
val result = compile(listOf(featureA, experiment))

// then
assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.OK)
val remoteFieldConfigDefaultsClass =
result.classLoader.loadClass("org.wordpress.android.util.config.RemoteFeatureConfigDefaults")
val remoteFieldConfigDefaultsObject = remoteFieldConfigDefaultsClass.kotlin.objectInstance

assertThat(
remoteFieldConfigDefaultsClass.getDeclaredField("remoteFeatureConfigDefaults")
.apply { isAccessible = true }
.get(remoteFieldConfigDefaultsObject)
.cast<Map<String, Any>>()
).containsExactlyInAnyOrderEntriesOf(
mapOf(
"experimentFeature" to "defaultVariant",
"remoteField" to "false"
)
)
}

@Test
fun `given class with feature in development annotation, when compiling, generate expected list of classes`() {
// given
val experiment = SourceFile.kotlin(
"Experiment.kt", """
import org.wordpress.android.annotation.FeatureInDevelopment
import org.wordpress.android.util.config.AppConfig

@FeatureInDevelopment
class DevFeature
"""
)

// when
val result = compile(
listOf(
experiment,
featureA, /* adding a feature, as without it, annotation processor won't start */
)
)

// then

val featuresInDevelopmentClass =
result.classLoader.loadClass("org.wordpress.android.util.config.FeaturesInDevelopment")
val featuresInDevelopmentObject = featuresInDevelopmentClass.kotlin.objectInstance
assertThat(
featuresInDevelopmentClass.getDeclaredField("featuresInDevelopment")
.apply { isAccessible = true }
.get(featuresInDevelopmentObject)
.cast<List<String>>()
).containsOnly("DevFeature")
}

private fun compile(src: List<SourceFile>) = KotlinCompilation().apply {
sources = src + fakeAppConfig
annotationProcessors = listOf(RemoteConfigProcessor())
inheritClassPath = true
messageOutputStream = System.out
}.compile()

// Fake AppConfig is needed, as it's a class that is expected to be present in the classpath. Originally, this class
// is placed in `WordPress` module.
private val fakeAppConfig = SourceFile.kotlin(
"AppConfig.kt", """
package org.wordpress.android.util.config

class AppConfig
"""
)

private val featureA = SourceFile.kotlin(
"Feature.kt", """
import org.wordpress.android.annotation.Feature
import org.wordpress.android.util.config.AppConfig

@Feature("remoteField", false)
class FeatureA(appConfig: AppConfig, val remoteField: String ="foo")
"""
)
}