aboutsummaryrefslogtreecommitdiff
path: root/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains
diff options
context:
space:
mode:
Diffstat (limited to 'integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains')
-rw-r--r--integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/AbstractAndroidAppTest.kt51
-rw-r--r--integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/AbstractDokkaAndroidGradleTest.kt45
-rw-r--r--integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/AbstractDokkaGradleTest.kt108
-rw-r--r--integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/AndroidAppTest.kt25
-rw-r--r--integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/AndroidLibDependsOnJavaLibTest.kt48
-rw-r--r--integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/AndroidMultiFlavourAppTest.kt60
-rw-r--r--integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/BasicTest.kt51
-rw-r--r--integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/JavadocRSuppressionTest.kt24
-rw-r--r--integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/MultiProjectSingleOutTest.kt57
-rw-r--r--integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/MultiplatformProjectTest.kt54
-rw-r--r--integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/RebuildAfterSourceChangeTest.kt74
-rw-r--r--integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/TypeSafeConfigurationTest.kt36
-rw-r--r--integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/Utils.kt56
13 files changed, 689 insertions, 0 deletions
diff --git a/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/AbstractAndroidAppTest.kt b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/AbstractAndroidAppTest.kt
new file mode 100644
index 00000000..c3fe2ea9
--- /dev/null
+++ b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/AbstractAndroidAppTest.kt
@@ -0,0 +1,51 @@
+package org.jetbrains.dokka.gradle
+
+import org.gradle.testkit.runner.TaskOutcome
+import kotlin.test.assertEquals
+
+abstract class AbstractAndroidAppTest(val testDataRootPath: String) : AbstractDokkaAndroidGradleTest() {
+
+ fun prepareTestData() {
+ val testDataRoot = testDataFolder.resolve(testDataRootPath)
+ val tmpRoot = testProjectDir.root.toPath()
+
+ testDataRoot.resolve("app").copy(tmpRoot.resolve("app"))
+ testDataRoot.resolve("build.gradle").copy(tmpRoot.resolve("build.gradle"))
+ testDataRoot.resolve("settings.gradle").copy(tmpRoot.resolve("settings.gradle"))
+
+ androidLocalProperties?.copy(tmpRoot.resolve("local.properties"))
+ }
+
+
+ data class AndroidPluginParams(val pluginVersion: String, val buildToolsVersion: String, val compileSdk: Int) {
+ fun asArguments(): List<String> = listOf(
+ "-Pabt_plugin_version=$pluginVersion",
+ "-Pabt_version=$buildToolsVersion",
+ "-Psdk_version=$compileSdk"
+ )
+ }
+
+
+ protected fun doTest(gradleVersion: String, kotlinVersion: String, androidPluginParams: AndroidPluginParams) {
+ prepareTestData()
+
+ val result = configure(gradleVersion, kotlinVersion,
+ arguments = arrayOf("dokka", "--stacktrace") + androidPluginParams.asArguments())
+ .build()
+
+ println(result.output)
+
+ assertEquals(TaskOutcome.SUCCESS, result.task(":app:dokka")?.outcome)
+
+ val docsOutput = "app/build/dokka"
+
+ checkOutputStructure("$testDataRootPath/fileTree.txt", docsOutput)
+
+ checkNoErrorClasses(docsOutput)
+ checkNoUnresolvedLinks(docsOutput)
+
+ checkExternalLink(docsOutput, "<span class=\"identifier\">Activity</span>",
+ """<a href="https://developer.android.com/reference/android/app/Activity.html"><span class="identifier">Activity</span></a>""")
+ }
+
+} \ No newline at end of file
diff --git a/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/AbstractDokkaAndroidGradleTest.kt b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/AbstractDokkaAndroidGradleTest.kt
new file mode 100644
index 00000000..334fc7c8
--- /dev/null
+++ b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/AbstractDokkaAndroidGradleTest.kt
@@ -0,0 +1,45 @@
+package org.jetbrains.dokka.gradle
+
+import org.junit.BeforeClass
+import java.io.File
+
+abstract class AbstractDokkaAndroidGradleTest : AbstractDokkaGradleTest() {
+
+ override val pluginClasspath: List<File> = pluginClasspathData.toFile().readLines().map { File(it) }
+
+ companion object {
+
+ @JvmStatic
+ @BeforeClass
+ fun acceptAndroidSdkLicenses() {
+ val sdkDir = androidLocalProperties?.toFile()?.let {
+ val lines = it.readLines().map { it.trim() }
+ val sdkDirLine = lines.firstOrNull { "sdk.dir" in it }
+ sdkDirLine?.substringAfter("=")?.trim()
+ } ?: System.getenv("ANDROID_HOME")
+
+ if (sdkDir == null || sdkDir.isEmpty()) {
+ error("Android SDK home not set, " +
+ "try setting \$ANDROID_HOME " +
+ "or sdk.dir in runners/gradle-integration-tests/testData/android.local.properties")
+ }
+ val sdkDirFile = File(sdkDir)
+ if (!sdkDirFile.exists()) error("\$ANDROID_HOME and android.local.properties points to non-existing location")
+ val sdkLicensesDir = sdkDirFile.resolve("licenses")
+
+ val acceptedLicenses = File("android-licenses")
+ acceptedLicenses.listFiles().forEach { licenseFile ->
+ val target = sdkLicensesDir.resolve(licenseFile.name)
+ if(!target.exists() || target.readText() != licenseFile.readText()) {
+ val overwrite = System.getProperty("android.licenses.overwrite", "false")!!.toBoolean()
+ if (!target.exists() || overwrite) {
+ licenseFile.copyTo(target, true)
+ println("Accepted ${licenseFile.name}, by copying $licenseFile to $target")
+ }
+ }
+
+ }
+ }
+
+ }
+} \ No newline at end of file
diff --git a/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/AbstractDokkaGradleTest.kt b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/AbstractDokkaGradleTest.kt
new file mode 100644
index 00000000..4814e707
--- /dev/null
+++ b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/AbstractDokkaGradleTest.kt
@@ -0,0 +1,108 @@
+package org.jetbrains.dokka.gradle
+
+
+import com.intellij.rt.execution.junit.FileComparisonFailure
+import org.gradle.testkit.runner.GradleRunner
+import org.junit.Rule
+import org.junit.rules.TemporaryFolder
+import java.io.File
+import java.nio.file.Files
+import java.nio.file.Path
+import java.nio.file.Paths
+
+
+val testDataFolder: Path = Paths.get("testData")
+
+val pluginClasspathData: Path = Paths.get("build", "createClasspathManifest", "dokka-plugin-classpath.txt")
+
+val dokkaFatJarPathData: Path = pluginClasspathData.resolveSibling("fatjar.txt")
+
+val androidLocalProperties = testDataFolder.resolve("android.local.properties").let { if (Files.exists(it)) it else null }
+
+abstract class AbstractDokkaGradleTest {
+ @get:Rule val testProjectDir = TemporaryFolder()
+
+ open val pluginClasspath: List<File> = pluginClasspathData.toFile().readLines().map { File(it) }
+
+ fun checkOutputStructure(expected: String, actualSubpath: String) {
+ val expectedPath = testDataFolder.resolve(expected)
+ val actualPath = testProjectDir.root.toPath().resolve(actualSubpath).normalize()
+
+ assertEqualsIgnoringSeparators(expectedPath.toFile(), buildString {
+ actualPath.toFile().writeStructure(this, File(actualPath.toFile(), "."))
+ })
+ }
+
+ fun checkNoErrorClasses(actualSubpath: String, extension: String = "html", errorClassMarker: String = "ERROR CLASS") {
+ val actualPath = testProjectDir.root.toPath().resolve(actualSubpath).normalize()
+ var checked = 0
+ Files.walk(actualPath).filter { Files.isRegularFile(it) && it.fileName.toString().endsWith(".$extension") }.forEach {
+ val text = it.toFile().readText()
+
+ val noErrorClasses = text.replace(errorClassMarker, "?!")
+
+ if (noErrorClasses != text) {
+ throw FileComparisonFailure("", noErrorClasses, text, null)
+ }
+
+ checked++
+ }
+ println("$checked files checked for error classes")
+ }
+
+ fun checkNoUnresolvedLinks(actualSubpath: String, extension: String = "html", marker: Regex = "[\"']#[\"']".toRegex()) {
+ val actualPath = testProjectDir.root.toPath().resolve(actualSubpath).normalize()
+ var checked = 0
+ Files.walk(actualPath).filter { Files.isRegularFile(it) && it.fileName.toString().endsWith(".$extension") }.forEach {
+ val text = it.toFile().readText()
+
+ val noErrorClasses = text.replace(marker, "?!")
+
+ if (noErrorClasses != text) {
+ throw FileComparisonFailure("", noErrorClasses, text, null)
+ }
+
+ checked++
+ }
+ println("$checked files checked for unresolved links")
+ }
+
+ fun checkExternalLink(actualSubpath: String, linkBody: String, fullLink: String, extension: String = "html") {
+ val match = "!!match!!"
+ val notMatch = "!!not-match!!"
+
+ val actualPath = testProjectDir.root.toPath().resolve(actualSubpath).normalize()
+ var checked = 0
+ var totalEntries = 0
+ Files.walk(actualPath).filter { Files.isRegularFile(it) && it.fileName.toString().endsWith(".$extension") }.forEach {
+ val text = it.toFile().readText()
+
+ val textWithoutMatches = text.replace(fullLink, match)
+
+ val textWithoutNonMatches = textWithoutMatches.replace(linkBody, notMatch)
+
+ if (textWithoutNonMatches != textWithoutMatches) {
+
+ val expected = textWithoutNonMatches.replace(notMatch, fullLink).replace(match, fullLink)
+ val actual = textWithoutMatches.replace(match, fullLink)
+
+ throw FileComparisonFailure("", expected, actual, null)
+ }
+ if (text != textWithoutMatches)
+ totalEntries++
+
+ checked++
+ }
+ println("$checked files checked for valid external links '$linkBody', found $totalEntries links")
+ }
+
+ fun configure(gradleVersion: String = "3.5", kotlinVersion: String = "1.1.2", arguments: Array<String>): GradleRunner {
+ val fatjar = dokkaFatJarPathData.toFile().readText()
+
+ return GradleRunner.create().withProjectDir(testProjectDir.root)
+ .withArguments("-Pdokka_fatjar=$fatjar", "-Ptest_kotlin_version=$kotlinVersion", *arguments)
+ .withPluginClasspath(pluginClasspath)
+ .withGradleVersion(gradleVersion)
+ .withDebug(true)
+ }
+} \ No newline at end of file
diff --git a/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/AndroidAppTest.kt b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/AndroidAppTest.kt
new file mode 100644
index 00000000..bbb63909
--- /dev/null
+++ b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/AndroidAppTest.kt
@@ -0,0 +1,25 @@
+package org.jetbrains.dokka.gradle
+
+import org.junit.Test
+
+class AndroidAppTest : AbstractAndroidAppTest("androidApp") {
+ @Test
+ fun `test kotlin 1_1_2-5 and gradle 4_0 and abt 3_0_0-alpha3`() {
+ doTest("4.0", "1.1.2-5", AndroidPluginParams("3.0.0-alpha3", "25.0.2", 25))
+ }
+
+ @Test
+ fun `test kotlin 1_1_2 and gradle 3_5 and abt 2_3_0`() {
+ doTest("3.5", "1.1.2", AndroidPluginParams("2.3.0", "25.0.0", 24))
+ }
+
+ @Test
+ fun `test kotlin 1_0_7 and gradle 2_14_1 and abt 2_2_3`() {
+ doTest("2.14.1", "1.0.7", AndroidPluginParams("2.2.3", "25.0.0", 24))
+ }
+
+ @Test
+ fun `test kotlin 1_2_20 and gradle 4_5 and abt 3_0_1`() {
+ doTest("4.5", "1.2.20", AndroidPluginParams("3.0.1", "27.0.0", 27))
+ }
+} \ No newline at end of file
diff --git a/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/AndroidLibDependsOnJavaLibTest.kt b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/AndroidLibDependsOnJavaLibTest.kt
new file mode 100644
index 00000000..9bc52273
--- /dev/null
+++ b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/AndroidLibDependsOnJavaLibTest.kt
@@ -0,0 +1,48 @@
+package org.jetbrains.dokka.gradle
+
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.Test
+import kotlin.test.assertEquals
+
+class AndroidLibDependsOnJavaLibTest: AbstractDokkaAndroidGradleTest() {
+
+ private val testDataRootPath = "androidLibDependsOnJavaLib"
+
+ private fun prepareTestData() {
+ val testDataRoot = testDataFolder.resolve(testDataRootPath)
+ val tmpRoot = testProjectDir.root.toPath()
+
+ testDataRoot.copy(tmpRoot)
+
+ androidLocalProperties?.copy(tmpRoot.resolve("local.properties"))
+ }
+
+
+ private fun doTest(gradleVersion: String, kotlinVersion: String, androidPluginParams: AbstractAndroidAppTest.AndroidPluginParams) {
+ prepareTestData()
+
+ val result = configure(gradleVersion, kotlinVersion,
+ arguments = arrayOf("dokka", "--stacktrace") + androidPluginParams.asArguments())
+ .build()
+
+ println(result.output)
+
+ assertEquals(TaskOutcome.SUCCESS, result.task(":lib:dokka")?.outcome)
+
+ val docsOutput = "lib/build/dokka"
+
+ checkOutputStructure("$testDataRootPath/fileTree.txt", docsOutput)
+
+ checkNoErrorClasses(docsOutput)
+ checkNoUnresolvedLinks(docsOutput)
+
+ checkExternalLink(docsOutput, "<span class=\"identifier\">LibClz</span>",
+ """<a href="https://example.com/example/jlib/LibClz.html"><span class="identifier">LibClz</span></a>""")
+ }
+
+
+ @Test
+ fun `test kotlin 1_2_20 and gradle 4_5 and abt 3_0_1`() {
+ doTest("4.5", "1.2.20", AbstractAndroidAppTest.AndroidPluginParams("3.0.1", "27.0.0", 27))
+ }
+} \ No newline at end of file
diff --git a/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/AndroidMultiFlavourAppTest.kt b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/AndroidMultiFlavourAppTest.kt
new file mode 100644
index 00000000..ef1b94d8
--- /dev/null
+++ b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/AndroidMultiFlavourAppTest.kt
@@ -0,0 +1,60 @@
+package org.jetbrains.dokka.gradle
+
+import org.gradle.testkit.runner.TaskOutcome
+import org.jetbrains.dokka.gradle.AbstractAndroidAppTest.AndroidPluginParams
+import org.junit.Test
+import kotlin.test.assertEquals
+
+class AndroidMultiFlavourAppTest : AbstractDokkaAndroidGradleTest() {
+
+ fun prepareTestData(testDataRootPath: String) {
+ val testDataRoot = testDataFolder.resolve(testDataRootPath)
+ val tmpRoot = testProjectDir.root.toPath()
+
+ testDataRoot.resolve("app").copy(tmpRoot.resolve("app"))
+ testDataRoot.resolve("build.gradle").copy(tmpRoot.resolve("build.gradle"))
+ testDataRoot.resolve("settings.gradle").copy(tmpRoot.resolve("settings.gradle"))
+
+ androidLocalProperties?.copy(tmpRoot.resolve("local.properties"))
+ }
+
+ private fun doTest(gradleVersion: String, kotlinVersion: String, androidPluginParams: AndroidPluginParams) {
+ prepareTestData("androidMultiFlavourApp")
+
+ val result = configure(gradleVersion, kotlinVersion,
+ arguments = arrayOf("dokka", "dokkaFullFlavourOnly", "--stacktrace") + androidPluginParams.asArguments())
+ .build()
+
+ println(result.output)
+
+ assertEquals(TaskOutcome.SUCCESS, result.task(":app:dokka")?.outcome)
+ assertEquals(TaskOutcome.SUCCESS, result.task(":app:dokkaFullFlavourOnly")?.outcome)
+
+ val docsOutput = "app/build/dokka"
+
+ checkOutputStructure("androidMultiFlavourApp/fileTree.txt", docsOutput)
+
+ checkNoErrorClasses(docsOutput)
+ checkNoUnresolvedLinks(docsOutput)
+
+ checkExternalLink(docsOutput, "<span class=\"identifier\">Activity</span>",
+ """<a href="https://developer.android.com/reference/android/app/Activity.html"><span class="identifier">Activity</span></a>""")
+ }
+
+ @Test fun `test kotlin 1_1_2-5 and gradle 4_0 and abt 3_0_0-alpha3`() {
+ doTest("4.0", "1.1.2-5", AndroidPluginParams("3.0.0-alpha3", "25.0.2", 25))
+ }
+
+ @Test fun `test kotlin 1_1_2 and gradle 3_5 and abt 2_3_0`() {
+ doTest("3.5", "1.1.2", AndroidPluginParams("2.3.0", "25.0.0", 24))
+ }
+
+ @Test fun `test kotlin 1_0_7 and gradle 2_14_1 and abt 2_2_3`() {
+ doTest("2.14.1", "1.0.7", AndroidPluginParams("2.2.3", "25.0.0", 24))
+ }
+
+ @Test fun `test kotlin 1_2_20 and gradle 4_5 and abt 3_0_1`() {
+ doTest("4.5", "1.2.20", AndroidPluginParams("3.0.1", "27.0.0", 27))
+ }
+
+} \ No newline at end of file
diff --git a/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/BasicTest.kt b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/BasicTest.kt
new file mode 100644
index 00000000..2e1a0d41
--- /dev/null
+++ b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/BasicTest.kt
@@ -0,0 +1,51 @@
+package org.jetbrains.dokka.gradle
+
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.Test
+import kotlin.test.assertEquals
+
+class BasicTest : AbstractDokkaGradleTest() {
+
+ fun prepareTestData(testDataRootPath: String) {
+ val testDataRoot = testDataFolder.resolve(testDataRootPath)
+ val tmpRoot = testProjectDir.root.toPath()
+
+ testDataRoot.resolve("src").copy(tmpRoot.resolve("src"))
+ testDataRoot.resolve("classDir").copy(tmpRoot.resolve("classDir"))
+ testDataRoot.resolve("build.gradle").copy(tmpRoot.resolve("build.gradle"))
+ testDataRoot.resolve("settings.gradle").copy(tmpRoot.resolve("settings.gradle"))
+ }
+
+ private fun doTest(gradleVersion: String, kotlinVersion: String) {
+
+ prepareTestData("basic")
+
+ val result = configure(gradleVersion, kotlinVersion, arguments = arrayOf("dokka", "--stacktrace")).build()
+
+ println(result.output)
+
+ assertEquals(TaskOutcome.SUCCESS, result.task(":dokka")?.outcome)
+
+ val docsOutput = "build/dokka"
+
+ checkOutputStructure("basic/fileTree.txt", docsOutput)
+
+ checkNoErrorClasses(docsOutput)
+ checkNoUnresolvedLinks(docsOutput)
+
+ checkExternalLink(docsOutput, "<span class=\"identifier\">String</span>",
+ """<a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html"><span class="identifier">String</span></a>""")
+ }
+
+ @Test fun `test kotlin 1_0_7 and gradle 2_14_1`() {
+ doTest("2.14.1", "1.0.7")
+ }
+
+ @Test fun `test kotlin 1_1_2 and gradle 4_0`() {
+ doTest("4.0", "1.1.2")
+ }
+
+ @Test fun `test kotlin 1_2_20 and gradle 4_5`() {
+ doTest("4.5", "1.2.20")
+ }
+} \ No newline at end of file
diff --git a/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/JavadocRSuppressionTest.kt b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/JavadocRSuppressionTest.kt
new file mode 100644
index 00000000..3a4d08b8
--- /dev/null
+++ b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/JavadocRSuppressionTest.kt
@@ -0,0 +1,24 @@
+package org.jetbrains.dokka.gradle
+
+import org.junit.Test
+
+class JavadocRSuppressionTest : AbstractAndroidAppTest("androidAppJavadoc") {
+ @Test
+ fun `test kotlin 1_1_2-5 and gradle 4_0 and abt 3_0_0-alpha3`() {
+ doTest("4.0", "1.1.2-5", AndroidPluginParams("3.0.0-alpha3", "25.0.2", 25))
+ }
+
+ @Test
+ fun `test kotlin 1_1_2 and gradle 3_5 and abt 2_3_0`() {
+ doTest("3.5", "1.1.2", AndroidPluginParams("2.3.0", "25.0.0", 24))
+ }
+
+ @Test
+ fun `test kotlin 1_0_7 and gradle 2_14_1 and abt 2_2_3`() {
+ doTest("2.14.1", "1.0.7", AndroidPluginParams("2.2.3", "25.0.0", 24))
+ }
+
+ @Test fun `test kotlin 1_2_20 and gradle 4_5 and abt 3_0_1`() {
+ doTest("4.5", "1.2.20", AndroidPluginParams("3.0.1", "27.0.0", 27))
+ }
+} \ No newline at end of file
diff --git a/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/MultiProjectSingleOutTest.kt b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/MultiProjectSingleOutTest.kt
new file mode 100644
index 00000000..9458528c
--- /dev/null
+++ b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/MultiProjectSingleOutTest.kt
@@ -0,0 +1,57 @@
+package org.jetbrains.dokka.gradle
+
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.Test
+import kotlin.test.assertEquals
+
+class MultiProjectSingleOutTest : AbstractDokkaGradleTest() {
+
+ fun prepareTestData(testDataRootPath: String) {
+ val testDataRoot = testDataFolder.resolve(testDataRootPath)
+ val tmpRoot = testProjectDir.root.toPath()
+
+ testDataRoot.apply {
+ resolve("build.gradle").copy(tmpRoot.resolve("build.gradle"))
+ resolve("settings.gradle").copy(tmpRoot.resolve("settings.gradle"))
+ resolve("subA").copy(tmpRoot.resolve("subA"))
+ resolve("subB").copy(tmpRoot.resolve("subB"))
+ }
+ }
+
+ private fun doTest(gradleVersion: String, kotlinVersion: String) {
+
+ prepareTestData("multiProjectSingleOut")
+
+ val result = configure(gradleVersion, kotlinVersion, arguments = arrayOf("dokka", "--stacktrace")).build()
+
+ println(result.output)
+
+ assertEquals(TaskOutcome.SUCCESS, result.task(":dokka")?.outcome)
+
+ val docsOutput = "build/dokka"
+
+ checkOutputStructure("multiProjectSingleOut/fileTree.txt", docsOutput)
+
+ checkNoErrorClasses(docsOutput)
+ checkNoUnresolvedLinks(docsOutput)
+
+ checkExternalLink(docsOutput, "<span class=\"identifier\">String</span>",
+ """<a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html"><span class="identifier">String</span></a>""")
+ }
+
+ @Test fun `test kotlin 1_1_2 and gradle 3_5`() {
+ doTest("3.5", "1.1.2")
+ }
+
+ @Test fun `test kotlin 1_0_7 and gradle 2_14_1`() {
+ doTest("2.14.1", "1.0.7")
+ }
+
+ @Test fun `test kotlin 1_1_2 and gradle 4_0`() {
+ doTest("4.0", "1.1.2")
+ }
+
+ @Test fun `test kotlin 1_2_20 and gradle 4_5`() {
+ doTest("4.5", "1.2.20")
+ }
+} \ No newline at end of file
diff --git a/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/MultiplatformProjectTest.kt b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/MultiplatformProjectTest.kt
new file mode 100644
index 00000000..3e61d79e
--- /dev/null
+++ b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/MultiplatformProjectTest.kt
@@ -0,0 +1,54 @@
+package org.jetbrains.dokka.gradle
+
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.Test
+import java.io.File
+import kotlin.test.assertEquals
+
+class MultiplatformProjectTest : AbstractDokkaGradleTest() {
+
+ fun prepareTestData(testDataRootPath: String) {
+ val testDataRoot = testDataFolder.resolve(testDataRootPath)
+ val tmpRoot = testProjectDir.root.toPath()
+
+ testDataRoot.apply {
+ resolve("build.gradle").copy(tmpRoot.resolve("build.gradle"))
+ resolve("settings.gradle").copy(tmpRoot.resolve("settings.gradle"))
+ resolve("src").copy(tmpRoot.resolve("src"))
+ }
+ }
+
+ private fun doTest(gradleVersion: String, kotlinVersion: String) {
+ val kotlinGradlePlugin = pluginClasspathData.resolveSibling("kotlin-gradle.txt").toFile().readLines().map { File(it) }
+ prepareTestData("multiplatformProject")
+
+ // Remove withDebug(false) when https://github.com/gradle/gradle/issues/6862 is solved
+ val result = configure(gradleVersion, kotlinVersion, arguments = arrayOf("dokka", "--stacktrace"))
+ .withDebug(false)
+ .withPluginClasspath(pluginClasspath.union(kotlinGradlePlugin))
+ .build()
+
+ println(result.output)
+
+ assertEquals(TaskOutcome.SUCCESS, result.task(":dokka")?.outcome)
+
+ val docsOutput = "build/dokka"
+
+ checkOutputStructure("multiplatformProject/fileTree.txt", docsOutput)
+
+ checkNoErrorClasses(docsOutput)
+ checkNoUnresolvedLinks(docsOutput)
+ }
+
+ @Test fun `test kotlin 1_3_30 and gradle 4_7`() {
+ doTest("4.7", "1.3.30")
+ }
+
+ @Test fun `test kotlin 1_3_40 and gradle 4_10_3`() {
+ doTest("4.10.3", "1.3.40")
+ }
+
+ @Test fun `test kotlin 1_3_40 and gradle 5_6_1`() {
+ doTest("5.6.1", "1.3.50")
+ }
+} \ No newline at end of file
diff --git a/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/RebuildAfterSourceChangeTest.kt b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/RebuildAfterSourceChangeTest.kt
new file mode 100644
index 00000000..8b2db560
--- /dev/null
+++ b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/RebuildAfterSourceChangeTest.kt
@@ -0,0 +1,74 @@
+package org.jetbrains.dokka.gradle
+
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.Test
+import java.nio.file.Path
+import kotlin.test.assertEquals
+
+class RebuildAfterSourceChangeTest : AbstractDokkaGradleTest() {
+
+ fun prepareTestData(testDataRootPath: String): Pair<Path, Path> {
+ val testDataRoot = testDataFolder.resolve(testDataRootPath)
+ val tmpRoot = testProjectDir.root.toPath()
+
+ testDataRoot.resolve("src").copy(tmpRoot.resolve("src"))
+ testDataRoot.resolve("build.gradle").copy(tmpRoot.resolve("build.gradle"))
+ testDataRoot.resolve("settings.gradle").copy(tmpRoot.resolve("settings.gradle"))
+
+ return testDataRoot to tmpRoot
+ }
+
+ private fun doTest(gradleVersion: String, kotlinVersion: String) {
+
+ val (testDataRoot, tmpRoot) = prepareTestData("sourcesChange")
+ val docsOutput = "build/dokka"
+
+ configure(gradleVersion, kotlinVersion, arguments = arrayOf("dokka", "--stacktrace")).build().let { result ->
+ println(result.output)
+
+ assertEquals(TaskOutcome.SUCCESS, result.task(":dokka")?.outcome)
+ }
+
+
+ configure(gradleVersion, kotlinVersion, arguments = arrayOf("dokka", "-i", "--stacktrace")).build().let { result ->
+ println(result.output)
+
+ assertEquals(TaskOutcome.UP_TO_DATE, result.task(":dokka")?.outcome)
+ }
+
+ checkOutputStructure("sourcesChange/fileTree.txt", docsOutput)
+
+ testDataRoot.resolve("src1").copy(tmpRoot.resolve("src"))
+
+ configure(gradleVersion, kotlinVersion, arguments = arrayOf("dokka", "--stacktrace")).build().let { result ->
+ println(result.output)
+
+ assertEquals(TaskOutcome.SUCCESS, result.task(":dokka")?.outcome)
+ }
+
+
+ checkOutputStructure("sourcesChange/fileTree1.txt", docsOutput)
+
+ }
+
+
+ @Test
+ fun `test kotlin 1_0_7 and gradle 2_14_1`() {
+ doTest("2.14.1", "1.0.7")
+ }
+
+ @Test
+ fun `test kotlin 1_1_2 and gradle 3_5`() {
+ doTest("3.5", "1.1.2")
+ }
+
+ @Test
+ fun `test kotlin 1_1_2 and gradle 4_0`() {
+ doTest("4.0", "1.1.2")
+ }
+
+ @Test
+ fun `test kotlin 1_2_20 and gradle 4_5`() {
+ doTest("4.5", "1.2.20")
+ }
+} \ No newline at end of file
diff --git a/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/TypeSafeConfigurationTest.kt b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/TypeSafeConfigurationTest.kt
new file mode 100644
index 00000000..7b179e92
--- /dev/null
+++ b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/TypeSafeConfigurationTest.kt
@@ -0,0 +1,36 @@
+package org.jetbrains.dokka.gradle
+
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+class TypeSafeConfigurationTest(private val testCase: TestCase) : AbstractDokkaGradleTest() {
+
+ data class TestCase(val gradleVersion: String, val kotlinVersion: String) {
+ override fun toString(): String = "Gradle $gradleVersion and Kotlin $kotlinVersion"
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun testCases() = listOf(
+ TestCase("4.0", "1.1.2"),
+ TestCase("4.5", "1.2.20"),
+ TestCase("4.10.1", "1.2.60")
+ )
+ }
+
+ @Test
+ fun test() {
+
+ testDataFolder.resolve("typeSafeConfiguration").toFile()
+ .copyRecursively(testProjectDir.root)
+
+ configure(
+ testCase.gradleVersion,
+ testCase.kotlinVersion,
+ arguments = arrayOf("help", "-s")
+ ).build()
+ }
+}
diff --git a/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/Utils.kt b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/Utils.kt
new file mode 100644
index 00000000..6f17af22
--- /dev/null
+++ b/integration-tests/gradle-integration-tests/src/test/kotlin/org/jetbrains/dokka/gradle/Utils.kt
@@ -0,0 +1,56 @@
+package org.jetbrains.dokka.gradle
+
+import com.intellij.rt.execution.junit.FileComparisonFailure
+import java.io.File
+import java.io.IOException
+import java.nio.file.*
+import java.nio.file.attribute.BasicFileAttributes
+
+
+fun File.writeStructure(builder: StringBuilder, relativeTo: File = this, spaces: Int = 0) {
+ builder.append(" ".repeat(spaces))
+ val out = if (this != relativeTo) this.relativeTo(relativeTo) else this
+
+ builder.append(out)
+ if (this.isDirectory) {
+ builder.appendln("/")
+ this.listFiles().sortedBy { it.name }.forEach { it.writeStructure(builder, this, spaces + 4) }
+ } else {
+ builder.appendln()
+ }
+}
+
+fun assertEqualsIgnoringSeparators(expectedFile: File, output: String) {
+ if (!expectedFile.exists()) expectedFile.createNewFile()
+ val expectedText = expectedFile.readText().replace("\r\n", "\n")
+ val actualText = output.replace("\r\n", "\n")
+
+ if (expectedText != actualText)
+ throw FileComparisonFailure("", expectedText, actualText, expectedFile.canonicalPath)
+}
+
+class CopyFileVisitor(private var sourcePath: Path?, private val targetPath: Path) : SimpleFileVisitor<Path>() {
+
+ @Throws(IOException::class)
+ override fun preVisitDirectory(dir: Path,
+ attrs: BasicFileAttributes): FileVisitResult {
+ if (sourcePath == null) {
+ sourcePath = dir
+ } else {
+ Files.createDirectories(targetPath.resolve(sourcePath?.relativize(dir)))
+ }
+ return FileVisitResult.CONTINUE
+ }
+
+ @Throws(IOException::class)
+ override fun visitFile(file: Path,
+ attrs: BasicFileAttributes): FileVisitResult {
+ Files.copy(file, targetPath.resolve(sourcePath?.relativize(file)), StandardCopyOption.REPLACE_EXISTING)
+ return FileVisitResult.CONTINUE
+ }
+}
+
+fun Path.copy(to: Path) {
+ Files.walkFileTree(this, CopyFileVisitor(this, to))
+}
+