-
Notifications
You must be signed in to change notification settings - Fork 642
/
GradlePostDiscoveryFilterExtractor.kt
75 lines (60 loc) · 2.82 KB
/
GradlePostDiscoveryFilterExtractor.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package io.kotest.runner.junit.platform.gradle
import io.kotest.mpp.Logger
import org.junit.platform.launcher.PostDiscoveryFilter
import java.util.regex.Pattern
/**
* JUnit has this concept of 'PostDiscoveryFilter's which can be applied after test discovery.
* Gradle implements --tests Foo.mytest by passing a ClassMethodNameFilter which is an implementation
* of PostDiscoveryFilter.
*
* But ClassMethodNameFilter, as the name implies, only handles clases and methods.
* Kotest is more advanced, and JUnit5 Platform allows for hierarchical tests, so this is a limitation
* of Gradle not implementing the spec fully.
*
* Since ClassMethodNameFilter is private, we can't get access to the underlying patterns, so we resort
* to this reflection bullshit to get the raw strings out, so we can parse and apply the patterns ourselves,
* thus allowing kotest to properly support the --tests options.
*
*/
object GradlePostDiscoveryFilterExtractor {
private val logger = Logger(GradlePostDiscoveryFilterExtractor::class)
fun extract(filters: List<PostDiscoveryFilter>): List<String> {
val classMethodFilters = filters.filter { it.javaClass.simpleName == "ClassMethodNameFilter" }
return classMethodFilters.flatMap { extract(it) }
}
private fun extract(filter: Any): List<String> = runCatching {
val matcher = testMatcher(filter)
logger.log { Pair(null, "TestMatcher [$matcher]") }
val buildScriptIncludePatterns = buildScriptIncludePatterns(matcher)
logger.log { Pair(null, "buildScriptIncludePatterns [$buildScriptIncludePatterns]") }
val commandLineIncludePatterns = commandLineIncludePatterns(matcher)
logger.log { Pair(null, "commandLineIncludePatterns [$commandLineIncludePatterns]") }
val regexes = buildList {
addAll(buildScriptIncludePatterns)
addAll(commandLineIncludePatterns)
}.map { pattern(it) }
logger.log { Pair(null, "ClassMethodNameFilter regexes [$regexes]") }
regexes
}.getOrElse { emptyList() }
private fun testMatcher(obj: Any): Any {
val field = obj::class.java.getDeclaredField("matcher")
field.isAccessible = true
return field.get(obj)
}
private fun commandLineIncludePatterns(obj: Any): List<Any> {
val field = obj::class.java.getDeclaredField("commandLineIncludePatterns")
field.isAccessible = true
return field.get(obj) as List<Any>
}
private fun buildScriptIncludePatterns(obj: Any): List<Any> {
val field = obj::class.java.getDeclaredField("buildScriptIncludePatterns")
field.isAccessible = true
return field.get(obj) as List<Any>
}
private fun pattern(obj: Any): String {
val field = obj::class.java.getDeclaredField("pattern")
field.isAccessible = true
val pattern: Pattern = field.get(obj) as Pattern
return pattern.pattern()
}
}