aboutsummaryrefslogtreecommitdiff
path: root/plugins/base/src/test/kotlin/utils
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/base/src/test/kotlin/utils')
-rw-r--r--plugins/base/src/test/kotlin/utils/JsoupUtils.kt29
-rw-r--r--plugins/base/src/test/kotlin/utils/ModelUtils.kt37
-rw-r--r--plugins/base/src/test/kotlin/utils/TestUtils.kt79
-rw-r--r--plugins/base/src/test/kotlin/utils/contentUtils.kt243
4 files changed, 388 insertions, 0 deletions
diff --git a/plugins/base/src/test/kotlin/utils/JsoupUtils.kt b/plugins/base/src/test/kotlin/utils/JsoupUtils.kt
new file mode 100644
index 00000000..e8c7838d
--- /dev/null
+++ b/plugins/base/src/test/kotlin/utils/JsoupUtils.kt
@@ -0,0 +1,29 @@
+package utils
+
+import org.jsoup.nodes.Element
+import org.jsoup.nodes.Node
+import org.jsoup.nodes.TextNode
+
+fun Element.match(vararg matchers: Any): Unit =
+ childNodes()
+ .filter { it !is TextNode || it.text().isNotBlank() }
+ .let { it.drop(it.size - matchers.size) }
+ .zip(matchers)
+ .forEach { (n, m) -> m.accepts(n) }
+
+open class Tag(val name: String, vararg val matchers: Any)
+class Div(vararg matchers: Any) : Tag("div", *matchers)
+class P(vararg matchers: Any) : Tag("p", *matchers)
+class Span(vararg matchers: Any) : Tag("span", *matchers)
+class A(vararg matchers: Any) : Tag("a", *matchers)
+object Wbr : Tag("wbr")
+private fun Any.accepts(n: Node) {
+ when (this) {
+ is String -> assert(n is TextNode && n.text().trim() == this.trim()) { "\"$this\" expected but found: $n" }
+ is Tag -> {
+ assert(n is Element && n.tagName() == name) { "Tag $name expected but found: $n" }
+ if (n is Element && matchers.isNotEmpty()) n.match(*matchers)
+ }
+ else -> throw IllegalArgumentException("$this is not proper matcher")
+ }
+} \ No newline at end of file
diff --git a/plugins/base/src/test/kotlin/utils/ModelUtils.kt b/plugins/base/src/test/kotlin/utils/ModelUtils.kt
new file mode 100644
index 00000000..87a9c802
--- /dev/null
+++ b/plugins/base/src/test/kotlin/utils/ModelUtils.kt
@@ -0,0 +1,37 @@
+package utils
+
+import org.jetbrains.dokka.DokkaConfigurationImpl
+import org.jetbrains.dokka.model.DModule
+import org.jetbrains.dokka.plugability.DokkaPlugin
+
+abstract class AbstractModelTest(val path: String? = null, val pkg: String) : ModelDSL(), AssertDSL {
+
+ fun inlineModelTest(
+ query: String,
+ platform: String = "jvm",
+ prependPackage: Boolean = true,
+ cleanupOutput: Boolean = true,
+ pluginsOverrides: List<DokkaPlugin> = emptyList(),
+ configuration: DokkaConfigurationImpl? = null,
+ block: DModule.() -> Unit
+ ) {
+ val testConfiguration = configuration ?: dokkaConfiguration {
+ sourceSets {
+ sourceSet {
+ sourceRoots = listOf("src/")
+ analysisPlatform = platform
+ }
+ }
+ }
+ val prepend = path.let { p -> p?.let { "|$it\n" } ?: "" } + if (prependPackage) "|package $pkg" else ""
+
+ testInline(
+ query = ("$prepend\n$query").trim().trimIndent(),
+ configuration = testConfiguration,
+ cleanupOutput = cleanupOutput,
+ pluginOverrides = pluginsOverrides
+ ) {
+ documentablesTransformationStage = block
+ }
+ }
+}
diff --git a/plugins/base/src/test/kotlin/utils/TestUtils.kt b/plugins/base/src/test/kotlin/utils/TestUtils.kt
new file mode 100644
index 00000000..bd0e1fe2
--- /dev/null
+++ b/plugins/base/src/test/kotlin/utils/TestUtils.kt
@@ -0,0 +1,79 @@
+package utils
+
+import org.jetbrains.dokka.model.*
+import org.jetbrains.dokka.model.doc.*
+import org.jetbrains.dokka.model.doc.P
+import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest
+import org.junit.jupiter.api.Assertions.assertTrue
+import kotlin.collections.orEmpty
+
+@DslMarker
+annotation class TestDSL
+
+@TestDSL
+abstract class ModelDSL : AbstractCoreTest() {
+ operator fun Documentable?.div(name: String): Documentable? =
+ this?.children?.find { it.name == name }
+
+ inline fun <reified T : Documentable> Documentable?.cast(): T =
+ (this as? T).assertNotNull()
+}
+
+@TestDSL
+interface AssertDSL {
+ infix fun Any?.equals(other: Any?) = this.assertEqual(other)
+ infix fun Collection<Any>?.allEquals(other: Any?) =
+ this?.also { c -> c.forEach { it equals other } } ?: run { assert(false) { "Collection is empty" } }
+ infix fun <T> Collection<T>?.exists(e: T) {
+ assertTrue(this.orEmpty().isNotEmpty(), "Collection cannot be null or empty")
+ assertTrue(this!!.any{it == e}, "Collection doesn't contain $e")
+ }
+
+ infix fun <T> Collection<T>?.counts(n: Int) = this.orEmpty().assertCount(n)
+
+ infix fun <T> T?.notNull(name: String): T = this.assertNotNull(name)
+
+ fun <T> Collection<T>.assertCount(n: Int, prefix: String = "") =
+ assert(count() == n) { "${prefix}Expected $n, got ${count()}" }
+
+ fun <T> T?.assertEqual(expected: T, prefix: String = "") = assert(this == expected) {
+ "${prefix}Expected $expected, got $this"
+ }
+}
+
+inline fun <reified T : Any> Any?.assertIsInstance(name: String): T =
+ this.let { it as? T } ?: throw AssertionError("$name should not be null")
+
+fun TagWrapper.text(): String = when (val t = this) {
+ is NamedTagWrapper -> "${t.name}: [${t.root.text()}]"
+ else -> t.root.text()
+}
+
+fun DocTag.text(): String = when (val t = this) {
+ is Text -> t.body
+ is Code -> t.children.joinToString("\n") { it.text() }
+ is P -> t.children.joinToString(separator = "\n") { it.text() }
+ else -> t.toString()
+}
+
+fun <T : Documentable> T?.comments(): String = docs().map { it.text() }
+ .joinToString(separator = "\n") { it }
+
+fun <T> T?.assertNotNull(name: String = ""): T = this ?: throw AssertionError("$name should not be null")
+
+fun <T : Documentable> T?.docs() = this?.documentation.orEmpty().values.flatMap { it.children }
+
+val DClass.supers
+ get() = supertypes.flatMap { it.component2() }
+
+val Bound.name: String?
+ get() = when (this) {
+ is Nullable -> inner.name
+ is OtherParameter -> name
+ is PrimitiveJavaType -> name
+ is TypeConstructor -> dri.classNames
+ is JavaObject -> "Object"
+ is Void -> "void"
+ is Dynamic -> "dynamic"
+ is UnresolvedBound -> "<ERROR CLASS>"
+ } \ No newline at end of file
diff --git a/plugins/base/src/test/kotlin/utils/contentUtils.kt b/plugins/base/src/test/kotlin/utils/contentUtils.kt
new file mode 100644
index 00000000..7fcd8e89
--- /dev/null
+++ b/plugins/base/src/test/kotlin/utils/contentUtils.kt
@@ -0,0 +1,243 @@
+package utils
+
+import matchers.content.*
+import org.jetbrains.dokka.model.*
+import org.jetbrains.dokka.pages.ContentGroup
+import kotlin.text.Typography.nbsp
+
+//TODO: Try to unify those functions after update to 1.4
+fun ContentMatcherBuilder<*>.functionSignature(
+ annotations: Map<String, Set<String>>,
+ visibility: String,
+ modifier: String,
+ keywords: Set<String>,
+ name: String,
+ returnType: String? = null,
+ vararg params: Pair<String, ParamAttributes>
+) =
+ platformHinted {
+ bareSignature(annotations, visibility, modifier, keywords, name, returnType, *params)
+ }
+
+fun ContentMatcherBuilder<*>.bareSignature(
+ annotations: Map<String, Set<String>>,
+ visibility: String,
+ modifier: String,
+ keywords: Set<String>,
+ name: String,
+ returnType: String? = null,
+ vararg params: Pair<String, ParamAttributes>
+) = group {
+ annotations.entries.forEach {
+ group {
+ unwrapAnnotation(it)
+ }
+ }
+ +("$visibility $modifier ${keywords.joinToString("") { "$it " }} fun")
+ link { +name }
+ +"("
+ params.forEachIndexed { id, (n, t) ->
+
+ t.annotations.forEach {
+ unwrapAnnotation(it)
+ }
+ t.keywords.forEach {
+ +it
+ }
+
+ +"$n:"
+ group { link { +(t.type) } }
+ if (id != params.lastIndex)
+ +", "
+ }
+ +")"
+ if (returnType != null) {
+ +(": ")
+ group {
+ link {
+ +(returnType)
+ }
+ }
+ }
+}
+
+fun ContentMatcherBuilder<*>.functionSignatureWithReceiver(
+ annotations: Map<String, Set<String>>,
+ visibility: String?,
+ modifier: String?,
+ keywords: Set<String>,
+ receiver: String,
+ name: String,
+ returnType: String? = null,
+ vararg params: Pair<String, ParamAttributes>
+) =
+ platformHinted {
+ bareSignatureWithReceiver(annotations, visibility, modifier, keywords, receiver, name, returnType, *params)
+ }
+
+fun ContentMatcherBuilder<*>.bareSignatureWithReceiver(
+ annotations: Map<String, Set<String>>,
+ visibility: String?,
+ modifier: String?,
+ keywords: Set<String>,
+ receiver: String,
+ name: String,
+ returnType: String? = null,
+ vararg params: Pair<String, ParamAttributes>
+) = group { // TODO: remove it when double wrapping for signatures will be resolved
+ annotations.entries.forEach {
+ group {
+ unwrapAnnotation(it)
+ }
+ }
+ +("$visibility $modifier ${keywords.joinToString("") { "$it " }} fun")
+ group {
+ link { +receiver }
+ }
+ +"."
+ link { +name }
+ +"("
+ params.forEachIndexed { id, (n, t) ->
+
+ t.annotations.forEach {
+ unwrapAnnotation(it)
+ }
+ t.keywords.forEach {
+ +it
+ }
+
+ +"$n:"
+ group { link { +(t.type) } }
+ if (id != params.lastIndex)
+ +", "
+ }
+ +")"
+ if (returnType != null) {
+ +(": ")
+ group {
+ link {
+ +(returnType)
+ }
+ }
+ }
+}
+
+fun ContentMatcherBuilder<*>.propertySignature(
+ annotations: Map<String, Set<String>>,
+ visibility: String,
+ modifier: String,
+ keywords: Set<String>,
+ preposition: String,
+ name: String,
+ type: String? = null
+) {
+ group {
+ header { +"Package test" }
+ skipAllNotMatching()
+ }
+ group {
+ group {
+ skipAllNotMatching()
+ header { +"Properties" }
+ table {
+ group {
+ link { +name }
+ platformHinted {
+ group {
+ annotations.entries.forEach {
+ group {
+ unwrapAnnotation(it)
+ }
+ }
+ +("$visibility $modifier ${keywords.joinToString("") { "$it " }} $preposition")
+ link { +name }
+ if (type != null) {
+ +(": ")
+ group {
+ link {
+ +(type)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+fun ContentMatcherBuilder<*>.typealiasSignature(name: String, expressionTarget: String) {
+ group {
+ header { +"Package test" }
+ skipAllNotMatching()
+ }
+ group {
+ group {
+ skipAllNotMatching()
+ header { +"Types" }
+ table {
+ group {
+ link { +name }
+ divergentGroup {
+ divergentInstance {
+ group {
+ group {
+ group {
+ group {
+ +"typealias "
+ group {
+ link { +name }
+ skipAllNotMatching()
+ }
+ +" = "
+ group {
+ link { +expressionTarget }
+ }
+ }
+ }
+ }
+ }
+ }
+ skipAllNotMatching()
+ }
+ }
+ skipAllNotMatching()
+ }
+ skipAllNotMatching()
+ }
+ }
+}
+
+fun ContentMatcherBuilder<*>.pWrapped(text: String) =
+ group {// TODO: remove it when double wrapping for descriptions will be resolved
+ group { +text }
+ }
+
+fun ContentMatcherBuilder<*>.unnamedTag(tag: String, content: ContentMatcherBuilder<ContentGroup>.() -> Unit) =
+ group {
+ header(4) { +tag }
+ group { content() }
+ }
+
+fun ContentMatcherBuilder<*>.unwrapAnnotation(elem: Map.Entry<String, Set<String>>) {
+ group {
+ +"@"
+ link { +elem.key }
+ +"("
+ elem.value.forEach {
+ group {
+ +("$it = ")
+ skipAllNotMatching()
+ }
+ }
+ +")"
+ }
+}
+
+data class ParamAttributes(
+ val annotations: Map<String, Set<String>>,
+ val keywords: Set<String>,
+ val type: String
+)