Created
August 6, 2025 15:34
-
-
Save Kritarie/681b1f95f6616b1b44b695bfed63c1a8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| annotation class Exhaustive( | |
| val sealedType: KClass<*>, | |
| ) | |
| @Repeatable | |
| annotation class ExhaustiveCase( | |
| val sealedType: KClass<*>, | |
| val test: KClass<*>, | |
| ) | |
| class ExhaustiveTestRunner(testClass: Class<*>) : Suite(testClass, getTests(testClass)) { | |
| companion object { | |
| private fun getTests(testClass: Class<*>): Array<Class<*>> { | |
| check(testClass.isAnnotationPresent(Exhaustive::class.java)) { | |
| "ExhaustiveTestRunner's test class must be annotated with @Exhaustive" | |
| } | |
| val exhaustive = testClass.getAnnotation(Exhaustive::class.java)!! | |
| val sealedType = exhaustive.sealedType | |
| check(sealedType.isSealed) { | |
| "@Exhaustive class parameter must represent a sealed type" | |
| } | |
| val cases = testClass.getAnnotationsByType(ExhaustiveCase::class.java) | |
| check(cases.contentEquals(cases.sortedBy { it.sealedType.simpleName }.toTypedArray())) { | |
| "ExhaustiveCase must be in alphabetical order" | |
| } | |
| check(cases.contentEquals(cases.distinctBy { it.sealedType }.toTypedArray())) { | |
| "ExhaustiveCase must be distinct by key" | |
| } | |
| check(cases.contentEquals(cases.distinctBy { it.test }.toTypedArray())) { | |
| "ExhaustiveCase must be distinct by value" | |
| } | |
| val testLookup = cases.associate { it.sealedType to it.test } | |
| testLookup.keys.forEach { key -> | |
| check(key.isSubclassOf(sealedType)) { | |
| "Expected ExhaustiveCase key to be a subtype of $sealedType" | |
| } | |
| } | |
| return sealedType.sealedSubclasses | |
| .map { sealedSubclass -> | |
| checkNotNull(testLookup[sealedSubclass]) { | |
| "Missing required exhaustive case for type $sealedSubclass" | |
| } | |
| } | |
| .map(KClass<*>::java) | |
| .toTypedArray() | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment