diff options
12 files changed, 346 insertions, 40 deletions
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 1bec35e5..31d977a0 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -1,6 +1,22 @@ <component name="ProjectCodeStyleConfiguration"> <code_scheme name="Project" version="173"> <JetCodeStyleSettings> + <option name="PACKAGES_TO_USE_STAR_IMPORTS"> + <value> + <package name="java.util" alias="false" withSubpackages="false" /> + <package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" /> + <package name="io.ktor" alias="false" withSubpackages="true" /> + </value> + </option> + <option name="PACKAGES_IMPORT_LAYOUT"> + <value> + <package name="" alias="false" withSubpackages="true" /> + <package name="java" alias="false" withSubpackages="true" /> + <package name="javax" alias="false" withSubpackages="true" /> + <package name="kotlin" alias="false" withSubpackages="true" /> + <package name="" alias="true" withSubpackages="true" /> + </value> + </option> <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> </JetCodeStyleSettings> <codeStyleSettings language="kotlin"> diff --git a/integration-tests/build.gradle.kts b/integration-tests/build.gradle.kts index ec9b4004..44da74cf 100644 --- a/integration-tests/build.gradle.kts +++ b/integration-tests/build.gradle.kts @@ -5,6 +5,7 @@ subprojects { runtimeClasspath += sourceSets.main.get().output } } + configurations.getByName("integrationTestImplementation") { extendsFrom(configurations.implementation.get()) } @@ -13,6 +14,10 @@ subprojects { extendsFrom(configurations.runtimeOnly.get()) } + dependencies { + implementation(project(":integration-tests")) + } + val integrationTest = task<Test>("integrationTest") { maxHeapSize = "2G" description = "Runs integration tests." @@ -28,3 +33,8 @@ subprojects { dependsOn(integrationTest) } } + +dependencies { + implementation(kotlin("stdlib")) + implementation(kotlin("test-junit")) +} diff --git a/integration-tests/cli/build.gradle.kts b/integration-tests/cli/build.gradle.kts new file mode 100644 index 00000000..c3e98d0a --- /dev/null +++ b/integration-tests/cli/build.gradle.kts @@ -0,0 +1,39 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + + +plugins { + id("com.github.johnrengelman.shadow") +} + +val dokka_version: String by project +evaluationDependsOn(":runners:cli") +evaluationDependsOn(":plugins:base") + +dependencies { + implementation(kotlin("stdlib")) + implementation(kotlin("test-junit")) + + val coroutines_version: String by project + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version") + +} + +/* Create a fat base plugin jar for cli tests */ +val basePluginShadow: Configuration by configurations.creating +dependencies { + basePluginShadow(project(":plugins:base")) +} +val basePluginShadowJar = tasks.create("basePluginShadowJar", ShadowJar::class) { + configurations = listOf(basePluginShadow) + archiveFileName.set("fat-base-plugin-$dokka_version.jar") + archiveClassifier.set("") +} + +tasks.integrationTest { + val cliJar = tasks.getByPath(":runners:cli:shadowJar") as ShadowJar + environment("CLI_JAR_PATH", cliJar.archiveFile.get()) + environment("BASE_PLUGIN_JAR_PATH", basePluginShadowJar.archiveFile.get()) + dependsOn(cliJar) + dependsOn(basePluginShadowJar) +} + diff --git a/integration-tests/cli/projects/it-cli/src/main/java/it/basic/java/SampleJavaClass.java b/integration-tests/cli/projects/it-cli/src/main/java/it/basic/java/SampleJavaClass.java new file mode 100644 index 00000000..23b0202c --- /dev/null +++ b/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/integration-tests/cli/projects/it-cli/src/main/kotlin/it/basic/PublicClass.kt b/integration-tests/cli/projects/it-cli/src/main/kotlin/it/basic/PublicClass.kt new file mode 100644 index 00000000..71bc7e63 --- /dev/null +++ b/integration-tests/cli/projects/it-cli/src/main/kotlin/it/basic/PublicClass.kt @@ -0,0 +1,48 @@ +@file:Suppress("unused") + +package it.basic + +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 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/integration-tests/cli/src/integrationTest/kotlin/org/jetbrains/dokka/it/cli/CliIntegrationTest.kt b/integration-tests/cli/src/integrationTest/kotlin/org/jetbrains/dokka/it/cli/CliIntegrationTest.kt new file mode 100644 index 00000000..5e24c1cd --- /dev/null +++ b/integration-tests/cli/src/integrationTest/kotlin/org/jetbrains/dokka/it/cli/CliIntegrationTest.kt @@ -0,0 +1,82 @@ +package org.jetbrains.dokka.it.cli + +import java.io.File +import kotlin.test.BeforeTest +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +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, + "-format", "html", + "-pluginsClasspath", basePluginJarFile.path, + "-sourceSet", + buildString { + append(" -moduleName it-cli") + append(" -moduleDisplayName CLI-Example") + 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)" + ) + + 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) + } + } +} diff --git a/integration-tests/cli/src/main/kotlin/org/jetbrains/dokka/it/cli/AbstractCliIntegrationTest.kt b/integration-tests/cli/src/main/kotlin/org/jetbrains/dokka/it/cli/AbstractCliIntegrationTest.kt new file mode 100644 index 00000000..7f6f9433 --- /dev/null +++ b/integration-tests/cli/src/main/kotlin/org/jetbrains/dokka/it/cli/AbstractCliIntegrationTest.kt @@ -0,0 +1,36 @@ +package org.jetbrains.dokka.it.cli + +import org.jetbrains.dokka.it.AbstractIntegrationTest +import java.io.File +import kotlin.test.BeforeTest +import kotlin.test.assertTrue + +abstract class AbstractCliIntegrationTest : AbstractIntegrationTest() { + + protected val cliJarFile: File by lazy { + File(temporaryTestFolder.root, "dokka.jar") + } + + protected val basePluginJarFile: File by lazy { + File(temporaryTestFolder.root, "base-plugin.jar") + } + + @BeforeTest + 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) + } +} diff --git a/integration-tests/cli/src/main/kotlin/org/jetbrains/dokka/it/cli/processUtils.kt b/integration-tests/cli/src/main/kotlin/org/jetbrains/dokka/it/cli/processUtils.kt new file mode 100644 index 00000000..d2fa3b31 --- /dev/null +++ b/integration-tests/cli/src/main/kotlin/org/jetbrains/dokka/it/cli/processUtils.kt @@ -0,0 +1,51 @@ +package org.jetbrains.dokka.it.cli + +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.async +import kotlinx.coroutines.runBlocking +import kotlin.concurrent.thread + +class ProcessResult( + val exitCode: Int, + val output: String +) + +fun Process.awaitProcessResult() = runBlocking { + val exitCode = async { awaitExitCode() } + val output = async { awaitOutput() } + ProcessResult( + exitCode.await(), + output.await() + ) +} + +private suspend fun Process.awaitExitCode(): Int { + val deferred = CompletableDeferred<Int>() + thread { + try { + deferred.complete(this.waitFor()) + } catch (e: Throwable) { + deferred.completeExceptionally(e) + } + } + + return deferred.await() +} + +private suspend fun Process.awaitOutput(): String { + val deferred = CompletableDeferred<String>() + thread { + try { + var string = "" + this.inputStream.bufferedReader().forEachLine { line -> + println(line) + string += line + System.lineSeparator() + } + deferred.complete(string) + } catch (e: Throwable) { + deferred.completeExceptionally(e) + } + } + + return deferred.await() +} diff --git a/integration-tests/gradle/src/main/kotlin/org/jetbrains/dokka/it/gradle/AbstractGradleIntegrationTest.kt b/integration-tests/gradle/src/main/kotlin/org/jetbrains/dokka/it/gradle/AbstractGradleIntegrationTest.kt index bb2d0cc6..c8c8c844 100644 --- a/integration-tests/gradle/src/main/kotlin/org/jetbrains/dokka/it/gradle/AbstractGradleIntegrationTest.kt +++ b/integration-tests/gradle/src/main/kotlin/org/jetbrains/dokka/it/gradle/AbstractGradleIntegrationTest.kt @@ -2,25 +2,17 @@ package org.jetbrains.dokka.it.gradle import org.gradle.testkit.runner.GradleRunner import org.gradle.testkit.runner.internal.DefaultGradleRunner -import org.junit.Rule -import org.junit.rules.TemporaryFolder +import org.jetbrains.dokka.it.AbstractIntegrationTest import org.junit.runner.RunWith import org.junit.runners.Parameterized import java.io.File import kotlin.test.BeforeTest -import kotlin.test.Test -import kotlin.test.assertFalse @RunWith(Parameterized::class) -abstract class AbstractGradleIntegrationTest { +abstract class AbstractGradleIntegrationTest : AbstractIntegrationTest() { abstract val versions: BuildVersions - @get:Rule - val temporaryTestFolder = TemporaryFolder() - - val projectDir get() = File(temporaryTestFolder.root, "project") - @BeforeTest fun copyTemplates() { File("projects").listFiles().orEmpty() @@ -49,30 +41,5 @@ abstract class AbstractGradleIntegrationTest { ).run { this as DefaultGradleRunner } .withJvmArguments("-Xmx4G", "-XX:MaxMetaspaceSize=512M") } - - fun File.allDescendentsWithExtension(extension: String): Sequence<File> { - return this.walkTopDown().filter { it.isFile && it.extension == extension } - } - - fun File.allHtmlFiles(): Sequence<File> { - return allDescendentsWithExtension("html") - } - - protected fun assertContainsNoErrorClass(file: File) { - val fileText = file.readText() - assertFalse( - fileText.contains("ERROR CLASS", ignoreCase = true), - "Unexpected `ERROR CLASS` in ${file.path}\n" + fileText - ) - } - - protected fun assertNoUnresolvedLInks(file: File) { - val regex = Regex("[\"']#[\"']") - val fileText = file.readText() - assertFalse( - fileText.contains(regex), - "Unexpected unresolved link in ${file.path}\n" + fileText - ) - } } diff --git a/integration-tests/src/main/kotlin/org/jetbrains/dokka/it/AbstractIntegrationTest.kt b/integration-tests/src/main/kotlin/org/jetbrains/dokka/it/AbstractIntegrationTest.kt new file mode 100644 index 00000000..4af523a2 --- /dev/null +++ b/integration-tests/src/main/kotlin/org/jetbrains/dokka/it/AbstractIntegrationTest.kt @@ -0,0 +1,39 @@ +package org.jetbrains.dokka.it + +import org.junit.Rule +import org.junit.rules.TemporaryFolder +import java.io.File +import kotlin.test.assertFalse + +abstract class AbstractIntegrationTest { + + @get:Rule + val temporaryTestFolder = TemporaryFolder() + + val projectDir get() = File(temporaryTestFolder.root, "project") + + fun File.allDescendentsWithExtension(extension: String): Sequence<File> { + return this.walkTopDown().filter { it.isFile && it.extension == extension } + } + + fun File.allHtmlFiles(): Sequence<File> { + return allDescendentsWithExtension("html") + } + + protected fun assertContainsNoErrorClass(file: File) { + val fileText = file.readText() + assertFalse( + fileText.contains("ERROR CLASS", ignoreCase = true), + "Unexpected `ERROR CLASS` in ${file.path}\n" + fileText + ) + } + + protected fun assertNoUnresolvedLInks(file: File) { + val regex = Regex("[\"']#[\"']") + val fileText = file.readText() + assertFalse( + fileText.contains(regex), + "Unexpected unresolved link in ${file.path}\n" + fileText + ) + } +} diff --git a/runners/cli/src/main/kotlin/cli/main.kt b/runners/cli/src/main/kotlin/cli/main.kt index 5e5cd6b2..d284e653 100644 --- a/runners/cli/src/main/kotlin/cli/main.kt +++ b/runners/cli/src/main/kotlin/cli/main.kt @@ -118,7 +118,7 @@ private fun parseSourceSet(args: Array<String>): DokkaConfiguration.DokkaSourceS val moduleName by parser.option( ArgType.String, description = "Name of the documentation module", - fullName = "module" + fullName = "moduleName" ).required() val moduleDisplayName by parser.option( @@ -126,12 +126,12 @@ private fun parseSourceSet(args: Array<String>): DokkaConfiguration.DokkaSourceS description = "Name of the documentation module" ) - val name by parser.option( + val sourceSetName by parser.option( ArgType.String, description = "Name of the source set" ).default("main") - val displayName by parser.option( + val sourceSetDisplayName by parser.option( ArgType.String, description = "Displayed name of the source set" ).default("JVM") @@ -235,8 +235,8 @@ private fun parseSourceSet(args: Array<String>): DokkaConfiguration.DokkaSourceS return object : DokkaConfiguration.DokkaSourceSet { override val moduleDisplayName = moduleDisplayName ?: moduleName - override val displayName = displayName - override val sourceSetID = DokkaSourceSetID(moduleName, name) + override val displayName = sourceSetDisplayName + override val sourceSetID = DokkaSourceSetID(moduleName, sourceSetName) override val classpath = classpath override val sourceRoots = sourceRoots.map { SourceRootImpl(it.toAbsolutePath()) } override val dependentSourceSets: Set<DokkaSourceSetID> = dependentSourceSets diff --git a/settings.gradle.kts b/settings.gradle.kts index 969bb53f..54245a96 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -19,6 +19,7 @@ include("plugins:kotlin-as-java") include("plugins:javadoc") include("integration-tests") include("integration-tests:gradle") +include("integration-tests:cli") pluginManagement { val kotlin_version: String by settings |