aboutsummaryrefslogtreecommitdiff
path: root/dokka-subprojects/analysis-kotlin-api/src
diff options
context:
space:
mode:
Diffstat (limited to 'dokka-subprojects/analysis-kotlin-api/src')
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/KotlinAnalysisPlugin.kt10
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/InternalKotlinAnalysisPlugin.kt2
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/SampleProvider.kt36
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/sample/SampleAnalysisEnvironment.kt43
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/sample/SampleAnalysisEnvironmentCreator.kt38
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/sample/SampleSnippet.kt45
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/sample/SampleAnalysisTest.kt495
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestProject.kt18
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestAnalysisServices.kt4
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestProjectAnalyzer.kt83
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/java/JavaConfigurationBuilder.kt2
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/java/JavaTestProject.kt6
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/kotlin/KotlinJvmConfigurationBuilder.kt2
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/kotlin/KotlinJvmTestProject.kt6
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/mixed/MixedJvmTestProject.kt18
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/util/DokkaLoggerUtils.kt63
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/util/TestAnalysisApiUtils.kt27
17 files changed, 793 insertions, 105 deletions
diff --git a/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/KotlinAnalysisPlugin.kt b/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/KotlinAnalysisPlugin.kt
index 7d434bd5..1df1dfe6 100644
--- a/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/KotlinAnalysisPlugin.kt
+++ b/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/KotlinAnalysisPlugin.kt
@@ -4,17 +4,21 @@
package org.jetbrains.dokka.analysis.kotlin
+import org.jetbrains.dokka.analysis.kotlin.sample.SampleAnalysisEnvironmentCreator
+import org.jetbrains.dokka.analysis.kotlin.sample.SampleAnalysisEnvironment
import org.jetbrains.dokka.plugability.DokkaPlugin
import org.jetbrains.dokka.plugability.DokkaPluginApiPreview
+import org.jetbrains.dokka.plugability.ExtensionPoint
import org.jetbrains.dokka.plugability.PluginApiPreviewAcknowledgement
public class KotlinAnalysisPlugin : DokkaPlugin() {
- /*
- * This is where stable public API will go.
+ /**
+ * An extension for analyzing Kotlin sample functions used in the `@sample` KDoc tag.
*
- * No stable public API for now.
+ * @see SampleAnalysisEnvironment for more details
*/
+ public val sampleAnalysisEnvironmentCreator: ExtensionPoint<SampleAnalysisEnvironmentCreator> by extensionPoint()
@OptIn(DokkaPluginApiPreview::class)
override fun pluginApiPreviewAcknowledgement(): PluginApiPreviewAcknowledgement = PluginApiPreviewAcknowledgement
diff --git a/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/InternalKotlinAnalysisPlugin.kt b/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/InternalKotlinAnalysisPlugin.kt
index 0ef1399a..d032d490 100644
--- a/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/InternalKotlinAnalysisPlugin.kt
+++ b/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/InternalKotlinAnalysisPlugin.kt
@@ -31,8 +31,6 @@ public class InternalKotlinAnalysisPlugin : DokkaPlugin() {
public val documentableSourceLanguageParser: ExtensionPoint<DocumentableSourceLanguageParser> by extensionPoint()
- public val sampleProviderFactory: ExtensionPoint<SampleProviderFactory> by extensionPoint()
-
@OptIn(DokkaPluginApiPreview::class)
override fun pluginApiPreviewAcknowledgement(): PluginApiPreviewAcknowledgement = PluginApiPreviewAcknowledgement
}
diff --git a/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/SampleProvider.kt b/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/SampleProvider.kt
deleted file mode 100644
index 472d17f0..00000000
--- a/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/SampleProvider.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package org.jetbrains.dokka.analysis.kotlin.internal
-
-import org.jetbrains.dokka.DokkaConfiguration
-import org.jetbrains.dokka.InternalDokkaApi
-
-@InternalDokkaApi
-public interface SampleProviderFactory {
- /**
- * [SampleProvider] is a short-lived closeable instance.
- * It assumes that [SampleProvider] scope of use is not big.
- * Otherwise, it can lead to high memory consumption / leaks during Dokka running.
- */
- public fun build(): SampleProvider
-}
-
-/**
- * It is closeable.
- * Otherwise, there is a chance of high memory consumption / leak.
- * In general case, it creates a separate project to analysis samples directories.
- */
-@InternalDokkaApi
-public interface SampleProvider: AutoCloseable {
- public class SampleSnippet(
- public val imports: String,
- public val body: String
- )
-
- /**
- * @return [SampleSnippet] or null if it has not found by [fqLink]
- */
- public fun getSample(sourceSet: DokkaConfiguration.DokkaSourceSet, fqLink: String): SampleSnippet?
-}
diff --git a/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/sample/SampleAnalysisEnvironment.kt b/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/sample/SampleAnalysisEnvironment.kt
new file mode 100644
index 00000000..3620808a
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/sample/SampleAnalysisEnvironment.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package org.jetbrains.dokka.analysis.kotlin.sample
+
+import org.jetbrains.dokka.DokkaConfiguration
+
+/**
+ * Fully-configured and ready-to-use sample analysis environment.
+ *
+ * It's best to limit the scope of use and lifetime of this environment as it takes up
+ * additional resources which could be freed once the samples have been analyzed.
+ * Therefore, it's best to use it through the [SampleAnalysisEnvironmentCreator.use] lambda.
+ *
+ * For example, if you need to process all samples in an arbitrary project, it's best to do it
+ * in one iteration and at the same time, so that the environment is created once and lives for
+ * as little is possible, as opposed to creating it again and again for every individual sample.
+ */
+public interface SampleAnalysisEnvironment {
+
+ /**
+ * Resolves a Kotlin sample function by its fully qualified name, and returns its import statements and body.
+ *
+ * @param sourceSet must be either the source set in which this sample function resides, or the source set
+ * for which [DokkaConfiguration#samples] or [DokkaConfiguration#sourceRoots]
+ * have been configured with the sample's sources.
+ * @param fullyQualifiedLink fully qualified path to the sample function, including all middle packages
+ * and the name of the function. Only links to Kotlin functions are valid,
+ * which can reside within a class. The package must be the same as the package
+ * declared in the sample file. The function must be resolvable by Dokka,
+ * meaning it must reside either in the main sources of the project or its
+ * sources must be included in [DokkaConfiguration#samples] or
+ * [DokkaConfiguration#sourceRoots]. Example: `com.example.pckg.topLevelKotlinFunction`
+ *
+ * @return a sample code snippet which includes import statements and the function body,
+ * or null if the link could not be resolved (examine the logs to find out the reason).
+ */
+ public fun resolveSample(
+ sourceSet: DokkaConfiguration.DokkaSourceSet,
+ fullyQualifiedLink: String
+ ): SampleSnippet?
+}
diff --git a/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/sample/SampleAnalysisEnvironmentCreator.kt b/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/sample/SampleAnalysisEnvironmentCreator.kt
new file mode 100644
index 00000000..d64734ef
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/sample/SampleAnalysisEnvironmentCreator.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package org.jetbrains.dokka.analysis.kotlin.sample
+
+import org.jetbrains.dokka.analysis.kotlin.KotlinAnalysisPlugin
+
+/**
+ * Entry point to analyzing Kotlin samples.
+ *
+ * Can be acquired via [KotlinAnalysisPlugin.sampleAnalysisEnvironmentCreator].
+ */
+public interface SampleAnalysisEnvironmentCreator {
+
+ /**
+ * Creates and configures the sample analysis environment for a limited-time use.
+ *
+ * Configuring sample analysis environment is a rather expensive operation that takes up additional
+ * resources since Dokka needs to configure and analyze source roots additional to the main ones.
+ * It's best to limit the scope of use and the lifetime of the created environment
+ * so that the resources could be freed as soon as possible.
+ *
+ * No specific cleanup is required by the caller - everything is taken care of automatically
+ * as soon as you exit the [block] block.
+ *
+ * Usage example:
+ * ```kotlin
+ * // create a short-lived environment and resolve all the needed samples
+ * val sample = sampleAnalysisEnvironmentCreator.use {
+ * resolveSample(sampleSourceSet, "org.jetbrains.dokka.sample.functionName")
+ * }
+ * // process the samples
+ * // ...
+ * ```
+ */
+ public fun <T> use(block: SampleAnalysisEnvironment.() -> T): T
+}
diff --git a/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/sample/SampleSnippet.kt b/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/sample/SampleSnippet.kt
new file mode 100644
index 00000000..41b3fa5c
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/sample/SampleSnippet.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package org.jetbrains.dokka.analysis.kotlin.sample
+
+/**
+ * Represents a sample code snippet of a Kotlin function. The snippet includes both file
+ * import directives (all, even unused) and the sample function body.
+ *
+ * @property imports list of import statement values, without the `import` prefix.
+ * Contains no blank lines. Example of a single value: `com.example.pckg.MyClass.function`.
+ * @property body body of the sample function, without the function name or curly braces, only the inner body.
+ * Common minimal indent of all lines is trimmed. Leading and trailing line breaks are removed.
+ * Trailing whitespaces are removed. Example: given the sample function `fun foo() { println("foo") }`,
+ * the sample body will be `println("foo")`.
+ *
+ * @see SampleAnalysisEnvironment for how to acquire it
+ */
+public class SampleSnippet(
+ public val imports: List<String>,
+ public val body: String
+) {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as SampleSnippet
+
+ if (imports != other.imports) return false
+ if (body != other.body) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = imports.hashCode()
+ result = 31 * result + body.hashCode()
+ return result
+ }
+
+ override fun toString(): String {
+ return "SampleSnippet(imports=$imports, body='$body')"
+ }
+}
diff --git a/dokka-subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/sample/SampleAnalysisTest.kt b/dokka-subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/sample/SampleAnalysisTest.kt
index 618e28a8..3b8a2afd 100644
--- a/dokka-subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/sample/SampleAnalysisTest.kt
+++ b/dokka-subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/sample/SampleAnalysisTest.kt
@@ -4,52 +4,515 @@
package org.jetbrains.dokka.analysis.test.sample
+import org.jetbrains.dokka.analysis.kotlin.sample.SampleSnippet
import org.jetbrains.dokka.analysis.test.api.kotlinJvmTestProject
+import org.jetbrains.dokka.analysis.test.api.mixedJvmTestProject
import org.jetbrains.dokka.analysis.test.api.useServices
-import kotlin.test.Test
-import kotlin.test.assertEquals
-import kotlin.test.assertNotNull
+import org.jetbrains.dokka.analysis.test.api.util.CollectingDokkaConsoleLogger
+import org.jetbrains.dokka.analysis.test.api.util.singleSourceSet
+import org.junit.jupiter.api.Tag
+import kotlin.test.*
class SampleAnalysisTest {
@Test
- fun `should return sources of a kotlin sample`() {
+ fun `should resolve a valid sample if set via the samples option`() {
val testProject = kotlinJvmTestProject {
dokkaConfiguration {
kotlinSourceSet {
- additionalSourceRoots = setOf("/samples")
+ samples = setOf("/samples/collections.kt")
}
}
- sampleFile("/samples/stringListOf-sample.kt", fqPackageName = "org.jetbrains.dokka.sample.generator") {
+ sampleFile("/samples/collections.kt", fqPackageName = "org.jetbrains.dokka.sample.collections") {
+"""
import org.jetbrains.dokka.DokkaConfiguration
import org.jetbrains.dokka.DokkaGenerator
import org.jetbrains.dokka.utilities.DokkaLogger
- fun runGenerator(configuration: DokkaConfiguration, logger: DokkaLogger) {
- DokkaGenerator(configuration, logger).generate()
+ fun specificPositionOperations() {
+ val numbers = mutableListOf(1, 2, 3, 4)
+ numbers.add(5)
+ numbers.removeAt(1)
+ numbers[0] = 0
+ numbers.shuffle()
+ if (numbers.size > 0) {
+ println(numbers)
+ }
}
"""
}
}
testProject.useServices { context ->
- val sampleSourceSet = context.configuration.sourceSets.single()
+ val sample = sampleAnalysisEnvironmentCreator.use {
+ resolveSample(
+ sourceSet = context.singleSourceSet(),
+ fullyQualifiedLink = "org.jetbrains.dokka.sample.collections.specificPositionOperations"
+ )
+ }
+ assertNotNull(sample)
+
+ val expectedImports = listOf(
+ "org.jetbrains.dokka.DokkaConfiguration",
+ "org.jetbrains.dokka.DokkaGenerator",
+ "org.jetbrains.dokka.utilities.DokkaLogger"
+ )
- val sampleProvider = sampleProviderFactory.build()
- val sample = sampleProvider.getSample(sampleSourceSet, "org.jetbrains.dokka.sample.generator.runGenerator")
+ val expectedBody = """
+ val numbers = mutableListOf(1, 2, 3, 4)
+ numbers.add(5)
+ numbers.removeAt(1)
+ numbers[0] = 0
+ numbers.shuffle()
+ if (numbers.size > 0) {
+ println(numbers)
+ }
+ """.trimIndent()
+
+ assertEquals(expectedImports, sample.imports)
+ assertEquals(expectedBody, sample.body)
+ }
+ }
+
+ @Test
+ @Tag("onlyDescriptors") // TODO #3359
+ fun `should resolve a valid sample if set via the additionalSourceRoots option`() {
+ val testProject = kotlinJvmTestProject {
+ dokkaConfiguration {
+ kotlinSourceSet {
+ additionalSourceRoots = setOf("/samples")
+ }
+ }
+ sampleFile("/samples/collections.kt", fqPackageName = "org.jetbrains.dokka.sample.collections") {
+ +"""
+ import org.jetbrains.dokka.DokkaConfiguration
+ import org.jetbrains.dokka.DokkaGenerator
+ import org.jetbrains.dokka.utilities.DokkaLogger
+
+ fun specificPositionOperations() {
+ val numbers = mutableListOf(1, 2, 3, 4)
+ numbers.add(5)
+ numbers.removeAt(1)
+ numbers[0] = 0
+ numbers.shuffle()
+ if (numbers.size > 0) {
+ println(numbers)
+ }
+ }
+ """
+ }
+ }
+
+ testProject.useServices { context ->
+ val sample = sampleAnalysisEnvironmentCreator.use {
+ resolveSample(
+ sourceSet = context.singleSourceSet(),
+ fullyQualifiedLink = "org.jetbrains.dokka.sample.collections.specificPositionOperations"
+ )
+ }
assertNotNull(sample)
val expectedImports = listOf(
- "import org.jetbrains.dokka.DokkaConfiguration",
- "import org.jetbrains.dokka.DokkaGenerator",
- "import org.jetbrains.dokka.utilities.DokkaLogger"
- ).joinToString(separator = "\n")
+ "org.jetbrains.dokka.DokkaConfiguration",
+ "org.jetbrains.dokka.DokkaGenerator",
+ "org.jetbrains.dokka.utilities.DokkaLogger"
+ )
+
+ val expectedBody = """
+ val numbers = mutableListOf(1, 2, 3, 4)
+ numbers.add(5)
+ numbers.removeAt(1)
+ numbers[0] = 0
+ numbers.shuffle()
+ if (numbers.size > 0) {
+ println(numbers)
+ }
+ """.trimIndent()
+
+ assertEquals(expectedImports, sample.imports)
+ assertEquals(expectedBody, sample.body)
+ }
+ }
+
+ @Test
+ @Tag("onlyDescriptors") // TODO #3359
+ fun `should resolve a valid sample function that exists in the main source set`() {
+ val testProject = kotlinJvmTestProject {
+ ktFile("org/jetbrains/dokka/test/MyKotlinFile.kt") {
+ +"""
+ import org.jetbrains.dokka.DokkaConfiguration
+
+ fun myAverageTopLevelFunction() {
+ println("hello from the average top level function")
+ }
+ """
+ }
+ }
+
+ testProject.useServices { context ->
+ val sample = sampleAnalysisEnvironmentCreator.use {
+ resolveSample(context.singleSourceSet(), "org.jetbrains.dokka.test.myAverageTopLevelFunction")
+ }
+ assertNotNull(sample)
+
+ val expectedImports = listOf("org.jetbrains.dokka.DokkaConfiguration")
+ val expectedBody = "println(\"hello from the average top level function\")"
+
+ assertEquals(expectedImports, sample.imports)
+ assertEquals(expectedBody, sample.body)
+ }
+ }
+
+ @Test
+ fun `should resolve a valid sample in the root package`() {
+ val testProject = kotlinJvmTestProject {
+ dokkaConfiguration {
+ kotlinSourceSet {
+ samples = setOf("/samples/TopLevelSample.kt")
+ }
+ }
+
+ sampleFile("/samples/TopLevelSample.kt", fqPackageName = "") {
+ +"""
+ import org.jetbrains.dokka.DokkaConfiguration
+
+ fun foo() {
+ println("hello from the root")
+ }
+ """
+ }
+ }
+
+ testProject.useServices { context ->
+ val sample = sampleAnalysisEnvironmentCreator.use {
+ resolveSample(context.singleSourceSet(), "foo")
+ }
+ assertNotNull(sample)
+
+ val expectedImports = listOf("org.jetbrains.dokka.DokkaConfiguration")
+ val expectedBody = "println(\"hello from the root\")"
+
+ assertEquals(expectedImports, sample.imports)
+ assertEquals(expectedBody, sample.body)
+ }
+ }
+
+ @Test
+ fun `should resolve a valid sample function from a class in the root package`() {
+ val testProject = kotlinJvmTestProject {
+ dokkaConfiguration {
+ kotlinSourceSet {
+ samples = setOf("/samples/RootClassSample.kt")
+ }
+ }
+
+ sampleFile("/samples/RootClassSample.kt", fqPackageName = "") {
+ +"""
+ import org.jetbrains.dokka.DokkaConfiguration
+
+ class RootClass {
+ fun foo() {
+ println("hello from within a root class")
+ }
+ }
+ """
+ }
+ }
+
+ testProject.useServices { context ->
+ val sample = sampleAnalysisEnvironmentCreator.use {
+ resolveSample(context.singleSourceSet(), "RootClass.foo")
+ }
+ assertNotNull(sample)
+
+ val expectedImports = listOf("org.jetbrains.dokka.DokkaConfiguration")
+ val expectedBody = "println(\"hello from within a root class\")"
+
+ assertEquals(expectedImports, sample.imports)
+ assertEquals(expectedBody, sample.body)
+ }
+ }
+
+ @Test
+ fun `should resolve a valid sample function from a class`() {
+ val testProject = kotlinJvmTestProject {
+ dokkaConfiguration {
+ kotlinSourceSet {
+ samples = setOf("/samples/SampleWithinClass.kt")
+ }
+ }
+
+ sampleFile("/samples/SampleWithinClass.kt", fqPackageName = "samples") {
+ +"""
+ import org.jetbrains.dokka.DokkaConfiguration
+
+ package samples
+
+ class SampleWithinClass {
+ fun foo() {
+ println("hello from within a class")
+ }
+ }
+ """
+ }
+ }
+
+ testProject.useServices { context ->
+ val sample = sampleAnalysisEnvironmentCreator.use {
+ resolveSample(context.singleSourceSet(), "samples.SampleWithinClass.foo")
+ }
+ assertNotNull(sample)
+
+ val expectedImports = listOf("org.jetbrains.dokka.DokkaConfiguration")
+ val expectedBody = "println(\"hello from within a class\")"
+
+ assertEquals(expectedImports, sample.imports)
+ assertEquals(expectedBody, sample.body)
+ }
+ }
+
+ @Test
+ fun `should return null for non-existing sample`() {
+ val testProject = kotlinJvmTestProject {
+ // nothing
+ }
+
+ testProject.useServices { context ->
+ val nonExistingSample = sampleAnalysisEnvironmentCreator.use {
+ resolveSample(context.singleSourceSet(), "com.example.non.existing.sampleFunction")
+ }
+
+ assertNull(nonExistingSample)
+ }
+ }
+
+ @Test
+ fun `should return null if sample is resolved just by class name`() {
+ val testProject = kotlinJvmTestProject {
+ dokkaConfiguration {
+ kotlinSourceSet {
+ samples = setOf("/samples/FooSampleFile.kt")
+ }
+ }
+ sampleFile("/samples/FooSampleFile.kt", fqPackageName = "org.jetbrains.dokka.sample") {
+ +"""
+ import org.jetbrains.dokka.DokkaConfiguration
+
+ fun topLevelFunction() {}
+
+ class FooSampleClass {
+ fun foo() {
+ println("foo")
+ }
+ }
+ """
+ }
+ }
+
+ val collectingLogger = CollectingDokkaConsoleLogger()
+ testProject.useServices(collectingLogger) { context ->
+ val sampleByClassName = sampleAnalysisEnvironmentCreator.use {
+ resolveSample(context.singleSourceSet(), "org.jetbrains.dokka.sample.FooSampleClass")
+ }
+ assertNull(sampleByClassName)
+ }
+
+ val containsNonKotlinSampleLinkLog = collectingLogger.collectedLogMessages.contains(
+ "Unable to process a @sample link: \"org.jetbrains.dokka.sample.FooSampleClass\". " +
+ "Only function links allowed."
+ )
+ assertTrue(containsNonKotlinSampleLinkLog)
+ }
+
+ @Test
+ @Tag("onlyDescriptors") // TODO #3359
+ fun `should return null if trying to resolve a non-kotlin sample link`() {
+ val testProject = mixedJvmTestProject {
+ kotlinSourceDirectory {
+ javaFile("org/jetbrains/test/sample/JavaClass.java") {
+ +"""
+ public class JavaClass {
+ public void foo() {
+ System.out.println("foo");
+ }
+ }
+ """
+ }
+ ktFile("org/jetbrains/test/sample/KotlinFile.kt") {
+ +"""
+ fun foo() {}
+ """
+ }
+ }
+ }
+
+ val collectingLogger = CollectingDokkaConsoleLogger()
+ testProject.useServices(collectingLogger) { context ->
+ sampleAnalysisEnvironmentCreator.use {
+ val kotlinSourceSet = context.singleSourceSet()
+
+ val byClassName = resolveSample(kotlinSourceSet, "org.jetbrains.test.sample.JavaClass")
+ assertNull(byClassName)
+
+ val byClassFunctionName = resolveSample(kotlinSourceSet, "org.jetbrains.test.sample.JavaClass.foo")
+ assertNull(byClassFunctionName)
+ }
+ }
+
+ val containsNonKotlinSampleLinkLog = collectingLogger.collectedLogMessages.contains(
+ "Unable to resolve non-Kotlin @sample links: \"org.jetbrains.test.sample.JavaClass\""
+ )
+ assertTrue(containsNonKotlinSampleLinkLog)
+ }
+
+ @Test
+ @Tag("onlyDescriptors") // TODO #3359
+ fun `should filter out empty import statement lines`() {
+ val testProject = kotlinJvmTestProject {
+ ktFile("org/jetbrains/dokka/test/MyKotlinFile.kt") {
+ +"""
+ import org.jetbrains.dokka.DokkaConfiguration
+
+ import org.jetbrains.dokka.DokkaGenerator
+
+ import org.jetbrains.dokka.utilities.DokkaLogger
+
+ fun sample() {
+ println("hello from sample")
+ }
+ """
+ }
+ }
+
+ testProject.useServices { context ->
+ val sample = sampleAnalysisEnvironmentCreator.use {
+ resolveSample(context.singleSourceSet(), "org.jetbrains.dokka.test.sample")
+ }
+ assertNotNull(sample)
- val expectedBody = "DokkaGenerator(configuration, logger).generate()"
+ val expectedImports = listOf(
+ "org.jetbrains.dokka.DokkaConfiguration",
+ "org.jetbrains.dokka.DokkaGenerator",
+ "org.jetbrains.dokka.utilities.DokkaLogger",
+ )
+ val expectedBody = "println(\"hello from sample\")"
assertEquals(expectedImports, sample.imports)
assertEquals(expectedBody, sample.body)
}
}
+
+ @Test
+ @Tag("onlyDescriptors") // TODO #3359
+ fun `should return an empty list of imports if sample file has none`() {
+ val testProject = kotlinJvmTestProject {
+ ktFile("org/jetbrains/dokka/test/MyKotlinFile.kt") {
+ +"""
+ fun sample() {
+ println("hello from sample")
+ }
+ """
+ }
+ }
+
+ testProject.useServices { context ->
+ val sample = sampleAnalysisEnvironmentCreator.use {
+ resolveSample(context.singleSourceSet(), "org.jetbrains.dokka.test.sample")
+ }
+ assertNotNull(sample)
+
+ assertTrue(sample.imports.isEmpty())
+
+ val expectedBody = "println(\"hello from sample\")"
+ assertEquals(expectedBody, sample.body)
+
+ }
+ }
+
+ @Test
+ @Tag("onlyDescriptors") // TODO #3359
+ fun `should filter out leading and trailing line breaks`() {
+ val testProject = kotlinJvmTestProject {
+ ktFile("org/jetbrains/dokka/test/MyKotlinFile.kt") {
+ +"""
+ fun sample() {
+
+
+ println("hello from sample")
+
+
+
+ }
+ """
+ }
+ }
+
+ testProject.useServices { context ->
+ val sample = sampleAnalysisEnvironmentCreator.use {
+ resolveSample(context.singleSourceSet(), "org.jetbrains.dokka.test.sample")
+ }
+ assertNotNull(sample)
+
+ val expectedBody = "println(\"hello from sample\")"
+ assertEquals(expectedBody, sample.body)
+ }
+ }
+
+ @Test
+ @Tag("onlyDescriptors") // TODO #3359
+ fun `should filter out trailing whitespace`() {
+ val testProject = kotlinJvmTestProject {
+ ktFile("org/jetbrains/dokka/test/MyKotlinFile.kt") {
+ +"""
+ fun sample() {
+ println("hello from sample")
+ }
+ """
+ }
+ }
+
+ testProject.useServices { context ->
+ val sample = sampleAnalysisEnvironmentCreator.use {
+ resolveSample(context.singleSourceSet(), "org.jetbrains.dokka.test.sample")
+ }
+ assertNotNull(sample)
+
+ val expectedBody = "println(\"hello from sample\")"
+ assertEquals(expectedBody, sample.body)
+ }
+ }
+
+ @Test
+ fun `should see two identical snippets as equal`() {
+ val firstSnippet = createHardcodedSnippet()
+ val secondSnippet = createHardcodedSnippet()