All Downloads are FREE. Search and download functionalities are using the official Maven repository.

run.smt.ktest.api.lifecycle.Lifecycle.kt Maven / Gradle / Ivy

There is a newer version: 1.0.0
Show newest version
package run.smt.ktest.api.lifecycle

import com.typesafe.config.ConfigFactory
import org.slf4j.LoggerFactory
import run.smt.ktest.api.*
import run.smt.ktest.config.config
import run.smt.ktest.config.fallbackTo
import run.smt.ktest.config.get
import run.smt.ktest.util.reflection.canBeAssignedTo

object Lifecycle {
    private val log = LoggerFactory.getLogger(Lifecycle::class.java)

    private val listenerFactories =
        config.getObject("kTest.lifecycle.listeners").mapNotNull { (name, it) ->
            val cfg = it.atKey("listener") fallbackTo ConfigFactory.parseMap(mapOf("listener.priority" to 0))
            val listenerFactory = listenerFactoryFor(name, cfg["listener.class"])
            val priority = cfg.getInt("listener.priority")

            listenerFactory?.let { priority to it }
        }.sortedByDescending { it.first }.map { it.second }

    private fun listenerFactoryFor(name: String, className: String): ((BaseSpec) -> CaseLifecycleListener)? {
        @Suppress("UNCHECKED_CAST")
        val clazz = try {
            Class.forName(className)
        } catch (e: Exception) {
            log.error("Failed to find class for listener named \"$name\"... Attempted to use class: $className", e)
            null
        }?.takeIf {
            it canBeAssignedTo CaseLifecycleListener::class
        } as? Class
            ?: run {
                log.error("\"$name\" is not a listener! \"$className\" can not be cast to \"${CaseLifecycleListener::class.qualifiedName}\"")
                return null
            }

        val defaultConstructor = clazz.declaredConstructors.find { it.parameterCount == 0 }

        if (defaultConstructor != null) {
            return {
                defaultConstructor.newInstance() as CaseLifecycleListener
            }
        }

        val specConsumingConstructor = clazz.declaredConstructors
            .filter { it.parameterCount == 1 }
            .find { it.parameterTypes.any { BaseSpec::class canBeAssignedTo it } }

        return specConsumingConstructor?.let { { spec: BaseSpec -> it.newInstance(spec) as CaseLifecycleListener } } ?: run {
            log.error("No valid constructor found for listener named \"$name\" of type \"$className\". Valid constructors are: default (zero arguments), constructor with single argument of (sub)type ${BaseSpec::class.qualifiedName}")
            null
        }
    }

    fun createNotifierFor(spec: BaseSpec): LifecycleNotifier {
        return LifecycleNotifier(listenerFactories.map { it(spec) })
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy