Skip to content

Commit

Permalink
Remove robolectric deprecated override (#18)
Browse files Browse the repository at this point in the history
  • Loading branch information
uOOOO authored Jun 8, 2024
1 parent b73ec0f commit 0fbb721
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 22 deletions.
2 changes: 1 addition & 1 deletion kotest-extensions-android/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ configurations {
dependencies {
implementation(kotlin("reflect"))
implementation("io.kotest:kotest-framework-api:5.9.0")
implementation("org.robolectric:robolectric:4.11.1")
implementation("org.robolectric:robolectric:4.12.2")
implementation("junit:junit:4.13.2")
implementation("androidx.appcompat:appcompat:1.7.0")

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
package br.com.colman.kotest.android.extensions.robolectric

import org.junit.experimental.runners.Enclosed
import org.junit.runner.RunWith
import org.junit.runners.model.FrameworkMethod
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import org.robolectric.internal.bytecode.InstrumentationConfiguration
import org.robolectric.pluginapi.config.ConfigurationStrategy
import org.robolectric.plugins.ConfigConfigurer
import org.robolectric.pluginapi.config.Configurer
import org.robolectric.plugins.HierarchicalConfigurationStrategy
import java.lang.reflect.Method

@RunWith(Enclosed::class)
internal class ContainedRobolectricRunner(
private val config: Config?
private val config: Config
) : RobolectricTestRunner(PlaceholderTest::class.java, injector) {
init {
injectKotestConfig()
}

private val placeHolderMethod: FrameworkMethod = children[0]
val sdkEnvironment = getSandbox(placeHolderMethod).also {
configureSandbox(it, placeHolderMethod)
Expand All @@ -35,16 +43,14 @@ internal class ContainedRobolectricRunner(
.build()
}

override fun getConfig(method: Method?): Config {
val defaultConfiguration = injector.getInstance(ConfigurationStrategy::class.java)
.getConfig(testClass.javaClass, method)

if (config != null) {
val configConfigurer = injector.getInstance(ConfigConfigurer::class.java)
return configConfigurer.merge(defaultConfiguration[Config::class.java], config)
}

return super.getConfig(method)
private fun injectKotestConfig() {
val configurationStrategyField =
RobolectricTestRunner::class.java
.getField(ConfigurationStrategy::class.java)
.apply { isAccessible = true }
val configurers = injector.getInstance(arrayOf<Configurer<*>>()::class.java)
val newConfigurationStrategy = KotestHierarchicalConfigurationStrategy(config, configurers)
configurationStrategyField.set(this, newConfigurationStrategy)
}

class PlaceholderTest {
Expand All @@ -56,6 +62,19 @@ internal class ContainedRobolectricRunner(
}
}

class KotestHierarchicalConfigurationStrategy(
private val config: Config,
configurers: Array<Configurer<*>>
) : HierarchicalConfigurationStrategy(*configurers) {
override fun getConfig(testClass: Class<*>?, method: Method?): ConfigurationImpl {
val configurationImpl = super.getConfig(testClass, method)
val config = (configurationImpl.get(Config::class.java) as Config)
val newConfig = Config.Builder(config).overlay(this.config).build()
configurationImpl.map()[Config::class.java] = newConfig
return configurationImpl
}
}

companion object {
private val injector = defaultInjector().build()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package br.com.colman.kotest.android.extensions.robolectric

import java.lang.reflect.Field
import java.lang.reflect.Type

internal fun Class<*>.getField(fieldClass: Type): Field {
return declaredFields.firstOrNull { it.type == fieldClass }
?: throw IllegalStateException("Not found $fieldClass field.")
}

internal inline fun <reified T> Class<*>.getValue(obj: Any): T {
val field = getField(T::class.java)
field.isAccessible = true
return field.get(obj) as T
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ class RobolectricExtension : ConstructorExtension, TestCaseExtension {
val containedRobolectricRunner = runnerMap[testCase.spec]!!
// Using sdkEnvironment.executorService to ensure Robolectric's
// looper state doesn't carry over to the next test class.
val executorService = containedRobolectricRunner.sdkEnvironment.getExecutorService()
val executorService =
Sandbox::class.java
.getValue<ExecutorService>(containedRobolectricRunner.sdkEnvironment)
return withContext(executorService.asCoroutineDispatcher()) {
if (testCase.isRootTest()) {
containedRobolectricRunner.containedBefore()
Expand All @@ -129,14 +131,6 @@ class RobolectricExtension : ConstructorExtension, TestCaseExtension {
}
}

private fun Sandbox.getExecutorService(): ExecutorService {
val field = Sandbox::class.java.declaredFields
.firstOrNull { it.type == ExecutorService::class.java }
checkNotNull(field) { "Not found ExecutorService field." }
field.isAccessible = true
return field.get(this) as ExecutorService
}

internal class KotestDefaultApplication : Application()

annotation class RobolectricTest(
Expand Down

0 comments on commit 0fbb721

Please sign in to comment.