diff options
| author | Ignat Beresnev <ignat.beresnev@jetbrains.com> | 2023-10-27 13:11:41 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-10-27 13:11:41 +0200 |
| commit | edcd1fb24d01e11b5a8185328255f2005aadf037 (patch) | |
| tree | 8156df7d2d29d8fd9d0fdaccad0fbb92b26e895f /subprojects/analysis-kotlin-api/src | |
| parent | b1ccc2b346ea858762653933f9dd304b91c18505 (diff) | |
| download | dokka-edcd1fb24d01e11b5a8185328255f2005aadf037.tar.gz dokka-edcd1fb24d01e11b5a8185328255f2005aadf037.tar.bz2 dokka-edcd1fb24d01e11b5a8185328255f2005aadf037.zip | |
Implement analysis test API (#3184)
Diffstat (limited to 'subprojects/analysis-kotlin-api/src')
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 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/m |
