aboutsummaryrefslogtreecommitdiff
path: root/subprojects/analysis-kotlin-api/src
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/analysis-kotlin-api/src')
-rw-r--r--subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/jvm/java/SampleJavaAnalysisTest.kt49
-rw-r--r--subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/jvm/kotlin/SampleKotlinJvmAnalysisTest.kt43
-rw-r--r--subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/jvm/mixed/SampleMixedJvmAnalysisTest.kt81
-rw-r--r--subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/moduledocs/PackageDocumentationAnalysisTest.kt66
-rw-r--r--subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/sample/SampleAnalysisTest.kt55
-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
38 files changed, 2267 insertions, 0 deletions
diff --git a/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/jvm/java/SampleJavaAnalysisTest.kt b/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/jvm/java/SampleJavaAnalysisTest.kt
new file mode 100644
index 00000000..f6632f60
--- /dev/null
+++ b/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/jvm/java/SampleJavaAnalysisTest.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.jvm.java
+
+import org.jetbrains.dokka.analysis.test.api.javaTestProject
+import org.jetbrains.dokka.analysis.test.api.parse
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+class SampleJavaAnalysisTest {
+
+ /**
+ * Used as a sample for [javaTestProject]
+ */
+ @Test
+ fun sample() {
+ val testProject = javaTestProject {
+ dokkaConfiguration {
+ moduleName = "java-module-name-for-unit-test"
+
+ javaSourceSet {
+ // source-set specific configuration
+ }
+ }
+ javaFile(pathFromSrc = "org/jetbrains/dokka/test/java/Bar.java") {
+ +"""
+ public class Bar {
+ public static void bar() {
+ System.out.println("Bar");
+ }
+ }
+ """
+ }
+ }
+
+ val module = testProject.parse()
+ assertEquals("java-module-name-for-unit-test", module.name)
+ assertEquals(1, module.packages.size)
+
+ val pckg = module.packages[0]
+ assertEquals("org.jetbrains.dokka.test.java", pckg.name)
+ assertEquals(1, pckg.classlikes.size)
+
+ val fooClass = pckg.classlikes[0]
+ assertEquals("Bar", fooClass.name)
+ }
+}
diff --git a/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/jvm/kotlin/SampleKotlinJvmAnalysisTest.kt b/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/jvm/kotlin/SampleKotlinJvmAnalysisTest.kt
new file mode 100644
index 00000000..6c73af1f
--- /dev/null
+++ b/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/jvm/kotlin/SampleKotlinJvmAnalysisTest.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.test.jvm.kotlin
+
+import org.jetbrains.dokka.analysis.test.api.kotlinJvmTestProject
+import org.jetbrains.dokka.analysis.test.api.parse
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+class SampleKotlinJvmAnalysisTest {
+
+ /**
+ * Used as a sample for [kotlinJvmTestProject]
+ */
+ @Test
+ fun sample() {
+ val testProject = kotlinJvmTestProject {
+ dokkaConfiguration {
+ moduleName = "kotlin-jvm-module-name-for-unit-test"
+
+ kotlinSourceSet {
+ // source-set specific configuration
+ }
+ }
+ ktFile(pathFromSrc = "org/jetbrains/dokka/test/kotlin/MyFile.kt") {
+ +"public class Foo {}"
+ }
+ }
+
+ val module = testProject.parse()
+ assertEquals("kotlin-jvm-module-name-for-unit-test", module.name)
+ assertEquals(1, module.packages.size)
+
+ val pckg = module.packages[0]
+ assertEquals("org.jetbrains.dokka.test.kotlin", pckg.name)
+ assertEquals(1, pckg.classlikes.size)
+
+ val fooClass = pckg.classlikes[0]
+ assertEquals("Foo", fooClass.name)
+ }
+}
diff --git a/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/jvm/mixed/SampleMixedJvmAnalysisTest.kt b/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/jvm/mixed/SampleMixedJvmAnalysisTest.kt
new file mode 100644
index 00000000..fec2ceb8
--- /dev/null
+++ b/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/jvm/mixed/SampleMixedJvmAnalysisTest.kt
@@ -0,0 +1,81 @@
+/*
+ * 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.jvm.mixed
+
+import org.jetbrains.dokka.analysis.test.api.mixedJvmTestProject
+import org.jetbrains.dokka.analysis.test.api.parse
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+class SampleMixedJvmAnalysisTest {
+
+ /**
+ * Used as a sample for [mixedJvmTestProject]
+ */
+ @Test
+ fun sample() {
+ val testProject = mixedJvmTestProject {
+ dokkaConfiguration {
+ moduleName = "mixed-project-module-name-for-unit-test"
+
+ jvmSourceSet {
+ // source-set specific configuration
+ }
+ }
+
+ kotlinSourceDirectory {
+ ktFile(pathFromSrc = "test/MyFile.kt") {
+ +"fun foo(): String = \"Foo\""
+ }
+ javaFile(pathFromSrc = "test/MyJavaFileInKotlin.java") {
+ +"""
+ public class MyJavaFileInKotlin {
+ public static void bar() {
+ System.out.println("Bar");
+ }
+ }
+ """
+ }
+ }
+
+ javaSourceDirectory {
+ ktFile(pathFromSrc = "test/MyFile.kt") {
+ +"fun bar(): String = \"Bar\""
+ }
+ javaFile(pathFromSrc = "test/MyJavaFileInJava.java") {
+ +"""
+ public class MyJavaFileInJava {
+ public static void bar() {
+ System.out.println("Bar");
+ }
+ }
+ """
+ }
+ }
+ }
+
+ val module = testProject.parse()
+ assertEquals("mixed-project-module-name-for-unit-test", module.name)
+ assertEquals(1, module.packages.size)
+
+ val pckg = module.packages[0]
+ assertEquals("test", pckg.name)
+
+ assertEquals(2, pckg.classlikes.size)
+ assertEquals(2, pckg.functions.size)
+
+ val firstClasslike = pckg.classlikes[0]
+ assertEquals("MyJavaFileInKotlin", firstClasslike.name)
+
+ val secondClasslike = pckg.classlikes[1]
+ assertEquals("MyJavaFileInJava", secondClasslike.name)
+
+ val firstFunction = pckg.functions[0]
+ assertEquals("bar", firstFunction.name)
+
+ val secondFunction = pckg.functions[1]
+ assertEquals("foo", secondFunction.name)
+ }
+}
diff --git a/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/moduledocs/PackageDocumentationAnalysisTest.kt b/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/moduledocs/PackageDocumentationAnalysisTest.kt
new file mode 100644
index 00000000..55507023
--- /dev/null
+++ b/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/moduledocs/PackageDocumentationAnalysisTest.kt
@@ -0,0 +1,66 @@
+/*
+ * 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.moduledocs
+
+import org.jetbrains.dokka.analysis.test.api.kotlinJvmTestProject
+import org.jetbrains.dokka.analysis.test.api.useServices
+import org.jetbrains.dokka.model.doc.CodeInline
+import org.jetbrains.dokka.model.doc.Description
+import org.jetbrains.dokka.model.doc.P
+import org.jetbrains.dokka.model.doc.Text
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+class PackageDocumentationAnalysisTest {
+
+ @Test
+ fun `should parse include description for a nested package in kotlin-jvm`() {
+ val testProject = kotlinJvmTestProject {
+ dokkaConfiguration {
+ kotlinSourceSet {
+ includes = setOf("/documentation/cool-package-description.md")
+ }
+ }
+
+ ktFile(pathFromSrc = "org/jetbrains/dokka/pckg/docs/test/TestFile.kt") {
+ +"class TestFile {}"
+ }
+
+ mdFile(pathFromProjectRoot = "/documentation/cool-package-description.md") {
+ +"""
+ # Package org.jetbrains.dokka.pckg.docs.test
+
+ This is my test description for the package `org.jetbrains.dokka.pckg.docs.test`,
+ which contains only one file named TestFile.kt. It has one empty class.
+ """
+ }
+ }
+
+ testProject.useServices { context ->
+ val pckg = context.module.packages.single { it.name == "org.jetbrains.dokka.pckg.docs.test" }
+
+ val allPackageDocs = moduleAndPackageDocumentationReader.read(pckg)
+ assertEquals(1, allPackageDocs.size)
+
+ val sourceSetPackageDocs = allPackageDocs.entries.single().value
+ assertEquals(1, sourceSetPackageDocs.children.size)
+
+ val descriptionTag = sourceSetPackageDocs.children.single() as Description
+ assertEquals(1, descriptionTag.children.size)
+
+ val paragraphTag = descriptionTag.children.single() as P
+ assertEquals(3, paragraphTag.children.size)
+
+ val expectedParagraphChildren = listOf(
+ Text("This is my test description for the package "),
+ CodeInline(children = listOf(Text(
+ "org.jetbrains.dokka.pckg.docs.test"
+ ))),
+ Text(", which contains only one file named TestFile.kt. It has one empty class.")
+ )
+ assertEquals(expectedParagraphChildren, paragraphTag.children)
+ }
+ }
+}
diff --git a/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/sample/SampleAnalysisTest.kt b/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/sample/SampleAnalysisTest.kt
new file mode 100644
index 00000000..618e28a8
--- /dev/null
+++ b/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/sample/SampleAnalysisTest.kt
@@ -0,0 +1,55 @@
+/*
+ * 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.sample
+
+import org.jetbrains.dokka.analysis.test.api.kotlinJvmTestProject
+import org.jetbrains.dokka.analysis.test.api.useServices
+import kotlin.test.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertNotNull
+
+class SampleAnalysisTest {
+
+ @Test
+ fun `should return sources of a kotlin sample`() {
+ val testProject = kotlinJvmTestProject {
+ dokkaConfiguration {
+ kotlinSourceSet {
+ additionalSourceRoots = setOf("/samples")
+ }
+ }
+ sampleFile("/samples/stringListOf-sample.kt", fqPackageName = "org.jetbrains.dokka.sample.generator") {
+ +"""
+ 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()
+ }
+ """
+ }
+ }
+
+ testProject.useServices { context ->
+ val sampleSourceSet = context.configuration.sourceSets.single()
+
+ val sampleProvider = sampleProviderFactory.build()
+ val sample = sampleProvider.getSample(sampleSourceSet, "org.jetbrains.dokka.sample.generator.runGenerator")
+ assertNotNull(sample)
+
+ val expectedImports = listOf(
+ "import org.jetbrains.dokka.DokkaConfiguration",
+ "import org.jetbrains.dokka.DokkaGenerator",
+ "import org.jetbrains.dokka.utilities.DokkaLogger"
+ ).joinToString(separator = "\n")
+
+ val expectedBody = "DokkaGenerator(configuration, logger).generate()"
+
+ assertEquals(expectedImports, sample.imports)
+ assertEquals(expectedBody, sample.body)
+ }
+ }
+}
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