aboutsummaryrefslogtreecommitdiff
path: root/dokka-integration-tests/cli
diff options
context:
space:
mode:
Diffstat (limited to 'dokka-integration-tests/cli')
-rw-r--r--dokka-integration-tests/cli/build.gradle.kts64
-rw-r--r--dokka-integration-tests/cli/projects/it-cli/src/main/java/it/basic/java/SampleJavaClass.java17
-rw-r--r--dokka-integration-tests/cli/projects/it-cli/src/main/kotlin/it/basic/EmptyPackage.kt1
-rw-r--r--dokka-integration-tests/cli/projects/it-cli/src/main/kotlin/it/basic/PublicClass.kt57
-rw-r--r--dokka-integration-tests/cli/projects/it-cli/src/main/kotlin/it/internal/InternalClass.kt7
-rw-r--r--dokka-integration-tests/cli/projects/it-cli/src/main/kotlin/it/overriddenVisibility/VisiblePrivateClass.kt12
-rw-r--r--dokka-integration-tests/cli/projects/it-cli/src/main/kotlin/it/protected/ProtectedClass.kt10
-rw-r--r--dokka-integration-tests/cli/src/integrationTest/kotlin/org/jetbrains/dokka/it/cli/CliIntegrationTest.kt377
-rw-r--r--dokka-integration-tests/cli/src/integrationTest/kotlin/org/jetbrains/dokka/it/cli/jsonBuilder.kt56
-rw-r--r--dokka-integration-tests/cli/src/integrationTest/resources/my-file.json0
-rw-r--r--dokka-integration-tests/cli/src/main/kotlin/org/jetbrains/dokka/it/cli/AbstractCliIntegrationTest.kt40
11 files changed, 641 insertions, 0 deletions
diff --git a/dokka-integration-tests/cli/build.gradle.kts b/dokka-integration-tests/cli/build.gradle.kts
new file mode 100644
index 00000000..34f1f797
--- /dev/null
+++ b/dokka-integration-tests/cli/build.gradle.kts
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
+
+plugins {
+ id("dokkabuild.test-integration")
+ id("com.github.johnrengelman.shadow")
+}
+
+dependencies {
+ implementation(kotlin("test-junit5"))
+ implementation(libs.junit.jupiterApi)
+ implementation(projects.utilities)
+}
+
+/* Create a fat base plugin jar for cli tests */
+val basePluginShadow: Configuration by configurations.creating {
+ attributes {
+ attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage::class.java, "java-runtime"))
+ }
+}
+
+val cliConfiguration: Configuration by configurations.creating {
+ attributes {
+ attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage::class.java, Usage.JAVA_RUNTIME))
+ attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling::class.java, Bundling.SHADOWED))
+ }
+ // we should have single artifact here
+ isTransitive = false
+}
+
+dependencies {
+ cliConfiguration("org.jetbrains.dokka:runner-cli")
+
+ basePluginShadow("org.jetbrains.dokka:plugin-base")
+
+ // TODO [beresnev] analysis switcher
+ basePluginShadow("org.jetbrains.dokka:analysis-kotlin-descriptors") {
+ attributes {
+ attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named(Bundling::class.java, Bundling.SHADOWED))
+ }
+ }
+}
+
+val basePluginShadowJar by tasks.register("basePluginShadowJar", ShadowJar::class) {
+ configurations = listOf(basePluginShadow)
+ archiveFileName.set("fat-base-plugin-${project.version}.jar")
+ archiveClassifier.set("")
+
+ // service files are merged to make sure all Dokka plugins
+ // from the dependencies are loaded, and not just a single one.
+ mergeServiceFiles()
+}
+
+tasks.integrationTest {
+ dependsOn(cliConfiguration)
+ dependsOn(basePluginShadowJar)
+
+ inputs.dir(file("projects"))
+ environment("CLI_JAR_PATH", cliConfiguration.singleFile)
+ environment("BASE_PLUGIN_JAR_PATH", basePluginShadowJar.archiveFile.get())
+}
diff --git a/dokka-integration-tests/cli/projects/it-cli/src/main/java/it/basic/java/SampleJavaClass.java b/dokka-integration-tests/cli/projects/it-cli/src/main/java/it/basic/java/SampleJavaClass.java
new file mode 100644
index 00000000..23b0202c
--- /dev/null
+++ b/dokka-integration-tests/cli/projects/it-cli/src/main/java/it/basic/java/SampleJavaClass.java
@@ -0,0 +1,17 @@
+package it.basic.java;
+
+import it.basic.PublicClass;
+
+/**
+ * This class is, unlike {@link PublicClass}, written in Java
+ */
+@SuppressWarnings("unused")
+public class SampleJavaClass {
+
+ /**
+ * @return Empty instance of {@link PublicClass}
+ */
+ public PublicClass publicDocumentedFunction() {
+ return new PublicClass();
+ }
+}
diff --git a/dokka-integration-tests/cli/projects/it-cli/src/main/kotlin/it/basic/EmptyPackage.kt b/dokka-integration-tests/cli/projects/it-cli/src/main/kotlin/it/basic/EmptyPackage.kt
new file mode 100644
index 00000000..50f02c00
--- /dev/null
+++ b/dokka-integration-tests/cli/projects/it-cli/src/main/kotlin/it/basic/EmptyPackage.kt
@@ -0,0 +1 @@
+package emptypackagetest \ No newline at end of file
diff --git a/dokka-integration-tests/cli/projects/it-cli/src/main/kotlin/it/basic/PublicClass.kt b/dokka-integration-tests/cli/projects/it-cli/src/main/kotlin/it/basic/PublicClass.kt
new file mode 100644
index 00000000..d7a72392
--- /dev/null
+++ b/dokka-integration-tests/cli/projects/it-cli/src/main/kotlin/it/basic/PublicClass.kt
@@ -0,0 +1,57 @@
+@file:Suppress("unused")
+
+package it.basic
+
+/**
+ * §PUBLIC§ (marker for asserts)
+ */
+class PublicClass {
+ /**
+ * This function is public and documented
+ */
+ fun publicDocumentedFunction(): String = ""
+
+ fun publicUndocumentedFunction(): String = ""
+
+ /**
+ * This function is internal and documented
+ */
+ internal fun internalDocumentedFunction(): String = ""
+
+ internal fun internalUndocumentedFunction(): String = ""
+
+ /**
+ * This function is private and documented
+ */
+ private fun privateDocumentedFunction(): String = ""
+
+ private fun privateUndocumentedFunction(): String = ""
+
+ /**
+ * This function is protected and documented
+ */
+ protected fun protectedDocumentedFunction(): String = ""
+
+ protected fun protectedUndocumentedFunction(): String = ""
+
+ /**
+ * This property is public and documented
+ */
+ val publicDocumentedProperty: Int = 0
+
+ val publicUndocumentedProperty: Int = 0
+
+ /**
+ * This property internal and documented
+ */
+ val internalDocumentedProperty: Int = 0
+
+ val internalUndocumentedProperty: Int = 0
+
+ /**
+ * This property private and documented
+ */
+ private val privateDocumentedProperty: Int = 0
+
+ private val privateUndocumentedProperty: Int = 0
+}
diff --git a/dokka-integration-tests/cli/projects/it-cli/src/main/kotlin/it/internal/InternalClass.kt b/dokka-integration-tests/cli/projects/it-cli/src/main/kotlin/it/internal/InternalClass.kt
new file mode 100644
index 00000000..f5be5406
--- /dev/null
+++ b/dokka-integration-tests/cli/projects/it-cli/src/main/kotlin/it/internal/InternalClass.kt
@@ -0,0 +1,7 @@
+package it.internal
+
+/**
+ * §INTERNAL§ (marker for asserts)
+ * This class is internal and should not be rendered
+ */
+internal class InternalClass \ No newline at end of file
diff --git a/dokka-integration-tests/cli/projects/it-cli/src/main/kotlin/it/overriddenVisibility/VisiblePrivateClass.kt b/dokka-integration-tests/cli/projects/it-cli/src/main/kotlin/it/overriddenVisibility/VisiblePrivateClass.kt
new file mode 100644
index 00000000..230f5e0b
--- /dev/null
+++ b/dokka-integration-tests/cli/projects/it-cli/src/main/kotlin/it/overriddenVisibility/VisiblePrivateClass.kt
@@ -0,0 +1,12 @@
+package it.overriddenVisibility
+
+/**
+ * Private classes and methods generally should not be visible, but [documentedVisibilities]
+ * are overriden for this specific package to include private code
+ *
+ * §PRIVATE§ (marker for asserts)
+ */
+private class VisiblePrivateClass {
+ private val privateVal: Int = 0
+ private fun privateMethod() {}
+} \ No newline at end of file
diff --git a/dokka-integration-tests/cli/projects/it-cli/src/main/kotlin/it/protected/ProtectedClass.kt b/dokka-integration-tests/cli/projects/it-cli/src/main/kotlin/it/protected/ProtectedClass.kt
new file mode 100644
index 00000000..ad19f1a1
--- /dev/null
+++ b/dokka-integration-tests/cli/projects/it-cli/src/main/kotlin/it/protected/ProtectedClass.kt
@@ -0,0 +1,10 @@
+package it.protected
+
+/**
+ * Protected class should be visible because it's included in documentedVisibilities
+ *
+ * §PROTECTED§ (marker for asserts)
+ */
+protected class ProtectedClass {
+ protected fun protectedFun(): String = "protected"
+}
diff --git a/dokka-integration-tests/cli/src/integrationTest/kotlin/org/jetbrains/dokka/it/cli/CliIntegrationTest.kt b/dokka-integration-tests/cli/src/integrationTest/kotlin/org/jetbrains/dokka/it/cli/CliIntegrationTest.kt
new file mode 100644
index 00000000..8bab690b
--- /dev/null
+++ b/dokka-integration-tests/cli/src/integrationTest/kotlin/org/jetbrains/dokka/it/cli/CliIntegrationTest.kt
@@ -0,0 +1,377 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package org.jetbrains.dokka.it.cli
+
+import org.jetbrains.dokka.it.awaitProcessResult
+import java.io.File
+import java.io.PrintWriter
+import java.lang.IllegalStateException
+import kotlin.test.*
+
+class CliIntegrationTest : AbstractCliIntegrationTest() {
+
+ @BeforeTest
+ fun copyProject() {
+ val templateProjectDir = File("projects", "it-cli")
+ templateProjectDir.copyRecursively(projectDir)
+ }
+
+ @Test
+ fun runHelp() {
+ val process = ProcessBuilder("java", "-jar", cliJarFile.path, "-h")
+ .redirectErrorStream(true)
+ .start()
+
+ val result = process.awaitProcessResult()
+ assertEquals(0, result.exitCode, "Expected exitCode 0 (Success)")
+ assertTrue("Usage: " in result.output)
+ }
+
+ @Test
+ fun runCli() {
+ val dokkaOutputDir = File(projectDir, "output")
+ assertTrue(dokkaOutputDir.mkdirs())
+ val process = ProcessBuilder(
+ "java", "-jar", cliJarFile.path,
+ "-outputDir", dokkaOutputDir.path,
+ "-pluginsClasspath", basePluginJarFile.path,
+ "-moduleName", "Basic Project",
+ "-sourceSet",
+ buildString {
+ append(" -sourceSetName cliMain")
+ append(" -src ${File(projectDir, "src").path}")
+ append(" -jdkVersion 8")
+ append(" -analysisPlatform jvm")
+ append(" -reportUndocumented")
+ append(" -skipDeprecated")
+ }
+ )
+ .redirectErrorStream(true)
+ .start()
+
+ val result = process.awaitProcessResult()
+ assertEquals(0, result.exitCode, "Expected exitCode 0 (Success)")
+
+ val extensionLoadedRegex = Regex("""Extension: org\.jetbrains\.dokka\.base\.DokkaBase""")
+ val amountOfExtensionsLoaded = extensionLoadedRegex.findAll(result.output).count()
+
+ assertTrue(
+ amountOfExtensionsLoaded > 10,
+ "Expected more than 10 extensions being present (found $amountOfExtensionsLoaded)"
+ )
+
+ val undocumentedReportRegex = Regex("""Undocumented:""")
+ val amountOfUndocumentedReports = undocumentedReportRegex.findAll(result.output).count()
+ assertTrue(
+ amountOfUndocumentedReports > 0,
+ "Expected at least one report of undocumented code (found $amountOfUndocumentedReports)"
+ )
+
+ assertTrue(dokkaOutputDir.isDirectory, "Missing dokka output directory")
+
+ val imagesDir = File(dokkaOutputDir, "images")
+ assertTrue(imagesDir.isDirectory, "Missing images directory")
+
+ val scriptsDir = File(dokkaOutputDir, "scripts")
+ assertTrue(scriptsDir.isDirectory, "Missing scripts directory")
+
+ val stylesDir = File(dokkaOutputDir, "styles")
+ assertTrue(stylesDir.isDirectory, "Missing styles directory")
+
+ val navigationHtml = File(dokkaOutputDir, "navigation.html")
+ assertTrue(navigationHtml.isFile, "Missing navigation.html")
+
+ projectDir.allHtmlFiles().forEach { file ->
+ assertContainsNoErrorClass(file)
+ assertNoUnresolvedLinks(file)
+ assertNoEmptyLinks(file)
+ assertNoEmptySpans(file)
+ }
+
+ assertContentVisibility(
+ contentFiles = projectDir.allHtmlFiles().toList(),
+ documentPublic = true,
+ documentInternal = false,
+ documentProtected = false,
+ documentPrivate = false
+ )
+
+ assertFalse(
+ projectDir.resolve("output").resolve("index.html").readText().contains("emptypackagetest"),
+ "Expected not to render empty packages"
+ )
+ }
+
+ @Test
+ fun failCli() {
+ val dokkaOutputDir = File(projectDir, "output")
+ assertTrue(dokkaOutputDir.mkdirs())
+ val process = ProcessBuilder(
+ "java", "-jar", cliJarFile.path,
+ "-outputDir", dokkaOutputDir.path,
+ "-pluginsClasspath", basePluginJarFile.path,
+ "-moduleName", "Basic Project",
+ "-failOnWarning",
+ "-sourceSet",
+ buildString {
+ append(" -sourceSetName cliMain")
+ append(" -src ${File(projectDir, "src").path}")
+ append(" -jdkVersion 8")
+ append(" -analysisPlatform jvm")
+ append(" -reportUndocumented")
+ }
+ )
+ .redirectErrorStream(true)
+ .start()
+
+ val result = process.awaitProcessResult()
+ assertEquals(1, result.exitCode, "Expected exitCode 1 (Fail)")
+
+ assertTrue(result.output.contains("Exception in thread \"main\" org.jetbrains.dokka.DokkaException: Failed with warningCount"))
+ }
+
+ @Test
+ fun emptyPackagesTest() {
+ val dokkaOutputDir = File(projectDir, "output")
+ assertTrue(dokkaOutputDir.mkdirs())
+ val process = ProcessBuilder(
+ "java", "-jar", cliJarFile.path,
+ "-outputDir", dokkaOutputDir.path,
+ "-pluginsClasspath", basePluginJarFile.path,
+ "-moduleName", "Basic Project",
+ "-sourceSet",
+ buildString {
+ append(" -sourceSetName cliMain")
+ append(" -src ${File(projectDir, "src").path}")
+ append(" -jdkVersion 8")
+ append(" -analysisPlatform jvm")
+ append(" -noSkipEmptyPackages")
+ }
+ )
+ .redirectErrorStream(true)
+ .start()
+
+ val result = process.awaitProcessResult()
+ assertEquals(0, result.exitCode, "Expected exitCode 0 (Success)")
+
+ assertTrue(
+ projectDir.resolve("output").resolve("index.html").readText().contains("emptypackagetest"),
+ "Expected to render empty packages"
+ )
+ }
+
+ @Test
+ fun `module name should be optional`() {
+ val dokkaOutputDir = File(projectDir, "output")
+ assertTrue(dokkaOutputDir.mkdirs())
+ val process = ProcessBuilder(
+ "java", "-jar", cliJarFile.path,
+ "-outputDir", dokkaOutputDir.path,
+ "-loggingLevel", "DEBUG",
+ "-pluginsClasspath", basePluginJarFile.path,
+ "-sourceSet",
+ buildString {
+ append(" -src ${File(projectDir, "src").path}")
+ }
+ )
+ .redirectErrorStream(true)
+ .start()
+
+ val result = process.awaitProcessResult()
+ assertEquals(0, result.exitCode, "Expected exitCode 0 (Success)")
+ assertTrue(result.output.contains("Loaded plugins: "), "Expected output to not contain info logs")
+
+ assertTrue(dokkaOutputDir.isDirectory, "Missing dokka output directory")
+
+ val imagesDir = File(dokkaOutputDir, "images")
+ assertTrue(imagesDir.isDirectory, "Missing images directory")
+
+ val scriptsDir = File(dokkaOutputDir, "scripts")
+ assertTrue(scriptsDir.isDirectory, "Missing scripts directory")
+
+ val stylesDir = File(dokkaOutputDir, "styles")
+ assertTrue(stylesDir.isDirectory, "Missing styles directory")
+
+ val navigationHtml = File(dokkaOutputDir, "navigation.html")
+ assertTrue(navigationHtml.isFile, "Missing navigation.html")
+ }
+
+ @Test
+ fun `logging level should be respected`() {
+ val dokkaOutputDir = File(projectDir, "output")
+ assertTrue(dokkaOutputDir.mkdirs())
+ val process = ProcessBuilder(
+ "java", "-jar", cliJarFile.path,
+ "-outputDir", dokkaOutputDir.path,
+ "-loggingLevel", "WARN",
+ "-pluginsClasspath", basePluginJarFile.path,
+ "-sourceSet",
+ buildString {
+ append(" -src ${File(projectDir, "src").path}")
+ }
+ )
+ .redirectErrorStream(true)
+ .start()
+
+ val result = process.awaitProcessResult()
+ assertEquals(0, result.exitCode, "Expected exitCode 0 (Success)")
+ assertFalse(result.output.contains("Loaded plugins: "), "Expected output to not contain info logs")
+ }
+
+ @Test
+ fun `custom documented visibility`() {
+ val dokkaOutputDir = File(projectDir, "output")
+ assertTrue(dokkaOutputDir.mkdirs())
+ val process = ProcessBuilder(
+ "java", "-jar", cliJarFile.path,
+ "-outputDir", dokkaOutputDir.path,
+ "-pluginsClasspath", basePluginJarFile.path,
+ "-moduleName", "Basic Project",
+ "-sourceSet",
+ buildString {
+ append(" -sourceSetName cliMain")
+ append(" -src ${File(projectDir, "src").path}")
+ append(" -jdkVersion 8")
+ append(" -analysisPlatform jvm")
+ append(" -documentedVisibilities PUBLIC;PROTECTED")
+ append(" -perPackageOptions it.overriddenVisibility.*,+visibility:PRIVATE")
+ }
+ )
+ .redirectErrorStream(true)
+ .start()
+
+ val result = process.awaitProcessResult()
+ assertEquals(0, result.exitCode, "Expected exitCode 0 (Success)")
+
+ val allHtmlFiles = projectDir.allHtmlFiles().toList()
+
+ assertContentVisibility(
+ contentFiles = allHtmlFiles,
+ documentPublic = true,
+ documentProtected = true, // sourceSet documentedVisibilities
+ documentInternal = false,
+ documentPrivate = true // for overriddenVisibility package
+ )
+
+ assertContainsFilePaths(
+ outputFiles = allHtmlFiles,
+ expectedFilePaths = listOf(
+ // documentedVisibilities is overridden for package `overriddenVisibility` specifically
+ // to include private code, so html pages for it are expected to have been created
+ Regex("it\\.overriddenVisibility/-visible-private-class/private-method\\.html"),
+ Regex("it\\.overriddenVisibility/-visible-private-class/private-val\\.html"),
+ )
+ )
+ }
+
+
+ @Test
+ fun `should accept json as input configuration`() {
+ val dokkaOutputDir = File(projectDir, "output")
+ assertTrue(dokkaOutputDir.mkdirs())
+ val resourcePath = javaClass.getResource("/my-file.json")?.toURI() ?: throw IllegalStateException("No JSON found!")
+ val jsonPath = File(resourcePath).absolutePath
+ PrintWriter(jsonPath).run {
+ write(jsonBuilder(dokkaOutputDir.invariantSeparatorsPath, basePluginJarFile.invariantSeparatorsPath, File(projectDir, "src").invariantSeparatorsPath, reportUndocumented = true))
+ close()
+ }
+
+ val process = ProcessBuilder(
+ "java", "-jar", cliJarFile.path, jsonPath
+ ).redirectErrorStream(true).start()
+
+ val result = process.awaitProcessResult()
+ assertEquals(0, result.exitCode, "Expected exitCode 0 (Success)")
+
+ val extensionLoadedRegex = Regex("""Extension: org\.jetbrains\.dokka\.base\.DokkaBase""")
+ val amountOfExtensionsLoaded = extensionLoadedRegex.findAll(result.output).count()
+
+ assertTrue(
+ amountOfExtensionsLoaded > 10,
+ "Expected more than 10 extensions being present (found $amountOfExtensionsLoaded)"
+ )
+
+ val undocumentedReportRegex = Regex("""Undocumented:""")
+ val amountOfUndocumentedReports = undocumentedReportRegex.findAll(result.output).count()
+ assertTrue(
+ amountOfUndocumentedReports > 0,
+ "Expected at least one report of undocumented code (found $amountOfUndocumentedReports)"
+ )
+
+ assertTrue(dokkaOutputDir.isDirectory, "Missing dokka output directory")
+ }
+
+ /**
+ * This test disables global `reportUndocumneted` property and set `reportUndocumented` via perPackageOptions to
+ * make sure that global settings apply to dokka context.
+ */
+ @Test
+ fun `global settings should overwrite package options in configuration`() {
+ val dokkaOutputDir = File(projectDir, "output")
+ assertTrue(dokkaOutputDir.mkdirs())
+ val resourcePath = javaClass.getResource("/my-file.json")?.toURI() ?: throw IllegalStateException("No JSON found!")
+ val jsonPath = File(resourcePath).absolutePath
+ PrintWriter(jsonPath).run {
+ write(
+ jsonBuilder(
+ outputPath = dokkaOutputDir.invariantSeparatorsPath,
+ pluginsClasspath = basePluginJarFile.invariantSeparatorsPath,
+ projectPath = File(projectDir, "src").invariantSeparatorsPath,
+ globalSourceLinks = """
+ {
+ "localDirectory": "/home/Vadim.Mishenev/dokka/examples/cli/src/main/kotlin",
+ "remoteUrl": "https://github.com/Kotlin/dokka/tree/master/examples/gradle/dokka-gradle-example/src/main/kotlin",
+ "remoteLineSuffix": "#L"
+ }
+ """.trimIndent(),
+ globalExternalDocumentationLinks = """
+ {
+ "url": "https://docs.oracle.com/javase/8/docs/api/",
+ "packageListUrl": "https://docs.oracle.com/javase/8/docs/api/package-list"
+ },
+ {
+ "url": "https://kotlinlang.org/api/latest/jvm/stdlib/",
+ "packageListUrl": "https://kotlinlang.org/api/latest/jvm/stdlib/package-list"
+ }
+ """.trimIndent(),
+ globalPerPackageOptions = """
+ {
+ "matchingRegex": ".*",
+ "skipDeprecated": "true",
+ "reportUndocumented": "true",
+ "documentedVisibilities": ["PUBLIC", "PRIVATE", "PROTECTED", "INTERNAL", "PACKAGE"]
+ }
+ """.trimIndent(),
+ reportUndocumented = false
+ ),
+ )
+ close()
+ }
+
+ val process = ProcessBuilder(
+ "java", "-jar", cliJarFile.path, jsonPath
+ ).redirectErrorStream(true).start()
+
+ val result = process.awaitProcessResult()
+ assertEquals(0, result.exitCode, "Expected exitCode 0 (Success)")
+
+ val extensionLoadedRegex = Regex("""Extension: org\.jetbrains\.dokka\.base\.DokkaBase""")
+ val amountOfExtensionsLoaded = extensionLoadedRegex.findAll(result.output).count()
+
+ assertTrue(
+ amountOfExtensionsLoaded > 10,
+ "Expected more than 10 extensions being present (found $amountOfExtensionsLoaded)"
+ )
+
+ val undocumentedReportRegex = Regex("""Undocumented:""")
+ val amountOfUndocumentedReports = undocumentedReportRegex.findAll(result.output).count()
+ assertTrue(
+ amountOfUndocumentedReports > 0,
+ "Expected at least one report of undocumented code (found $amountOfUndocumentedReports)"
+ )
+
+ assertTrue(dokkaOutputDir.isDirectory, "Missing dokka output directory")
+ }
+}
diff --git a/dokka-integration-tests/cli/src/integrationTest/kotlin/org/jetbrains/dokka/it/cli/jsonBuilder.kt b/dokka-integration-tests/cli/src/integrationTest/kotlin/org/jetbrains/dokka/it/cli/jsonBuilder.kt
new file mode 100644
index 00000000..093df961
--- /dev/null
+++ b/dokka-integration-tests/cli/src/integrationTest/kotlin/org/jetbrains/dokka/it/cli/jsonBuilder.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package org.jetbrains.dokka.it.cli
+
+fun jsonBuilder(
+ outputPath: String,
+ pluginsClasspath: String,
+ projectPath: String,
+ globalSourceLinks: String = "",
+ globalExternalDocumentationLinks: String = "",
+ globalPerPackageOptions: String = "",
+ reportUndocumented: Boolean = false
+
+): String {
+ return """{
+ "moduleName": "Dokka Example",
+ "moduleVersion": null,
+ "outputDir": "$outputPath",
+ "pluginsClasspath": ["$pluginsClasspath"],
+ "cacheRoot": null,
+ "offlineMode": false,
+ "sourceLinks": [$globalSourceLinks],
+ "externalDocumentationLinks": [$globalExternalDocumentationLinks],
+ "perPackageOptions": [$globalPerPackageOptions],
+ "sourceSets": [
+ {
+ "displayName": "jvm",
+ "sourceSetID": {
+ "scopeId": ":dokkaHtml",
+ "sourceSetName": "main"
+ },
+ "sourceRoots": [
+ "$projectPath"
+ ],
+ "dependentSourceSets": [],
+ "samples": [],
+ "includes": [],
+ "includeNonPublic": false,
+ "reportUndocumented": $reportUndocumented,
+ "skipEmptyPackages": true,
+ "skipDeprecated": false,
+ "jdkVersion": 8,
+ "sourceLinks": [],
+ "perPackageOptions": [],
+ "externalDocumentationLinks": [],
+ "noStdlibLink": false,
+ "noJdkLink": false,
+ "suppressedFiles": [],
+ "analysisPlatform": "jvm"
+ }
+ ]
+}
+"""
+}
diff --git a/dokka-integration-tests/cli/src/integrationTest/resources/my-file.json b/dokka-integration-tests/cli/src/integrationTest/resources/my-file.json
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/dokka-integration-tests/cli/src/integrationTest/resources/my-file.json
diff --git a/dokka-integration-tests/cli/src/main/kotlin/org/jetbrains/dokka/it/cli/AbstractCliIntegrationTest.kt b/dokka-integration-tests/cli/src/main/kotlin/org/jetbrains/dokka/it/cli/AbstractCliIntegrationTest.kt
new file mode 100644
index 00000000..c7c77e68
--- /dev/null
+++ b/dokka-integration-tests/cli/src/main/kotlin/org/jetbrains/dokka/it/cli/AbstractCliIntegrationTest.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package org.jetbrains.dokka.it.cli
+
+import org.jetbrains.dokka.it.AbstractIntegrationTest
+import java.io.File
+import kotlin.test.BeforeTest
+import kotlin.test.assertTrue
+
+public abstract class AbstractCliIntegrationTest : AbstractIntegrationTest() {
+
+ protected val cliJarFile: File by lazy {
+ File(tempFolder, "dokka.jar")
+ }
+
+ protected val basePluginJarFile: File by lazy {
+ File(tempFolder, "base-plugin.jar")
+ }
+
+ @BeforeTest
+ public fun copyJarFiles() {
+ val cliJarPathEnvironmentKey = "CLI_JAR_PATH"
+ val cliJarFile = File(System.getenv(cliJarPathEnvironmentKey))
+ assertTrue(
+ cliJarFile.exists() && cliJarFile.isFile,
+ "Missing path to CLI jar System.getenv($cliJarPathEnvironmentKey)"
+ )
+ cliJarFile.copyTo(this.cliJarFile)
+
+ val basePluginPathEnvironmentKey = "BASE_PLUGIN_JAR_PATH"
+ val basePluginJarFile = File(System.getenv(basePluginPathEnvironmentKey))
+ assertTrue(
+ basePluginJarFile.exists() && basePluginJarFile.isFile,
+ "Missing path to base plugin jar System.getenv($basePluginPathEnvironmentKey)"
+ )
+ basePluginJarFile.copyTo(this.basePluginJarFile)
+ }
+}