From 3792ef312ef347ef3300690e71c1cbf963a175e3 Mon Sep 17 00:00:00 2001 From: Andrzej Ratajczak Date: Wed, 9 Sep 2020 14:26:28 +0200 Subject: Add tests --- plugins/base/base-test-utils/build.gradle.kts | 1 + .../src/main/kotlin/renderers/JsoupUtils.kt | 29 +++++++ .../src/main/kotlin/renderers/SignatureUtils.kt | 12 +++ .../kotlin/signatures/KotlinSignatureProvider.kt | 1 - .../DefaultDescriptorToDocumentableTranslator.kt | 30 ++++---- .../src/test/kotlin/signatures/SignatureTest.kt | 30 ++++++++ .../src/test/kotlin/signatures/SignatureUtils.kt | 12 --- plugins/base/src/test/kotlin/utils/JsoupUtils.kt | 29 ------- plugins/base/src/test/kotlin/utils/TestUtils.kt | 3 +- plugins/kotlin-as-java/build.gradle.kts | 1 + .../kotlin/converters/KotlinToJavaConverter.kt | 27 +++++-- .../kotlin/signatures/JavaSignatureProvider.kt | 13 +++- .../src/test/kotlin/KotlinAsJavaPluginTest.kt | 90 ++++++++++++++++++++-- 13 files changed, 202 insertions(+), 76 deletions(-) create mode 100644 plugins/base/base-test-utils/src/main/kotlin/renderers/JsoupUtils.kt create mode 100644 plugins/base/base-test-utils/src/main/kotlin/renderers/SignatureUtils.kt delete mode 100644 plugins/base/src/test/kotlin/signatures/SignatureUtils.kt delete mode 100644 plugins/base/src/test/kotlin/utils/JsoupUtils.kt (limited to 'plugins') diff --git a/plugins/base/base-test-utils/build.gradle.kts b/plugins/base/base-test-utils/build.gradle.kts index a4a4df69..1de0ac0f 100644 --- a/plugins/base/base-test-utils/build.gradle.kts +++ b/plugins/base/base-test-utils/build.gradle.kts @@ -1,4 +1,5 @@ dependencies { compileOnly(project(":plugins:base")) implementation(project(":core:test-api")) + implementation("org.jsoup:jsoup:1.12.1") } diff --git a/plugins/base/base-test-utils/src/main/kotlin/renderers/JsoupUtils.kt b/plugins/base/base-test-utils/src/main/kotlin/renderers/JsoupUtils.kt new file mode 100644 index 00000000..e8c7838d --- /dev/null +++ b/plugins/base/base-test-utils/src/main/kotlin/renderers/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/base-test-utils/src/main/kotlin/renderers/SignatureUtils.kt b/plugins/base/base-test-utils/src/main/kotlin/renderers/SignatureUtils.kt new file mode 100644 index 00000000..e77b8757 --- /dev/null +++ b/plugins/base/base-test-utils/src/main/kotlin/renderers/SignatureUtils.kt @@ -0,0 +1,12 @@ +package signatures + +import org.jsoup.Jsoup +import org.jsoup.nodes.Element +import utils.TestOutputWriter + +fun TestOutputWriter.renderedContent(path: String = "root/example.html") = + contents.getValue(path).let { Jsoup.parse(it) }.select("#content") + .single() + +fun Element.signature() = select("div.symbol.monospace") +fun Element.firstSignature() = signature().first() \ No newline at end of file diff --git a/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt b/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt index 2a091ff5..08e702ba 100644 --- a/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt +++ b/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt @@ -346,7 +346,6 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog } is TypeAliased -> signatureForProjection(p.typeAlias) - is JavaObject -> link("Any", DriOfAny) is Void -> link("Unit", DriOfUnit) is PrimitiveJavaType -> signatureForProjection(p.translateToKotlin(), showFullyQualifiedName) diff --git a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt index 392bba7e..b1c82efb 100644 --- a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt @@ -635,22 +635,20 @@ private class DokkaDescriptorVisitor( abbreviation.toBound(), expandedType.toBound() ) - else -> { - when (val ctor = constructor.declarationDescriptor) { - is TypeParameterDescriptor -> TypeParameter( - dri = DRI.from(ctor), - name = ctor.name.asString() - ) - else -> TypeConstructor( - DRI.from(ctor!!), // TODO: remove '!!' - arguments.map { it.toProjection() }, - if (isExtensionFunctionType) FunctionModifiers.EXTENSION - else if (isFunctionType) FunctionModifiers.FUNCTION - else FunctionModifiers.NONE - ) - }.let { - if (isMarkedNullable) Nullable(it) else it - } + else -> when (val ctor = constructor.declarationDescriptor) { + is TypeParameterDescriptor -> TypeParameter( + dri = DRI.from(ctor), + name = ctor.name.asString() + ) + else -> TypeConstructor( + DRI.from(ctor!!), // TODO: remove '!!' + arguments.map { it.toProjection() }, + if (isExtensionFunctionType) FunctionModifiers.EXTENSION + else if (isFunctionType) FunctionModifiers.FUNCTION + else FunctionModifiers.NONE + ) + }.let { + if (isMarkedNullable) Nullable(it) else it } } diff --git a/plugins/base/src/test/kotlin/signatures/SignatureTest.kt b/plugins/base/src/test/kotlin/signatures/SignatureTest.kt index df2c3825..f5b1bf2e 100644 --- a/plugins/base/src/test/kotlin/signatures/SignatureTest.kt +++ b/plugins/base/src/test/kotlin/signatures/SignatureTest.kt @@ -1,6 +1,8 @@ package signatures +import org.jetbrains.dokka.DokkaConfiguration import org.jetbrains.dokka.DokkaSourceSetID +import org.jetbrains.dokka.jdk import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest import org.jsoup.Jsoup import org.jsoup.nodes.Element @@ -449,6 +451,34 @@ class SignatureTest : AbstractCoreTest() { } } + @Test + fun `typealias with generic params swapped`() { + + val writerPlugin = TestOutputWriterPlugin() + + testInline( + """ + |/src/main/kotlin/kotlinAsJavaPlugin/Test.kt + |package kotlinAsJavaPlugin + | + |typealias XD = Map + | + |class ABC { + | fun someFun(xd: XD) = 1 + |} + """.trimMargin(), + configuration, + pluginOverrides = listOf(writerPlugin) + ) { + renderingStage = { _, _ -> + writerPlugin.writer.renderedContent("root/kotlinAsJavaPlugin/-a-b-c/some-fun.html").signature().first().match( + "fun ", A("someFun"), "(xd: ", A("XD"), "<", A("Int"), + ", ", A("String"), ">):", A("Int"), Span() + ) + } + } + } + @Test fun `generic constructor params`() { diff --git a/plugins/base/src/test/kotlin/signatures/SignatureUtils.kt b/plugins/base/src/test/kotlin/signatures/SignatureUtils.kt deleted file mode 100644 index e77b8757..00000000 --- a/plugins/base/src/test/kotlin/signatures/SignatureUtils.kt +++ /dev/null @@ -1,12 +0,0 @@ -package signatures - -import org.jsoup.Jsoup -import org.jsoup.nodes.Element -import utils.TestOutputWriter - -fun TestOutputWriter.renderedContent(path: String = "root/example.html") = - contents.getValue(path).let { Jsoup.parse(it) }.select("#content") - .single() - -fun Element.signature() = select("div.symbol.monospace") -fun Element.firstSignature() = signature().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 deleted file mode 100644 index e8c7838d..00000000 --- a/plugins/base/src/test/kotlin/utils/JsoupUtils.kt +++ /dev/null @@ -1,29 +0,0 @@ -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 5183972a..2ef6534e 100644 --- a/plugins/base/src/test/kotlin/utils/TestUtils.kt +++ b/plugins/base/src/test/kotlin/utils/TestUtils.kt @@ -76,4 +76,5 @@ val Bound.name: String? is Void -> "void" is Dynamic -> "dynamic" is UnresolvedBound -> "" - } \ No newline at end of file + is TypeAliased -> typeAlias.name + } diff --git a/plugins/kotlin-as-java/build.gradle.kts b/plugins/kotlin-as-java/build.gradle.kts index f03a28c6..2c7f1e01 100644 --- a/plugins/kotlin-as-java/build.gradle.kts +++ b/plugins/kotlin-as-java/build.gradle.kts @@ -5,6 +5,7 @@ dependencies { testImplementation(project(":plugins:base")) testImplementation(project(":plugins:base:base-test-utils")) testImplementation(project(":core:content-matcher-test-utils")) + testImplementation("org.jsoup:jsoup:1.12.1") } registerDokkaArtifactPublication("kotlinAsJavaPlugin") { diff --git a/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt b/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt index d79bd7b1..38d904e4 100644 --- a/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt +++ b/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt @@ -175,20 +175,33 @@ internal fun DClass.asJava(): DClass = copy( private fun DTypeParameter.asJava(): DTypeParameter = copy( variantTypeParameter = variantTypeParameter.withDri(dri.possiblyAsJava()), - bounds = bounds.map { it.asJava() } + bounds = bounds.map { it.asJava() as Bound } ) -private fun Bound.asJava(): Bound = when (this) { +private fun Projection.asJava(): Projection = when(this) { + is Star -> Star + is Covariance<*> -> copy(inner.asJava()) + is Contravariance<*> -> copy(inner.asJava()) + is Invariance<*> -> copy(inner.asJava()) + is Bound -> asJava() +} + +private fun Bound.asJava(): Bound = when(this) { + is TypeParameter -> copy(dri.possiblyAsJava()) is TypeConstructor -> copy( - dri = dri.possiblyAsJava() + dri = dri.possiblyAsJava(), + projections = projections.map { it.asJava() } ) is TypeAliased -> copy( + typeAlias = typeAlias.asJava(), inner = inner.asJava() ) - is Nullable -> copy( - inner = inner.asJava() - ) - else -> this + is Nullable -> copy(inner.asJava()) + is PrimitiveJavaType -> this + is Void -> this + is JavaObject -> this + is Dynamic -> this + is UnresolvedBound -> this } internal fun DEnum.asJava(): DEnum = copy( diff --git a/plugins/kotlin-as-java/src/main/kotlin/signatures/JavaSignatureProvider.kt b/plugins/kotlin-as-java/src/main/kotlin/signatures/JavaSignatureProvider.kt index d24fa428..1d62a206 100644 --- a/plugins/kotlin-as-java/src/main/kotlin/signatures/JavaSignatureProvider.kt +++ b/plugins/kotlin-as-java/src/main/kotlin/signatures/JavaSignatureProvider.kt @@ -79,10 +79,10 @@ class JavaSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLogge c.supertypes.map { (p, dris) -> val (classes, interfaces) = dris.partition { it.kind == JavaClassKindTypes.CLASS } list(classes, prefix = " extends ", sourceSets = setOf(p)) { - link(it.typeConstructor.dri.sureClassNames, it.typeConstructor.dri, sourceSets = setOf(p)) + signatureForProjection(it.typeConstructor) } - list(interfaces, prefix = " implements ", sourceSets = setOf(p)){ - link(it.typeConstructor.dri.sureClassNames, it.typeConstructor.dri, sourceSets = setOf(p)) + list(interfaces, prefix = " implements ", sourceSets = setOf(p)) { + signatureForProjection(it.typeConstructor) } } } @@ -160,7 +160,12 @@ class JavaSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLogge } is Variance<*> -> group(styles = emptySet()) { - text("$p ".takeIf { it.isNotBlank() } ?: "") // TODO: "super" && "extends" + val variance = when(p) { + is Covariance<*> -> "? extends " + is Contravariance<*> -> "? super " + is Invariance<*> -> "" + } + text(variance) signatureForProjection(p.inner) } diff --git a/plugins/kotlin-as-java/src/test/kotlin/KotlinAsJavaPluginTest.kt b/plugins/kotlin-as-java/src/test/kotlin/KotlinAsJavaPluginTest.kt index 3dbe5888..c6dc9a25 100644 --- a/plugins/kotlin-as-java/src/test/kotlin/KotlinAsJavaPluginTest.kt +++ b/plugins/kotlin-as-java/src/test/kotlin/KotlinAsJavaPluginTest.kt @@ -6,6 +6,14 @@ import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest import org.jetbrains.kotlin.utils.addToStdlib.cast import org.junit.jupiter.api.Test import matchers.content.* +import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.jdk +import signatures.renderedContent +import signatures.signature +import utils.A +import utils.Span +import utils.TestOutputWriterPlugin +import utils.match class KotlinAsJavaPluginTest : AbstractCoreTest() { @@ -31,7 +39,7 @@ class KotlinAsJavaPluginTest : AbstractCoreTest() { |fun testF3(to: TestObj) = to |fun testF4(t: T) = listOf(t) |val testV = 1 - """, + """.trimMargin(), configuration, cleanupOutput = true ) { @@ -68,7 +76,7 @@ class KotlinAsJavaPluginTest : AbstractCoreTest() { | |fun testF(i: Int) = i |val testV = 1 - """, + """.trimMargin(), configuration, cleanupOutput = true ) { @@ -109,7 +117,7 @@ class KotlinAsJavaPluginTest : AbstractCoreTest() { |class TestJ { | int testF(int i) { return i; } |} - """, + """.trimMargin(), configuration, cleanupOutput = true ) { @@ -149,7 +157,7 @@ class KotlinAsJavaPluginTest : AbstractCoreTest() { |class Test { | public val publicProperty: String = "" |} - """, + """.trimMargin(), configuration, cleanupOutput = true ) { @@ -202,7 +210,7 @@ class KotlinAsJavaPluginTest : AbstractCoreTest() { |class TestJ { | public Int publicProperty = 1; |} - """, + """.trimMargin(), configuration, cleanupOutput = true ) { @@ -252,7 +260,7 @@ class KotlinAsJavaPluginTest : AbstractCoreTest() { | open class A { } | interface B | class C : A(), B - """, + """.trimMargin(), configuration, cleanupOutput = true ) { @@ -290,6 +298,76 @@ class KotlinAsJavaPluginTest : AbstractCoreTest() { private fun Collection.assertCount(n: Int, prefix: String = "") = assert(count() == n) { "${prefix}Expected $n, got ${count()}" } + @Test + fun `typealias`() { + val writerPlugin = TestOutputWriterPlugin() + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + externalDocumentationLinks = listOf(DokkaConfiguration.ExternalDocumentationLink.jdk(8)) + } + } + } + testInline( + """ + |/src/main/kotlin/kotlinAsJavaPlugin/Test.kt + |package kotlinAsJavaPlugin + | + |typealias XD = Int + |class ABC { + | fun someFun(xd: XD): Int = 1 + |} + """.trimMargin(), + configuration, + pluginOverrides = listOf(writerPlugin), + cleanupOutput = true + ) { + renderingStage = { _, _ -> + writerPlugin.writer.renderedContent("root/kotlinAsJavaPlugin/-a-b-c/some-fun.html").signature().first().match( + "final ", A("Integer"), A("someFun"), "(", A("Integer"), A("xd"), ")", Span() + ) + } + } + } + + @Test + fun `typealias with generic`() { + val writerPlugin = TestOutputWriterPlugin() + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + externalDocumentationLinks = listOf( + DokkaConfiguration.ExternalDocumentationLink.jdk(8), + stdlibExternalDocumentationLink + ) + } + } + } + testInline( + """ + |/src/main/kotlin/kotlinAsJavaPlugin/Test.kt + |package kotlinAsJavaPlugin + | + |typealias XD = Map + | + |class ABC { + | fun someFun(xd: XD) = 1 + |} + """.trimMargin(), + configuration, + pluginOverrides = listOf(writerPlugin), + cleanupOutput = true + ) { + renderingStage = { _, _ -> + writerPlugin.writer.renderedContent("root/kotlinAsJavaPlugin/-a-b-c/some-fun.html").signature().first().match( + "final ", A("Integer"), A("someFun"), "(", A("Map"), "<", A("String"), + ", ", A("Integer"), ">", A("xd"), ")", Span() + ) + } + } + } } private val ContentNode.mainContents: List -- cgit