aboutsummaryrefslogtreecommitdiff
path: root/subprojects/analysis-kotlin-api/src/testFixtures
diff options
context:
space:
mode:
authorIgnat Beresnev <ignat.beresnev@jetbrains.com>2023-10-27 13:11:41 +0200
committerGitHub <noreply@github.com>2023-10-27 13:11:41 +0200
commitedcd1fb24d01e11b5a8185328255f2005aadf037 (patch)
tree8156df7d2d29d8fd9d0fdaccad0fbb92b26e895f /subprojects/analysis-kotlin-api/src/testFixtures
parentb1ccc2b346ea858762653933f9dd304b91c18505 (diff)
downloaddokka-edcd1fb24d01e11b5a8185328255f2005aadf037.tar.gz
dokka-edcd1fb24d01e11b5a8185328255f2005aadf037.tar.bz2
dokka-edcd1fb24d01e11b5a8185328255f2005aadf037.zip
Implement analysis test API (#3184)
Diffstat (limited to 'subprojects/analysis-kotlin-api/src/testFixtures')
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestData.kt21
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestDataFile.kt37
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestProject.kt97
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestProjectFactory.kt67
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestAnalysisContext.kt36
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestAnalysisServices.kt20
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestProjectAnalyzer.kt223
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/configuration/TestDokkaConfiguration.kt171
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/configuration/TestDokkaConfigurationBuilder.kt145
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/configuration/TestDokkaConfigurationMapper.kt177
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/java/JavaConfigurationBuilder.kt61
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/java/JavaFileCreator.kt25
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/java/JavaTestData.kt54
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/java/JavaTestDataFile.kt27
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/java/JavaTestProject.kt73
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/kotlin/KotlinJvmConfigurationBuilder.kt56
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/kotlin/KotlinJvmDependencyUtils.kt22
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/kotlin/KotlinJvmTestProject.kt93
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/mixed/MixedJvmConfigurationBuilder.kt69
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/mixed/MixedJvmTestData.kt47
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/mixed/MixedJvmTestProject.kt80
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/kotlin/KotlinTestData.kt48
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/kotlin/KotlinTestDataFile.kt27
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/kotlin/KtFileCreator.kt32
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/kotlin/sample/KotlinSampleFileCreator.kt32
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/kotlin/sample/KotlinSampleTestData.kt44
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/kotlin/sample/KotlinSampleTestDataFile.kt27
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/markdown/MarkdownTestData.kt40
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/markdown/MarkdownTestDataFile.kt26
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/markdown/MdFileCreator.kt28
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/util/CollectionUtils.kt18
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/util/DslApiUtils.kt9
-rw-r--r--subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/util/FileUtils.kt41
33 files changed, 1973 insertions, 0 deletions
diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestData.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestData.kt
new file mode 100644
index 00000000..64bfd7a3
--- /dev/null
+++ b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestData.kt
@@ -0,0 +1,21 @@
+/*
+ * 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.test.api
+
+import org.jetbrains.dokka.analysis.test.api.util.AnalysisTestDslMarker
+
+/**
+ * Represents some sort of data of a [TestProject], which normally consists of a number of [TestDataFile].
+ *
+ * This can be anything that can usually be found in a user-defined project:
+ * programming language source code, markdown files with documentation, samples, etc.
+ *
+ * This virtual test data will be materialized and created physically before running Dokka,
+ * and then passed as input files into it.
+ */
+@AnalysisTestDslMarker
+interface TestData {
+ fun getFiles(): List<TestDataFile>
+}
diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestDataFile.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestDataFile.kt
new file mode 100644
index 00000000..5b2233ba
--- /dev/null
+++ b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestDataFile.kt
@@ -0,0 +1,37 @@
+/*
+ * 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.test.api
+
+import org.jetbrains.dokka.analysis.test.api.util.AnalysisTestDslMarker
+
+/**
+ * Represents a single file of a project's [TestData].
+ *
+ * This file will be materialized and created physically before running Dokka,
+ * and then passed as one of the input files into it.
+ *
+ * @property pathFromProjectRoot this file's path from the root of the project. Must begin
+ * with `/` to not confuse it with relative paths.
+ */
+@AnalysisTestDslMarker
+abstract class TestDataFile(val pathFromProjectRoot: String) {
+
+ init {
+ require(pathFromProjectRoot.startsWith("/")) {
+ "File path going from the project's root must begin with \"/\" to not confuse it with relative paths."
+ }
+ }
+
+ /**
+ * Returns the string contents of this file.
+ *
+ * The contents must be complete, as if the user themselves wrote it. For Kotlin files,
+ * it should return Kotlin source code (including the package and all import statements).
+ * For `.md` files, it should return valid Markdown documentation.
+ *
+ * These contents will be used to populate the real input file to be used by Dokka.
+ */
+ abstract fun getContents(): String
+}
diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestProject.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestProject.kt
new file mode 100644
index 00000000..9c0fa936
--- /dev/null
+++ b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestProject.kt
@@ -0,0 +1,97 @@
+/*
+ * 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.test.api
+
+import org.jetbrains.dokka.DokkaConfiguration
+import org.jetbrains.dokka.analysis.test.api.analysis.TestAnalysisContext
+import org.jetbrains.dokka.analysis.test.api.analysis.TestAnalysisServices
+import org.jetbrains.dokka.analysis.test.api.analysis.TestProjectAnalyzer
+import org.jetbrains.dokka.analysis.test.api.configuration.BaseTestDokkaConfigurationBuilder
+import org.jetbrains.dokka.analysis.test.api.configuration.TestDokkaConfiguration
+import org.jetbrains.dokka.analysis.test.api.util.withTempDirectory
+import org.jetbrains.dokka.model.DModule
+
+/**
+ * Represents a virtual test project (as if it's user-defined) that will be used to run Dokka.
+ *
+ * A test project consists of some Dokka configuration (represented as [TestDokkaConfiguration])
+ * and some project-specific data like source code and markdown files (represented as [TestData]).
+ *
+ * See [kotlinJvmTestProject], [javaTestProject] and [mixedJvmTestProject] for convenient ways
+ * of bootstrapping test projects.
+ *
+ * See [parse] and [useServices] functions to learn how to run Dokka with this project as input.
+ */
+interface TestProject {
+
+ /**
+ * Verifies that this project is valid from the user's and Dokka's perspectives.
+ * Exists to save time with debugging difficult to catch mistakes, such as copy-pasted
+ * test data that is not applicable to this project.
+ *
+ * Must throw an exception if there's misconfiguration, incorrect / corrupted test data
+ * or API misuse.
+ *
+ * Verification is performed before running Dokka on this project.
+ */
+ fun verify()
+
+ /**
+ * Returns the configuration of this project, which will then be mapped to [DokkaConfiguration].
+ *
+ * This is typically constructed using [BaseTestDokkaConfigurationBuilder].
+ */
+ fun getConfiguration(): TestDokkaConfiguration
+
+ /**
+ * Returns this project's test data - a collection of source code files, markdown files
+ * and whatever else that can be usually found in a user-defined project.
+ */
+ fun getTestData(): TestData
+}
+
+/**
+ * Runs Dokka on the given [TestProject] and returns the generated documentable model.
+ *
+ * Can be used to verify the resulting documentable model, to check that
+ * everything was parsed and converted correctly.
+ *
+ * Usage example:
+ * ```kotlin
+ * val testProject = kotlinJvmTestProject {
+ * ...
+ * }
+ *
+ * val module: DModule = testProject.parse()
+ * ```
+ */
+fun TestProject.parse(): DModule = TestProjectAnalyzer.parse(this)
+
+/**
+ * Runs Dokka on the given [TestProject] and provides not only the resulting documentable model,
+ * but analysis context and configuration as well, which gives you the ability to call public
+ * analysis services.
+ *
+ * Usage example:
+ *
+ * ```kotlin
+ * val testProject = kotlinJvmTestProject {
+ * ...
+ * }
+ *
+ * testProject.useServices { context ->
+ * val pckg: DPackage = context.module.packages.single()
+ *
+ * // use `moduleAndPackageDocumentationReader` service to get documentation of a package
+ * val allPackageDocs: SourceSetDependent<DocumentationNode> = moduleAndPackageDocumentationReader.read(pckg)
+ * }
+ * ```
+ */
+fun TestProject.useServices(block: TestAnalysisServices.(context: TestAnalysisContext) -> Unit) {
+ withTempDirectory { tempDirectory ->
+ val (services, context) = TestProjectAnalyzer.analyze(this, tempDirectory)
+ services.block(context)
+ }
+}
diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestProjectFactory.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestProjectFactory.kt
new file mode 100644
index 00000000..81a20243
--- /dev/null
+++ b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestProjectFactory.kt
@@ -0,0 +1,67 @@
+/*
+ * 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.test.api
+
+import org.jetbrains.dokka.analysis.test.api.jvm.java.JavaTestProject
+import org.jetbrains.dokka.analysis.test.api.jvm.kotlin.KotlinJvmTestProject
+import org.jetbrains.dokka.analysis.test.api.jvm.mixed.MixedJvmTestProject
+import org.jetbrains.dokka.analysis.test.api.util.AnalysisTestDslMarker
+
+/**
+ * Creates a single-target Kotlin/JVM test project that only has Kotlin source code.
+ *
+ * See [javaTestProject] and [mixedJvmTestProject] if you want to check interoperability
+ * with other JVM languages.
+ *
+ * By default, the sources are put in `/src/main/kotlin`, and the JVM version of Kotlin's
+ * standard library is available on classpath.
+ *
+ * See [parse] and [useServices] functions to learn how to run Dokka with this project as input.
+ *
+ * @sample org.jetbrains.dokka.analysis.test.jvm.kotlin.SampleKotlinJvmAnalysisTest.sample
+ */
+fun kotlinJvmTestProject(init: (@AnalysisTestDslMarker KotlinJvmTestProject).() -> Unit): TestProject {
+ val testData = KotlinJvmTestProject()
+ testData.init()
+ return testData
+}
+
+/**
+ * Creates a Java-only test project.
+ *
+ * This can be used to test Dokka's Java support or specific
+ * corner cases related to parsing Java sources.
+ *
+ * By default, the sources are put in `/src/main/java`. No Kotlin source code is allowed.
+ *
+ * See [parse] and [useServices] functions to learn how to run Dokka with this project as input.
+ *
+ * @sample org.jetbrains.dokka.analysis.test.jvm.java.SampleJavaAnalysisTest.sample
+ */
+fun javaTestProject(init: (@AnalysisTestDslMarker JavaTestProject).() -> Unit): TestProject {
+ val testData = JavaTestProject()
+ testData.init()
+ return testData
+}
+
+/**
+ * Creates a project where a number of JVM language sources are allowed,
+ * like Java and Kotlin sources co-existing in the same source directory.
+ *
+ * This can be used to test interoperability between JVM languages.
+ *
+ * By default, this project consists of a single "jvm" source set, which has two source root directories:
+ * * `/src/main/kotlin`
+ * * `/src/main/java`
+ *
+ * See [parse] and [useServices] functions to learn how to run Dokka with this project as input.
+ *
+ * @sample org.jetbrains.dokka.analysis.test.jvm.mixed.SampleMixedJvmAnalysisTest.sample
+ */
+fun mixedJvmTestProject(init: (@AnalysisTestDslMarker MixedJvmTestProject).() -> Unit): TestProject {
+ val testProject = MixedJvmTestProject()
+ testProject.init()
+ return testProject
+}
diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestAnalysisContext.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestAnalysisContext.kt
new file mode 100644
index 00000000..de6efb1b
--- /dev/null
+++ b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestAnalysisContext.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.test.api.analysis
+
+import org.jetbrains.dokka.DokkaConfiguration
+import org.jetbrains.dokka.analysis.test.api.TestProject
+import org.jetbrains.dokka.analysis.test.api.configuration.TestDokkaConfiguration
+import org.jetbrains.dokka.model.DModule
+import org.jetbrains.dokka.plugability.DokkaContext
+
+/**
+ * Context and data gathered during the analysis of a [TestProject].
+ */
+class TestAnalysisContext(
+
+ /**
+ * The actual [DokkaContext] that was used to run Dokka.
+ *
+ * Includes all plugins and classes available on classpath during the analysis.
+ */
+ val context: DokkaContext,
+
+ /**
+ * The actual [DokkaConfiguration] that was used to run Dokka.
+ *
+ * It was initially mapped from [TestDokkaConfiguration], and then added to by Dokka itself.
+ */
+ val configuration: DokkaConfiguration,
+
+ /**
+ * The entry point to the documentable model of the analyzed [TestProject].
+ */
+ val module: DModule
+)
diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestAnalysisServices.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestAnalysisServices.kt
new file mode 100644
index 00000000..ab70bbd4
--- /dev/null
+++ b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestAnalysisServices.kt
@@ -0,0 +1,20 @@
+/*
+ * 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.test.api.analysis
+
+import org.jetbrains.dokka.analysis.kotlin.KotlinAnalysisPlugin
+import org.jetbrains.dokka.analysis.kotlin.internal.ModuleAndPackageDocumentationReader
+import org.jetbrains.dokka.analysis.kotlin.internal.SampleProviderFactory
+
+/**
+ * Services exposed in [KotlinAnalysisPlugin] that are ready to be used.
+ *
+ * This class exists purely for convenience and to reduce boilerplate in tests.
+ * It is analogous to calling `context.plugin<KotlinAnalysisPlugin>().querySingle { serviceName }`.
+ */
+class TestAnalysisServices(
+ val sampleProviderFactory: SampleProviderFactory,
+ val moduleAndPackageDocumentationReader: ModuleAndPackageDocumentationReader
+)
diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestProjectAnalyzer.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestProjectAnalyzer.kt
new file mode 100644
index 00000000..1668b53f
--- /dev/null
+++ b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestProjectAnalyzer.kt
@@ -0,0 +1,223 @@
+/*
+ * 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.test.api.analysis
+
+import org.jetbrains.dokka.CoreExtensions
+import org.jetbrains.dokka.DokkaConfiguration
+import org.jetbrains.dokka.analysis.kotlin.internal.InternalKotlinAnalysisPlugin
+import org.jetbrains.dokka.analysis.test.api.TestDataFile
+import org.jetbrains.dokka.analysis.test.api.TestProject
+import org.jetbrains.dokka.analysis.test.api.configuration.toDokkaConfiguration
+import org.jetbrains.dokka.analysis.test.api.parse
+import org.jetbrains.dokka.analysis.test.api.useServices
+import org.jetbrains.dokka.analysis.test.api.util.withTempDirectory
+import org.jetbrains.dokka.model.DModule
+import org.jetbrains.dokka.plugability.DokkaContext
+import org.jetbrains.dokka.plugability.plugin
+import org.jetbrains.dokka.plugability.querySingle
+import org.jetbrains.dokka.transformers.documentation.DefaultDocumentableMerger
+import org.jetbrains.dokka.transformers.documentation.DocumentableMerger
+import org.jetbrains.dokka.transformers.sources.SourceToDocumentableTranslator
+import org.jetbrains.dokka.utilities.DokkaConsoleLogger
+import org.jetbrains.dokka.utilities.LoggingLevel
+import java.io.File
+
+/**
+ * The main logger used for running Dokka and analyzing projects.
+ *
+ * Changing the level to [LoggingLevel.DEBUG] can help with debugging faulty tests
+ * or tricky corner cases.
+ */
+val analysisLogger = DokkaConsoleLogger(minLevel = LoggingLevel.INFO)
+
+/**
+ * Analyzer of the test projects, it is essentially a very simple Dokka runner.
+ *
+ * Takes all virtual files of the given [TestProject], creates the real files for
+ * them in a temporary directory, and then runs Dokka with this temporary directory
+ * as the input user project. This allows us to simulate Dokka's behavior and results
+ * on a made-up project as if it were real and run via the CLI runner.
+ *
+ * Executes only a limited number of steps and uses a small subset of [CoreExtensions]
+ * that are necessary to test the analysis logic.
+ *
+ * Works only with single-module projects, where the source code of this project
+ * resides in the root `src` directory. Works with multiple source sets and targets,
+ * so both simple Kotlin/JVM and more complicated Kotlin Multiplatform project must work.
+ */
+object TestProjectAnalyzer {
+
+ /**
+ * A quick way to analyze a [TestProject], for cases when only the documentable
+ * model is needed to verify the result.
+ *
+ * Creates the input test files, runs Dokka and then deletes them right after the documentable
+ * model has been created, leaving no trailing files or any other garbage behind.
+ *
+ * @see [TestProject.parse] for a user-friendly way to call it
+ */
+ fun parse(testProject: TestProject): DModule {
+ // since we only need documentables, we can delete the input test files right away
+ return withTempDirectory(analysisLogger) { tempDirectory ->
+ val (_, context) = testProject.initialize(outputDirectory = tempDirectory)
+ generateDocumentableModel(context)
+ }
+ }
+
+ /**
+ * Works in the same way as [parse], but it returns the context and configuration used for
+ * running Dokka, and does not delete the input test files at the end of the execution - it
+ * must be taken care of on call site.
+ *
+ * @param persistentDirectory a directory that will be used to generate the input test files into.
+ * It must be available during the test run, especially if services are used,
+ * otherwise parts of Dokka might not work as expected. Can be safely deleted
+ * at the end of the test after all asserts have been run.
+ *
+ * @see [TestProject.useServices] for a user-friendly way to call it
+ */
+ fun analyze(
+ testProject: TestProject,
+ persistentDirectory: File
+ ): Pair<TestAnalysisServices, TestAnalysisContext> {
+ val (dokkaConfiguration, dokkaContext) = testProject.initialize(outputDirectory = persistentDirectory)
+ val analysisServices = createTestAnalysisServices(dokkaContext)
+ val testAnalysisContext = TestAnalysisContext(
+ context = dokkaContext,
+ configuration = dokkaConfiguration,
+ module = generateDocumentableModel(dokkaContext)
+ )
+ return analysisServices to testAnalysisContext
+ }
+
+ /**
+ * Prepares this [TestProject] for analysis by creating
+ * the test files, setting up context and configuration.
+ */
+ private fun TestProject.initialize(outputDirectory: File): Pair<DokkaConfiguration, DokkaContext> {
+ analysisLogger.progress("Initializing and verifying project $this")
+ this.verify()
+ require(outputDirectory.isDirectory) {
+ "outputDirectory has to exist and be a directory: $outputDirectory"
+ }
+ this.initializeTestFiles(relativeToDir = outputDirectory)
+
+ analysisLogger.progress("Creating configuration and context")
+ val testDokkaConfiguration = this.getConfiguration()
+ val dokkaConfiguration = testDokkaConfiguration.toDokkaConfiguration(projectDir = outputDirectory).also {
+ it.verify()
+ }
+ return dokkaConfiguration to createContext(dokkaConfiguration)
+ }
+
+ /**
+ * Takes the virtual [TestDataFile] of this [TestProject] and creates
+ * the real files relative to the [relativeToDir] param.
+ */
+ private fun TestProject.initializeTestFiles(relativeToDir: File) {
+ analysisLogger.progress("Initializing test files relative to the \"$relativeToDir\" directory")
+
+ this.getTestData().getFiles().forEach {
+ val testDataFile = relativeToDir.resolve(it.pathFromProjectRoot.removePrefix("/"))
+ try {
+ testDataFile.parentFile.mkdirs()
+ } catch (e: Exception) {
+ // the IOException thrown from `mkdirs()` has no details and thus is more difficult to debug.
+ throw IllegalStateException("Unable to create dirs \"${testDataFile.parentFile}\"", e)
+ }
+
+ analysisLogger.debug("Creating \"${testDataFile.absolutePath}\"")
+ check(testDataFile.createNewFile()) {
+ "Unable to create a test file: ${testDataFile.absolutePath}"
+ }
+ testDataFile.writeText(it.getContents(), Charsets.UTF_8)
+ }
+ }
+
+ /**
+ * Verifies this [DokkaConfiguration] to make sure there are no unexpected
+ * parameter option values, such as non-existing classpath entries.
+ *
+ * If this method fails, it's likely there's a configuration error in the test,
+ * or an exception must be made in one of the checks.
+ */
+ private fun DokkaConfiguration.verify() {
+ this.includes.forEach { verifyFileExists(it) }
+ this.sourceSets.forEach { sourceSet ->
+ sourceSet.classpath.forEach { verifyFileExists(it) }
+ sourceSet.includes.forEach { verifyFileExists(it) }
+ sourceSet.samples.forEach { verifyFileExists(it) }
+ // we do not verify sourceRoots since the source directory
+ // is not guaranteed to exist even if it was configured.
+ }
+ }
+
+ private fun verifyFileExists(file: File) {
+ if (!file.exists() && !file.absolutePath.contains("non-existing")) {
+ throw IllegalArgumentException(
+ "The provided file does not exist. Bad test data or configuration? " +
+ "If it is done intentionally, add \"non-existing\" to the path or the name. File: \"$file\""
+ )
+ }
+ }
+
+ private fun createContext(dokkaConfiguration: DokkaConfiguration): DokkaContext {
+ analysisLogger.progress("Creating DokkaContext from test configuration")
+ return DokkaContext.create(
+ configuration = dokkaConfiguration,
+ logger = analysisLogger,
+ pluginOverrides = listOf()
+ )
+ }
+
+ /**
+ * Generates the documentable model by using all available [SourceToDocumentableTranslator] extensions,
+ * and then merging all the results into a single [DModule] by calling [DocumentableMerger].
+ */
+ private fun generateDocumentableModel(context: DokkaContext): DModule {
+ analysisLogger.progress("Generating the documentable model")
+ val sourceSetModules = context
+ .configuration
+ .sourceSets
+ .map { sourceSet -> translateSources(sourceSet, context) }
+ .flatten()
+
+ if (sourceSetModules.isEmpty()) {
+ throw IllegalStateException("Got no modules after translating sources. Is the test data set up?")
+ }
+
+ return DefaultDocumentableMerger(context).invoke(sourceSetModules)
+ ?: error("Unable to merge documentables for some reason")
+ }
+
+ /**
+ * Translates input source files to the documentable model by using
+ * all registered [SourceToDocumentableTranslator] core extensions.
+ */
+ private fun translateSources(sourceSet: DokkaConfiguration.DokkaSourceSet, context: DokkaContext): List<DModule> {
+ val translators = context[CoreExtensions.sourceToDocumentableTranslator]
+ require(translators.isNotEmpty()) {
+ "Need at least one source to documentable translator to run tests, otherwise no data will be generated."
+ }
+ analysisLogger.debug("Translating sources for ${sourceSet.sourceSetID}")
+ return translators.map { it.invoke(sourceSet, context) }
+ }
+
+ /**
+ * A helper function to query analysis services, to avoid
+ * boilerplate and misconfiguration in the tests.
+ *
+ * The idea is to provide the users with ready-to-use services,
+ * without them having to know how to query or configure them.
+ */
+ private fun createTestAnalysisServices(context: DokkaContext): TestAnalysisServices {
+ analysisLogger.progress("Creating analysis services")
+ val internalPlugin = context.plugin<InternalKotlinAnalysisPlugin>()
+ return TestAnalysisServices(
+ sampleProviderFactory = internalPlugin.querySingle { sampleProviderFactory },
+ moduleAndPackageDocumentationReader = internalPlugin.querySingle { moduleAndPackageDocumentationReader }
+ )
+ }
+}
diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/configuration/TestDokkaConfiguration.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/configuration/TestDokkaConfiguration.kt
new file mode 100644
index 00000000..5c5a0daf
--- /dev/null
+++ b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/configuration/TestDokkaConfiguration.kt
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2014-2023 JetBrai