aboutsummaryrefslogtreecommitdiff
path: root/dokka-integration-tests/gradle/src/integrationTest/kotlin/org
diff options
context:
space:
mode:
authorIgnat Beresnev <ignat.beresnev@jetbrains.com>2023-11-10 11:46:54 +0100
committerGitHub <noreply@github.com>2023-11-10 11:46:54 +0100
commit8e5c63d035ef44a269b8c43430f43f5c8eebfb63 (patch)
tree1b915207b2b9f61951ddbf0ff2e687efd053d555 /dokka-integration-tests/gradle/src/integrationTest/kotlin/org
parenta44efd4ba0c2e4ab921ff75e0f53fc9335aa79db (diff)
downloaddokka-8e5c63d035ef44a269b8c43430f43f5c8eebfb63.tar.gz
dokka-8e5c63d035ef44a269b8c43430f43f5c8eebfb63.tar.bz2
dokka-8e5c63d035ef44a269b8c43430f43f5c8eebfb63.zip
Restructure the project to utilize included builds (#3174)
* Refactor and simplify artifact publishing * Update Gradle to 8.4 * Refactor and simplify convention plugins and build scripts Fixes #3132 --------- Co-authored-by: Adam <897017+aSemy@users.noreply.github.com> Co-authored-by: Oleg Yukhnevich <whyoleg@gmail.com>
Diffstat (limited to 'dokka-integration-tests/gradle/src/integrationTest/kotlin/org')
-rw-r--r--dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/StdLibDocumentationIntegrationTest.kt42
-rw-r--r--dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/AbstractGradleCachingIntegrationTest.kt142
-rw-r--r--dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Android0GradleIntegrationTest.kt100
-rw-r--r--dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicCachingIntegrationTest.kt74
-rw-r--r--dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGradleIntegrationTest.kt201
-rw-r--r--dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGroovyIntegrationTest.kt96
-rw-r--r--dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Collector0IntegrationTest.kt83
-rw-r--r--dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/ConfigurationTest.kt76
-rw-r--r--dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/GradleRelocatedCachingIntegrationTest.kt38
-rw-r--r--dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/JsIRGradleIntegrationTest.kt67
-rw-r--r--dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/MultiModule0IntegrationTest.kt103
-rw-r--r--dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/MultiModule1IntegrationTest.kt58
-rw-r--r--dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Multiplatform0GradleIntegrationTest.kt57
-rw-r--r--dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/SequentialTasksExecutionStressTest.kt48
-rw-r--r--dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/TestedVersions.kt72
-rw-r--r--dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Versioning0IntegrationTest.kt87
-rw-r--r--dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/WasmGradleIntegrationTest.kt66
-rw-r--r--dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/WasmJsWasiGradleIntegrationTest.kt65
-rw-r--r--dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/kotlin/CoroutinesGradleIntegrationTest.kt70
-rw-r--r--dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/kotlin/SerializationGradleIntegrationTest.kt64
20 files changed, 1609 insertions, 0 deletions
diff --git a/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/StdLibDocumentationIntegrationTest.kt b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/StdLibDocumentationIntegrationTest.kt
new file mode 100644
index 00000000..bf0fc808
--- /dev/null
+++ b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/StdLibDocumentationIntegrationTest.kt
@@ -0,0 +1,42 @@
+/*
+ * 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
+
+import java.net.URL
+import kotlin.test.Test
+
+class StdLibDocumentationIntegrationTest {
+
+ /**
+ * Documentation for Enum's synthetic values() and valueOf() functions is only present in source code,
+ * but not present in the descriptors. However, Dokka needs to generate documentation for these functions,
+ * so it ships with hardcoded kdoc templates.
+ *
+ * This test exists to make sure documentation for these hardcoded synthetic functions does not change,
+ * and fails if it does, indicating that it needs to be updated.
+ */
+ @Test
+ fun shouldAssertEnumDocumentationHasNotChanged() {
+ val sourcesLink = "https://raw.githubusercontent.com/JetBrains/kotlin/master/core/builtins/native/kotlin/Enum.kt"
+ val sources = URL(sourcesLink).readText()
+
+ val expectedValuesDoc =
+ " /**\n" +
+ " * Returns an array containing the constants of this enum type, in the order they're declared.\n" +
+ " * This method may be used to iterate over the constants.\n" +
+ " * @values\n" +
+ " */"
+ check(sources.contains(expectedValuesDoc))
+
+ val expectedValueOfDoc =
+ " /**\n" +
+ " * Returns the enum constant of this type with the specified name. The string must match exactly " +
+ "an identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.)\n" +
+ " * @throws IllegalArgumentException if this enum type has no constant with the specified name\n" +
+ " * @valueOf\n" +
+ " */"
+ check(sources.contains(expectedValueOfDoc))
+ }
+}
diff --git a/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/AbstractGradleCachingIntegrationTest.kt b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/AbstractGradleCachingIntegrationTest.kt
new file mode 100644
index 00000000..e72d2490
--- /dev/null
+++ b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/AbstractGradleCachingIntegrationTest.kt
@@ -0,0 +1,142 @@
+/*
+ * 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.gradle
+
+import org.gradle.util.GradleVersion
+import java.io.File
+import kotlin.test.assertTrue
+
+abstract class AbstractGradleCachingIntegrationTest : AbstractGradleIntegrationTest() {
+
+ fun setupProject(buildVersions: BuildVersions, project: File) {
+ val templateProjectDir = File("projects", "it-basic")
+ project.mkdirs()
+ templateProjectDir.listFiles().orEmpty()
+ .filter { it.isFile }
+ .forEach { topLevelFile -> topLevelFile.copyTo(File(project, topLevelFile.name)) }
+
+ File(templateProjectDir, "src").copyRecursively(File(project, "src"))
+ val customResourcesDir = File(templateProjectDir, "customResources")
+ if(customResourcesDir.exists() && customResourcesDir.isDirectory) {
+ val destination = File(project.parentFile, "customResources")
+ destination.mkdirs()
+ destination.deleteRecursively()
+ customResourcesDir.copyRecursively(destination)
+ }
+
+ // clean local cache for each test
+ if (buildVersions.gradleVersion >= GradleVersion.version("7.0")) {
+ //Gradle 7.0 removed the old syntax
+ project.toPath().resolve("settings.gradle.kts").toFile().appendText(
+ """
+ buildCache {
+ local {
+ // Set local build cache directory.
+ directory = File("${projectDir.invariantSeparatorsPath}", "build-cache")
+ }
+ }
+ """.trimIndent()
+ )
+ } else {
+ project.toPath().resolve("settings.gradle.kts").toFile().appendText(
+ """
+ buildCache {
+ local<DirectoryBuildCache> {
+ // Set local build cache directory.
+ directory = File("${projectDir.invariantSeparatorsPath}", "build-cache")
+ }
+ }
+ """.trimIndent()
+ )
+ }
+ }
+
+ fun File.assertHtmlOutputDir() {
+ assertTrue(isDirectory, "Missing dokka html output directory")
+
+ val imagesDir = File(this, "images")
+ assertTrue(imagesDir.isDirectory, "Missing images directory")
+
+ val scriptsDir = File(this, "scripts")
+ assertTrue(scriptsDir.isDirectory, "Missing scripts directory")
+ val reactFile = File(this, "scripts/main.js")
+ assertTrue(reactFile.isFile, "Missing main.js")
+
+ val stylesDir = File(this, "styles")
+ assertTrue(stylesDir.isDirectory, "Missing styles directory")
+ val reactStyles = File(this, "styles/main.css")
+ assertTrue(reactStyles.isFile, "Missing main.css")
+
+ val navigationHtml = File(this, "navigation.html")
+ assertTrue(navigationHtml.isFile, "Missing navigation.html")
+
+ val moduleOutputDir = File(this, "-basic -project")
+ assertTrue(moduleOutputDir.isDirectory, "Missing module directory")
+
+ val moduleIndexHtml = File(this, "index.html")
+ assertTrue(moduleIndexHtml.isFile, "Missing module index.html")
+
+ val modulePackageDir = File(moduleOutputDir, "it.basic")
+ assertTrue(modulePackageDir.isDirectory, "Missing it.basic package directory")
+
+ val modulePackageIndexHtml = File(modulePackageDir, "index.html")
+ assertTrue(modulePackageIndexHtml.isFile, "Missing module package index.html")
+
+ val moduleJavaPackageDir = File(moduleOutputDir, "it.basic.java")
+ assertTrue(moduleJavaPackageDir.isDirectory, "Missing it.basic.java package directory")
+
+ allHtmlFiles().forEach { file ->
+ assertContainsNoErrorClass(file)
+ assertNoUnresolvedLinks(file)
+ assertNoHrefToMissingLocalFileOrDirectory(file)
+ assertNoSuppressedMarker(file)
+ assertNoEmptyLinks(file)
+ assertNoEmptySpans(file)
+ }
+
+ assertTrue(
+ allHtmlFiles().any { file -> "Basic Project" in file.readText() },
+ "Expected configured moduleName to be present in html"
+ )
+
+ assertTrue(
+ allHtmlFiles().any { file ->
+ "https://github.com/Kotlin/dokka/tree/master/" +
+ "dokka-integration-tests/gradle/projects/it-basic/" +
+ "src/main/kotlin/it/basic/PublicClass.kt" in file.readText()
+ },
+ "Expected `PublicClass` source link to GitHub"
+ )
+
+ assertTrue(
+ allHtmlFiles().any { file ->
+ "https://github.com/Kotlin/dokka/tree/master/" +
+ "dokka-integration-tests/gradle/projects/it-basic/" +
+ "src/main/java/it/basic/java/SampleJavaClass.java" in file.readText()
+ },
+ "Expected `SampleJavaClass` source link to GitHub"
+ )
+
+ val anchorsShouldNotHaveHashes = "<a data-name=\".*#.*\"\\sanchor-label=\"*.*\">".toRegex()
+ assertTrue(
+ allHtmlFiles().all { file ->
+ !anchorsShouldNotHaveHashes.containsMatchIn(file.readText())
+ },
+ "Anchors should not have hashes inside"
+ )
+
+ assertTrue(
+ stylesDir.resolve("logo-styles.css").readText().contains(
+ "--dokka-logo-image-url: url('https://upload.wikimedia.org/wikipedia/commons/9/9d/Ubuntu_logo.svg');",
+ )
+ )
+ assertTrue(stylesDir.resolve("custom-style-to-add.css").isFile)
+ assertTrue(stylesDir.resolve("custom-style-to-add.css").readText().contains("/* custom stylesheet */"))
+ allHtmlFiles().forEach { file ->
+ if(file.name != "navigation.html") assertTrue("custom-style-to-add.css" in file.readText(), "custom styles not added to html file ${file.name}")
+ }
+ assertTrue(imagesDir.resolve("custom-resource.svg").isFile)
+ }
+}
diff --git a/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Android0GradleIntegrationTest.kt b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Android0GradleIntegrationTest.kt
new file mode 100644
index 00000000..209d6284
--- /dev/null
+++ b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Android0GradleIntegrationTest.kt
@@ -0,0 +1,100 @@
+/*
+ * 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.gradle
+
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.ArgumentsSource
+import java.io.File
+import kotlin.test.BeforeTest
+import kotlin.test.assertEquals
+import kotlin.test.assertNotNull
+import kotlin.test.assertTrue
+
+internal class AndroidTestedVersionsArgumentsProvider : TestedVersionsArgumentsProvider(TestedVersions.ANDROID)
+
+class Android0GradleIntegrationTest : AbstractGradleIntegrationTest() {
+
+ companion object {
+ /**
+ * Indicating whether or not the current machine executing the test is a CI
+ */
+ private val isCI: Boolean get() = System.getenv("CI") == "true"
+
+ private val isAndroidSdkInstalled: Boolean = System.getenv("ANDROID_SDK_ROOT") != null ||
+ System.getenv("ANDROID_HOME") != null
+
+ fun assumeAndroidSdkInstalled() {
+ if (isCI) return
+ if (!isAndroidSdkInstalled) {
+ throw IllegalStateException("Expected Android SDK to be installed")
+ }
+ }
+ }
+
+ @BeforeTest
+ fun prepareProjectFiles() {
+ assumeAndroidSdkInstalled()
+ val templateProjectDir = File("projects", "it-android-0")
+
+ templateProjectDir.listFiles().orEmpty()
+ .filter { it.isFile }
+ .filterNot { it.name == "local.properties" }
+ .filterNot { it.name.startsWith("gradlew") }
+ .forEach { topLevelFile -> topLevelFile.copyTo(File(projectDir, topLevelFile.name)) }
+
+ File(templateProjectDir, "src").copyRecursively(File(projectDir, "src"))
+ }
+
+ @ParameterizedTest(name = "{0}")
+ @ArgumentsSource(AndroidTestedVersionsArgumentsProvider::class)
+ fun execute(buildVersions: BuildVersions) {
+ val result = createGradleRunner(buildVersions, "dokkaHtml", "-i", "-s").buildRelaxed()
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":dokkaHtml")).outcome)
+
+ val htmlOutputDir = File(projectDir, "build/dokka/html")
+ assertTrue(htmlOutputDir.isDirectory, "Missing html output directory")
+
+ assertTrue(
+ htmlOutputDir.allHtmlFiles().count() > 0,
+ "Expected html files in html output directory"
+ )
+
+ htmlOutputDir.allHtmlFiles().forEach { file ->
+ assertContainsNoErrorClass(file)
+ assertNoUnresolvedLinks(file, knownUnresolvedDRIs)
+ assertNoHrefToMissingLocalFileOrDirectory(file)
+ assertNoEmptyLinks(file)
+ assertNoEmptySpans(file)
+ }
+
+ assertTrue(
+ htmlOutputDir.allHtmlFiles().any { file ->
+ "https://developer.android.com/reference/kotlin/android/content/Context.html" in file.readText()
+ }, "Expected link to developer.android.com"
+ )
+
+ assertTrue(
+ htmlOutputDir.allHtmlFiles().any { file ->
+ "https://developer.android.com/reference/kotlin/androidx/appcompat/app/AppCompatActivity.html" in
+ file.readText()
+ }, "Expected link to developer.android.com/.../androidx/"
+ )
+
+ htmlOutputDir.allHtmlFiles().forEach { file ->
+ assertContainsNoErrorClass(file)
+ assertNoUnresolvedLinks(file)
+ assertNoHrefToMissingLocalFileOrDirectory(file)
+ }
+ }
+
+ // TODO: remove this list when https://github.com/Kotlin/dokka/issues/1306 is closed
+ private val knownUnresolvedDRIs = setOf(
+ "it.android/IntegrationTestActivity/findViewById/#kotlin.Int/PointingToGenericParameters(0)/",
+ "it.android/IntegrationTestActivity/getExtraData/#java.lang.Class[TypeParam(bounds=[androidx.core.app.ComponentActivity.ExtraData])]/PointingToGenericParameters(0)/",
+ "it.android/IntegrationTestActivity/getSystemService/#java.lang.Class[TypeParam(bounds=[kotlin.Any])]/PointingToGenericParameters(0)/",
+ "it.android/IntegrationTestActivity/requireViewById/#kotlin.Int/PointingToGenericParameters(0)/"
+ )
+}
diff --git a/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicCachingIntegrationTest.kt b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicCachingIntegrationTest.kt
new file mode 100644
index 00000000..bab55154
--- /dev/null
+++ b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicCachingIntegrationTest.kt
@@ -0,0 +1,74 @@
+/*
+ * 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.gradle
+
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.ArgumentsSource
+import java.io.File
+import kotlin.test.assertEquals
+import kotlin.test.assertNotNull
+import kotlin.test.assertTrue
+
+class BasicCachingIntegrationTest : AbstractGradleCachingIntegrationTest() {
+
+
+ @ParameterizedTest(name = "{0}")
+ @ArgumentsSource(AllSupportedTestedVersionsArgumentsProvider::class)
+ fun execute(buildVersions: BuildVersions) {
+ setupProject(buildVersions, projectDir)
+
+ runAndAssertOutcomeAndContents(buildVersions, TaskOutcome.SUCCESS)
+ runAndAssertOutcomeAndContents(buildVersions, TaskOutcome.FROM_CACHE)
+ }
+
+ @ParameterizedTest(name = "{0}")
+ @ArgumentsSource(AllSupportedTestedVersionsArgumentsProvider::class)
+ fun localDirectoryPointingToRoot(buildVersions: BuildVersions) {
+ setupProject(buildVersions, projectDir)
+
+ fun String.findAndReplace(oldValue: String, newValue: String): String {
+ assertTrue(oldValue in this, "Expected to replace '$oldValue'")
+ return replace(oldValue, newValue)
+ }
+ val projectKts = projectDir.resolve("build.gradle.kts")
+
+ projectKts.readText()
+ .findAndReplace("localDirectory.set(file(\"src/main\"))", "localDirectory.set(projectDir)")
+ .findAndReplace("integration-tests/gradle/projects/it-basic/src/main", "integration-tests/gradle/projects/it-basic")
+ .also { projectKts.writeText(it) }
+
+ runAndAssertOutcomeAndContents(buildVersions, TaskOutcome.SUCCESS)
+ projectDir.resolve("unrelated.txt").writeText("modified")
+ // despite projectDir is used as an input in localDirectory, changing its contents shouldn't invalidate the cache
+ runAndAssertOutcomeAndContents(buildVersions, TaskOutcome.FROM_CACHE)
+
+ projectKts.readText()
+ .findAndReplace("localDirectory.set(projectDir)", "localDirectory.set(file(\"src\"))")
+ .also { projectKts.writeText(it) }
+ // changing localDirectory path invalidates cached task results
+ runAndAssertOutcome(buildVersions, TaskOutcome.SUCCESS)
+ }
+
+
+ private fun runAndAssertOutcomeAndContents(buildVersions: BuildVersions, expectedOutcome: TaskOutcome) {
+ runAndAssertOutcome(buildVersions, expectedOutcome)
+ File(projectDir, "build/dokka/html").assertHtmlOutputDir()
+ }
+
+ private fun runAndAssertOutcome(buildVersions: BuildVersions, expectedOutcome: TaskOutcome) {
+ val result = createGradleRunner(
+ buildVersions,
+ "clean",
+ "dokkaHtml",
+ "-i",
+ "-s",
+ "-Dorg.gradle.caching.debug=true",
+ "--build-cache"
+ ).buildRelaxed()
+
+ assertEquals(expectedOutcome, assertNotNull(result.task(":dokkaHtml")).outcome)
+ }
+}
diff --git a/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGradleIntegrationTest.kt b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGradleIntegrationTest.kt
new file mode 100644
index 00000000..daf029fc
--- /dev/null
+++ b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGradleIntegrationTest.kt
@@ -0,0 +1,201 @@
+/*
+ * 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.gradle
+
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.ArgumentsSource
+import java.io.File
+import kotlin.test.*
+
+class BasicGradleIntegrationTest : AbstractGradleIntegrationTest() {
+
+ @BeforeTest
+ fun prepareProjectFiles() {
+ val templateProjectDir = File("projects", "it-basic")
+
+ templateProjectDir.listFiles().orEmpty()
+ .filter { it.isFile }
+ .forEach { topLevelFile -> topLevelFile.copyTo(File(projectDir, topLevelFile.name)) }
+
+ File(templateProjectDir, "src").copyRecursively(File(projectDir, "src"))
+ val customResourcesDir = File(templateProjectDir, "customResources")
+
+ if (customResourcesDir.exists() && customResourcesDir.isDirectory) {
+ val destination = File(projectDir.parentFile, "customResources")
+ destination.mkdirs()
+ destination.deleteRecursively()
+ customResourcesDir.copyRecursively(destination)
+ }
+ }
+
+ @ParameterizedTest(name = "{0}")
+ @ArgumentsSource(AllSupportedTestedVersionsArgumentsProvider::class)
+ fun execute(buildVersions: BuildVersions) {
+ runAndAssertOutcome(buildVersions, TaskOutcome.SUCCESS)
+ runAndAssertOutcome(buildVersions, TaskOutcome.UP_TO_DATE)
+ }
+
+ private fun runAndAssertOutcome(buildVersions: BuildVersions, expectedOutcome: TaskOutcome) {
+ val result = createGradleRunner(
+ buildVersions,
+ "dokkaHtml",
+ "dokkaJavadoc",
+ "dokkaGfm",
+ "dokkaJekyll",
+ "-i",
+ "-s"
+ ).buildRelaxed()
+
+ assertEquals(expectedOutcome, assertNotNull(result.task(":dokkaHtml")).outcome)
+ assertEquals(expectedOutcome, assertNotNull(result.task(":dokkaJavadoc")).outcome)
+ assertEquals(expectedOutcome, assertNotNull(result.task(":dokkaGfm")).outcome)
+ assertEquals(expectedOutcome, assertNotNull(result.task(":dokkaJekyll")).outcome)
+
+ File(projectDir, "build/dokka/html").assertHtmlOutputDir()
+ File(projectDir, "build/dokka/javadoc").assertJavadocOutputDir()
+ File(projectDir, "build/dokka/gfm").assertGfmOutputDir()
+ File(projectDir, "build/dokka/jekyll").assertJekyllOutputDir()
+ }
+
+ private fun File.assertHtmlOutputDir() {
+ assertTrue(isDirectory, "Missing dokka html output directory")
+
+ val imagesDir = File(this, "images")
+ assertTrue(imagesDir.isDirectory, "Missing images directory")
+
+ val scriptsDir = File(this, "scripts")
+ assertTrue(scriptsDir.isDirectory, "Missing scripts directory")
+ val reactFile = File(this, "scripts/main.js")
+ assertTrue(reactFile.isFile, "Missing main.js")
+
+ val stylesDir = File(this, "styles")
+ assertTrue(stylesDir.isDirectory, "Missing styles directory")
+ val reactStyles = File(this, "styles/main.css")
+ assertTrue(reactStyles.isFile, "Missing main.css")
+
+ val navigationHtml = File(this, "navigation.html")
+ assertTrue(navigationHtml.isFile, "Missing navigation.html")
+
+ val moduleOutputDir = File(this, "-basic -project")
+ assertTrue(moduleOutputDir.isDirectory, "Missing module directory")
+
+ val moduleIndexHtml = File(this, "index.html")
+ assertTrue(moduleIndexHtml.isFile, "Missing module index.html")
+
+ val modulePackageDir = File(moduleOutputDir, "it.basic")
+ assertTrue(modulePackageDir.isDirectory, "Missing it.basic package directory")
+
+ val modulePackageIndexHtml = File(modulePackageDir, "index.html")
+ assertTrue(modulePackageIndexHtml.isFile, "Missing module package index.html")
+
+ val moduleJavaPackageDir = File(moduleOutputDir, "it.basic.java")
+ assertTrue(moduleJavaPackageDir.isDirectory, "Missing it.basic.java package directory")
+
+ allHtmlFiles().forEach { file ->
+ assertContainsNoErrorClass(file)
+ assertNoUnresolvedLinks(file)
+ assertNoHrefToMissingLocalFileOrDirectory(file)
+ assertNoSuppressedMarker(file)
+ assertNoEmptyLinks(file)
+ assertNoEmptySpans(file)
+ }
+
+ assertTrue(
+ allHtmlFiles().any { file -> "Basic Project" in file.readText() },
+ "Expected configured moduleName to be present in html"
+ )
+
+ assertTrue(
+ allHtmlFiles().any { file ->
+ "https://github.com/Kotlin/dokka/tree/master/" +
+ "dokka-integration-tests/gradle/projects/it-basic/" +
+ "src/main/kotlin/it/basic/PublicClass.kt" in file.readText()
+ },
+ "Expected `PublicClass` source link to GitHub"
+ )
+
+ assertTrue(
+ allHtmlFiles().any { file ->
+ "https://github.com/Kotlin/dokka/tree/master/" +
+ "dokka-integration-tests/gradle/projects/it-basic/" +
+ "src/main/java/it/basic/java/SampleJavaClass.java" in file.readText()
+ },
+ "Expected `SampleJavaClass` source link to GitHub"
+ )
+
+ val anchorsShouldNotHaveHashes = "<a data-name=\".*#.*\"\\sanchor-label=\"*.*\">".toRegex()
+ assertTrue(
+ allHtmlFiles().all { file ->
+ !anchorsShouldNotHaveHashes.containsMatchIn(file.readText())
+ },
+ "Anchors should not have hashes inside"
+ )
+
+ assertTrue(
+ stylesDir.resolve("logo-styles.css").readText().contains(
+ "--dokka-logo-image-url: url('https://upload.wikimedia.org/wikipedia/commons/9/9d/Ubuntu_logo.svg');",
+ )
+ )
+ assertTrue(stylesDir.resolve("custom-style-to-add.css").isFile)
+ assertTrue(stylesDir.resolve("custom-style-to-add.css").readText().contains("/* custom stylesheet */"))
+ allHtmlFiles().forEach { file ->
+ if (file.name != "navigation.html") assertTrue(
+ "custom-style-to-add.css" in file.readText(),
+ "custom styles not added to html file ${file.name}"
+ )
+ }
+ assertTrue(imagesDir.resolve("custom-resource.svg").isFile)
+
+ assertConfiguredVisibility(this)
+ }
+
+ private fun File.assertJavadocOutputDir() {
+ assertTrue(isDirectory, "Missing dokka javadoc output directory")
+
+ val indexFile = File(this, "index.html")
+ assertTrue(indexFile.isFile, "Missing index.html")
+ assertTrue(
+ """<title>Basic Project 1.9.20-SNAPSHOT API </title>""" in indexFile.readText(),
+ "Header with version number not present in index.html"
+ )
+
+ assertTrue {
+ allHtmlFiles().all {
+ "0.0.1" !in it.readText()
+ }
+ }
+ }
+
+ private fun File.assertGfmOutputDir() {
+ assertTrue(isDirectory, "Missing dokka gfm output directory")
+ }
+
+ private fun File.assertJekyllOutputDir() {
+ assertTrue(isDirectory, "Missing dokka jekyll output directory")
+ }
+
+ private fun assertConfiguredVisibility(outputDir: File) {
+ val allHtmlFiles = outputDir.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"),
+ )
+ )
+ }
+}
diff --git a/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGroovyIntegrationTest.kt b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGroovyIntegrationTest.kt
new file mode 100644
index 00000000..0d7d32c0
--- /dev/null
+++ b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGroovyIntegrationTest.kt
@@ -0,0 +1,96 @@
+/*
+ * 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.gradle
+
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.ArgumentsSource
+import java.io.File
+import kotlin.test.BeforeTest
+import kotlin.test.assertEquals
+import kotlin.test.assertNotNull
+import kotlin.test.assertTrue
+
+class BasicGroovyIntegrationTest : AbstractGradleIntegrationTest() {
+
+ @BeforeTest
+ fun prepareProjectFiles() {
+ val templateProjectDir = File("projects", "it-basic-groovy")
+
+ templateProjectDir.listFiles().orEmpty()
+ .filter { it.isFile }
+ .forEach { topLevelFile -> topLevelFile.copyTo(File(projectDir, topLevelFile.name)) }
+
+ File(templateProjectDir, "src").copyRecursively(File(projectDir, "src"))
+ }
+
+ @ParameterizedTest(name = "{0}")
+ @ArgumentsSource(AllSupportedTestedVersionsArgumentsProvider::class)
+ fun execute(buildVersions: BuildVersions) {
+ val result = createGradleRunner(buildVersions, "dokkaHtml", "dokkaJavadoc", "dokkaGfm", "dokkaJekyll", "-i", "-s")
+ .buildRelaxed()
+
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":dokkaHtml")).outcome)
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":dokkaJavadoc")).outcome)
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":dokkaGfm")).outcome)
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":dokkaJekyll")).outcome)
+
+ File(projectDir, "build/dokka/customHtml").assertKdocOutputDir()
+ File(projectDir, "build/dokka/customJavadoc").assertJavadocOutputDir()
+ File(projectDir, "build/dokka/customGfm").assertGfmOutputDir()
+ File(projectDir, "build/dokka/customJekyll").assertJekyllOutputDir()
+ }
+
+ private fun File.assertKdocOutputDir() {
+ assertTrue(isDirectory, "Missing dokka html output directory")
+
+ val imagesDir = File(this, "images")
+ assertTrue(imagesDir.isDirectory, "Missing images directory")
+
+ val scriptsDir = File(this, "scripts")
+ assertTrue(scriptsDir.isDirectory, "Missing scripts directory")
+
+ val stylesDir = File(this, "styles")
+ assertTrue(stylesDir.isDirectory, "Missing styles directory")
+
+ val navigationHtml = File(this, "navigation.html")
+ assertTrue(navigationHtml.isFile, "Missing navigation.html")
+
+ val moduleOutputDir = File(this, "it-basic-groovy")
+ assertTrue(moduleOutputDir.isDirectory, "Missing module directory")
+
+ val moduleIndexHtml = File(this, "index.html")
+ assertTrue(moduleIndexHtml.isFile, "Missing module index.html")
+
+ val modulePackageDir = File(moduleOutputDir, "it.basic")
+ assertTrue(modulePackageDir.isDirectory, "Missing it.basic package directory")
+
+ val modulePackageIndexHtml = File(modulePackageDir, "index.html")
+ assertTrue(modulePackageIndexHtml.isFile, "Missing module package index.html")
+
+ val moduleJavaPackageDir = File(moduleOutputDir, "it.basic.java")
+ assertTrue(moduleJavaPackageDi