diff options
Diffstat (limited to 'dokka-subprojects/plugin-base/src/test/kotlin/translators')
9 files changed, 3264 insertions, 0 deletions
diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/translators/AccessorMethodNamingTest.kt b/dokka-subprojects/plugin-base/src/test/kotlin/translators/AccessorMethodNamingTest.kt new file mode 100644 index 00000000..ff36337a --- /dev/null +++ b/dokka-subprojects/plugin-base/src/test/kotlin/translators/AccessorMethodNamingTest.kt @@ -0,0 +1,123 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package translators + +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.model.DProperty +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +/** + * https://kotlinlang.org/docs/java-to-kotlin-interop.html#properties + * https://kotlinlang.org/docs/java-interop.html#getters-and-setters + */ +class AccessorMethodNamingTest : BaseAbstractTest() { + + @Test + fun `standard property`() { + testAccessors("data class TestCase(var standardString: String, var standardBoolean: Boolean)") { + doTest("standardString", "getStandardString", "setStandardString") + doTest("standardBoolean", "getStandardBoolean", "setStandardBoolean") + } + } + + @Test + fun `properties that start with the word 'is' use the special is rules`() { + testAccessors("data class TestCase(var isFoo: String, var isBar: Boolean)") { + doTest("isFoo", "isFoo", "setFoo") + doTest("isBar", "isBar", "setBar") + } + } + + @Test + fun `properties that start with a word that starts with 'is' use get and set`() { + testAccessors("data class TestCase(var issuesFetched: Int, var issuesWereDisplayed: Boolean)") { + doTest("issuesFetched", "getIssuesFetched", "setIssuesFetched") + doTest("issuesWereDisplayed", "getIssuesWereDisplayed", "setIssuesWereDisplayed") + } + } + + @Test + fun `properties that start with the word 'is' followed by underscore use the special is rules`() { + testAccessors("data class TestCase(var is_foo: String, var is_bar: Boolean)") { + doTest("is_foo", "is_foo", "set_foo") + doTest("is_bar", "is_bar", "set_bar") + } + } + + @Test + fun `properties that start with the word 'is' followed by a number use the special is rules`() { + testAccessors("data class TestCase(var is1of: String, var is2of: Boolean)") { + doTest("is1of", "is1of", "set1of") + doTest("is2of", "is2of", "set2of") + } + } + + @Test + fun `sanity check short names`() { + testAccessors( + """ + data class TestCase( + var i: Boolean, + var `is`: Boolean, + var isz: Boolean, + var isA: Int, + var isB: Boolean, + ) + """.trimIndent() + ) { + doTest("i", "getI", "setI") + doTest("is", "getIs", "setIs") + doTest("isz", "getIsz", "setIsz") + doTest("isA", "isA", "setA") + doTest("isB", "isB", "setB") + } + } + + private fun testAccessors(code: String, block: PropertyTestCase.() -> Unit) { + val configuration = dokkaConfiguration { + suppressObviousFunctions = false + sourceSets { + sourceSet { + sourceRoots = listOf("src/main/kotlin") + } + } + } + + testInline(""" + /src/main/kotlin/sample/TestCase.kt + package sample + + $code + """.trimIndent(), + configuration) { + documentablesMergingStage = { module -> + val properties = module.packages.single().classlikes.first().properties + PropertyTestCase(properties).apply { + block() + finish() + } + } + } + } + + private class PropertyTestCase(private val properties: List<DProperty>) { + private var testsDone: Int = 0 + + fun doTest(kotlinName: String, getter: String? = null, setter: String? = null) { + properties.first { it.name == kotlinName }.let { + assertEquals(getter, it.getter?.name) + assertEquals(setter, it.setter?.name) + } + testsDone += 1 + } + + fun finish() { + assertTrue(testsDone > 0, "No tests in TestCase") + assertEquals(testsDone, properties.size) + } + } +} diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/translators/Bug1341.kt b/dokka-subprojects/plugin-base/src/test/kotlin/translators/Bug1341.kt new file mode 100644 index 00000000..6a7bfc97 --- /dev/null +++ b/dokka-subprojects/plugin-base/src/test/kotlin/translators/Bug1341.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package translators + +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.links.DRI +import kotlin.test.Test +import kotlin.test.assertEquals + +class Bug1341 : BaseAbstractTest() { + @Test + fun `reproduce bug #1341`() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src") + analysisPlatform = "jvm" + } + } + } + + testInline( + """ + /src/com/sample/OtherClass.kt + package com.sample + class OtherClass internal constructor() { + internal annotation class CustomAnnotation + } + + /src/com/sample/ClassUsingAnnotation.java + package com.sample + public class ClassUsingAnnotation { + @OtherClass.CustomAnnotation + public int doSomething() { + return 1; + } + } + """.trimIndent(), + configuration + ) { + this.documentablesMergingStage = { module -> + assertEquals(DRI("com.sample"), module.packages.single().dri) + } + } + } +} diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/translators/DefaultDescriptorToDocumentableTranslatorTest.kt b/dokka-subprojects/plugin-base/src/test/kotlin/translators/DefaultDescriptorToDocumentableTranslatorTest.kt new file mode 100644 index 00000000..6812f0b4 --- /dev/null +++ b/dokka-subprojects/plugin-base/src/test/kotlin/translators/DefaultDescriptorToDocumentableTranslatorTest.kt @@ -0,0 +1,1107 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package translators + +import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.base.signatures.KotlinSignatureUtils.modifiers +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.links.PointingToDeclaration +import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.model.doc.* +import utils.text +import kotlin.test.* +import utils.OnlyDescriptors + +class DefaultDescriptorToDocumentableTranslatorTest : BaseAbstractTest() { + val configuration = dokkaConfiguration { + suppressObviousFunctions = false + sourceSets { + sourceSet { + sourceRoots = listOf("src/main/kotlin") + classpath = listOf(commonStdlibPath!!, jvmStdlibPath!!) + } + } + } + + @Suppress("DEPRECATION") // for includeNonPublic + val javaConfiguration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/main/java") + includeNonPublic = true + } + } + } + + @Test + fun `data class kdocs over generated methods`() { + testInline( + """ + |/src/main/kotlin/sample/XD.kt + |package sample + |/** + | * But the fat Hobbit, he knows. Eyes always watching. + | */ + |data class XD(val xd: String) { + | /** + | * But the fat Hobbit, he knows. Eyes always watching. + | */ + | fun custom(): String = "" + | + | /** + | * Memory is not what the heart desires. That is only a mirror. + | */ + | override fun equals(other: Any?): Boolean = true + |} + """.trimIndent(), + configuration + ) { + documentablesMergingStage = { module -> + assertEquals("", module.documentationOf("XD", "copy")) + assertEquals( + "Memory is not what the heart desires. That is only a mirror.", + module.documentationOf( + "XD", + "equals" + ) + ) + assertEquals("", module.documentationOf("XD", "hashCode")) + assertEquals("", module.documentationOf("XD", "toString")) + assertEquals("But the fat Hobbit, he knows. Eyes always watching.", module.documentationOf("XD", "custom")) + } + } + } + + @Test + fun `simple class kdocs`() { + testInline( + """ + |/src/main/kotlin/sample/XD.kt + |package sample + |/** + | * But the fat Hobbit, he knows. Eyes always watching. + | */ + |class XD(val xd: String) { + | /** + | * But the fat Hobbit, he knows. Eyes always watching. + | */ + | fun custom(): String = "" + | + | /** + | * Memory is not what the heart desires. That is only a mirror. + | */ + | override fun equals(other: Any?): Boolean = true + |} + """.trimIndent(), + configuration + ) { + documentablesMergingStage = { module -> + assertEquals("But the fat Hobbit, he knows. Eyes always watching.", module.documentationOf("XD", "custom")) + assertEquals( + "Memory is not what the heart desires. That is only a mirror.", + module.documentationOf( + "XD", + "equals" + ) + ) + } + } + } + + @Test + fun `kdocs with code block`() { + testInline( + """ + |/src/main/kotlin/sample/TestForCodeInDocs.kt + |package sample + |/** + | * Utility for building a String that represents an XML document. + | * The XmlBlob object is immutable and the passed values are copied where it makes sense. + | * + | * Note the XML Declaration is not output as part of the XmlBlob + | * + | * + | * val soapAttrs = attrs("soap-env" to "http://www.w3.org/2001/12/soap-envelope", + | * "soap-env:encodingStyle" to "http://www.w3.org/2001/12/soap-encoding") + | * val soapXml = node("soap-env:Envelope", soapAttrs, + | * node("soap-env:Body", attrs("xmlns:m" to "http://example"), + | * node("m:GetExample", + | * node("m:GetExampleName", "BasePair") + | * ) + | * ) + | * ) + | * + | * + | */ + |class TestForCodeInDocs { + |} + """.trimIndent(), configuration + ) { + documentablesMergingStage = { module -> + val description = module.descriptionOf("TestForCodeInDocs") + val expected = listOf( + P( + children = listOf(Text("Utility for building a String that represents an XML document. The XmlBlob object is immutable and the passed values are copied where it makes sense.")) + ), + P( + children = listOf(Text("Note the XML Declaration is not output as part of the XmlBlob")) + ), + CodeBlock( + children = listOf( + Text( + """val soapAttrs = attrs("soap-env" to "http://www.w3.org/2001/12/soap-envelope", + "soap-env:encodingStyle" to "http://www.w3.org/2001/12/soap-encoding") +val soapXml = node("soap-env:Envelope", soapAttrs, + node("soap-env:Body", attrs("xmlns:m" to "http://example"), + node("m:GetExample", + node("m:GetExampleName", "BasePair") + ) + ) +)""" + ) + ) + ) + ) + assertEquals(expected, description?.root?.children) + } + } + } + + private fun runTestSuitesAgainstGivenClasses(classlikes: List<DClasslike>, testSuites: List<List<TestSuite>>) { + classlikes.zip(testSuites).forEach { (classlike, testSuites) -> + testSuites.forEach { testSuite -> + when (testSuite) { + is TestSuite.PropertyDoesntExist -> assertEquals( + null, + classlike.properties.firstOrNull { it.name == testSuite.propertyName }, + "Test for class ${classlike.name} failed" + ) + is TestSuite.PropertyExists -> classlike.properties.single { it.name == testSuite.propertyName } + .run { + assertEquals( + testSuite.modifier, + modifier.values.single(), + "Test for class ${classlike.name} with property $name failed" + ) + assertEquals( + testSuite.visibility, + visibility.values.single(), + "Test for class ${classlike.name} with property $name failed" + ) + assertEquals( + testSuite.additionalModifiers, + extra[AdditionalModifiers]?.content?.values?.single() ?: emptySet<ExtraModifiers>(), + "Test for class ${classlike.name} with property $name failed" + ) + } + is TestSuite.FunctionDoesntExist -> assertEquals( + null, + classlike.functions.firstOrNull { it.name == testSuite.propertyName }, + "Test for class ${classlike.name} failed" + ) + is TestSuite.FunctionExists -> classlike.functions.single { it.name == testSuite.propertyName } + .run { + assertEquals( + testSuite.modifier, + modifier.values.single(), + "Test for class ${classlike.name} with function $name failed" + ) + assertEquals( + testSuite.visibility, + visibility.values.single(), + "Test for class ${classlike.name} with function $name failed" + ) + assertEquals( + testSuite.additionalModifiers, + extra[AdditionalModifiers]?.content?.values?.single() ?: emptySet<ExtraModifiers>(), + "Test for class ${classlike.name} with function $name failed" + ) + } + } + } + } + } + + @Test + fun `derived properties with non-public code included`() { + + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/main/kotlin") + documentedVisibilities = setOf( + DokkaConfiguration.Visibility.PUBLIC, + DokkaConfiguration.Visibility.PRIVATE, + DokkaConfiguration.Visibility.PROTECTED, + DokkaConfiguration.Visibility.INTERNAL, + ) + } + } + } + + testInline( + """ + |/src/main/kotlin/sample/XD.kt + |package sample + | + |open class A { + | private val privateProperty: Int = 1 + | protected val protectedProperty: Int = 2 + | internal val internalProperty: Int = 3 + | val publicProperty: Int = 4 + | open val propertyToOverride: Int = 5 + | + | private fun privateFun(): Int = 6 + | protected fun protectedFun(): Int = 7 + | internal fun internalFun(): Int = 8 + | fun publicFun(): Int = 9 + | open fun funToOverride(): Int = 10 + |} + | + |open class B : A() { + | override val propertyToOverride: Int = 11 + | + | override fun funToOverride(): Int = 12 + |} + |class C : B() + """.trimIndent(), + configuration + ) { + + documentablesMergingStage = { module -> + val classes = module.packages.single().classlikes.sortedBy { it.name } + + val testSuites: List<List<TestSuite>> = listOf( + listOf( + TestSuite.PropertyExists( + "privateProperty", + KotlinModifier.Final, + KotlinVisibility.Private, + emptySet() + ), + TestSuite.PropertyExists( + "protectedProperty", + KotlinModifier.Final, + KotlinVisibility.Protected, + emptySet() + ), + TestSuite.PropertyExists( + "internalProperty", + KotlinModifier.Final, + KotlinVisibility.Internal, + emptySet() + ), + TestSuite.PropertyExists( + "publicProperty", + KotlinModifier.Final, + KotlinVisibility.Public, + emptySet() + ), + TestSuite.PropertyExists( + "propertyToOverride", + KotlinModifier.Open, + KotlinVisibility.Public, + emptySet() + ), + TestSuite.FunctionExists( + "privateFun", + KotlinModifier.Final, + KotlinVisibility.Private, + emptySet() + ), + TestSuite.FunctionExists( + "protectedFun", + KotlinModifier.Final, + KotlinVisibility.Protected, + emptySet() + ), + TestSuite.FunctionExists( + "internalFun", + KotlinModifier.Final, + KotlinVisibility.Internal, + emptySet() + ), + TestSuite.FunctionExists( + "publicFun", + KotlinModifier.Final, + KotlinVisibility.Public, + emptySet() + ), + TestSuite.FunctionExists( + "funToOverride", + KotlinModifier.Open, + KotlinVisibility.Public, + emptySet() + ) + ), + listOf( + TestSuite.PropertyExists( + "privateProperty", + KotlinModifier.Final, + KotlinVisibility.Private, + emptySet() + ), + TestSuite.PropertyExists( + "protectedProperty", + KotlinModifier.Final, + KotlinVisibility.Protected, + emptySet() + ), + TestSuite.PropertyExists( + "internalProperty", + KotlinModifier.Final, + KotlinVisibility.Internal, + emptySet() + ), + TestSuite.PropertyExists( + "publicProperty", + KotlinModifier.Final, + KotlinVisibility.Public, + emptySet() + ), + TestSuite.PropertyExists( + "propertyToOverride", + KotlinModifier.Open, + KotlinVisibility.Public, + setOf(ExtraModifiers.KotlinOnlyModifiers.Override) + ), + TestSuite.FunctionExists( + "privateFun", + KotlinModifier.Final, + KotlinVisibility.Private, + emptySet() + ), + TestSuite.FunctionExists( + "protectedFun", + KotlinModifier.Final, + KotlinVisibility.Protected, + emptySet() + ), + TestSuite.FunctionExists( + "internalFun", + KotlinModifier.Final, + KotlinVisibility.Internal, + emptySet() + ), + TestSuite.FunctionExists( + "publicFun", + KotlinModifier.Final, + KotlinVisibility.Public, + emptySet() + ), + TestSuite.FunctionExists( + "funToOverride", + KotlinModifier.Open, + KotlinVisibility.Public, + setOf(ExtraModifiers.KotlinOnlyModifiers.Override) + ) + ), + listOf( + TestSuite.PropertyExists( + "privateProperty", + KotlinModifier.Final, + KotlinVisibility.Private, + emptySet() + ), + TestSuite.PropertyExists( + "protectedProperty", + KotlinModifier.Final, + KotlinVisibility.Protected, + emptySet() + ), + TestSuite.PropertyExists( + "internalProperty", + KotlinModifier.Final, + KotlinVisibility.Internal, + emptySet() + ), + TestSuite.PropertyExists( + "publicProperty", + KotlinModifier.Final, + KotlinVisibility.Public, + emptySet() + ), + TestSuite.PropertyExists( + "propertyToOverride", + KotlinModifier.Open, + KotlinVisibility.Public, + setOf(ExtraModifiers.KotlinOnlyModifiers.Override) + ), + TestSuite.FunctionExists( + "privateFun", + KotlinModifier.Final, + KotlinVisibility.Private, + emptySet() + ), + TestSuite.FunctionExists( + "protectedFun", + KotlinModifier.Final, + KotlinVisibility.Protected, + emptySet() + ), + TestSuite.FunctionExists( + "internalFun", + KotlinModifier.Final, + KotlinVisibility.Internal, + emptySet() + ), + TestSuite.FunctionExists( + "publicFun", + KotlinModifier.Final, + KotlinVisibility.Public, + emptySet() + ), + TestSuite.FunctionExists( + "funToOverride", + KotlinModifier.Open, + KotlinVisibility.Public, + setOf(ExtraModifiers.KotlinOnlyModifiers.Override) + ) + ) + ) + + runTestSuitesAgainstGivenClasses(classes, testSuites) + } + } + } + + + @Test + fun `derived properties with only public code`() { + + @Suppress("DEPRECATION") // for includeNonPublic + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/main/kotlin") + includeNonPublic = false + } + } + } + + testInline( + """ + |/src/main/kotlin/sample/XD.kt + |package sample + | + |open class A { + | private val privateProperty: Int = 1 + | protected val protectedProperty: Int = 2 + | internal val internalProperty: Int = 3 + | val publicProperty: Int = 4 + | open val propertyToOverride: Int = 5 + | open val propertyToOverrideButCloseMeanwhile: Int = 6 + | + | private fun privateFun(): Int = 7 + | protected fun protectedFun(): Int = 8 + | internal fun internalFun(): Int = 9 + | fun publicFun(): Int = 10 + | open fun funToOverride(): Int = 11 + | open fun funToOverrideButCloseMeanwhile(): Int = 12 + |} + | + |open class B : A() { + | override val propertyToOverride: Int = 13 + | final override val propertyToOverrideButCloseMeanwhile: Int = 14 + | + | override fun funToOverride(): Int = 15 + | final override fun funToOverrideButCloseMeanwhile(): Int = 16 + |} + |class C : B() + """.trimIndent(), + configuration + ) { + + documentablesMergingStage = { module -> + val classes = module.packages.single().classlikes.sortedBy { it.name } + + val testSuites: List<List<TestSuite>> = listOf( + listOf( + TestSuite.PropertyDoesntExist("privateProperty"), + TestSuite.PropertyDoesntExist("protectedProperty"), + TestSuite.PropertyDoesntExist("internalProperty"), + TestSuite.PropertyExists( + "publicProperty", + KotlinModifier.Final, + KotlinVisibility.Public, + emptySet() + ), + TestSuite.PropertyExists( + "propertyToOverride", + KotlinModifier.Open, + KotlinVisibility.Public, + emptySet() + ), + TestSuite.PropertyExists( + "propertyToOverrideButCloseMeanwhile", + KotlinModifier.Open, + KotlinVisibility.Public, + emptySet() + ), + TestSuite.FunctionDoesntExist("privateFun"), + TestSuite.FunctionDoesntExist("protectedFun"), + TestSuite.FunctionDoesntExist("internalFun"), + TestSuite.FunctionExists( + "publicFun", + KotlinModifier.Final, + KotlinVisibility.Public, + emptySet() + ), + TestSuite.FunctionExists( + "funToOverride", + KotlinModifier.Open, + KotlinVisibility.Public, + emptySet() + ), + TestSuite.FunctionExists( + "funToOverrideButCloseMeanwhile", + KotlinModifier.Open, + KotlinVisibility.Public, + emptySet() + ) + ), + listOf( + TestSuite.PropertyDoesntExist("privateProperty"), + TestSuite.PropertyDoesntExist("protectedProperty"), + TestSuite.PropertyDoesntExist("internalProperty"), + TestSuite.PropertyExists( + "publicProperty", + KotlinModifier.Final, + KotlinVisibility.Public, + emptySet() + ), + TestSuite.PropertyExists( + "propertyToOverride", + KotlinModifier.Open, + KotlinVisibility.Public, + setOf(ExtraModifiers.KotlinOnlyModifiers.Override) + ), + TestSuite.PropertyExists( + "propertyToOverrideButCloseMeanwhile", + KotlinModifier.Final, + KotlinVisibility.Public, + setOf(ExtraModifiers.KotlinOnlyModifiers.Override) + ), + TestSuite.FunctionDoesntExist("privateFun"), + TestSuite.FunctionDoesntExist("protectedFun"), + TestSuite.FunctionDoesntExist("internalFun"), + TestSuite.FunctionExists( + "publicFun", + KotlinModifier.Final, + KotlinVisibility.Public, + emptySet() + ), + TestSuite.FunctionExists( + "funToOverride", + KotlinModifier.Open, + KotlinVisibility.Public, + setOf(ExtraModifiers.KotlinOnlyModifiers.Override) + ), + TestSuite.FunctionExists( + "funToOverrideButCloseMeanwhile", + KotlinModifier.Final, + KotlinVisibility.Public, + setOf(ExtraModifiers.KotlinOnlyModifiers.Override) + ) + ), + listOf( + TestSuite.PropertyDoesntExist("privateProperty"), + TestSuite.PropertyDoesntExist("protectedProperty"), + TestSuite.PropertyDoesntExist("internalProperty"), + TestSuite.PropertyExists( + "publicProperty", + KotlinModifier.Final, + KotlinVisibility.Public, + emptySet() + ), + TestSuite.PropertyExists( + "propertyToOverride", + KotlinModifier.Open, + KotlinVisibility.Public, + setOf(ExtraModifiers.KotlinOnlyModifiers.Override) + ), + TestSuite.PropertyExists( + "propertyToOverrideButCloseMeanwhile", + KotlinModifier.Final, + KotlinVisibility.Public, + setOf(ExtraModifiers.KotlinOnlyModifiers.Override) + ), + TestSuite.FunctionDoesntExist("privateFun"), + TestSuite.FunctionDoesntExist("protectedFun"), + TestSuite.FunctionDoesntExist("internalFun"), + TestSuite.FunctionExists( + "publicFun", + KotlinModifier.Final, + KotlinVisibility.Public, + emptySet() + ), + TestSuite.FunctionExists( + "funToOverride", + KotlinModifier.Open, + KotlinVisibility.Public, + setOf(ExtraModifiers.KotlinOnlyModifiers.Override) + ), + TestSuite.FunctionExists( + "funToOverrideButCloseMeanwhile", + KotlinModifier.Final, + KotlinVisibility.Public, + setOf(ExtraModifiers.KotlinOnlyModifiers.Override) + ) + ) + ) + + runTestSuitesAgainstGivenClasses(classes, testSuites) + } + } + } + + @Ignore // The compiler throws away annotations on unresolved types upstream + @Test + fun `Can annotate unresolved type`() { + testInline( + """ + |/src/main/java/sample/FooLibrary.kt + |package sample; + |@MustBeDocumented + |@Target(AnnotationTarget.TYPE) + |ann |
