CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-kotest--kotest-assertions-core-jvm

Core assertion and matcher library for Kotest testing framework

Pending
Overview
Eval results
Files

reflection.mddocs/

Reflection Matchers

JVM reflection-based matchers for classes, annotations, properties, and method validation using Kotlin reflection API for comprehensive type and metadata assertion capabilities.

Capabilities

Class Annotation Validation

Matchers for validating class-level annotations and annotation metadata.

/**
 * Assert that class has at least one annotation
 * @return The original KClass for chaining
 */
fun KClass<*>.shouldHaveAnnotations(): KClass<*>

/**
 * Assert that class has no annotations
 * @return The original KClass for chaining
 */
fun KClass<*>.shouldNotHaveAnnotations(): KClass<*>

/**
 * Assert that class has exactly specified number of annotations
 * @param count Expected number of annotations
 * @return The original KClass for chaining
 */
infix fun KClass<*>.shouldHaveAnnotations(count: Int): KClass<*>

/**
 * Assert that class does not have specified number of annotations
 * @param count Annotation count that should not match
 * @return The original KClass for chaining
 */
infix fun KClass<*>.shouldNotHaveAnnotations(count: Int): KClass<*>

/**
 * Assert that class is annotated with specific annotation type
 * @param T The annotation type to check for
 * @param block Optional validation block for annotation properties
 * @return The original KClass for chaining
 */
inline fun <reified T : Annotation> KClass<*>.shouldBeAnnotatedWith(
    noinline block: (T) -> Unit = {}
): KClass<*>

/**
 * Assert that class is not annotated with specific annotation type
 * @param T The annotation type that should not be present
 * @return The original KClass for chaining
 */
inline fun <reified T : Annotation> KClass<*>.shouldNotBeAnnotatedWith(): KClass<*>

/**
 * Create matcher for annotation count validation
 * @param count Expected number of annotations (-1 for any positive count)
 * @return Matcher that passes when class has expected annotation count
 */
fun haveClassAnnotations(count: Int = -1): Matcher<KClass<*>>

/**
 * Create matcher for specific annotation presence
 * @param T The annotation type to check for
 * @param block Optional validation block for annotation properties
 * @return Matcher that passes when class has the specified annotation
 */
inline fun <reified T : Annotation> beAnnotatedWith(
    noinline block: (T) -> Unit = {}
): Matcher<KClass<*>>

Usage Examples:

import io.kotest.matchers.reflection.*
import kotlin.reflect.KClass

@Entity
@Table(name = "users")
@Serializable
data class User(
    @Id val id: Long,
    @Column(name = "username") val name: String
)

val userClass: KClass<User> = User::class

// Annotation presence validation
userClass.shouldHaveAnnotations()
userClass.shouldHaveAnnotations(3) // Entity, Table, Serializable

// Specific annotation validation
userClass.shouldBeAnnotatedWith<Entity>()
userClass.shouldBeAnnotatedWith<Table> { table ->
    table.name shouldBe "users"
}

// Using matcher syntax
userClass should haveClassAnnotations(3)
userClass should beAnnotatedWith<Serializable>()

Property and Field Validation

Matchers for validating class properties, fields, and their characteristics.

/**
 * Assert that class has property with specified name
 * @param name The property name to check for
 * @return The original KClass for chaining
 */
infix fun KClass<*>.shouldHaveProperty(name: String): KClass<*>

/**
 * Assert that class does not have property with specified name
 * @param name The property name that should not exist
 * @return The original KClass for chaining
 */
infix fun KClass<*>.shouldNotHaveProperty(name: String): KClass<*>

/**
 * Assert that class has exactly specified number of properties
 * @param count Expected number of properties
 * @return The original KClass for chaining
 */
infix fun KClass<*>.shouldHavePropertyCount(count: Int): KClass<*>

/**
 * Assert that class has mutable property with specified name
 * @param name The mutable property name to check for
 * @return The original KClass for chaining
 */
infix fun KClass<*>.shouldHaveMutableProperty(name: String): KClass<*>

/**
 * Assert that class has immutable property with specified name
 * @param name The immutable property name to check for
 * @return The original KClass for chaining
 */
infix fun KClass<*>.shouldHaveImmutableProperty(name: String): KClass<*>

/**
 * Assert that property has specific type
 * @param name Property name
 * @param type Expected property type
 * @return The original KClass for chaining
 */
fun KClass<*>.shouldHavePropertyOfType(name: String, type: KClass<*>): KClass<*>

/**
 * Create matcher for property existence validation
 * @param name The property name to check for
 * @return Matcher that passes when class has the named property
 */
fun haveProperty(name: String): Matcher<KClass<*>>

/**
 * Create matcher for property count validation
 * @param count Expected number of properties
 * @return Matcher that passes when class has exact property count
 */
fun havePropertyCount(count: Int): Matcher<KClass<*>>

/**
 * Create matcher for mutable property validation
 * @param name The mutable property name
 * @return Matcher that passes when class has mutable property
 */
fun haveMutableProperty(name: String): Matcher<KClass<*>>

/**
 * Create matcher for property type validation
 * @param name Property name
 * @param type Expected property type
 * @return Matcher that passes when property has expected type
 */
fun havePropertyOfType(name: String, type: KClass<*>): Matcher<KClass<*>>

Constructor and Function Validation

Matchers for validating class constructors and member functions.

/**
 * Assert that class has primary constructor with specified parameter count
 * @param parameterCount Expected number of constructor parameters
 * @return The original KClass for chaining
 */
infix fun KClass<*>.shouldHavePrimaryConstructor(parameterCount: Int): KClass<*>

/**
 * Assert that class does not have primary constructor
 * @return The original KClass for chaining
 */
fun KClass<*>.shouldNotHavePrimaryConstructor(): KClass<*>

/**
 * Assert that class has function with specified name
 * @param name The function name to check for
 * @return The original KClass for chaining
 */
infix fun KClass<*>.shouldHaveFunction(name: String): KClass<*>

/**
 * Assert that class does not have function with specified name
 * @param name The function name that should not exist
 * @return The original KClass for chaining
 */
infix fun KClass<*>.shouldNotHaveFunction(name: String): KClass<*>

/**
 * Assert that class has exactly specified number of member functions
 * @param count Expected number of functions (excluding inherited)
 * @return The original KClass for chaining
 */
infix fun KClass<*>.shouldHaveFunctionCount(count: Int): KClass<*>

/**
 * Assert that function has specific parameter types
 * @param functionName Name of function to validate
 * @param parameterTypes Expected parameter types in order
 * @return The original KClass for chaining
 */
fun KClass<*>.shouldHaveFunctionWithParameters(
    functionName: String,
    vararg parameterTypes: KClass<*>
): KClass<*>

/**
 * Create matcher for primary constructor validation
 * @param parameterCount Expected parameter count
 * @return Matcher that passes when class has primary constructor with parameter count
 */
fun havePrimaryConstructor(parameterCount: Int): Matcher<KClass<*>>

/**
 * Create matcher for function existence validation
 * @param name The function name to check for
 * @return Matcher that passes when class has the named function
 */
fun haveFunction(name: String): Matcher<KClass<*>>

/**
 * Create matcher for function count validation
 * @param count Expected number of member functions
 * @return Matcher that passes when class has exact function count
 */
fun haveFunctionCount(count: Int): Matcher<KClass<*>>

/**
 * Create matcher for function signature validation
 * @param functionName Name of function
 * @param parameterTypes Expected parameter types
 * @return Matcher that passes when function has expected signature
 */
fun haveFunctionWithParameters(
    functionName: String,
    vararg parameterTypes: KClass<*>
): Matcher<KClass<*>>

Usage Examples:

import io.kotest.matchers.reflection.*
import kotlin.reflect.KClass

data class Person(
    val id: Long,
    var name: String,
    val email: String
) {
    fun updateName(newName: String) {
        name = newName
    }
    
    fun isValid(): Boolean = name.isNotEmpty() && email.contains("@")
}

val personClass: KClass<Person> = Person::class

// Property validation
personClass shouldHaveProperty "id"
personClass shouldHaveProperty "name"
personClass shouldHavePropertyCount 3
personClass shouldHaveMutableProperty "name"
personClass shouldHaveImmutableProperty "id"
personClass.shouldHavePropertyOfType("id", Long::class)

// Constructor validation
personClass shouldHavePrimaryConstructor 3

// Function validation
personClass shouldHaveFunction "updateName"
personClass shouldHaveFunction "isValid"
personClass shouldHaveFunctionCount 2
personClass.shouldHaveFunctionWithParameters("updateName", String::class)

Class Type and Inheritance

Matchers for validating class types, inheritance relationships, and type characteristics.

/**
 * Assert that class is abstract
 * @return The original KClass for chaining
 */
fun KClass<*>.shouldBeAbstract(): KClass<*>

/**
 * Assert that class is not abstract (concrete)
 * @return The original KClass for chaining
 */
fun KClass<*>.shouldNotBeAbstract(): KClass<*>

/**
 * Assert that class is a data class
 * @return The original KClass for chaining
 */
fun KClass<*>.shouldBeDataClass(): KClass<*>

/**
 * Assert that class is not a data class
 * @return The original KClass for chaining
 */
fun KClass<*>.shouldNotBeDataClass(): KClass<*>

/**
 * Assert that class is sealed
 * @return The original KClass for chaining
 */
fun KClass<*>.shouldBeSealed(): KClass<*>

/**
 * Assert that class is not sealed
 * @return The original KClass for chaining
 */
fun KClass<*>.shouldNotBeSealed(): KClass<*>

/**
 * Assert that class is an interface
 * @return The original KClass for chaining
 */
fun KClass<*>.shouldBeInterface(): KClass<*>

/**
 * Assert that class is not an interface
 * @return The original KClass for chaining
 */
fun KClass<*>.shouldNotBeInterface(): KClass<*>

/**
 * Assert that class is an enum class
 * @return The original KClass for chaining
 */
fun KClass<*>.shouldBeEnum(): KClass<*>

/**
 * Assert that class is not an enum class
 * @return The original KClass for chaining
 */
fun KClass<*>.shouldNotBeEnum(): KClass<*>

/**
 * Assert that class is subclass of specified parent class
 * @param parent The parent class type
 * @return The original KClass for chaining
 */
infix fun KClass<*>.shouldBeSubclassOf(parent: KClass<*>): KClass<*>

/**
 * Assert that class is not subclass of specified class
 * @param parent The class that should not be a parent
 * @return The original KClass for chaining
 */
infix fun KClass<*>.shouldNotBeSubclassOf(parent: KClass<*>): KClass<*>

/**
 * Create matcher for abstract class validation
 * @return Matcher that passes for abstract classes
 */
fun beAbstract(): Matcher<KClass<*>>

/**
 * Create matcher for data class validation
 * @return Matcher that passes for data classes
 */
fun beDataClass(): Matcher<KClass<*>>

/**
 * Create matcher for sealed class validation
 * @return Matcher that passes for sealed classes
 */
fun beSealed(): Matcher<KClass<*>>

/**
 * Create matcher for interface validation
 * @return Matcher that passes for interfaces
 */
fun beInterface(): Matcher<KClass<*>>

/**
 * Create matcher for enum validation
 * @return Matcher that passes for enum classes
 */
fun beEnum(): Matcher<KClass<*>>

/**
 * Create matcher for inheritance validation
 * @param parent The parent class to check inheritance from
 * @return Matcher that passes when class is subclass of parent
 */
fun beSubclassOf(parent: KClass<*>): Matcher<KClass<*>>

Member Visibility and Modifiers

Matchers for validating member visibility and modifier characteristics.

/**
 * Assert that class has public member with specified name
 * @param memberName Name of member to check visibility for
 * @return The original KClass for chaining
 */
infix fun KClass<*>.shouldHavePublicMember(memberName: String): KClass<*>

/**
 * Assert that class has private member with specified name
 * @param memberName Name of member to check visibility for
 * @return The original KClass for chaining
 */
infix fun KClass<*>.shouldHavePrivateMember(memberName: String): KClass<*>

/**
 * Assert that class has protected member with specified name
 * @param memberName Name of member to check visibility for
 * @return The original KClass for chaining
 */
infix fun KClass<*>.shouldHaveProtectedMember(memberName: String): KClass<*>

/**
 * Assert that class has internal member with specified name
 * @param memberName Name of member to check visibility for
 * @return The original KClass for chaining
 */
infix fun KClass<*>.shouldHaveInternalMember(memberName: String): KClass<*>

/**
 * Assert that function is suspend function
 * @param functionName Name of function to check
 * @return The original KClass for chaining
 */
infix fun KClass<*>.shouldHaveSuspendFunction(functionName: String): KClass<*>

/**
 * Assert that function is inline function
 * @param functionName Name of function to check
 * @return The original KClass for chaining
 */
infix fun KClass<*>.shouldHaveInlineFunction(functionName: String): KClass<*>

/**
 * Create matcher for public member validation
 * @param memberName Name of member to check
 * @return Matcher that passes when member is public
 */
fun havePublicMember(memberName: String): Matcher<KClass<*>>

/**
 * Create matcher for private member validation
 * @param memberName Name of member to check
 * @return Matcher that passes when member is private
 */
fun havePrivateMember(memberName: String): Matcher<KClass<*>>

/**
 * Create matcher for suspend function validation
 * @param functionName Name of function to check
 * @return Matcher that passes when function is suspend
 */
fun haveSuspendFunction(functionName: String): Matcher<KClass<*>>

Usage Examples:

import io.kotest.matchers.reflection.*

abstract class Shape {
    abstract fun area(): Double
}

data class Circle(val radius: Double) : Shape() {
    override fun area(): Double = Math.PI * radius * radius
}

interface Drawable {
    fun draw()
}

enum class Color { RED, GREEN, BLUE }

sealed class Result<out T> {
    data class Success<T>(val value: T) : Result<T>()
    data class Error(val message: String) : Result<Nothing>()
}

// Class type validation
Shape::class.shouldBeAbstract()
Circle::class.shouldBeDataClass()
Circle::class shouldBeSubclassOf Shape::class
Drawable::class.shouldBeInterface()
Color::class.shouldBeEnum()
Result::class.shouldBeSealed()

// Using matcher syntax
Shape::class should beAbstract()
Circle::class should beDataClass()
Circle::class should beSubclassOf(Shape::class)
Drawable::class should beInterface()

Generic Type Validation

Matchers for validating generic types and type parameters.

/**
 * Assert that class has specified number of type parameters
 * @param count Expected number of type parameters
 * @return The original KClass for chaining
 */
infix fun KClass<*>.shouldHaveTypeParameterCount(count: Int): KClass<*>

/**
 * Assert that class does not have type parameters (non-generic)
 * @return The original KClass for chaining
 */
fun KClass<*>.shouldNotBeGeneric(): KClass<*>

/**
 * Assert that class is generic (has type parameters)
 * @return The original KClass for chaining
 */
fun KClass<*>.shouldBeGeneric(): KClass<*>

/**
 * Create matcher for type parameter count validation
 * @param count Expected number of type parameters
 * @return Matcher that passes when class has expected type parameter count
 */
fun haveTypeParameterCount(count: Int): Matcher<KClass<*>>

/**
 * Create matcher for generic class validation
 * @return Matcher that passes for generic classes
 */
fun beGeneric(): Matcher<KClass<*>>

Usage Examples:

import io.kotest.matchers.reflection.*

class Container<T> {
    var item: T? = null
}

class Repository<K, V> {
    private val storage = mutableMapOf<K, V>()
}

class SimpleClass {
    val value: String = ""
}

// Generic type validation
Container::class.shouldBeGeneric()
Container::class shouldHaveTypeParameterCount 1
Repository::class shouldHaveTypeParameterCount 2
SimpleClass::class.shouldNotBeGeneric()

// Using matcher syntax
Container::class should beGeneric()
Repository::class should haveTypeParameterCount(2)

Error Handling

Reflection matchers provide detailed error information for assertion failures:

  • Annotation failures: Show expected vs actual annotations with full annotation details
  • Property failures: List all available properties when expected property is missing
  • Type failures: Clear indication of expected vs actual class types and inheritance relationships
  • Visibility failures: Specific information about member visibility and access modifiers
  • Generic failures: Details about type parameters and generic constraints
  • Signature failures: Complete function signatures with parameter types and return types

All reflection matchers handle edge cases like null types, missing members, and access restrictions while providing meaningful error messages that help debug reflection-based assertions.

Install with Tessl CLI

npx tessl i tessl/maven-io-kotest--kotest-assertions-core-jvm

docs

collections.md

concurrency.md

core-dsl.md

datetime.md

filesystem.md

index.md

nondeterministic.md

primitives.md

reflection.md

result.md

strings.md

throwable.md

tuples.md

types.md

tile.json