From 2ab810271d2b2dba7448a8cb2b53f0031e6ef40e Mon Sep 17 00:00:00 2001 From: Andrzej Ratajczak Date: Fri, 3 Jul 2020 16:52:56 +0200 Subject: Add tests for signatures rendering --- .../test/kotlin/renderers/html/DivergentTest.kt | 3 + .../kotlin/renderers/html/GroupWrappingTest.kt | 3 + .../renderers/html/HtmlRenderingOnlyTestBase.kt | 5 - .../renderers/html/SourceSetDependentHintTest.kt | 3 + .../kotlin/signatures/DivergentSignatureTest.kt | 122 +++++++ .../src/test/kotlin/signatures/SignatureTest.kt | 379 +++++++++++++++++++++ plugins/base/src/test/kotlin/utils/JsoupUtils.kt | 29 ++ plugins/base/src/test/kotlin/utils/TestUtils.kt | 1 + 8 files changed, 540 insertions(+), 5 deletions(-) create mode 100644 plugins/base/src/test/kotlin/signatures/DivergentSignatureTest.kt create mode 100644 plugins/base/src/test/kotlin/signatures/SignatureTest.kt create mode 100644 plugins/base/src/test/kotlin/utils/JsoupUtils.kt (limited to 'plugins/base/src/test/kotlin') diff --git a/plugins/base/src/test/kotlin/renderers/html/DivergentTest.kt b/plugins/base/src/test/kotlin/renderers/html/DivergentTest.kt index f5565b48..54d55721 100644 --- a/plugins/base/src/test/kotlin/renderers/html/DivergentTest.kt +++ b/plugins/base/src/test/kotlin/renderers/html/DivergentTest.kt @@ -7,6 +7,9 @@ import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.pages.ContentDivergentGroup import org.junit.jupiter.api.Test import renderers.* +import utils.Div +import utils.Span +import utils.match class DivergentTest : HtmlRenderingOnlyTestBase() { private val js = defaultSourceSet.copy( diff --git a/plugins/base/src/test/kotlin/renderers/html/GroupWrappingTest.kt b/plugins/base/src/test/kotlin/renderers/html/GroupWrappingTest.kt index 59150e18..c0c03998 100644 --- a/plugins/base/src/test/kotlin/renderers/html/GroupWrappingTest.kt +++ b/plugins/base/src/test/kotlin/renderers/html/GroupWrappingTest.kt @@ -4,6 +4,9 @@ import org.jetbrains.dokka.base.renderers.html.HtmlRenderer import org.jetbrains.dokka.pages.TextStyle import org.junit.jupiter.api.Test import renderers.* +import utils.Div +import utils.P +import utils.match class GroupWrappingTest : HtmlRenderingOnlyTestBase() { diff --git a/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt b/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt index f93eccb5..5ac5aafa 100644 --- a/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt +++ b/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt @@ -1,16 +1,11 @@ package renderers.html -import org.jetbrains.dokka.DokkaConfiguration import org.jetbrains.dokka.DokkaConfigurationImpl import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.base.renderers.RootCreator import org.jetbrains.dokka.base.resolvers.external.DokkaExternalLocationProviderFactory import org.jetbrains.dokka.base.resolvers.external.JavadocExternalLocationProviderFactory import org.jetbrains.dokka.base.resolvers.local.DefaultLocationProviderFactory -import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter -import org.jetbrains.dokka.model.doc.DocTag -import org.jetbrains.dokka.model.properties.PropertyContainer -import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.testApi.context.MockContext import org.jsoup.Jsoup import org.jsoup.nodes.Element diff --git a/plugins/base/src/test/kotlin/renderers/html/SourceSetDependentHintTest.kt b/plugins/base/src/test/kotlin/renderers/html/SourceSetDependentHintTest.kt index 87c67842..cf7f47e6 100644 --- a/plugins/base/src/test/kotlin/renderers/html/SourceSetDependentHintTest.kt +++ b/plugins/base/src/test/kotlin/renderers/html/SourceSetDependentHintTest.kt @@ -7,6 +7,9 @@ import org.jetbrains.dokka.pages.TextStyle import org.junit.jupiter.api.Test import renderers.TestPage import renderers.defaultSourceSet +import renderers.RenderingOnlyTestBase +import utils.Div +import utils.match class SourceSetDependentHintTest : HtmlRenderingOnlyTestBase() { diff --git a/plugins/base/src/test/kotlin/signatures/DivergentSignatureTest.kt b/plugins/base/src/test/kotlin/signatures/DivergentSignatureTest.kt new file mode 100644 index 00000000..6ed17110 --- /dev/null +++ b/plugins/base/src/test/kotlin/signatures/DivergentSignatureTest.kt @@ -0,0 +1,122 @@ +package signatures + +import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest +import org.jsoup.Jsoup +import org.junit.jupiter.api.Test +import utils.* +import java.nio.file.Paths + +class DivergentSignatureTest : AbstractCoreTest() { + + @Test + fun `three divergent signatures for class`() { + + val testDataDir = getTestDataDir("multiplatform/basicMultiplatformTest").toAbsolutePath() + + + val configuration = dokkaConfiguration { + passes { + pass { + moduleName = "example" + analysisPlatform = "js" + sourceRoots = listOf("jsMain", "commonMain", "jvmAndJsSecondCommonMain").map { + Paths.get("$testDataDir/$it/kotlin").toString() + } + sourceSetID = "js" + } + pass { + moduleName = "example" + analysisPlatform = "jvm" + sourceRoots = listOf("jvmMain", "commonMain", "jvmAndJsSecondCommonMain").map { + Paths.get("$testDataDir/$it/kotlin").toString() + } + sourceSetID = "jvm" + } + pass { + moduleName = "example" + analysisPlatform = "common" + sourceRoots = listOf("jvmMain", "commonMain", "jvmAndJsSecondCommonMain").map { + Paths.get("$testDataDir/$it/kotlin").toString() + } + sourceSetID = "jvm" + } + } + } + + val writerPlugin = TestOutputWriterPlugin() + + testFromData( + configuration, + pluginOverrides = listOf(writerPlugin) + ) { + renderingStage = { _, _ -> + assert(writerPlugin.writer.contents.getValue("example/example/-clock/index.html") + .let { Jsoup.parse(it) }.select("#content").single() + .select("div.sourceset-depenent-content") + .fold(0) { acc, elem -> + acc + if (elem.child(0).html().contains( + Regex("Documentation for (expected|actual) class Clock .*") + ) + ) 1 else 0 + } == 3 + ) + } + } + } + + @Test + fun `three divergent signatures for class`() { + + val testDataDir = getTestDataDir("multiplatform/basicMultiplatformTest").toAbsolutePath() + + + val configuration = dokkaConfiguration { + passes { + pass { + moduleName = "example" + analysisPlatform = "js" + sourceRoots = listOf("jsMain", "commonMain", "jvmAndJsSecondCommonMain").map { + Paths.get("$testDataDir/$it/kotlin").toString() + } + sourceSetID = "js" + } + pass { + moduleName = "example" + analysisPlatform = "jvm" + sourceRoots = listOf("jvmMain", "commonMain", "jvmAndJsSecondCommonMain").map { + Paths.get("$testDataDir/$it/kotlin").toString() + } + sourceSetID = "jvm" + } + pass { + moduleName = "example" + analysisPlatform = "common" + sourceRoots = listOf("jvmMain", "commonMain", "jvmAndJsSecondCommonMain").map { + Paths.get("$testDataDir/$it/kotlin").toString() + } + sourceSetID = "jvm" + } + } + } + + val writerPlugin = TestOutputWriterPlugin() + + testFromData( + configuration, + pluginOverrides = listOf(writerPlugin) + ) { + renderingStage = { _, _ -> + assert(writerPlugin.writer.contents.getValue("example/example/-clock/index.html") + .let { Jsoup.parse(it) }.select("#content").single() + .select("div.sourceset-depenent-content") + .fold(0) { acc, elem -> + acc + if (elem.child(0).html().contains( + Regex("Documentation for (expected|actual) class Clock .*") + ) + ) 1 else 0 + } == 3 + ) + } + } + } +} \ No newline at end of file diff --git a/plugins/base/src/test/kotlin/signatures/SignatureTest.kt b/plugins/base/src/test/kotlin/signatures/SignatureTest.kt new file mode 100644 index 00000000..fbdebfa2 --- /dev/null +++ b/plugins/base/src/test/kotlin/signatures/SignatureTest.kt @@ -0,0 +1,379 @@ +package signatures + +import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest +import org.jsoup.Jsoup +import org.junit.jupiter.api.Test +import utils.* + +class SignatureTest : AbstractCoreTest() { + + fun source(signature: String) = + """ + |/src/main/kotlin/test/Test.kt + |package example + | + | $signature + """.trimIndent() + + @Test + fun `fun`() { + + val configuration = dokkaConfiguration { + passes { + pass { + sourceRoots = listOf("src/main/kotlin/test/Test.kt") + } + } + } + + val source = source("fun simpleFun(): String = \"Celebrimbor\"") + val writerPlugin = TestOutputWriterPlugin() + + testInline( + source, + configuration, + pluginOverrides = listOf(writerPlugin) + ) { + renderingStage = { _, _ -> + writerPlugin.writer.renderedContent("root/example/simple-fun.html").match( + "fun ", A("simpleFun"), "(): ", A("String"), Span() + ) + } + } + } + + @Test + fun `open fun`() { + + val configuration = dokkaConfiguration { + passes { + pass { + sourceRoots = listOf("src/main/kotlin/test/Test.kt") + } + } + } + + val source = source("open fun simpleFun(): String = \"Celebrimbor\"") + val writerPlugin = TestOutputWriterPlugin() + + testInline( + source, + configuration, + pluginOverrides = listOf(writerPlugin) + ) { + renderingStage = { _, _ -> + writerPlugin.writer.renderedContent("root/example/simple-fun.html").match( + "open fun ", A("simpleFun"), "(): ", A("String"), Span() + ) + } + } + } + + @Test + fun `open suspend fun`() { + + val configuration = dokkaConfiguration { + passes { + pass { + sourceRoots = listOf("src/main/kotlin/test/Test.kt") + } + } + } + + val source = source("open suspend fun simpleFun(): String = \"Celebrimbor\"") + val writerPlugin = TestOutputWriterPlugin() + + testInline( + source, + configuration, + pluginOverrides = listOf(writerPlugin) + ) { + renderingStage = { _, _ -> + writerPlugin.writer.renderedContent("root/example/simple-fun.html").match( + "open suspend fun ", A("simpleFun"), "(): ", A("String"), Span() + ) + } + } + } + + @Test + fun `fun with params`() { + + val configuration = dokkaConfiguration { + passes { + pass { + sourceRoots = listOf("src/main/kotlin/test/Test.kt") + } + } + } + + val source = source("fun simpleFun(a: Int, b: Boolean, c: Any): String = \"Celebrimbor\"") + val writerPlugin = TestOutputWriterPlugin() + + testInline( + source, + configuration, + pluginOverrides = listOf(writerPlugin) + ) { + renderingStage = { _, _ -> + writerPlugin.writer.renderedContent("root/example/simple-fun.html").match( + "fun ", A("simpleFun"), "(a: ", A("Int"), + ", b: ", A("Boolean"), ", c: ", A("Any"), + "): ", A("String"), Span() + ) + } + } + } + + @Test + fun `fun with function param`() { + + val configuration = dokkaConfiguration { + passes { + pass { + sourceRoots = listOf("src/main/kotlin/test/Test.kt") + } + } + } + + val source = source("fun simpleFun(a: (Int) -> String): String = \"Celebrimbor\"") + val writerPlugin = TestOutputWriterPlugin() + + testInline( + source, + configuration, + pluginOverrides = listOf(writerPlugin) + ) { + renderingStage = { _, _ -> + writerPlugin.writer.renderedContent("root/example/simple-fun.html").match( + "fun ", A("simpleFun"), "(a: (", A("Int"), + ") -> ", A("String"), "): ", A("String"), Span() + ) + } + } + } + + @Test + fun `fun with generic param`() { + + val configuration = dokkaConfiguration { + passes { + pass { + sourceRoots = listOf("src/main/kotlin/test/Test.kt") + } + } + } + + val source = source("fun simpleFun(): T = \"Celebrimbor\" as T") + val writerPlugin = TestOutputWriterPlugin() + + testInline( + source, + configuration, + pluginOverrides = listOf(writerPlugin) + ) { + renderingStage = { _, _ -> + writerPlugin.writer.renderedContent("root/example/simple-fun.html").match( + "fun <", A("T"), " : ", A("Any"), "?> ", A("simpleFun"), "(): ", + A("T"), Span() + ) + } + } + } + + @Test + fun `fun with generic bounded param`() { + + val configuration = dokkaConfiguration { + passes { + pass { + sourceRoots = listOf("src/main/kotlin/test/Test.kt") + } + } + } + + val source = source("fun simpleFun(): T = \"Celebrimbor\" as T") + val writerPlugin = TestOutputWriterPlugin() + + testInline( + source, + configuration, + pluginOverrides = listOf(writerPlugin) + ) { + renderingStage = { _, _ -> + writerPlugin.writer.renderedContent("root/example/simple-fun.html").match( + "fun <", A("T"), " : ", A("String"), "> ", A("simpleFun"), + "(): ", A("T"), Span() + ) + } + } + } + + @Test + fun `fun with keywords, params and generic bound`() { + + val configuration = dokkaConfiguration { + passes { + pass { + sourceRoots = listOf("src/main/kotlin/test/Test.kt") + } + } + } + + val source = source("inline suspend fun simpleFun(a: Int, b: String): T = \"Celebrimbor\" as T") + val writerPlugin = TestOutputWriterPlugin() + + testInline( + source, + configuration, + pluginOverrides = listOf(writerPlugin) + ) { + renderingStage = { _, _ -> + writerPlugin.writer.renderedContent("root/example/simple-fun.html").match( + "inline suspend fun <", A("T"), " : ", A("String"), "> ", A("simpleFun"), + "(a: ", A("Int"), ", b: ", A("String"), "): ", A("T"), Span() + ) + } + } + } + + + @Test + fun `fun with annotation`() { + + val configuration = dokkaConfiguration { + passes { + pass { + sourceRoots = listOf("src/main/kotlin/test/Test.kt") + } + } + } + + val source = """ + |/src/main/kotlin/test/Test.kt + |package example + | + | @MustBeDocumented() + | @Target(AnnotationTarget.FUNCTION) + | annotation class Marking + | + | @Marking() + | fun simpleFun(): String = "Celebrimbor" + """.trimIndent() + val writerPlugin = TestOutputWriterPlugin() + + testInline( + source, + configuration, + pluginOverrides = listOf(writerPlugin) + ) { + renderingStage = { _, _ -> + writerPlugin.writer.renderedContent("root/example/simple-fun.html").match( + Div( + Div("@", A("Marking"), "()") + ), + "fun ", A("simpleFun"), + "(): ", A("String"), Span() + ) + } + } + } + + @Test + fun `fun with two annotations`() { + + val configuration = dokkaConfiguration { + passes { + pass { + sourceRoots = listOf("src/main/kotlin/test/Test.kt") + } + } + } + + val source = """ + |/src/main/kotlin/test/Test.kt + |package example + | + | @MustBeDocumented() + | @Target(AnnotationTarget.FUNCTION) + | annotation class Marking(val msg: String) + | + | @MustBeDocumented() + | @Target(AnnotationTarget.FUNCTION) + | annotation class Marking2(val int: Int) + | + | @Marking("Nenya") + | @Marking2(1) + | fun simpleFun(): String = "Celebrimbor" + """.trimIndent() + val writerPlugin = TestOutputWriterPlugin() + + testInline( + source, + configuration, + pluginOverrides = listOf(writerPlugin) + ) { + renderingStage = { _, _ -> + writerPlugin.writer.renderedContent("root/example/simple-fun.html") + .match( + Div( + Div("@", A("Marking"), "(", Span("msg = ", Span("\"Nenya\"")), Wbr, ")"), + Div("@", A("Marking2"), "(", Span("int = ", Span("1")), Wbr, ")") + ), + "fun ", A("simpleFun"), + "(): ", A("String"), Span() + ) + } + } + } + + @Test + fun `fun with annotation with array`() { + + val configuration = dokkaConfiguration { + passes { + pass { + sourceRoots = listOf("src/main/kotlin/test/Test.kt") + } + } + } + + val source = """ + |/src/main/kotlin/test/Test.kt + |package example + | + | @MustBeDocumented() + | @Target(AnnotationTarget.FUNCTION) + | annotation class Marking(val msg: Array) + | + | @Marking(["Nenya", "Vilya", "Narya"]) + | @Marking2(1) + | fun simpleFun(): String = "Celebrimbor" + """.trimIndent() + val writerPlugin = TestOutputWriterPlugin() + + testInline( + source, + configuration, + pluginOverrides = listOf(writerPlugin) + ) { + renderingStage = { _, _ -> + writerPlugin.writer.renderedContent("root/example/simple-fun.html").match( + Div( + Div("@", A("Marking"), "(", Span("msg = [", + Span(Span("\"Nenya\""), ", "), Wbr, + Span(Span("\"Vilya\""), ", "), Wbr, + Span(Span("\"Narya\"")), Wbr, "]"), Wbr, ")" + ) + ), + "fun ", A("simpleFun"), + "(): ", A("String"), Span() + ) + } + } + } + + private fun TestOutputWriter.renderedContent(path: String = "root/example.html") = + contents.getValue(path).let { Jsoup.parse(it) }.select("#content") + .single().select("div.symbol div.monospace").first() +} \ No newline at end of file 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/TestUtils.kt b/plugins/base/src/test/kotlin/utils/TestUtils.kt index 44c23e96..bd0e1fe2 100644 --- a/plugins/base/src/test/kotlin/utils/TestUtils.kt +++ b/plugins/base/src/test/kotlin/utils/TestUtils.kt @@ -2,6 +2,7 @@ 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 -- cgit