or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

collections.mdconcurrency.mdcore-dsl.mddatetime.mdfilesystem.mdindex.mdnondeterministic.mdprimitives.mdreflection.mdresult.mdstrings.mdthrowable.mdtuples.mdtypes.md

reflection.mddocs/

0

# Reflection Matchers

1

2

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

3

4

## Capabilities

5

6

### Class Annotation Validation

7

8

Matchers for validating class-level annotations and annotation metadata.

9

10

```kotlin { .api }

11

/**

12

* Assert that class has at least one annotation

13

* @return The original KClass for chaining

14

*/

15

fun KClass<*>.shouldHaveAnnotations(): KClass<*>

16

17

/**

18

* Assert that class has no annotations

19

* @return The original KClass for chaining

20

*/

21

fun KClass<*>.shouldNotHaveAnnotations(): KClass<*>

22

23

/**

24

* Assert that class has exactly specified number of annotations

25

* @param count Expected number of annotations

26

* @return The original KClass for chaining

27

*/

28

infix fun KClass<*>.shouldHaveAnnotations(count: Int): KClass<*>

29

30

/**

31

* Assert that class does not have specified number of annotations

32

* @param count Annotation count that should not match

33

* @return The original KClass for chaining

34

*/

35

infix fun KClass<*>.shouldNotHaveAnnotations(count: Int): KClass<*>

36

37

/**

38

* Assert that class is annotated with specific annotation type

39

* @param T The annotation type to check for

40

* @param block Optional validation block for annotation properties

41

* @return The original KClass for chaining

42

*/

43

inline fun <reified T : Annotation> KClass<*>.shouldBeAnnotatedWith(

44

noinline block: (T) -> Unit = {}

45

): KClass<*>

46

47

/**

48

* Assert that class is not annotated with specific annotation type

49

* @param T The annotation type that should not be present

50

* @return The original KClass for chaining

51

*/

52

inline fun <reified T : Annotation> KClass<*>.shouldNotBeAnnotatedWith(): KClass<*>

53

54

/**

55

* Create matcher for annotation count validation

56

* @param count Expected number of annotations (-1 for any positive count)

57

* @return Matcher that passes when class has expected annotation count

58

*/

59

fun haveClassAnnotations(count: Int = -1): Matcher<KClass<*>>

60

61

/**

62

* Create matcher for specific annotation presence

63

* @param T The annotation type to check for

64

* @param block Optional validation block for annotation properties

65

* @return Matcher that passes when class has the specified annotation

66

*/

67

inline fun <reified T : Annotation> beAnnotatedWith(

68

noinline block: (T) -> Unit = {}

69

): Matcher<KClass<*>>

70

```

71

72

**Usage Examples:**

73

74

```kotlin

75

import io.kotest.matchers.reflection.*

76

import kotlin.reflect.KClass

77

78

@Entity

79

@Table(name = "users")

80

@Serializable

81

data class User(

82

@Id val id: Long,

83

@Column(name = "username") val name: String

84

)

85

86

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

87

88

// Annotation presence validation

89

userClass.shouldHaveAnnotations()

90

userClass.shouldHaveAnnotations(3) // Entity, Table, Serializable

91

92

// Specific annotation validation

93

userClass.shouldBeAnnotatedWith<Entity>()

94

userClass.shouldBeAnnotatedWith<Table> { table ->

95

table.name shouldBe "users"

96

}

97

98

// Using matcher syntax

99

userClass should haveClassAnnotations(3)

100

userClass should beAnnotatedWith<Serializable>()

101

```

102

103

### Property and Field Validation

104

105

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

106

107

```kotlin { .api }

108

/**

109

* Assert that class has property with specified name

110

* @param name The property name to check for

111

* @return The original KClass for chaining

112

*/

113

infix fun KClass<*>.shouldHaveProperty(name: String): KClass<*>

114

115

/**

116

* Assert that class does not have property with specified name

117

* @param name The property name that should not exist

118

* @return The original KClass for chaining

119

*/

120

infix fun KClass<*>.shouldNotHaveProperty(name: String): KClass<*>

121

122

/**

123

* Assert that class has exactly specified number of properties

124

* @param count Expected number of properties

125

* @return The original KClass for chaining

126

*/

127

infix fun KClass<*>.shouldHavePropertyCount(count: Int): KClass<*>

128

129

/**

130

* Assert that class has mutable property with specified name

131

* @param name The mutable property name to check for

132

* @return The original KClass for chaining

133

*/

134

infix fun KClass<*>.shouldHaveMutableProperty(name: String): KClass<*>

135

136

/**

137

* Assert that class has immutable property with specified name

138

* @param name The immutable property name to check for

139

* @return The original KClass for chaining

140

*/

141

infix fun KClass<*>.shouldHaveImmutableProperty(name: String): KClass<*>

142

143

/**

144

* Assert that property has specific type

145

* @param name Property name

146

* @param type Expected property type

147

* @return The original KClass for chaining

148

*/

149

fun KClass<*>.shouldHavePropertyOfType(name: String, type: KClass<*>): KClass<*>

150

151

/**

152

* Create matcher for property existence validation

153

* @param name The property name to check for

154

* @return Matcher that passes when class has the named property

155

*/

156

fun haveProperty(name: String): Matcher<KClass<*>>

157

158

/**

159

* Create matcher for property count validation

160

* @param count Expected number of properties

161

* @return Matcher that passes when class has exact property count

162

*/

163

fun havePropertyCount(count: Int): Matcher<KClass<*>>

164

165

/**

166

* Create matcher for mutable property validation

167

* @param name The mutable property name

168

* @return Matcher that passes when class has mutable property

169

*/

170

fun haveMutableProperty(name: String): Matcher<KClass<*>>

171

172

/**

173

* Create matcher for property type validation

174

* @param name Property name

175

* @param type Expected property type

176

* @return Matcher that passes when property has expected type

177

*/

178

fun havePropertyOfType(name: String, type: KClass<*>): Matcher<KClass<*>>

179

```

180

181

### Constructor and Function Validation

182

183

Matchers for validating class constructors and member functions.

184

185

```kotlin { .api }

186

/**

187

* Assert that class has primary constructor with specified parameter count

188

* @param parameterCount Expected number of constructor parameters

189

* @return The original KClass for chaining

190

*/

191

infix fun KClass<*>.shouldHavePrimaryConstructor(parameterCount: Int): KClass<*>

192

193

/**

194

* Assert that class does not have primary constructor

195

* @return The original KClass for chaining

196

*/

197

fun KClass<*>.shouldNotHavePrimaryConstructor(): KClass<*>

198

199

/**

200

* Assert that class has function with specified name

201

* @param name The function name to check for

202

* @return The original KClass for chaining

203

*/

204

infix fun KClass<*>.shouldHaveFunction(name: String): KClass<*>

205

206

/**

207

* Assert that class does not have function with specified name

208

* @param name The function name that should not exist

209

* @return The original KClass for chaining

210

*/

211

infix fun KClass<*>.shouldNotHaveFunction(name: String): KClass<*>

212

213

/**

214

* Assert that class has exactly specified number of member functions

215

* @param count Expected number of functions (excluding inherited)

216

* @return The original KClass for chaining

217

*/

218

infix fun KClass<*>.shouldHaveFunctionCount(count: Int): KClass<*>

219

220

/**

221

* Assert that function has specific parameter types

222

* @param functionName Name of function to validate

223

* @param parameterTypes Expected parameter types in order

224

* @return The original KClass for chaining

225

*/

226

fun KClass<*>.shouldHaveFunctionWithParameters(

227

functionName: String,

228

vararg parameterTypes: KClass<*>

229

): KClass<*>

230

231

/**

232

* Create matcher for primary constructor validation

233

* @param parameterCount Expected parameter count

234

* @return Matcher that passes when class has primary constructor with parameter count

235

*/

236

fun havePrimaryConstructor(parameterCount: Int): Matcher<KClass<*>>

237

238

/**

239

* Create matcher for function existence validation

240

* @param name The function name to check for

241

* @return Matcher that passes when class has the named function

242

*/

243

fun haveFunction(name: String): Matcher<KClass<*>>

244

245

/**

246

* Create matcher for function count validation

247

* @param count Expected number of member functions

248

* @return Matcher that passes when class has exact function count

249

*/

250

fun haveFunctionCount(count: Int): Matcher<KClass<*>>

251

252

/**

253

* Create matcher for function signature validation

254

* @param functionName Name of function

255

* @param parameterTypes Expected parameter types

256

* @return Matcher that passes when function has expected signature

257

*/

258

fun haveFunctionWithParameters(

259

functionName: String,

260

vararg parameterTypes: KClass<*>

261

): Matcher<KClass<*>>

262

```

263

264

**Usage Examples:**

265

266

```kotlin

267

import io.kotest.matchers.reflection.*

268

import kotlin.reflect.KClass

269

270

data class Person(

271

val id: Long,

272

var name: String,

273

val email: String

274

) {

275

fun updateName(newName: String) {

276

name = newName

277

}

278

279

fun isValid(): Boolean = name.isNotEmpty() && email.contains("@")

280

}

281

282

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

283

284

// Property validation

285

personClass shouldHaveProperty "id"

286

personClass shouldHaveProperty "name"

287

personClass shouldHavePropertyCount 3

288

personClass shouldHaveMutableProperty "name"

289

personClass shouldHaveImmutableProperty "id"

290

personClass.shouldHavePropertyOfType("id", Long::class)

291

292

// Constructor validation

293

personClass shouldHavePrimaryConstructor 3

294

295

// Function validation

296

personClass shouldHaveFunction "updateName"

297

personClass shouldHaveFunction "isValid"

298

personClass shouldHaveFunctionCount 2

299

personClass.shouldHaveFunctionWithParameters("updateName", String::class)

300

```

301

302

### Class Type and Inheritance

303

304

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

305

306

```kotlin { .api }

307

/**

308

* Assert that class is abstract

309

* @return The original KClass for chaining

310

*/

311

fun KClass<*>.shouldBeAbstract(): KClass<*>

312

313

/**

314

* Assert that class is not abstract (concrete)

315

* @return The original KClass for chaining

316

*/

317

fun KClass<*>.shouldNotBeAbstract(): KClass<*>

318

319

/**

320

* Assert that class is a data class

321

* @return The original KClass for chaining

322

*/

323

fun KClass<*>.shouldBeDataClass(): KClass<*>

324

325

/**

326

* Assert that class is not a data class

327

* @return The original KClass for chaining

328

*/

329

fun KClass<*>.shouldNotBeDataClass(): KClass<*>

330

331

/**

332

* Assert that class is sealed

333

* @return The original KClass for chaining

334

*/

335

fun KClass<*>.shouldBeSealed(): KClass<*>

336

337

/**

338

* Assert that class is not sealed

339

* @return The original KClass for chaining

340

*/

341

fun KClass<*>.shouldNotBeSealed(): KClass<*>

342

343

/**

344

* Assert that class is an interface

345

* @return The original KClass for chaining

346

*/

347

fun KClass<*>.shouldBeInterface(): KClass<*>

348

349

/**

350

* Assert that class is not an interface

351

* @return The original KClass for chaining

352

*/

353

fun KClass<*>.shouldNotBeInterface(): KClass<*>

354

355

/**

356

* Assert that class is an enum class

357

* @return The original KClass for chaining

358

*/

359

fun KClass<*>.shouldBeEnum(): KClass<*>

360

361

/**

362

* Assert that class is not an enum class

363

* @return The original KClass for chaining

364

*/

365

fun KClass<*>.shouldNotBeEnum(): KClass<*>

366

367

/**

368

* Assert that class is subclass of specified parent class

369

* @param parent The parent class type

370

* @return The original KClass for chaining

371

*/

372

infix fun KClass<*>.shouldBeSubclassOf(parent: KClass<*>): KClass<*>

373

374

/**

375

* Assert that class is not subclass of specified class

376

* @param parent The class that should not be a parent

377

* @return The original KClass for chaining

378

*/

379

infix fun KClass<*>.shouldNotBeSubclassOf(parent: KClass<*>): KClass<*>

380

381

/**

382

* Create matcher for abstract class validation

383

* @return Matcher that passes for abstract classes

384

*/

385

fun beAbstract(): Matcher<KClass<*>>

386

387

/**

388

* Create matcher for data class validation

389

* @return Matcher that passes for data classes

390

*/

391

fun beDataClass(): Matcher<KClass<*>>

392

393

/**

394

* Create matcher for sealed class validation

395

* @return Matcher that passes for sealed classes

396

*/

397

fun beSealed(): Matcher<KClass<*>>

398

399

/**

400

* Create matcher for interface validation

401

* @return Matcher that passes for interfaces

402

*/

403

fun beInterface(): Matcher<KClass<*>>

404

405

/**

406

* Create matcher for enum validation

407

* @return Matcher that passes for enum classes

408

*/

409

fun beEnum(): Matcher<KClass<*>>

410

411

/**

412

* Create matcher for inheritance validation

413

* @param parent The parent class to check inheritance from

414

* @return Matcher that passes when class is subclass of parent

415

*/

416

fun beSubclassOf(parent: KClass<*>): Matcher<KClass<*>>

417

```

418

419

### Member Visibility and Modifiers

420

421

Matchers for validating member visibility and modifier characteristics.

422

423

```kotlin { .api }

424

/**

425

* Assert that class has public member with specified name

426

* @param memberName Name of member to check visibility for

427

* @return The original KClass for chaining

428

*/

429

infix fun KClass<*>.shouldHavePublicMember(memberName: String): KClass<*>

430

431

/**

432

* Assert that class has private member with specified name

433

* @param memberName Name of member to check visibility for

434

* @return The original KClass for chaining

435

*/

436

infix fun KClass<*>.shouldHavePrivateMember(memberName: String): KClass<*>

437

438

/**

439

* Assert that class has protected member with specified name

440

* @param memberName Name of member to check visibility for

441

* @return The original KClass for chaining

442

*/

443

infix fun KClass<*>.shouldHaveProtectedMember(memberName: String): KClass<*>

444

445

/**

446

* Assert that class has internal member with specified name

447

* @param memberName Name of member to check visibility for

448

* @return The original KClass for chaining

449

*/

450

infix fun KClass<*>.shouldHaveInternalMember(memberName: String): KClass<*>

451

452

/**

453

* Assert that function is suspend function

454

* @param functionName Name of function to check

455

* @return The original KClass for chaining

456

*/

457

infix fun KClass<*>.shouldHaveSuspendFunction(functionName: String): KClass<*>

458

459

/**

460

* Assert that function is inline function

461

* @param functionName Name of function to check

462

* @return The original KClass for chaining

463

*/

464

infix fun KClass<*>.shouldHaveInlineFunction(functionName: String): KClass<*>

465

466

/**

467

* Create matcher for public member validation

468

* @param memberName Name of member to check

469

* @return Matcher that passes when member is public

470

*/

471

fun havePublicMember(memberName: String): Matcher<KClass<*>>

472

473

/**

474

* Create matcher for private member validation

475

* @param memberName Name of member to check

476

* @return Matcher that passes when member is private

477

*/

478

fun havePrivateMember(memberName: String): Matcher<KClass<*>>

479

480

/**

481

* Create matcher for suspend function validation

482

* @param functionName Name of function to check

483

* @return Matcher that passes when function is suspend

484

*/

485

fun haveSuspendFunction(functionName: String): Matcher<KClass<*>>

486

```

487

488

**Usage Examples:**

489

490

```kotlin

491

import io.kotest.matchers.reflection.*

492

493

abstract class Shape {

494

abstract fun area(): Double

495

}

496

497

data class Circle(val radius: Double) : Shape() {

498

override fun area(): Double = Math.PI * radius * radius

499

}

500

501

interface Drawable {

502

fun draw()

503

}

504

505

enum class Color { RED, GREEN, BLUE }

506

507

sealed class Result<out T> {

508

data class Success<T>(val value: T) : Result<T>()

509

data class Error(val message: String) : Result<Nothing>()

510

}

511

512

// Class type validation

513

Shape::class.shouldBeAbstract()

514

Circle::class.shouldBeDataClass()

515

Circle::class shouldBeSubclassOf Shape::class

516

Drawable::class.shouldBeInterface()

517

Color::class.shouldBeEnum()

518

Result::class.shouldBeSealed()

519

520

// Using matcher syntax

521

Shape::class should beAbstract()

522

Circle::class should beDataClass()

523

Circle::class should beSubclassOf(Shape::class)

524

Drawable::class should beInterface()

525

```

526

527

### Generic Type Validation

528

529

Matchers for validating generic types and type parameters.

530

531

```kotlin { .api }

532

/**

533

* Assert that class has specified number of type parameters

534

* @param count Expected number of type parameters

535

* @return The original KClass for chaining

536

*/

537

infix fun KClass<*>.shouldHaveTypeParameterCount(count: Int): KClass<*>

538

539

/**

540

* Assert that class does not have type parameters (non-generic)

541

* @return The original KClass for chaining

542

*/

543

fun KClass<*>.shouldNotBeGeneric(): KClass<*>

544

545

/**

546

* Assert that class is generic (has type parameters)

547

* @return The original KClass for chaining

548

*/

549

fun KClass<*>.shouldBeGeneric(): KClass<*>

550

551

/**

552

* Create matcher for type parameter count validation

553

* @param count Expected number of type parameters

554

* @return Matcher that passes when class has expected type parameter count

555

*/

556

fun haveTypeParameterCount(count: Int): Matcher<KClass<*>>

557

558

/**

559

* Create matcher for generic class validation

560

* @return Matcher that passes for generic classes

561

*/

562

fun beGeneric(): Matcher<KClass<*>>

563

```

564

565

**Usage Examples:**

566

567

```kotlin

568

import io.kotest.matchers.reflection.*

569

570

class Container<T> {

571

var item: T? = null

572

}

573

574

class Repository<K, V> {

575

private val storage = mutableMapOf<K, V>()

576

}

577

578

class SimpleClass {

579

val value: String = ""

580

}

581

582

// Generic type validation

583

Container::class.shouldBeGeneric()

584

Container::class shouldHaveTypeParameterCount 1

585

Repository::class shouldHaveTypeParameterCount 2

586

SimpleClass::class.shouldNotBeGeneric()

587

588

// Using matcher syntax

589

Container::class should beGeneric()

590

Repository::class should haveTypeParameterCount(2)

591

```

592

593

## Error Handling

594

595

Reflection matchers provide detailed error information for assertion failures:

596

597

- **Annotation failures**: Show expected vs actual annotations with full annotation details

598

- **Property failures**: List all available properties when expected property is missing

599

- **Type failures**: Clear indication of expected vs actual class types and inheritance relationships

600

- **Visibility failures**: Specific information about member visibility and access modifiers

601

- **Generic failures**: Details about type parameters and generic constraints

602

- **Signature failures**: Complete function signatures with parameter types and return types

603

604

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.