aboutsummaryrefslogtreecommitdiff
path: root/dokka-integration-tests
diff options
context:
space:
mode:
Diffstat (limited to 'dokka-integration-tests')
-rwxr-xr-xdokka-integration-tests/aws_sync.sh38
-rw-r--r--dokka-integration-tests/build.gradle.kts34
-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
-rw-r--r--dokka-integration-tests/gradle.properties12
-rw-r--r--dokka-integration-tests/gradle/README.md21
-rw-r--r--dokka-integration-tests/gradle/build.gradle.kts37
-rw-r--r--dokka-integration-tests/gradle/projects/coroutines/coroutines.diff96
m---------dokka-integration-tests/gradle/projects/coroutines/kotlinx-coroutines0
l---------dokka-integration-tests/gradle/projects/coroutines/template.root.gradle.kts1
l---------dokka-integration-tests/gradle/projects/coroutines/template.settings.gradle.kts1
-rw-r--r--dokka-integration-tests/gradle/projects/it-android-0/build.gradle.kts22
-rw-r--r--dokka-integration-tests/gradle/projects/it-android-0/gradle.properties7
-rw-r--r--dokka-integration-tests/gradle/projects/it-android-0/gradle/wrapper/gradle-wrapper.jarbin0 -> 58695 bytes
-rw-r--r--dokka-integration-tests/gradle/projects/it-android-0/gradle/wrapper/gradle-wrapper.properties9
-rwxr-xr-xdokka-integration-tests/gradle/projects/it-android-0/gradlew183
-rw-r--r--dokka-integration-tests/gradle/projects/it-android-0/gradlew.bat100
-rw-r--r--dokka-integration-tests/gradle/projects/it-android-0/settings.gradle.kts9
-rw-r--r--dokka-integration-tests/gradle/projects/it-android-0/src/main/AndroidManifest.xml5
-rw-r--r--dokka-integration-tests/gradle/projects/it-android-0/src/main/java/it/android/AndroidSpecificClass.kt16
-rw-r--r--dokka-integration-tests/gradle/projects/it-android-0/src/main/java/it/android/IntegrationTestActivity.kt22
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic-groovy/build.gradle54
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic-groovy/gradle.properties5
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic-groovy/gradle/wrapper/gradle-wrapper.jarbin0 -> 58910 bytes
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic-groovy/gradle/wrapper/gradle-wrapper.properties9
-rwxr-xr-xdokka-integration-tests/gradle/projects/it-basic-groovy/gradlew185
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic-groovy/gradlew.bat104
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic-groovy/settings.gradle.kts9
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic-groovy/src/main/java/it/basic/java/SampleJavaClass.java17
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic-groovy/src/main/kotlin/it/basic/PublicClass.kt48
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic/build.gradle.kts67
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic/customResources/custom-resource.svg7
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic/customResources/custom-style-to-add.css5
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic/customResources/logo-styles.css7
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic/gradle.properties5
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic/gradle/wrapper/gradle-wrapper.jarbin0 -> 58910 bytes
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic/gradle/wrapper/gradle-wrapper.properties9
-rwxr-xr-xdokka-integration-tests/gradle/projects/it-basic/gradlew185
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic/gradlew.bat104
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic/settings.gradle.kts9
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic/src/main/java/it/basic/java/SampleJavaClass.java17
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic/src/main/kotlin/RootPackageClass.kt8
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic/src/main/kotlin/it/basic/PublicClass.kt69
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic/src/main/kotlin/it/internal/InternalClass.kt7
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic/src/main/kotlin/it/overriddenVisibility/VisiblePrivateClass.kt12
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic/src/main/kotlin/it/protected/ProtectedClass.kt10
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic/src/main/kotlin/it/suppressedByPackage/SuppressedByPackage.kt7
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic/src/main/kotlin/it/suppressedByPath/SuppressedByPath.kt7
-rw-r--r--dokka-integration-tests/gradle/projects/it-basic/src/test/kotlin/it/basic/TestClass.kt17
-rw-r--r--dokka-integration-tests/gradle/projects/it-collector-0/build.gradle.kts5
-rw-r--r--dokka-integration-tests/gradle/projects/it-collector-0/gradle.properties5
-rw-r--r--dokka-integration-tests/gradle/projects/it-collector-0/gradle/wrapper/gradle-wrapper.jarbin0 -> 58695 bytes
-rw-r--r--dokka-integration-tests/gradle/projects/it-collector-0/gradle/wrapper/gradle-wrapper.properties9
-rwxr-xr-xdokka-integration-tests/gradle/projects/it-collector-0/gradlew183
-rw-r--r--dokka-integration-tests/gradle/projects/it-collector-0/gradlew.bat100
-rw-r--r--dokka-integration-tests/gradle/projects/it-collector-0/moduleA/build.gradle.kts10
-rw-r--r--dokka-integration-tests/gradle/projects/it-collector-0/moduleA/moduleB/README.md2
-rw-r--r--dokka-integration-tests/gradle/projects/it-collector-0/moduleA/moduleB/build.gradle.kts8
-rw-r--r--dokka-integration-tests/gradle/projects/it-collector-0/moduleA/moduleB/src/main/kotlin/org/jetbrains/dokka/it/moduleB/ModuleB.kt6
-rw-r--r--dokka-integration-tests/gradle/projects/it-collector-0/moduleA/moduleC/README.md2
-rw-r--r--dokka-integration-tests/gradle/projects/it-collector-0/moduleA/moduleC/build.gradle.kts8
-rw-r--r--dokka-integration-tests/gradle/projects/it-collector-0/moduleA/moduleC/src/main/kotlin/org/jetbrains/dokka/it/moduleC/ModuleC.kt6
-rw-r--r--dokka-integration-tests/gradle/projects/it-collector-0/settings.gradle.kts9
-rw-r--r--dokka-integration-tests/gradle/projects/it-configuration/README.md5
-rw-r--r--dokka-integration-tests/gradle/projects/it-configuration/build.gradle.kts33
-rw-r--r--dokka-integration-tests/gradle/projects/it-configuration/gradle.properties7
-rw-r--r--dokka-integration-tests/gradle/projects/it-configuration/gradle/wrapper/gradle-wrapper.jarbin0 -> 58910 bytes
-rw-r--r--dokka-integration-tests/gradle/projects/it-configuration/gradle/wrapper/gradle-wrapper.properties9
-rwxr-xr-xdokka-integration-tests/gradle/projects/it-configuration/gradlew185
-rw-r--r--dokka-integration-tests/gradle/projects/it-configuration/gradlew.bat104
-rw-r--r--dokka-integration-tests/gradle/projects/it-configuration/settings.gradle.kts7
-rw-r--r--dokka-integration-tests/gradle/projects/it-configuration/src/main/kotlin/it/ClassWithUndocumentedDeclarations.kt12
-rw-r--r--dokka-integration-tests/gradle/projects/it-js-ir-0/build.gradle.kts25
-rw-r--r--dokka-integration-tests/gradle/projects/it-js-ir-0/gradle.properties6
-rw-r--r--dokka-integration-tests/gradle/projects/it-js-ir-0/gradle/wrapper/gradle-wrapper.jarbin0 -> 58910 bytes
-rw-r--r--dokka-integration-tests/gradle/projects/it-js-ir-0/gradle/wrapper/gradle-wrapper.properties9
-rwxr-xr-xdokka-integration-tests/gradle/projects/it-js-ir-0/gradlew185
-rw-r--r--dokka-integration-tests/gradle/projects/it-js-ir-0/gradlew.bat104
-rw-r--r--dokka-integration-tests/gradle/projects/it-js-ir-0/settings.gradle.kts9
-rw-r--r--dokka-integration-tests/gradle/projects/it-js-ir-0/src/main/kotlin/RootPackageClass.kt26
-rw-r--r--dokka-integration-tests/gradle/projects/it-js-ir-0/src/main/kotlin/it/basic/PublicClass.kt53
-rw-r--r--dokka-integration-tests/gradle/projects/it-js-ir-0/src/main/kotlin/it/internal/InternalClass.kt7
-rw-r--r--dokka-integration-tests/gradle/projects/it-js-ir-0/src/main/kotlin/it/suppressedByPackage/SuppressedByPackage.kt7
-rw-r--r--dokka-integration-tests/gradle/projects/it-js-ir-0/src/main/kotlin/it/suppressedByPath/SuppressedByPath.kt7
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-0/build.gradle.kts5
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-0/gradle.properties5
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-0/gradle/wrapper/gradle-wrapper.jarbin0 -> 58695 bytes
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-0/gradle/wrapper/gradle-wrapper.properties9
-rwxr-xr-xdokka-integration-tests/gradle/projects/it-multimodule-0/gradlew183
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-0/gradlew.bat100
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/build.gradle.kts21
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleB/Module.md6
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleB/build.gradle.kts17
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleB/src/main/kotlin/org/jetbrains/dokka/it/moduleB/ModuleB.kt6
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleC/Module.md2
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleC/build.gradle.kts16
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleC/src/main/kotlin/org/jetbrains/dokka/it/moduleC/ModuleC.kt6
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleD/build.gradle.kts10
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleD/src/main/kotlin/org/jetbrains/dokka/it/moduleD/ModuleC.kt6
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-0/settings.gradle.kts10
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-1/build.gradle18
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-1/first/build.gradle0
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-1/first/src/main/kotlin/foo/FirstClass.kt11
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-1/first/src/main/kotlin/foo/FirstSubclass.kt12
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-1/first/src/main/kotlin/foo/Main.kt8
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-1/first/src/main/kotlin/noPackage.kt3
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-1/gradle.properties5
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-1/gradle/wrapper/gradle-wrapper.jarbin0 -> 58910 bytes
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-1/gradle/wrapper/gradle-wrapper.properties9
-rwxr-xr-xdokka-integration-tests/gradle/projects/it-multimodule-1/gradlew185
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-1/gradlew.bat104
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-1/second/build.gradle14
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-1/second/src/main/kotlin/NoPackageClass.kt1
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-1/second/src/main/kotlin/bar/SecondClass.kt21
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-1/second/src/main/kotlin/foo/ThirdClass.kt11
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-1/settings.gradle.kts8
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/build.gradle43
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/first/build.gradle0
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/first/src/main/kotlin/foo/FirstClass.kt11
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/gradle.properties6
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/gradle/wrapper/gradle-wrapper.jarbin0 -> 61574 bytes
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/gradle/wrapper/gradle-wrapper.properties10
-rwxr-xr-xdokka-integration-tests/gradle/projects/it-multimodule-versioning-0/gradlew244
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/gradlew.bat92
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/second/build.gradle3
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/second/src/main/kotlin/bar/SecondClass.kt21
-rw-r--r--dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/settings.gradle.kts8
-rw-r--r--dokka-integration-tests/gradle/projects/it-multiplatform-0/build.gradle.kts52
-rw-r--r--dokka-integration-tests/gradle/projects/it-multiplatform-0/gradle.properties5
-rw-r--r--dokka-integration-tests/gradle/projects/it-multiplatform-0/gradle/wrapper/gradle-wrapper.jarbin0 -> 58695 bytes
-rw-r--r--dokka-integration-tests/gradle/projects/it-multiplatform-0/gradle/wrapper/gradle-wrapper.properties9
-rwxr-xr-xdokka-integration-tests/gradle/projects/it-multiplatform-0/gradlew183
-rw-r--r--dokka-integration-tests/gradle/projects/it-multiplatform-0/gradlew.bat100
-rw-r--r--dokka-integration-tests/gradle/projects/it-multiplatform-0/settings.gradle.kts6
-rw-r--r--dokka-integration-tests/gradle/projects/it-multiplatform-0/src/commonMain/kotlin/it/mpp0/CommonMainClass.kt8
-rw-r--r--dokka-integration-tests/gradle/projects/it-multiplatform-0/src/commonMain/kotlin/it/mpp0/ExpectedClass.kt5
-rw-r--r--dokka-integration-tests/gradle/projects/it-multiplatform-0/src/commonMain/kotlin/it/mpp0/coroutines.kt5
-rw-r--r--dokka-integration-tests/gradle/projects/it-multiplatform-0/src/desktopMain/kotlin/it/mpp0/CPointerExtension.kt11
-rw-r--r--dokka-integration-tests/gradle/projects/it-multiplatform-0/src/desktopMain/kotlin/it/mpp0/ExpectedClass.kt5
-rw-r--r--dokka-integration-tests/gradle/projects/it-multiplatform-0/src/jsMain/kotlin/it/mpp0/ExpectedClass.kt5
-rw-r--r--dokka-integration-tests/gradle/projects/it-multiplatform-0/src/jsMain/kotlin/it/mpp0/runBlocking.kt7
-rw-r--r--dokka-integration-tests/gradle/projects/it-multiplatform-0/src/jvmMain/kotlin/it/mpp0/ExpectedClass.kt11
-rw-r--r--dokka-integration-tests/gradle/projects/it-multiplatform-0/src/jvmMain/kotlin/it/mpp0/JvmOnlyClass.kt13
-rw-r--r--dokka-integration-tests/gradle/projects/it-multiplatform-0/src/jvmMain/kotlin/it/mpp0/runBlocking.kt7
-rw-r--r--dokka-integration-tests/gradle/projects/it-multiplatform-0/src/linuxMain/kotlin/it/mpp0/CPointerExtension.kt11
-rw-r--r--dokka-integration-tests/gradle/projects/it-multiplatform-0/src/linuxMain/kotlin/it/mpp0/ExpectedClass.kt5
-rw-r--r--dokka-integration-tests/gradle/projects/it-multiplatform-0/src/linuxMain/kotlin/it/mpp0/runBlocking.kt13
-rw-r--r--dokka-integration-tests/gradle/projects/it-multiplatform-0/src/macosMain/kotlin/it/mpp0/ExpectedClass.kt5
-rw-r--r--dokka-integration-tests/gradle/projects/it-multiplatform-0/src/macosMain/kotlin/it/mpp0/runBlocking.kt7
-rw-r--r--dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/build.gradle.kts44
-rw-r--r--dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/gradle.properties6
-rw-r--r--dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/gradle/wrapper/gradle-wrapper.jarbin0 -> 58910 bytes
-rw-r--r--dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/gradle/wrapper/gradle-wrapper.properties9
-rwxr-xr-xdokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/gradlew185
-rw-r--r--dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/gradlew.bat104
-rw-r--r--dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/settings.gradle.kts9
-rw-r--r--dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/src/main/java/it/basic/java/SampleJavaClass.java17
-rw-r--r--dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/src/main/kotlin/RootPackageClass.kt8
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-basic/build.gradle.kts51
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-basic/gradle.properties5
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-basic/gradle/wrapper/gradle-wrapper.jarbin0 -> 58695 bytes
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-basic/gradle/wrapper/gradle-wrapper.properties9
-rwxr-xr-xdokka-integration-tests/gradle/projects/it-wasm-basic/gradlew183
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-basic/gradlew.bat100
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-basic/settings.gradle.kts6
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-basic/src/wasmMain/kotlin/RootPackageClass.kt30
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-basic/src/wasmMain/kotlin/it/basic/PublicClass.kt53
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-basic/src/wasmMain/kotlin/it/internal/InternalClass.kt7
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-basic/src/wasmMain/kotlin/it/suppressedByPackage/SuppressedByPackage.kt7
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-basic/src/wasmMain/kotlin/it/suppressedByPath/SuppressedByPath.kt7
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/build.gradle.kts40
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/gradle.properties5
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/gradle/wrapper/gradle-wrapper.jarbin0 -> 58695 bytes
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/gradle/wrapper/gradle-wrapper.properties9
-rwxr-xr-xdokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/gradlew183
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/gradlew.bat100
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/settings.gradle.kts6
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmJsMain/kotlin/RootPackageClass.kt30
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmJsMain/kotlin/it/basic/PublicClass.kt53
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmJsMain/kotlin/it/internal/InternalClass.kt7
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmJsMain/kotlin/it/suppressedByPackage/SuppressedByPackage.kt7
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmJsMain/kotlin/it/suppressedByPath/SuppressedByPath.kt7
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmWasiMain/kotlin/RootPackageClass.kt10
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmWasiMain/kotlin/it/basic/PublicClass.kt53
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmWasiMain/kotlin/it/internal/InternalClass.kt7
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmWasiMain/kotlin/it/suppressedByPackage/SuppressedByPackage.kt7
-rw-r--r--dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmWasiMain/kotlin/it/suppressedByPath/SuppressedByPath.kt7
m---------dokka-integration-tests/gradle/projects/serialization/kotlinx-serialization0
-rw-r--r--dokka-integration-tests/gradle/projects/serialization/serialization.diff29
l---------dokka-integration-tests/gradle/projects/serialization/template.root.gradle.kts1
l---------dokka-integration-tests/gradle/projects/serialization/template.settings.gradle.kts1
-rw-r--r--dokka-integration-tests/gradle/projects/template.root.gradle.kts29
-rw-r--r--dokka-integration-tests/gradle/projects/template.settings.gradle.kts45
-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
-rw-r--r--dokka-integration-tests/gradle/src/main/kotlin/org/jetbrains/dokka/it/gradle/AbstractGradleIntegrationTest.kt84
-rw-r--r--dokka-integration-tests/gradle/src/main/kotlin/org/jetbrains/dokka/it/gradle/BuildVersions.kt52
-rw-r--r--dokka-integration-tests/gradle/src/main/kotlin/org/jetbrains/dokka/it/gradle/TestEnvironment.kt18
-rw-r--r--dokka-integration-tests/maven/build.gradle.kts35
m---------dokka-integration-tests/maven/projects/biojava/biojava0
-rw-r--r--dokka-integration-tests/maven/projects/biojava/biojava.diff37
-rw-r--r--dokka-integration-tests/maven/projects/it-maven/customResources/custom-resource.svg7
-rw-r--r--dokka-integration-tests/maven/projects/it-maven/customResources/custom-style-to-add.css5
-rw-r--r--dokka-integration-tests/maven/projects/it-maven/customResources/logo-styles.css7
-rw-r--r--dokka-integration-tests/maven/projects/it-maven/pom.xml192
-rw-r--r--dokka-integration-tests/maven/projects/it-maven/src/main/java/it/basic/java/SampleJavaClass.java22
-rw-r--r--dokka-integration-tests/maven/projects/it-maven/src/main/kotlin/it/basic/PublicClass.kt57
-rw-r--r--dokka-integration-tests/maven/projects/it-maven/src/main/kotlin/it/internal/InternalClass.kt7
-rw-r--r--dokka-integration-tests/maven/projects/it-maven/src/main/kotlin/it/overriddenVisibility/VisiblePrivateClass.kt12
-rw-r--r--dokka-integration-tests/maven/projects/it-maven/src/main/kotlin/it/protected/ProtectedClass.kt10
-rw-r--r--dokka-integration-tests/maven/src/integrationTest/kotlin/org/jetbrains/dokka/it/maven/BiojavaIntegrationTest.kt63
-rw-r--r--dokka-integration-tests/maven/src/integrationTest/kotlin/org/jetbrains/dokka/it/maven/MavenIntegrationTest.kt219
-rw-r--r--dokka-integration-tests/settings.gradle.kts42
-rw-r--r--dokka-integration-tests/utilities/build.gradle.kts17
-rw-r--r--dokka-integration-tests/utilities/src/main/kotlin/org/jetbrains/dokka/it/AbstractIntegrationTest.kt168
-rw-r--r--dokka-integration-tests/utilities/src/main/kotlin/org/jetbrains/dokka/it/TestOutputCopier.kt20
-rw-r--r--dokka-integration-tests/utilities/src/main/kotlin/org/jetbrains/dokka/it/gitSubmoduleUtils.kt43
-rw-r--r--dokka-integration-tests/utilities/src/main/kotlin/org/jetbrains/dokka/it/processUtils.kt55
245 files changed, 9370 insertions, 0 deletions
diff --git a/dokka-integration-tests/aws_sync.sh b/dokka-integration-tests/aws_sync.sh
new file mode 100755
index 00000000..bee584b6
--- /dev/null
+++ b/dokka-integration-tests/aws_sync.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+commits_to_store=3
+
+if [ $# -lt 3 ]; then
+ echo "Too little arguments. Usage: ./aws_generate <s3_address> <project_name> <path_to_project_output_dir>"
+ exit 1
+fi
+
+aws_s3_address=${1%/} # Remove trailing slash if given
+project_name=$2
+project_path=$3
+
+current_branch=$(git branch --show-current)
+s3_project_address="${aws_s3_address}/${current_branch}/${project_name}/"
+last_commits=$(git log --pretty=format:%h -n $commits_to_store)
+
+# List all project versions
+dir=$(aws s3 ls "$s3_project_address" | awk '{print $2}')
+
+# Remove old versions
+for d in $dir; do
+ for commit in "${last_commits[@]}"; do
+ [[ $d == "$commit/" ]] && continue
+ aws s3 rm --recursive "$s3_project_address$d"
+ done
+done
+
+# Sync the new one
+commit_hash=$(git log -1 --format="%h")
+
+aws s3 sync "$project_path" "$s3_project_address$commit_hash/"
+
+echo "$commit_hash"
diff --git a/dokka-integration-tests/build.gradle.kts b/dokka-integration-tests/build.gradle.kts
new file mode 100644
index 00000000..4642f952
--- /dev/null
+++ b/dokka-integration-tests/build.gradle.kts
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+plugins {
+ id("dokkabuild.base")
+}
+
+addDependencyToSubprojectTasks("assemble")
+addDependencyToSubprojectTasks("build")
+addDependencyToSubprojectTasks("clean")
+addDependencyToSubprojectTasks("check")
+
+registerParentTask("test", groupName = "verification")
+registerParentTask("integrationTest", groupName = "verification")
+
+fun addDependencyToSubprojectTasks(existingTaskName: String) {
+ tasks.named(existingTaskName) {
+ dependsOn(subprojectTasks(existingTaskName))
+ }
+}
+
+fun registerParentTask(taskName: String, groupName: String) {
+ tasks.register(taskName) {
+ group = groupName
+ description = "Runs $taskName tasks of all subprojects"
+ dependsOn(subprojectTasks(taskName))
+ }
+}
+
+fun subprojectTasks(taskName: String): List<String> =
+ subprojects
+ .filter { it.getTasksByName(taskName, false).isNotEmpty() }
+ .map { ":${it.name}:$taskName" }
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)
+ }
+}
diff --git a/dokka-integration-tests/gradle.properties b/dokka-integration-tests/gradle.properties
new file mode 100644
index 00000000..b130617c
--- /dev/null
+++ b/dokka-integration-tests/gradle.properties
@@ -0,0 +1,12 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+# while integration test projects aren't published,
+# the version here should be in sync with other versions,
+# because it's used to resolve dependencies
+version=1.9.20-SNAPSHOT
+
+org.jetbrains.dokka.javaToolchain.mainCompiler=8
+org.jetbrains.dokka.javaToolchain.testLauncher=8
+dokka_integration_test_parallelism=2
diff --git a/dokka-integration-tests/gradle/README.md b/dokka-integration-tests/gradle/README.md
new file mode 100644
index 00000000..706cfb61
--- /dev/null
+++ b/dokka-integration-tests/gradle/README.md
@@ -0,0 +1,21 @@
+### Note
+All Gradle projects inside the `project` subfolder can
+also be imported to the IDE by clicking on the corresponding
+build.gradle.kts file -> "import gradle project".
+
+Before importing: Make sure that you have dokka installed
+locally (`./gradlew publishToMavenLocal`).
+
+### To update git submodules
+
+Integration tests have fixed git revision number, with the diff patch applied from the corresponding file (e.g. [`coroutines.diff`](projects/coroutines/coroutines.diff)).
+
+In order to update:
+
+* Checkout the project with the requered revision
+ - It's some state of the `master`
+* Manually write the diff (or apply the existing one and tweak) to have the project buildable against locally published Dokka of version `for-integration-tests-SNAPSHOT`
+* `git diff > $pathToProjectInDokka/project.diff`
+* Go to `$pathToProjectInDokka`, `git fetch && git checkout $revisionNumber`
+ - Prior to that, ensure that you have your git submodules initialized
+* Ensure that the corresponding `GradleIntegrationTest` passes locally and push
diff --git a/dokka-integration-tests/gradle/build.gradle.kts b/dokka-integration-tests/gradle/build.gradle.kts
new file mode 100644
index 00000000..3b95cb69
--- /dev/null
+++ b/dokka-integration-tests/gradle/build.gradle.kts
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+
+plugins {
+ id("dokkabuild.test-integration")
+}
+
+dependencies {
+ implementation(projects.utilities)
+
+ implementation(kotlin("test-junit5"))
+ implementation(libs.junit.jupiterApi)
+ implementation(libs.junit.jupiterParams)
+
+ implementation(gradleTestKit())
+
+ implementation(libs.jsoup)
+}
+
+val aggregatingProject = gradle.includedBuild("dokka")
+
+tasks.integrationTest {
+ dependsOn(aggregatingProject.task(":publishToMavenLocal"))
+
+ environment("DOKKA_VERSION", project.version)
+
+ inputs.dir(file("projects"))
+
+ javaLauncher.set(javaToolchains.launcherFor {
+ // kotlinx.coroutines requires Java 11+
+ languageVersion.set(dokkaBuild.testJavaLauncherVersion.map {
+ maxOf(it, JavaLanguageVersion.of(11))
+ })
+ })
+}
diff --git a/dokka-integration-tests/gradle/projects/coroutines/coroutines.diff b/dokka-integration-tests/gradle/projects/coroutines/coroutines.diff
new file mode 100644
index 00000000..6fcf896c
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/coroutines/coroutines.diff
@@ -0,0 +1,96 @@
+diff --git a/build.gradle b/build.gradle
+index e7d405e12..236310823 100644
+--- a/build.gradle
++++ b/build.gradle
+@@ -59,8 +59,9 @@ buildscript {
+ }
+
+ dependencies {
++ def dokkaVersion = System.getenv('DOKKA_VERSION')
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+- classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version"
++ classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokkaVersion"
+ classpath "org.jetbrains.kotlinx:atomicfu-gradle-plugin:$atomicfu_version"
+ classpath "org.jetbrains.kotlinx:kotlinx-knit:$knit_version"
+ classpath "com.github.node-gradle:gradle-node-plugin:$gradle_node_version"
+@@ -107,6 +108,9 @@ allprojects {
+ mavenLocal()
+ }
+ }
++ repositories {
++ mavenLocal()
++ }
+
+ ext.unpublished = unpublished
+
+@@ -142,6 +146,7 @@ allprojects {
+ google()
+ mavenCentral()
+ CommunityProjectsBuild.addDevRepositoryIfEnabled(delegate, project)
++ mavenLocal()
+ }
+ }
+
+diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
+index ae54ad0f6..786cff366 100644
+--- a/buildSrc/build.gradle.kts
++++ b/buildSrc/build.gradle.kts
+@@ -25,6 +25,7 @@ repositories {
+ if (buildSnapshotTrain) {
+ mavenLocal()
+ }
++ mavenLocal()
+ }
+
+ val gradleProperties = Properties().apply {
+@@ -49,12 +50,12 @@ dependencies {
+ * our version of Gradle bundles Kotlin 1.4.x and can read metadata only up to 1.5.x,
+ * thus we're excluding stdlib compiled with 1.6.0 from dependencies.
+ */
+- implementation("org.jetbrains.dokka:dokka-gradle-plugin:${version("dokka")}") {
++ implementation("org.jetbrains.dokka:dokka-gradle-plugin:${System.getenv("DOKKA_VERSION")}") {
+ exclude(group = "org.jetbrains.kotlin", module = "kotlin-stdlib-jdk8")
+ exclude(group = "org.jetbrains.kotlin", module = "kotlin-stdlib-jdk7")
+ exclude(group = "org.jetbrains.kotlin", module = "kotlin-stdlib")
+ }
+- implementation("org.jetbrains.dokka:dokka-core:${version("dokka")}") {
++ implementation("org.jetbrains.dokka:dokka-core:${System.getenv("DOKKA_VERSION")}") {
+ exclude(group = "org.jetbrains.kotlin", module = "kotlin-stdlib-jdk8")
+ exclude(group = "org.jetbrains.kotlin", module = "kotlin-stdlib-jdk7")
+ exclude(group = "org.jetbrains.kotlin", module = "kotlin-stdlib")
+diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts
+index c2e859f65..43dc4f749 100644
+--- a/buildSrc/settings.gradle.kts
++++ b/buildSrc/settings.gradle.kts
+@@ -14,5 +14,6 @@ pluginManagement {
+ if (build_snapshot_train?.toBoolean() == true) {
+ mavenLocal()
+ }
++ mavenLocal()
+ }
+ }
+diff --git a/gradle.properties b/gradle.properties
+index 3d9431be0..9af01ef86 100644
+--- a/gradle.properties
++++ b/gradle.properties
+@@ -14,7 +14,7 @@ atomicfu_version=0.21.0
+ knit_version=0.5.0-Beta
+ html_version=0.7.2
+ lincheck_version=2.18.1
+-dokka_version=1.8.10
++dokka_version=non-existing-sanity-check-SNAPSHOT
+ byte_buddy_version=1.10.9
+ reactor_version=3.4.1
+ reactive_streams_version=1.0.3
+diff --git a/settings.gradle b/settings.gradle
+index 151c087fd..e578bdb93 100644
+--- a/settings.gradle
++++ b/settings.gradle
+@@ -11,6 +11,7 @@ pluginManagement {
+ repositories {
+ maven { url "https://maven.pkg.jetbrains.space/kotlin/p/dokka/dev/" }
+ gradlePluginPortal()
++ mavenLocal()
+ }
+ }
+
diff --git a/dokka-integration-tests/gradle/projects/coroutines/kotlinx-coroutines b/dokka-integration-tests/gradle/projects/coroutines/kotlinx-coroutines
new file mode 160000
+Subproject b78bbf518bd8e90e9ed2133ebdacc36441210cd
diff --git a/dokka-integration-tests/gradle/projects/coroutines/template.root.gradle.kts b/dokka-integration-tests/gradle/projects/coroutines/template.root.gradle.kts
new file mode 120000
index 00000000..895ca83d
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/coroutines/template.root.gradle.kts
@@ -0,0 +1 @@
+../template.root.gradle.kts \ No newline at end of file
diff --git a/dokka-integration-tests/gradle/projects/coroutines/template.settings.gradle.kts b/dokka-integration-tests/gradle/projects/coroutines/template.settings.gradle.kts
new file mode 120000
index 00000000..7b43b3e7
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/coroutines/template.settings.gradle.kts
@@ -0,0 +1 @@
+../template.settings.gradle.kts \ No newline at end of file
diff --git a/dokka-integration-tests/gradle/projects/it-android-0/build.gradle.kts b/dokka-integration-tests/gradle/projects/it-android-0/build.gradle.kts
new file mode 100644
index 00000000..d9d9e6be
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-android-0/build.gradle.kts
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+plugins {
+ id("com.android.library")
+ id("org.jetbrains.dokka")
+ kotlin("android")
+}
+
+apply(from = "../template.root.gradle.kts")
+
+android {
+ defaultConfig {
+ minSdkVersion(21)
+ setCompileSdkVersion(29)
+ }
+}
+
+dependencies {
+ implementation("androidx.appcompat:appcompat:1.1.0")
+}
diff --git a/dokka-integration-tests/gradle/projects/it-android-0/gradle.properties b/dokka-integration-tests/gradle/projects/it-android-0/gradle.properties
new file mode 100644
index 00000000..286fe3c3
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-android-0/gradle.properties
@@ -0,0 +1,7 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+dokka_it_kotlin_version=1.9.20
+dokka_it_android_gradle_plugin_version=4.2.2
+android.useAndroidX=true
diff --git a/dokka-integration-tests/gradle/projects/it-android-0/gradle/wrapper/gradle-wrapper.jar b/dokka-integration-tests/gradle/projects/it-android-0/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..f3d88b1c
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-android-0/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/dokka-integration-tests/gradle/projects/it-android-0/gradle/wrapper/gradle-wrapper.properties b/dokka-integration-tests/gradle/projects/it-android-0/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..a434026d
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-android-0/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,9 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.2-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/dokka-integration-tests/gradle/projects/it-android-0/gradlew b/dokka-integration-tests/gradle/projects/it-android-0/gradlew
new file mode 100755
index 00000000..2fe81a7d
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-android-0/gradlew
@@ -0,0 +1,183 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/dokka-integration-tests/gradle/projects/it-android-0/gradlew.bat b/dokka-integration-tests/gradle/projects/it-android-0/gradlew.bat
new file mode 100644
index 00000000..24467a14
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-android-0/gradlew.bat
@@ -0,0 +1,100 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/dokka-integration-tests/gradle/projects/it-android-0/settings.gradle.kts b/dokka-integration-tests/gradle/projects/it-android-0/settings.gradle.kts
new file mode 100644
index 00000000..a429a7b7
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-android-0/settings.gradle.kts
@@ -0,0 +1,9 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+@file:Suppress("LocalVariableName", "UnstableApiUsage")
+
+apply(from = "../template.settings.gradle.kts")
+rootProject.name = "it-android-0"
+
diff --git a/dokka-integration-tests/gradle/projects/it-android-0/src/main/AndroidManifest.xml b/dokka-integration-tests/gradle/projects/it-android-0/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..43894029
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-android-0/src/main/AndroidManifest.xml
@@ -0,0 +1,5 @@
+<!--
+ ~ Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ -->
+
+<manifest package="org.jetbrains.dokka.it.android"/>
diff --git a/dokka-integration-tests/gradle/projects/it-android-0/src/main/java/it/android/AndroidSpecificClass.kt b/dokka-integration-tests/gradle/projects/it-android-0/src/main/java/it/android/AndroidSpecificClass.kt
new file mode 100644
index 00000000..cb9046b1
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-android-0/src/main/java/it/android/AndroidSpecificClass.kt
@@ -0,0 +1,16 @@
+@file:Suppress("unused")
+
+package it.android
+
+import android.content.Context
+import android.util.SparseIntArray
+import android.view.View
+
+/**
+ * This class is specific to android and uses android classes like:
+ * [Context], [SparseIntArray] or [View]
+ */
+class AndroidSpecificClass {
+ fun sparseIntArray() = SparseIntArray()
+ fun createView(context: Context): View = View(context)
+}
diff --git a/dokka-integration-tests/gradle/projects/it-android-0/src/main/java/it/android/IntegrationTestActivity.kt b/dokka-integration-tests/gradle/projects/it-android-0/src/main/java/it/android/IntegrationTestActivity.kt
new file mode 100644
index 00000000..1792818b
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-android-0/src/main/java/it/android/IntegrationTestActivity.kt
@@ -0,0 +1,22 @@
+package it.android
+
+import android.annotation.SuppressLint
+import android.os.Bundle
+import android.widget.TextView
+import androidx.appcompat.app.AppCompatActivity
+
+/**
+ * Some Activity implementing [AppCompatActivity] from android x
+ */
+class IntegrationTestActivity : AppCompatActivity() {
+ /**
+ * Will show a small happy text
+ */
+ @SuppressLint("SetTextI18n")
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ val textView = TextView(this)
+ textView.text = "I am so happy :)"
+ setContentView(textView)
+ }
+} \ No newline at end of file
diff --git a/dokka-integration-tests/gradle/projects/it-basic-groovy/build.gradle b/dokka-integration-tests/gradle/projects/it-basic-groovy/build.gradle
new file mode 100644
index 00000000..4017bec0
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic-groovy/build.gradle
@@ -0,0 +1,54 @@
+plugins {
+ id 'org.jetbrains.kotlin.jvm'
+ id("org.jetbrains.dokka")
+}
+
+apply from: '../template.root.gradle.kts'
+
+dependencies {
+ implementation "org.jetbrains.kotlin:kotlin-stdlib"
+}
+
+dokkaHtml {
+ outputDirectory = new File(buildDir, "/dokka/customHtml")
+ failOnWarning = false
+ dokkaSourceSets {
+ customSourceSet {
+ sourceRoot(file("src/main/java"))
+ sourceRoot(file("src/main/kotlin"))
+ displayName.set("custom")
+ reportUndocumented.set(true)
+ }
+
+ configureEach {
+ perPackageOption { // testing closures
+ matchingRegex.set(".*internal.*")
+ suppress.set(true)
+ }
+
+ sourceLink { // testing closures
+ localDirectory.set(file("src/main"))
+ remoteUrl.set(
+ new URL(
+ "https://github.com/Kotlin/dokka/tree/master/" +
+ "dokka-integration-tests/gradle/projects/it-basic-groovy/src/main"
+ )
+ )
+ }
+ }
+ }
+
+}
+
+dokkaJavadoc {
+ outputDirectory = new File(buildDir, "dokka/customJavadoc")
+}
+
+dokkaGfm {
+ outputDirectory = new File(buildDir, "dokka/customGfm")
+}
+
+dokkaJekyll {
+ outputDirectory = new File(buildDir, "dokka/customJekyll")
+}
+
diff --git a/dokka-integration-tests/gradle/projects/it-basic-groovy/gradle.properties b/dokka-integration-tests/gradle/projects/it-basic-groovy/gradle.properties
new file mode 100644
index 00000000..5904fc21
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic-groovy/gradle.properties
@@ -0,0 +1,5 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+dokka_it_kotlin_version=1.9.20
diff --git a/dokka-integration-tests/gradle/projects/it-basic-groovy/gradle/wrapper/gradle-wrapper.jar b/dokka-integration-tests/gradle/projects/it-basic-groovy/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..62d4c053
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic-groovy/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/dokka-integration-tests/gradle/projects/it-basic-groovy/gradle/wrapper/gradle-wrapper.properties b/dokka-integration-tests/gradle/projects/it-basic-groovy/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..a434026d
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic-groovy/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,9 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.2-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/dokka-integration-tests/gradle/projects/it-basic-groovy/gradlew b/dokka-integration-tests/gradle/projects/it-basic-groovy/gradlew
new file mode 100755
index 00000000..fbd7c515
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic-groovy/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/dokka-integration-tests/gradle/projects/it-basic-groovy/gradlew.bat b/dokka-integration-tests/gradle/projects/it-basic-groovy/gradlew.bat
new file mode 100644
index 00000000..a9f778a7
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic-groovy/gradlew.bat
@@ -0,0 +1,104 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/dokka-integration-tests/gradle/projects/it-basic-groovy/settings.gradle.kts b/dokka-integration-tests/gradle/projects/it-basic-groovy/settings.gradle.kts
new file mode 100644
index 00000000..24867cf2
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic-groovy/settings.gradle.kts
@@ -0,0 +1,9 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+@file:Suppress("LocalVariableName", "UnstableApiUsage")
+
+apply(from = "../template.settings.gradle.kts")
+rootProject.name = "it-basic-groovy"
+
diff --git a/dokka-integration-tests/gradle/projects/it-basic-groovy/src/main/java/it/basic/java/SampleJavaClass.java b/dokka-integration-tests/gradle/projects/it-basic-groovy/src/main/java/it/basic/java/SampleJavaClass.java
new file mode 100644
index 00000000..23b0202c
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic-groovy/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/gradle/projects/it-basic-groovy/src/main/kotlin/it/basic/PublicClass.kt b/dokka-integration-tests/gradle/projects/it-basic-groovy/src/main/kotlin/it/basic/PublicClass.kt
new file mode 100644
index 00000000..71bc7e63
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic-groovy/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/dokka-integration-tests/gradle/projects/it-basic/build.gradle.kts b/dokka-integration-tests/gradle/projects/it-basic/build.gradle.kts
new file mode 100644
index 00000000..aaaf782c
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic/build.gradle.kts
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+import org.jetbrains.dokka.gradle.DokkaTask
+import org.jetbrains.dokka.gradle.kotlinSourceSet
+import org.jetbrains.dokka.base.DokkaBase
+import org.jetbrains.dokka.base.DokkaBaseConfiguration
+import org.jetbrains.dokka.DokkaConfiguration
+import java.net.URL
+
+plugins {
+ kotlin("jvm")
+ id("org.jetbrains.dokka")
+}
+
+buildscript {
+ dependencies {
+ classpath("org.jetbrains.dokka:dokka-base:${System.getenv("DOKKA_VERSION")}")
+ }
+}
+
+version = "1.9.20-SNAPSHOT"
+
+apply(from = "../template.root.gradle.kts")
+
+dependencies {
+ testImplementation(kotlin("test-junit"))
+}
+
+tasks.withType<DokkaTask> {
+ moduleName.set("Basic Project")
+ dokkaSourceSets {
+ configureEach {
+ documentedVisibilities.set(
+ setOf(DokkaConfiguration.Visibility.PUBLIC, DokkaConfiguration.Visibility.PROTECTED)
+ )
+ suppressedFiles.from(file("src/main/kotlin/it/suppressedByPath"))
+ perPackageOption {
+ matchingRegex.set("it.suppressedByPackage.*")
+ suppress.set(true)
+ }
+ perPackageOption {
+ matchingRegex.set("it.overriddenVisibility.*")
+ documentedVisibilities.set(
+ setOf(DokkaConfiguration.Visibility.PRIVATE)
+ )
+ }
+ sourceLink {
+ localDirectory.set(file("src/main"))
+ remoteUrl.set(
+ URL(
+ "https://github.com/Kotlin/dokka/tree/master/" +
+ "dokka-integration-tests/gradle/projects/it-basic/src/main"
+ )
+ )
+ }
+ }
+
+ register("myTest") {
+ kotlinSourceSet(kotlin.sourceSets["test"])
+ }
+ }
+ suppressObviousFunctions.set(false)
+
+ pluginsMapConfiguration.set(mapOf(DokkaBase::class.qualifiedName to """{ "customStyleSheets": ["${file("../customResources/logo-styles.css").invariantSeparatorsPath}", "${file("../customResources/custom-style-to-add.css").invariantSeparatorsPath}"], "customAssets" : ["${file("../customResources/custom-resource.svg").invariantSeparatorsPath}"] }"""))
+}
diff --git a/dokka-integration-tests/gradle/projects/it-basic/customResources/custom-resource.svg b/dokka-integration-tests/gradle/projects/it-basic/customResources/custom-resource.svg
new file mode 100644
index 00000000..c4b95383
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic/customResources/custom-resource.svg
@@ -0,0 +1,7 @@
+<!--
+ - Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ -->
+
+<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M18 9C18 14 14 18 9 18C4 18 0 14 0 9C0 4 4 0 9 0C14 0 18 4 18 9ZM14.2 6.2L12.8 4.8L7.5 10.1L5.3 7.8L3.8 9.2L7.5 13L14.2 6.2Z" fill="#4DBB5F"/>
+</svg>
diff --git a/dokka-integration-tests/gradle/projects/it-basic/customResources/custom-style-to-add.css b/dokka-integration-tests/gradle/projects/it-basic/customResources/custom-style-to-add.css
new file mode 100644
index 00000000..f949ca1c
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic/customResources/custom-style-to-add.css
@@ -0,0 +1,5 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+/* custom stylesheet */
diff --git a/dokka-integration-tests/gradle/projects/it-basic/customResources/logo-styles.css b/dokka-integration-tests/gradle/projects/it-basic/customResources/logo-styles.css
new file mode 100644
index 00000000..c7932753
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic/customResources/logo-styles.css
@@ -0,0 +1,7 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+:root {
+ --dokka-logo-image-url: url('https://upload.wikimedia.org/wikipedia/commons/9/9d/Ubuntu_logo.svg');
+}
diff --git a/dokka-integration-tests/gradle/projects/it-basic/gradle.properties b/dokka-integration-tests/gradle/projects/it-basic/gradle.properties
new file mode 100644
index 00000000..5904fc21
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic/gradle.properties
@@ -0,0 +1,5 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+dokka_it_kotlin_version=1.9.20
diff --git a/dokka-integration-tests/gradle/projects/it-basic/gradle/wrapper/gradle-wrapper.jar b/dokka-integration-tests/gradle/projects/it-basic/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..62d4c053
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/dokka-integration-tests/gradle/projects/it-basic/gradle/wrapper/gradle-wrapper.properties b/dokka-integration-tests/gradle/projects/it-basic/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..a434026d
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,9 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.2-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/dokka-integration-tests/gradle/projects/it-basic/gradlew b/dokka-integration-tests/gradle/projects/it-basic/gradlew
new file mode 100755
index 00000000..fbd7c515
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/dokka-integration-tests/gradle/projects/it-basic/gradlew.bat b/dokka-integration-tests/gradle/projects/it-basic/gradlew.bat
new file mode 100644
index 00000000..a9f778a7
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic/gradlew.bat
@@ -0,0 +1,104 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/dokka-integration-tests/gradle/projects/it-basic/settings.gradle.kts b/dokka-integration-tests/gradle/projects/it-basic/settings.gradle.kts
new file mode 100644
index 00000000..0345c020
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic/settings.gradle.kts
@@ -0,0 +1,9 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+@file:Suppress("LocalVariableName", "UnstableApiUsage")
+
+apply(from = "../template.settings.gradle.kts")
+rootProject.name = "it-basic"
+
diff --git a/dokka-integration-tests/gradle/projects/it-basic/src/main/java/it/basic/java/SampleJavaClass.java b/dokka-integration-tests/gradle/projects/it-basic/src/main/java/it/basic/java/SampleJavaClass.java
new file mode 100644
index 00000000..23b0202c
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic/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/gradle/projects/it-basic/src/main/kotlin/RootPackageClass.kt b/dokka-integration-tests/gradle/projects/it-basic/src/main/kotlin/RootPackageClass.kt
new file mode 100644
index 00000000..8ff6c750
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic/src/main/kotlin/RootPackageClass.kt
@@ -0,0 +1,8 @@
+@file:Suppress("unused")
+
+/**
+ * A class that lives inside the root package
+ */
+class RootPackageClass {
+ val description = "I do live in the root package!"
+}
diff --git a/dokka-integration-tests/gradle/projects/it-basic/src/main/kotlin/it/basic/PublicClass.kt b/dokka-integration-tests/gradle/projects/it-basic/src/main/kotlin/it/basic/PublicClass.kt
new file mode 100644
index 00000000..2958948c
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic/src/main/kotlin/it/basic/PublicClass.kt
@@ -0,0 +1,69 @@
+@file:Suppress("unused")
+
+package it.basic
+
+import RootPackageClass
+
+/**
+ * This class, unlike [RootPackageClass] is located in a sub-package
+ *
+ * §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 protected and documented
+ */
+ protected fun protectedDocumentedFunction(): String = ""
+
+ protected fun protectedUndocumentedFunction(): 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 is protected and documented
+ */
+ val protectedDocumentedProperty: Int = 0
+
+ val protectedUndocumentedProperty: Int = 0
+
+ /**
+ * This property private and documented
+ */
+ private val privateDocumentedProperty: Int = 0
+
+ private val privateUndocumentedProperty: Int = 0
+}
diff --git a/dokka-integration-tests/gradle/projects/it-basic/src/main/kotlin/it/internal/InternalClass.kt b/dokka-integration-tests/gradle/projects/it-basic/src/main/kotlin/it/internal/InternalClass.kt
new file mode 100644
index 00000000..6173d239
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic/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
diff --git a/dokka-integration-tests/gradle/projects/it-basic/src/main/kotlin/it/overriddenVisibility/VisiblePrivateClass.kt b/dokka-integration-tests/gradle/projects/it-basic/src/main/kotlin/it/overriddenVisibility/VisiblePrivateClass.kt
new file mode 100644
index 00000000..230f5e0b
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic/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/gradle/projects/it-basic/src/main/kotlin/it/protected/ProtectedClass.kt b/dokka-integration-tests/gradle/projects/it-basic/src/main/kotlin/it/protected/ProtectedClass.kt
new file mode 100644
index 00000000..ad19f1a1
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic/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/gradle/projects/it-basic/src/main/kotlin/it/suppressedByPackage/SuppressedByPackage.kt b/dokka-integration-tests/gradle/projects/it-basic/src/main/kotlin/it/suppressedByPackage/SuppressedByPackage.kt
new file mode 100644
index 00000000..d8dc9cff
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic/src/main/kotlin/it/suppressedByPackage/SuppressedByPackage.kt
@@ -0,0 +1,7 @@
+package it.suppressedByPackage
+
+/**
+ * §SUPPRESSED§
+ * This should not be rendered.
+ */
+class SuppressedByPackage
diff --git a/dokka-integration-tests/gradle/projects/it-basic/src/main/kotlin/it/suppressedByPath/SuppressedByPath.kt b/dokka-integration-tests/gradle/projects/it-basic/src/main/kotlin/it/suppressedByPath/SuppressedByPath.kt
new file mode 100644
index 00000000..4dda9da4
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic/src/main/kotlin/it/suppressedByPath/SuppressedByPath.kt
@@ -0,0 +1,7 @@
+package it.suppressedByPath
+
+/**
+ * §SUPPRESSED§
+ * This should not be rendered.
+ */
+class SuppressedByPath
diff --git a/dokka-integration-tests/gradle/projects/it-basic/src/test/kotlin/it/basic/TestClass.kt b/dokka-integration-tests/gradle/projects/it-basic/src/test/kotlin/it/basic/TestClass.kt
new file mode 100644
index 00000000..3584bdef
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-basic/src/test/kotlin/it/basic/TestClass.kt
@@ -0,0 +1,17 @@
+package it.basic
+
+import kotlin.test.Test
+import kotlin.test.assertTrue
+
+annotation class OurAnnotation
+
+class TestClass {
+ /**
+ * Asserts something. [PublicClass]
+ */
+ @Test
+ @OurAnnotation
+ fun test() {
+ assertTrue(1 == 1)
+ }
+}
diff --git a/dokka-integration-tests/gradle/projects/it-collector-0/build.gradle.kts b/dokka-integration-tests/gradle/projects/it-collector-0/build.gradle.kts
new file mode 100644
index 00000000..948e0c3b
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-collector-0/build.gradle.kts
@@ -0,0 +1,5 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+apply(from = "../template.root.gradle.kts")
diff --git a/dokka-integration-tests/gradle/projects/it-collector-0/gradle.properties b/dokka-integration-tests/gradle/projects/it-collector-0/gradle.properties
new file mode 100644
index 00000000..5904fc21
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-collector-0/gradle.properties
@@ -0,0 +1,5 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+dokka_it_kotlin_version=1.9.20
diff --git a/dokka-integration-tests/gradle/projects/it-collector-0/gradle/wrapper/gradle-wrapper.jar b/dokka-integration-tests/gradle/projects/it-collector-0/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..f3d88b1c
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-collector-0/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/dokka-integration-tests/gradle/projects/it-collector-0/gradle/wrapper/gradle-wrapper.properties b/dokka-integration-tests/gradle/projects/it-collector-0/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..a434026d
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-collector-0/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,9 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.2-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/dokka-integration-tests/gradle/projects/it-collector-0/gradlew b/dokka-integration-tests/gradle/projects/it-collector-0/gradlew
new file mode 100755
index 00000000..2fe81a7d
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-collector-0/gradlew
@@ -0,0 +1,183 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/dokka-integration-tests/gradle/projects/it-collector-0/gradlew.bat b/dokka-integration-tests/gradle/projects/it-collector-0/gradlew.bat
new file mode 100644
index 00000000..24467a14
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-collector-0/gradlew.bat
@@ -0,0 +1,100 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/dokka-integration-tests/gradle/projects/it-collector-0/moduleA/build.gradle.kts b/dokka-integration-tests/gradle/projects/it-collector-0/moduleA/build.gradle.kts
new file mode 100644
index 00000000..1e61f8b2
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-collector-0/moduleA/build.gradle.kts
@@ -0,0 +1,10 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+plugins {
+ // TODO: File bug report for gradle: :moduleA:moduleB:dokkaHtml is missing kotlin gradle plugin from
+ // the runtime classpath during execution without this plugin in the parent project
+ kotlin("jvm")
+ id("org.jetbrains.dokka")
+}
diff --git a/dokka-integration-tests/gradle/projects/it-collector-0/moduleA/moduleB/README.md b/dokka-integration-tests/gradle/projects/it-collector-0/moduleA/moduleB/README.md
new file mode 100644
index 00000000..f8c52880
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-collector-0/moduleA/moduleB/README.md
@@ -0,0 +1,2 @@
+# Module moduleB
+Here is some description for module B
diff --git a/dokka-integration-tests/gradle/projects/it-collector-0/moduleA/moduleB/build.gradle.kts b/dokka-integration-tests/gradle/projects/it-collector-0/moduleA/moduleB/build.gradle.kts
new file mode 100644
index 00000000..aa562cde
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-collector-0/moduleA/moduleB/build.gradle.kts
@@ -0,0 +1,8 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+plugins {
+ kotlin("jvm")
+ id("org.jetbrains.dokka")
+}
diff --git a/dokka-integration-tests/gradle/projects/it-collector-0/moduleA/moduleB/src/main/kotlin/org/jetbrains/dokka/it/moduleB/ModuleB.kt b/dokka-integration-tests/gradle/projects/it-collector-0/moduleA/moduleB/src/main/kotlin/org/jetbrains/dokka/it/moduleB/ModuleB.kt
new file mode 100644
index 00000000..430e2234
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-collector-0/moduleA/moduleB/src/main/kotlin/org/jetbrains/dokka/it/moduleB/ModuleB.kt
@@ -0,0 +1,6 @@
+package org.jetbrains.dokka.it.moduleB
+
+@Suppress("unused")
+class ModuleB {
+ fun undocumentedPublicFunction() {}
+}
diff --git a/dokka-integration-tests/gradle/projects/it-collector-0/moduleA/moduleC/README.md b/dokka-integration-tests/gradle/projects/it-collector-0/moduleA/moduleC/README.md
new file mode 100644
index 00000000..4ead5671
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-collector-0/moduleA/moduleC/README.md
@@ -0,0 +1,2 @@
+# Module moduleC
+Here is some description for module C
diff --git a/dokka-integration-tests/gradle/projects/it-collector-0/moduleA/moduleC/build.gradle.kts b/dokka-integration-tests/gradle/projects/it-collector-0/moduleA/moduleC/build.gradle.kts
new file mode 100644
index 00000000..aa562cde
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-collector-0/moduleA/moduleC/build.gradle.kts
@@ -0,0 +1,8 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+plugins {
+ kotlin("jvm")
+ id("org.jetbrains.dokka")
+}
diff --git a/dokka-integration-tests/gradle/projects/it-collector-0/moduleA/moduleC/src/main/kotlin/org/jetbrains/dokka/it/moduleC/ModuleC.kt b/dokka-integration-tests/gradle/projects/it-collector-0/moduleA/moduleC/src/main/kotlin/org/jetbrains/dokka/it/moduleC/ModuleC.kt
new file mode 100644
index 00000000..e14d68e0
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-collector-0/moduleA/moduleC/src/main/kotlin/org/jetbrains/dokka/it/moduleC/ModuleC.kt
@@ -0,0 +1,6 @@
+package org.jetbrains.dokka.it.moduleC
+
+@Suppress("unused")
+class ModuleC {
+ fun undocumentedPublicFunction() {}
+}
diff --git a/dokka-integration-tests/gradle/projects/it-collector-0/settings.gradle.kts b/dokka-integration-tests/gradle/projects/it-collector-0/settings.gradle.kts
new file mode 100644
index 00000000..6ca74d4b
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-collector-0/settings.gradle.kts
@@ -0,0 +1,9 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+apply(from = "../template.settings.gradle.kts")
+rootProject.name = "it-collector-0"
+include(":moduleA")
+include(":moduleA:moduleB")
+include(":moduleA:moduleC")
diff --git a/dokka-integration-tests/gradle/projects/it-configuration/README.md b/dokka-integration-tests/gradle/projects/it-configuration/README.md
new file mode 100644
index 00000000..1d5e34bb
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-configuration/README.md
@@ -0,0 +1,5 @@
+# it-configuration
+
+This is an integration test project for checking Dokka's configuration options.
+
+Please see the KDoc for the integration test itself. \ No newline at end of file
diff --git a/dokka-integration-tests/gradle/projects/it-configuration/build.gradle.kts b/dokka-integration-tests/gradle/projects/it-configuration/build.gradle.kts
new file mode 100644
index 00000000..736202bb
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-configuration/build.gradle.kts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+import org.jetbrains.dokka.gradle.DokkaTask
+import org.jetbrains.dokka.gradle.kotlinSourceSet
+
+plugins {
+ kotlin("jvm")
+ id("org.jetbrains.dokka")
+}
+
+buildscript {
+ dependencies {
+ classpath("org.jetbrains.dokka:dokka-base:${System.getenv("DOKKA_VERSION")}")
+ }
+}
+
+version = "1.9.20-SNAPSHOT"
+
+apply(from = "../template.root.gradle.kts")
+
+tasks.withType<DokkaTask> {
+ moduleName.set("Configuration Test Project")
+ dokkaSourceSets {
+ configureEach {
+ failOnWarning.set(project.getBooleanProperty("fail_on_warning"))
+ reportUndocumented.set(project.getBooleanProperty("report_undocumented"))
+ }
+ }
+}
+
+fun Project.getBooleanProperty(name: String): Boolean = (project.property(name) as String).toBoolean()
diff --git a/dokka-integration-tests/gradle/projects/it-configuration/gradle.properties b/dokka-integration-tests/gradle/projects/it-configuration/gradle.properties
new file mode 100644
index 00000000..f958d9e3
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-configuration/gradle.properties
@@ -0,0 +1,7 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+dokka_it_kotlin_version=1.9.20
+fail_on_warning=false
+report_undocumented=false
diff --git a/dokka-integration-tests/gradle/projects/it-configuration/gradle/wrapper/gradle-wrapper.jar b/dokka-integration-tests/gradle/projects/it-configuration/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..62d4c053
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-configuration/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/dokka-integration-tests/gradle/projects/it-configuration/gradle/wrapper/gradle-wrapper.properties b/dokka-integration-tests/gradle/projects/it-configuration/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..a434026d
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-configuration/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,9 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.2-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/dokka-integration-tests/gradle/projects/it-configuration/gradlew b/dokka-integration-tests/gradle/projects/it-configuration/gradlew
new file mode 100755
index 00000000..fbd7c515
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-configuration/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/dokka-integration-tests/gradle/projects/it-configuration/gradlew.bat b/dokka-integration-tests/gradle/projects/it-configuration/gradlew.bat
new file mode 100644
index 00000000..a9f778a7
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-configuration/gradlew.bat
@@ -0,0 +1,104 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/dokka-integration-tests/gradle/projects/it-configuration/settings.gradle.kts b/dokka-integration-tests/gradle/projects/it-configuration/settings.gradle.kts
new file mode 100644
index 00000000..6bedd2ef
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-configuration/settings.gradle.kts
@@ -0,0 +1,7 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+apply(from = "../template.settings.gradle.kts")
+rootProject.name = "it-configuration"
+
diff --git a/dokka-integration-tests/gradle/projects/it-configuration/src/main/kotlin/it/ClassWithUndocumentedDeclarations.kt b/dokka-integration-tests/gradle/projects/it-configuration/src/main/kotlin/it/ClassWithUndocumentedDeclarations.kt
new file mode 100644
index 00000000..04d0cb16
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-configuration/src/main/kotlin/it/ClassWithUndocumentedDeclarations.kt
@@ -0,0 +1,12 @@
+package it
+
+/**
+ * The class itself is documented, but its methods are not
+ *
+ * This can be used to test configuration properties that work with undocumented declarations,
+ * such as `reportUndocumented` and `failOnWarning`
+ */
+class ClassWithUndocumentedDeclarations {
+
+ fun foo() {}
+} \ No newline at end of file
diff --git a/dokka-integration-tests/gradle/projects/it-js-ir-0/build.gradle.kts b/dokka-integration-tests/gradle/projects/it-js-ir-0/build.gradle.kts
new file mode 100644
index 00000000..9746716e
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-js-ir-0/build.gradle.kts
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+plugins {
+ id("org.jetbrains.dokka")
+ kotlin("js")
+}
+
+apply(from = "../template.root.gradle.kts")
+
+kotlin {
+ js(IR) {
+ browser()
+ nodejs()
+ }
+}
+
+dependencies {
+ implementation(npm("is-sorted", "1.0.5"))
+
+ val reactVersion = properties["react_version"]
+ implementation("org.jetbrains.kotlin-wrappers:kotlin-react:$reactVersion")
+ implementation("org.jetbrains.kotlin-wrappers:kotlin-react-dom:$reactVersion")
+}
diff --git a/dokka-integration-tests/gradle/projects/it-js-ir-0/gradle.properties b/dokka-integration-tests/gradle/projects/it-js-ir-0/gradle.properties
new file mode 100644
index 00000000..a7b64215
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-js-ir-0/gradle.properties
@@ -0,0 +1,6 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+dokka_it_kotlin_version=1.9.20
+react_version=18.2.0-pre.467
diff --git a/dokka-integration-tests/gradle/projects/it-js-ir-0/gradle/wrapper/gradle-wrapper.jar b/dokka-integration-tests/gradle/projects/it-js-ir-0/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..62d4c053
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-js-ir-0/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/dokka-integration-tests/gradle/projects/it-js-ir-0/gradle/wrapper/gradle-wrapper.properties b/dokka-integration-tests/gradle/projects/it-js-ir-0/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..a434026d
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-js-ir-0/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,9 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.2-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/dokka-integration-tests/gradle/projects/it-js-ir-0/gradlew b/dokka-integration-tests/gradle/projects/it-js-ir-0/gradlew
new file mode 100755
index 00000000..fbd7c515
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-js-ir-0/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/dokka-integration-tests/gradle/projects/it-js-ir-0/gradlew.bat b/dokka-integration-tests/gradle/projects/it-js-ir-0/gradlew.bat
new file mode 100644
index 00000000..a9f778a7
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-js-ir-0/gradlew.bat
@@ -0,0 +1,104 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/dokka-integration-tests/gradle/projects/it-js-ir-0/settings.gradle.kts b/dokka-integration-tests/gradle/projects/it-js-ir-0/settings.gradle.kts
new file mode 100644
index 00000000..303c1b69
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-js-ir-0/settings.gradle.kts
@@ -0,0 +1,9 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+@file:Suppress("LocalVariableName", "UnstableApiUsage")
+
+apply(from = "../template.settings.gradle.kts")
+rootProject.name = "it-js-ir-0"
+
diff --git a/dokka-integration-tests/gradle/projects/it-js-ir-0/src/main/kotlin/RootPackageClass.kt b/dokka-integration-tests/gradle/projects/it-js-ir-0/src/main/kotlin/RootPackageClass.kt
new file mode 100644
index 00000000..cbe6240e
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-js-ir-0/src/main/kotlin/RootPackageClass.kt
@@ -0,0 +1,26 @@
+@file:Suppress("unused")
+
+import org.w3c.dom.url.URLSearchParams
+import org.w3c.dom.HTMLAnchorElement
+import react.dom.html.AnchorHTMLAttributes
+import react.Props
+import react.State
+
+/**
+ * A class that lives inside the root package
+ */
+class RootPackageClass {
+ val description = "I do live in the root package!"
+}
+
+// sample method that uses classes from dom and react, should compile
+fun URLSearchParams.react(props: Props, state: State) {}
+
+fun test(list: MutableList<Int>) = "list"
+
+@JsModule("is-sorted")
+@JsNonModule
+external fun <T> sorted(a: Array<T>): Boolean
+
+// this declaration can be used to check deserialization of dynamic type
+external interface TextLinkProps: AnchorHTMLAttributes<HTMLAnchorElement> \ No newline at end of file
diff --git a/dokka-integration-tests/gradle/projects/it-js-ir-0/src/main/kotlin/it/basic/PublicClass.kt b/dokka-integration-tests/gradle/projects/it-js-ir-0/src/main/kotlin/it/basic/PublicClass.kt
new file mode 100644
index 00000000..fc4b36bd
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-js-ir-0/src/main/kotlin/it/basic/PublicClass.kt
@@ -0,0 +1,53 @@
+@file:Suppress("unused")
+
+package it.basic
+
+import RootPackageClass
+
+/**
+ * This class, unlike [RootPackageClass] is located in a sub-package
+ */
+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/dokka-integration-tests/gradle/projects/it-js-ir-0/src/main/kotlin/it/internal/InternalClass.kt b/dokka-integration-tests/gradle/projects/it-js-ir-0/src/main/kotlin/it/internal/InternalClass.kt
new file mode 100644
index 00000000..7d42b978
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-js-ir-0/src/main/kotlin/it/internal/InternalClass.kt
@@ -0,0 +1,7 @@
+package it.internal
+
+/**
+ * §INTERNAL§
+ * This class is internal and should not be rendered
+ */
+internal class InternalClass
diff --git a/dokka-integration-tests/gradle/projects/it-js-ir-0/src/main/kotlin/it/suppressedByPackage/SuppressedByPackage.kt b/dokka-integration-tests/gradle/projects/it-js-ir-0/src/main/kotlin/it/suppressedByPackage/SuppressedByPackage.kt
new file mode 100644
index 00000000..d8dc9cff
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-js-ir-0/src/main/kotlin/it/suppressedByPackage/SuppressedByPackage.kt
@@ -0,0 +1,7 @@
+package it.suppressedByPackage
+
+/**
+ * §SUPPRESSED§
+ * This should not be rendered.
+ */
+class SuppressedByPackage
diff --git a/dokka-integration-tests/gradle/projects/it-js-ir-0/src/main/kotlin/it/suppressedByPath/SuppressedByPath.kt b/dokka-integration-tests/gradle/projects/it-js-ir-0/src/main/kotlin/it/suppressedByPath/SuppressedByPath.kt
new file mode 100644
index 00000000..4dda9da4
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-js-ir-0/src/main/kotlin/it/suppressedByPath/SuppressedByPath.kt
@@ -0,0 +1,7 @@
+package it.suppressedByPath
+
+/**
+ * §SUPPRESSED§
+ * This should not be rendered.
+ */
+class SuppressedByPath
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-0/build.gradle.kts b/dokka-integration-tests/gradle/projects/it-multimodule-0/build.gradle.kts
new file mode 100644
index 00000000..948e0c3b
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-0/build.gradle.kts
@@ -0,0 +1,5 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+apply(from = "../template.root.gradle.kts")
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-0/gradle.properties b/dokka-integration-tests/gradle/projects/it-multimodule-0/gradle.properties
new file mode 100644
index 00000000..5904fc21
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-0/gradle.properties
@@ -0,0 +1,5 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+dokka_it_kotlin_version=1.9.20
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-0/gradle/wrapper/gradle-wrapper.jar b/dokka-integration-tests/gradle/projects/it-multimodule-0/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..f3d88b1c
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-0/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-0/gradle/wrapper/gradle-wrapper.properties b/dokka-integration-tests/gradle/projects/it-multimodule-0/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..a434026d
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-0/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,9 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.2-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-0/gradlew b/dokka-integration-tests/gradle/projects/it-multimodule-0/gradlew
new file mode 100755
index 00000000..2fe81a7d
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-0/gradlew
@@ -0,0 +1,183 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-0/gradlew.bat b/dokka-integration-tests/gradle/projects/it-multimodule-0/gradlew.bat
new file mode 100644
index 00000000..24467a14
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-0/gradlew.bat
@@ -0,0 +1,100 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/build.gradle.kts b/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/build.gradle.kts
new file mode 100644
index 00000000..a28f73e8
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/build.gradle.kts
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+plugins {
+ // TODO: File bug report for gradle: :moduleA:moduleB:dokkaHtml is missing kotlin gradle plugin from
+ // the runtime classpath during execution without this plugin in the parent project
+ kotlin("jvm")
+ id("org.jetbrains.dokka")
+}
+
+
+allprojects {
+ tasks.withType<org.jetbrains.dokka.gradle.AbstractDokkaTask> {
+ pluginsMapConfiguration.set(
+ mapOf(
+ "org.jetbrains.dokka.base.DokkaBase" to """{ "homepageLink" : "https://github.com/Kotlin/dokka/tree/master/dokka-integration-tests/gradle/projects/it-multimodule-0/" }"""
+ )
+ )
+ }
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleB/Module.md b/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleB/Module.md
new file mode 100644
index 00000000..0570f467
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleB/Module.md
@@ -0,0 +1,6 @@
+# Module !Module B!
+Here is some description for Module B
+
+Module B: Second paragraph
+# Module moduleB
+§IGNORED$This documentation shall be ignored, because wrong module name§IGNORED$
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleB/build.gradle.kts b/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleB/build.gradle.kts
new file mode 100644
index 00000000..91ccea29
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleB/build.gradle.kts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+import org.jetbrains.dokka.gradle.DokkaTask
+
+plugins {
+ kotlin("jvm")
+ id("org.jetbrains.dokka")
+}
+
+tasks.withType<DokkaTask>().configureEach {
+ moduleName.set("!Module B!")
+ dokkaSourceSets.configureEach {
+ includes.from("Module.md")
+ }
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleB/src/main/kotlin/org/jetbrains/dokka/it/moduleB/ModuleB.kt b/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleB/src/main/kotlin/org/jetbrains/dokka/it/moduleB/ModuleB.kt
new file mode 100644
index 00000000..430e2234
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleB/src/main/kotlin/org/jetbrains/dokka/it/moduleB/ModuleB.kt
@@ -0,0 +1,6 @@
+package org.jetbrains.dokka.it.moduleB
+
+@Suppress("unused")
+class ModuleB {
+ fun undocumentedPublicFunction() {}
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleC/Module.md b/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleC/Module.md
new file mode 100644
index 00000000..4ead5671
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleC/Module.md
@@ -0,0 +1,2 @@
+# Module moduleC
+Here is some description for module C
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleC/build.gradle.kts b/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleC/build.gradle.kts
new file mode 100644
index 00000000..6a77c9ed
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleC/build.gradle.kts
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+import org.jetbrains.dokka.gradle.DokkaTask
+
+plugins {
+ kotlin("jvm")
+ id("org.jetbrains.dokka")
+}
+
+tasks.withType<DokkaTask>().configureEach {
+ dokkaSourceSets.configureEach {
+ includes.from("Module.md")
+ }
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleC/src/main/kotlin/org/jetbrains/dokka/it/moduleC/ModuleC.kt b/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleC/src/main/kotlin/org/jetbrains/dokka/it/moduleC/ModuleC.kt
new file mode 100644
index 00000000..e14d68e0
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleC/src/main/kotlin/org/jetbrains/dokka/it/moduleC/ModuleC.kt
@@ -0,0 +1,6 @@
+package org.jetbrains.dokka.it.moduleC
+
+@Suppress("unused")
+class ModuleC {
+ fun undocumentedPublicFunction() {}
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleD/build.gradle.kts b/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleD/build.gradle.kts
new file mode 100644
index 00000000..1598ecef
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleD/build.gradle.kts
@@ -0,0 +1,10 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+import org.jetbrains.dokka.gradle.DokkaTask
+
+plugins {
+ kotlin("jvm")
+ id("org.jetbrains.dokka")
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleD/src/main/kotlin/org/jetbrains/dokka/it/moduleD/ModuleC.kt b/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleD/src/main/kotlin/org/jetbrains/dokka/it/moduleD/ModuleC.kt
new file mode 100644
index 00000000..88174d53
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleD/src/main/kotlin/org/jetbrains/dokka/it/moduleD/ModuleC.kt
@@ -0,0 +1,6 @@
+package org.jetbrains.dokka.it.moduleD
+
+@Suppress("unused")
+class ModuleD {
+ fun undocumentedPublicFunction() {}
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-0/settings.gradle.kts b/dokka-integration-tests/gradle/projects/it-multimodule-0/settings.gradle.kts
new file mode 100644
index 00000000..5e70eee3
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-0/settings.gradle.kts
@@ -0,0 +1,10 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+apply(from = "../template.settings.gradle.kts")
+rootProject.name = "it-multimodule-0"
+include(":moduleA")
+include(":moduleA:moduleB")
+include(":moduleA:moduleC")
+include(":moduleA:moduleD")
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-1/build.gradle b/dokka-integration-tests/gradle/projects/it-multimodule-1/build.gradle
new file mode 100644
index 00000000..57d22b79
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-1/build.gradle
@@ -0,0 +1,18 @@
+plugins {
+ id 'org.jetbrains.kotlin.jvm'
+ id("org.jetbrains.dokka")
+}
+
+apply from: '../template.root.gradle.kts'
+
+dependencies {
+ implementation "org.jetbrains.kotlin:kotlin-stdlib"
+ implementation project(':first')
+ implementation project(':second')
+}
+
+
+subprojects {
+ apply plugin: 'org.jetbrains.kotlin.jvm'
+ apply plugin: 'org.jetbrains.dokka'
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-1/first/build.gradle b/dokka-integration-tests/gradle/projects/it-multimodule-1/first/build.gradle
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-1/first/build.gradle
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-1/first/src/main/kotlin/foo/FirstClass.kt b/dokka-integration-tests/gradle/projects/it-multimodule-1/first/src/main/kotlin/foo/FirstClass.kt
new file mode 100644
index 00000000..93f73bf4
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-1/first/src/main/kotlin/foo/FirstClass.kt
@@ -0,0 +1,11 @@
+package foo
+
+/**
+ * First class description
+ */
+open class FirstClass{
+ /**
+ * PropertyOne description
+ */
+ val propertyOne: Int = 5
+} \ No newline at end of file
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-1/first/src/main/kotlin/foo/FirstSubclass.kt b/dokka-integration-tests/gradle/projects/it-multimodule-1/first/src/main/kotlin/foo/FirstSubclass.kt
new file mode 100644
index 00000000..0deb65c0
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-1/first/src/main/kotlin/foo/FirstSubclass.kt
@@ -0,0 +1,12 @@
+package foo
+
+/**
+ * Subclass description
+ * @property surname Surname description
+ */
+class FirstSubclass(var surname: String) : FirstClass() {
+ /**
+ * printNewLine description
+ */
+ fun printNewline() = print("\r\n")
+} \ No newline at end of file
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-1/first/src/main/kotlin/foo/Main.kt b/dokka-integration-tests/gradle/projects/it-multimodule-1/first/src/main/kotlin/foo/Main.kt
new file mode 100644
index 00000000..8c7f58a7
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-1/first/src/main/kotlin/foo/Main.kt
@@ -0,0 +1,8 @@
+package foo
+
+/**
+ * Main function
+ */
+fun main(args : Array<String>) {
+ println("Hello, world!")
+} \ No newline at end of file
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-1/first/src/main/kotlin/noPackage.kt b/dokka-integration-tests/gradle/projects/it-multimodule-1/first/src/main/kotlin/noPackage.kt
new file mode 100644
index 00000000..c41e218f
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-1/first/src/main/kotlin/noPackage.kt
@@ -0,0 +1,3 @@
+fun noPackage(): String = "Hello there"
+
+open class NoPackage
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-1/gradle.properties b/dokka-integration-tests/gradle/projects/it-multimodule-1/gradle.properties
new file mode 100644
index 00000000..5904fc21
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-1/gradle.properties
@@ -0,0 +1,5 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+dokka_it_kotlin_version=1.9.20
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-1/gradle/wrapper/gradle-wrapper.jar b/dokka-integration-tests/gradle/projects/it-multimodule-1/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..62d4c053
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-1/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-1/gradle/wrapper/gradle-wrapper.properties b/dokka-integration-tests/gradle/projects/it-multimodule-1/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..a434026d
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-1/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,9 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.2-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-1/gradlew b/dokka-integration-tests/gradle/projects/it-multimodule-1/gradlew
new file mode 100755
index 00000000..fbd7c515
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-1/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-1/gradlew.bat b/dokka-integration-tests/gradle/projects/it-multimodule-1/gradlew.bat
new file mode 100644
index 00000000..a9f778a7
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-1/gradlew.bat
@@ -0,0 +1,104 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-1/second/build.gradle b/dokka-integration-tests/gradle/projects/it-multimodule-1/second/build.gradle
new file mode 100644
index 00000000..2b62f963
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-1/second/build.gradle
@@ -0,0 +1,14 @@
+dependencies {
+ implementation project(":first")
+}
+dokkaHtml {
+ dependsOn(":first:dokkaHtml")
+ dokkaSourceSets {
+ "main" {
+ externalDocumentationLink {
+ url.set(new URL("file://" + rootProject.rootDir.toPath().toAbsolutePath().resolve("first/build/dokka/html/")))
+ packageListUrl.set(new URL("file://" + rootProject.rootDir.toPath().toAbsolutePath().resolve("first/build/dokka/html/first/package-list")))
+ }
+ }
+ }
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-1/second/src/main/kotlin/NoPackageClass.kt b/dokka-integration-tests/gradle/projects/it-multimodule-1/second/src/main/kotlin/NoPackageClass.kt
new file mode 100644
index 00000000..d2f30ef7
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-1/second/src/main/kotlin/NoPackageClass.kt
@@ -0,0 +1 @@
+class NoPackageClass : NoPackage()
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-1/second/src/main/kotlin/bar/SecondClass.kt b/dokka-integration-tests/gradle/projects/it-multimodule-1/second/src/main/kotlin/bar/SecondClass.kt
new file mode 100644
index 00000000..6a0c935e
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-1/second/src/main/kotlin/bar/SecondClass.kt
@@ -0,0 +1,21 @@
+package bar
+/**
+ * Second class in second module description [foo.FirstClass]
+ * @author John Doe
+ * @version 0.1.3
+ * @param name Name description text text text.
+*/
+class SecondClass(val name: String) {
+ val firstProperty = "propertystring"
+ /**
+ * Second property in second module description [foo.FirstSubclass]
+ */
+ var secondProperty: String = ""
+ set(value) {
+ println("Second property not set")
+ }
+
+ init {
+ println("InitializerBlock")
+ }
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-1/second/src/main/kotlin/foo/ThirdClass.kt b/dokka-integration-tests/gradle/projects/it-multimodule-1/second/src/main/kotlin/foo/ThirdClass.kt
new file mode 100644
index 00000000..cc24a6b7
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-1/second/src/main/kotlin/foo/ThirdClass.kt
@@ -0,0 +1,11 @@
+package foo
+
+/**
+ * Third class description
+ */
+open class ThirdClass{
+ /**
+ * PropertyOne description
+ */
+ val propertyOne: Int = 5
+} \ No newline at end of file
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-1/settings.gradle.kts b/dokka-integration-tests/gradle/projects/it-multimodule-1/settings.gradle.kts
new file mode 100644
index 00000000..ced319f2
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-1/settings.gradle.kts
@@ -0,0 +1,8 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+apply(from = "../template.settings.gradle.kts")
+rootProject.name = "it-multimodule-1"
+include(":first")
+include(":second")
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/build.gradle b/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/build.gradle
new file mode 100644
index 00000000..e04e412b
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/build.gradle
@@ -0,0 +1,43 @@
+import org.jetbrains.dokka.gradle.DokkaMultiModuleTask
+
+plugins {
+ id 'org.jetbrains.kotlin.jvm'
+ id("org.jetbrains.dokka")
+}
+
+apply from: '../template.root.gradle.kts'
+
+dependencies {
+ implementation "org.jetbrains.kotlin:kotlin-stdlib"
+ dokkaPlugin "org.jetbrains.dokka:versioning-plugin:${System.getenv("DOKKA_VERSION")}"
+}
+
+
+subprojects {
+ apply plugin: 'org.jetbrains.kotlin.jvm'
+ apply plugin: 'org.jetbrains.dokka'
+}
+
+dokkaHtmlMultiModule {
+ pluginsMapConfiguration.set(["org.jetbrains.dokka.versioning.VersioningPlugin": """{ "version": "1.2", "olderVersionsDir": "$projectDir/dokkas" }"""])
+}
+
+tasks.register('dokkaHtmlMultiModuleBaseVersion', DokkaMultiModuleTask){
+ dependencies {
+ dokkaPlugin("org.jetbrains.dokka:all-modules-page-plugin:${System.getenv("DOKKA_VERSION")}")
+ dokkaPlugin("org.jetbrains.dokka:versioning-plugin:${System.getenv("DOKKA_VERSION")}")
+ }
+ outputDirectory.set(file(projectDir.toPath().resolve("dokkas").resolve("1.0")))
+ pluginsMapConfiguration.set(["org.jetbrains.dokka.versioning.VersioningPlugin": """{ "version": "1.0" }"""])
+ addChildTasks([project(":first"), project(":second")], "dokkaHtmlPartial")
+}
+
+tasks.register('dokkaHtmlMultiModuleNextVersion', DokkaMultiModuleTask){
+ dependencies {
+ dokkaPlugin("org.jetbrains.dokka:all-modules-page-plugin:${System.getenv("DOKKA_VERSION")}")
+ dokkaPlugin("org.jetbrains.dokka:versioning-plugin:${System.getenv("DOKKA_VERSION")}")
+ }
+ outputDirectory.set(file(projectDir.toPath().resolve("dokkas").resolve("1.1")))
+ pluginsMapConfiguration.set(["org.jetbrains.dokka.versioning.VersioningPlugin": """{ "version": "1.1", "olderVersionsDir": "$projectDir/dokkas" }"""])
+ addChildTasks([project(":first"), project(":second")], "dokkaHtmlPartial")
+} \ No newline at end of file
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/first/build.gradle b/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/first/build.gradle
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/first/build.gradle
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/first/src/main/kotlin/foo/FirstClass.kt b/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/first/src/main/kotlin/foo/FirstClass.kt
new file mode 100644
index 00000000..93f73bf4
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/first/src/main/kotlin/foo/FirstClass.kt
@@ -0,0 +1,11 @@
+package foo
+
+/**
+ * First class description
+ */
+open class FirstClass{
+ /**
+ * PropertyOne description
+ */
+ val propertyOne: Int = 5
+} \ No newline at end of file
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/gradle.properties b/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/gradle.properties
new file mode 100644
index 00000000..a8c59753
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/gradle.properties
@@ -0,0 +1,6 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+dokka_it_kotlin_version=1.9.20
+
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/gradle/wrapper/gradle-wrapper.jar b/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..943f0cbf
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/gradle/wrapper/gradle-wrapper.properties b/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..cc6c9292
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,10 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
+networkTimeout=10000
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/gradlew b/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/gradlew
new file mode 100755
index 00000000..65dcd68d
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/gradlew
@@ -0,0 +1,244 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+# Collect all arguments for the java command;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# shell script including quotes and variable substitutions, so put them in
+# double quotes to make sure that they get re-expanded; and
+# * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/gradlew.bat b/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/gradlew.bat
new file mode 100644
index 00000000..6689b85b
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/gradlew.bat
@@ -0,0 +1,92 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/second/build.gradle b/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/second/build.gradle
new file mode 100644
index 00000000..cf1d1f21
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/second/build.gradle
@@ -0,0 +1,3 @@
+dependencies {
+ implementation project(":first")
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/second/src/main/kotlin/bar/SecondClass.kt b/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/second/src/main/kotlin/bar/SecondClass.kt
new file mode 100644
index 00000000..6a0c935e
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/second/src/main/kotlin/bar/SecondClass.kt
@@ -0,0 +1,21 @@
+package bar
+/**
+ * Second class in second module description [foo.FirstClass]
+ * @author John Doe
+ * @version 0.1.3
+ * @param name Name description text text text.
+*/
+class SecondClass(val name: String) {
+ val firstProperty = "propertystring"
+ /**
+ * Second property in second module description [foo.FirstSubclass]
+ */
+ var secondProperty: String = ""
+ set(value) {
+ println("Second property not set")
+ }
+
+ init {
+ println("InitializerBlock")
+ }
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/settings.gradle.kts b/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/settings.gradle.kts
new file mode 100644
index 00000000..fc6f9f91
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multimodule-versioning-0/settings.gradle.kts
@@ -0,0 +1,8 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+apply(from = "../template.settings.gradle.kts")
+rootProject.name = "it-multimodule-versioning-0"
+include(":first")
+include(":second")
diff --git a/dokka-integration-tests/gradle/projects/it-multiplatform-0/build.gradle.kts b/dokka-integration-tests/gradle/projects/it-multiplatform-0/build.gradle.kts
new file mode 100644
index 00000000..a00b4b8d
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multiplatform-0/build.gradle.kts
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+import org.jetbrains.dokka.gradle.DokkaTask
+import java.net.URL
+
+plugins {
+ kotlin("multiplatform")
+ id("org.jetbrains.dokka")
+}
+
+apply(from = "../template.root.gradle.kts")
+
+kotlin {
+ jvm()
+ linuxX64("linux")
+ macosX64("macos")
+ js(IR) // Starting with Kotlin 1.9.0, using compiler types LEGACY or BOTH leads to an error.
+ //TODO Add wasm when kx.coroutines will be supported and published into the main repo
+ sourceSets {
+ val commonMain by sourceSets.getting
+ val linuxMain by sourceSets.getting
+ val macosMain by sourceSets.getting
+ val desktopMain by sourceSets.creating {
+ dependsOn(commonMain)
+ linuxMain.dependsOn(this)
+ macosMain.dependsOn(this)
+ }
+ named("commonMain") {
+ dependencies {
+ if (properties["dokka_it_kotlin_version"] in listOf("1.4.32", "1.5.31"))
+ // otherwise for a modern versin of coroutines:
+ // Failed to resolve Kotlin library: project/build/kotlinSourceSetMetadata/commonMain/org.jetbrains.kotlinx-kotlinx-coroutines-core/org.jetbrains.kotlinx-kotlinx-coroutines-core-commonMain.klib
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9")
+ else
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
+ }
+ }
+ }
+}
+
+tasks.withType<DokkaTask>().configureEach {
+ dokkaSourceSets {
+ configureEach {
+ externalDocumentationLink {
+ url.set(URL("https://kotlinlang.org/api/kotlinx.coroutines/"))
+ //packageListUrl.set(URL("https://kotlinlang.org/api/kotlinx.coroutines/package-list"))
+ }
+ }
+ }
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multiplatform-0/gradle.properties b/dokka-integration-tests/gradle/projects/it-multiplatform-0/gradle.properties
new file mode 100644
index 00000000..5904fc21
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multiplatform-0/gradle.properties
@@ -0,0 +1,5 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+dokka_it_kotlin_version=1.9.20
diff --git a/dokka-integration-tests/gradle/projects/it-multiplatform-0/gradle/wrapper/gradle-wrapper.jar b/dokka-integration-tests/gradle/projects/it-multiplatform-0/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..f3d88b1c
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multiplatform-0/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/dokka-integration-tests/gradle/projects/it-multiplatform-0/gradle/wrapper/gradle-wrapper.properties b/dokka-integration-tests/gradle/projects/it-multiplatform-0/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..a434026d
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multiplatform-0/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,9 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.2-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/dokka-integration-tests/gradle/projects/it-multiplatform-0/gradlew b/dokka-integration-tests/gradle/projects/it-multiplatform-0/gradlew
new file mode 100755
index 00000000..2fe81a7d
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multiplatform-0/gradlew
@@ -0,0 +1,183 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/dokka-integration-tests/gradle/projects/it-multiplatform-0/gradlew.bat b/dokka-integration-tests/gradle/projects/it-multiplatform-0/gradlew.bat
new file mode 100644
index 00000000..24467a14
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multiplatform-0/gradlew.bat
@@ -0,0 +1,100 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/dokka-integration-tests/gradle/projects/it-multiplatform-0/settings.gradle.kts b/dokka-integration-tests/gradle/projects/it-multiplatform-0/settings.gradle.kts
new file mode 100644
index 00000000..0f1c3d6c
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multiplatform-0/settings.gradle.kts
@@ -0,0 +1,6 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+apply(from = "../template.settings.gradle.kts")
+rootProject.name = "it-multiplatform-0"
diff --git a/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/commonMain/kotlin/it/mpp0/CommonMainClass.kt b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/commonMain/kotlin/it/mpp0/CommonMainClass.kt
new file mode 100644
index 00000000..499a4f1e
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/commonMain/kotlin/it/mpp0/CommonMainClass.kt
@@ -0,0 +1,8 @@
+package it.mpp0
+
+/**
+ * This class is defined in commonMain
+ */
+class CommonMainClass {
+ fun publicFunction(): String = "public"
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/commonMain/kotlin/it/mpp0/ExpectedClass.kt b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/commonMain/kotlin/it/mpp0/ExpectedClass.kt
new file mode 100644
index 00000000..e610b09a
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/commonMain/kotlin/it/mpp0/ExpectedClass.kt
@@ -0,0 +1,5 @@
+package it.mpp0
+
+expect class ExpectedClass {
+ val platform: String
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/commonMain/kotlin/it/mpp0/coroutines.kt b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/commonMain/kotlin/it/mpp0/coroutines.kt
new file mode 100644
index 00000000..8eee326f
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/commonMain/kotlin/it/mpp0/coroutines.kt
@@ -0,0 +1,5 @@
+package it.mpp0
+
+import kotlinx.coroutines.CoroutineScope
+
+expect fun <T> CoroutineScope.runBlocking(block: suspend () -> T) : T
diff --git a/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/desktopMain/kotlin/it/mpp0/CPointerExtension.kt b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/desktopMain/kotlin/it/mpp0/CPointerExtension.kt
new file mode 100644
index 00000000..342a749e
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/desktopMain/kotlin/it/mpp0/CPointerExtension.kt
@@ -0,0 +1,11 @@
+package it.mpp0
+
+import kotlinx.cinterop.CPointed
+import kotlinx.cinterop.CPointer
+
+/**
+ * Will print the raw value
+ */
+fun CPointer<CPointed>.customExtension() {
+ println(this.rawValue)
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/desktopMain/kotlin/it/mpp0/ExpectedClass.kt b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/desktopMain/kotlin/it/mpp0/ExpectedClass.kt
new file mode 100644
index 00000000..19070a96
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/desktopMain/kotlin/it/mpp0/ExpectedClass.kt
@@ -0,0 +1,5 @@
+package it.mpp0
+
+actual class ExpectedClass {
+ actual val platform: String = "linux"
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/jsMain/kotlin/it/mpp0/ExpectedClass.kt b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/jsMain/kotlin/it/mpp0/ExpectedClass.kt
new file mode 100644
index 00000000..1e4a6d22
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/jsMain/kotlin/it/mpp0/ExpectedClass.kt
@@ -0,0 +1,5 @@
+package it.mpp0
+
+actual class ExpectedClass {
+ actual val platform: String = "js"
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/jsMain/kotlin/it/mpp0/runBlocking.kt b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/jsMain/kotlin/it/mpp0/runBlocking.kt
new file mode 100644
index 00000000..03b3b0ea
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/jsMain/kotlin/it/mpp0/runBlocking.kt
@@ -0,0 +1,7 @@
+package it.mpp0
+
+import kotlinx.coroutines.CoroutineScope
+
+actual fun <T> CoroutineScope.runBlocking(block: suspend () -> T): T {
+ TODO("Not yet implemented")
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/jvmMain/kotlin/it/mpp0/ExpectedClass.kt b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/jvmMain/kotlin/it/mpp0/ExpectedClass.kt
new file mode 100644
index 00000000..6de30de6
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/jvmMain/kotlin/it/mpp0/ExpectedClass.kt
@@ -0,0 +1,11 @@
+package it.mpp0
+
+actual class ExpectedClass {
+ actual val platform: String = "jvm"
+
+ /**
+ * This function can only be used by JVM consumers
+ */
+ fun jvmOnlyFunction() = Unit
+
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/jvmMain/kotlin/it/mpp0/JvmOnlyClass.kt b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/jvmMain/kotlin/it/mpp0/JvmOnlyClass.kt
new file mode 100644
index 00000000..21101a89
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/jvmMain/kotlin/it/mpp0/JvmOnlyClass.kt
@@ -0,0 +1,13 @@
+@file:Suppress("unused")
+
+package it.mpp0
+
+/**
+ * This class can only be used by JVM consumers
+ */
+class JvmOnlyClass {
+ /**
+ * This function can only be used by JVM consumers
+ */
+ fun myJvm() = println("HI")
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/jvmMain/kotlin/it/mpp0/runBlocking.kt b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/jvmMain/kotlin/it/mpp0/runBlocking.kt
new file mode 100644
index 00000000..03b3b0ea
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/jvmMain/kotlin/it/mpp0/runBlocking.kt
@@ -0,0 +1,7 @@
+package it.mpp0
+
+import kotlinx.coroutines.CoroutineScope
+
+actual fun <T> CoroutineScope.runBlocking(block: suspend () -> T): T {
+ TODO("Not yet implemented")
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/linuxMain/kotlin/it/mpp0/CPointerExtension.kt b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/linuxMain/kotlin/it/mpp0/CPointerExtension.kt
new file mode 100644
index 00000000..342a749e
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/linuxMain/kotlin/it/mpp0/CPointerExtension.kt
@@ -0,0 +1,11 @@
+package it.mpp0
+
+import kotlinx.cinterop.CPointed
+import kotlinx.cinterop.CPointer
+
+/**
+ * Will print the raw value
+ */
+fun CPointer<CPointed>.customExtension() {
+ println(this.rawValue)
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/linuxMain/kotlin/it/mpp0/ExpectedClass.kt b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/linuxMain/kotlin/it/mpp0/ExpectedClass.kt
new file mode 100644
index 00000000..19070a96
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/linuxMain/kotlin/it/mpp0/ExpectedClass.kt
@@ -0,0 +1,5 @@
+package it.mpp0
+
+actual class ExpectedClass {
+ actual val platform: String = "linux"
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/linuxMain/kotlin/it/mpp0/runBlocking.kt b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/linuxMain/kotlin/it/mpp0/runBlocking.kt
new file mode 100644
index 00000000..b56fb80a
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/linuxMain/kotlin/it/mpp0/runBlocking.kt
@@ -0,0 +1,13 @@
+package it.mpp0
+
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.async
+
+actual fun <T> CoroutineScope.runBlocking(block: suspend () -> T): T {
+ TODO("Not yet implemented")
+}
+
+fun <T> CoroutineScope.customAsync(block: suspend () -> T): Deferred<T> {
+ return async { block() }
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/macosMain/kotlin/it/mpp0/ExpectedClass.kt b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/macosMain/kotlin/it/mpp0/ExpectedClass.kt
new file mode 100644
index 00000000..7a4a8f75
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/macosMain/kotlin/it/mpp0/ExpectedClass.kt
@@ -0,0 +1,5 @@
+package it.mpp0
+
+actual class ExpectedClass {
+ actual val platform: String = "macos"
+}
diff --git a/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/macosMain/kotlin/it/mpp0/runBlocking.kt b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/macosMain/kotlin/it/mpp0/runBlocking.kt
new file mode 100644
index 00000000..03b3b0ea
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-multiplatform-0/src/macosMain/kotlin/it/mpp0/runBlocking.kt
@@ -0,0 +1,7 @@
+package it.mpp0
+
+import kotlinx.coroutines.CoroutineScope
+
+actual fun <T> CoroutineScope.runBlocking(block: suspend () -> T): T {
+ TODO("Not yet implemented")
+}
diff --git a/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/build.gradle.kts b/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/build.gradle.kts
new file mode 100644
index 00000000..8ef23d4b
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/build.gradle.kts
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+import org.jetbrains.dokka.gradle.DokkaTask
+import org.jetbrains.dokka.gradle.kotlinSourceSet
+import org.jetbrains.dokka.base.DokkaBase
+import org.jetbrains.dokka.base.DokkaBaseConfiguration
+import org.jetbrains.dokka.DokkaConfiguration
+import java.net.URL
+
+plugins {
+ kotlin("jvm")
+ id("org.jetbrains.dokka")
+}
+
+buildscript {
+ dependencies {
+ classpath("org.jetbrains.dokka:dokka-base:${System.getenv("DOKKA_VERSION")}")
+ }
+}
+
+apply(from = "../template.root.gradle.kts")
+
+fun createTask(name: String) {
+ tasks.register(name, org.jetbrains.dokka.gradle.DokkaTask::class) {
+ dokkaSourceSets {
+ moduleName.set("Some example")
+ register("kotlin-stdlib-common") {
+ sourceRoots.from("src/main/java")
+ sourceRoots.from("src/main/kotlin")
+ samples.from("src/main/kotlin")
+ }
+ }
+ }
+}
+
+task("runTasks") {
+ val taskNumber = (properties["task_number"] as String).toInt()
+ repeat(taskNumber) { i ->
+ createTask("task_"+i)
+ dependsOn ("task_"+i)
+ }
+}
diff --git a/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/gradle.properties b/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/gradle.properties
new file mode 100644
index 00000000..c49881b9
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/gradle.properties
@@ -0,0 +1,6 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+dokka_it_kotlin_version=1.9.20
+task_number=100
diff --git a/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/gradle/wrapper/gradle-wrapper.jar b/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..62d4c053
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/gradle/wrapper/gradle-wrapper.properties b/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..a434026d
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,9 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.2-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/gradlew b/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/gradlew
new file mode 100755
index 00000000..fbd7c515
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/gradlew.bat b/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/gradlew.bat
new file mode 100644
index 00000000..a9f778a7
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/gradlew.bat
@@ -0,0 +1,104 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/settings.gradle.kts b/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/settings.gradle.kts
new file mode 100644
index 00000000..91c4c2f2
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/settings.gradle.kts
@@ -0,0 +1,9 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+@file:Suppress("LocalVariableName", "UnstableApiUsage")
+
+apply(from = "../template.settings.gradle.kts")
+rootProject.name = "it-sequential-tasks-execution-stress"
+
diff --git a/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/src/main/java/it/basic/java/SampleJavaClass.java b/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/src/main/java/it/basic/java/SampleJavaClass.java
new file mode 100644
index 00000000..23b0202c
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/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/gradle/projects/it-sequential-tasks-execution-stress/src/main/kotlin/RootPackageClass.kt b/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/src/main/kotlin/RootPackageClass.kt
new file mode 100644
index 00000000..8ff6c750
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-sequential-tasks-execution-stress/src/main/kotlin/RootPackageClass.kt
@@ -0,0 +1,8 @@
+@file:Suppress("unused")
+
+/**
+ * A class that lives inside the root package
+ */
+class RootPackageClass {
+ val description = "I do live in the root package!"
+}
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-basic/build.gradle.kts b/dokka-integration-tests/gradle/projects/it-wasm-basic/build.gradle.kts
new file mode 100644
index 00000000..251d1b8f
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-basic/build.gradle.kts
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+import org.jetbrains.dokka.gradle.DokkaTask
+import java.net.URL
+
+plugins {
+ kotlin("multiplatform")
+ id("org.jetbrains.dokka")
+}
+
+apply(from = "../template.root.gradle.kts")
+
+repositories {
+ // Remove it when wasm target will be published into public maven repository
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/wasm/experimental")
+}
+
+kotlin {
+ wasm()
+ sourceSets {
+ val wasmMain by getting {
+ dependencies {
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4-wasm1")
+ implementation("org.jetbrains.kotlinx:atomicfu-wasm:0.18.5-wasm1")
+ }
+ }
+ }
+}
+
+tasks.withType<DokkaTask>().configureEach {
+ dokkaSourceSets {
+ configureEach {
+ externalDocumentationLink {
+ url.set(URL("https://kotlinlang.org/api/kotlinx.coroutines/"))
+ }
+ }
+ }
+}
+
+// HACK: some dependencies (coroutines -wasm0 and atomicfu -wasm0) reference deleted *-dev libs
+configurations.all {
+ val conf = this
+ resolutionStrategy.eachDependency {
+ if (requested.version == "1.8.20-dev-3308") {
+ println("Substitute deleted version ${requested.module}:${requested.version} for ${conf.name}")
+ useVersion(project.properties["dokka_it_kotlin_version"] as String)
+ }
+ }
+}
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-basic/gradle.properties b/dokka-integration-tests/gradle/projects/it-wasm-basic/gradle.properties
new file mode 100644
index 00000000..5904fc21
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-basic/gradle.properties
@@ -0,0 +1,5 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+dokka_it_kotlin_version=1.9.20
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-basic/gradle/wrapper/gradle-wrapper.jar b/dokka-integration-tests/gradle/projects/it-wasm-basic/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..f3d88b1c
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-basic/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-basic/gradle/wrapper/gradle-wrapper.properties b/dokka-integration-tests/gradle/projects/it-wasm-basic/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..a434026d
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-basic/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,9 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.2-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-basic/gradlew b/dokka-integration-tests/gradle/projects/it-wasm-basic/gradlew
new file mode 100755
index 00000000..2fe81a7d
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-basic/gradlew
@@ -0,0 +1,183 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-basic/gradlew.bat b/dokka-integration-tests/gradle/projects/it-wasm-basic/gradlew.bat
new file mode 100644
index 00000000..24467a14
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-basic/gradlew.bat
@@ -0,0 +1,100 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-basic/settings.gradle.kts b/dokka-integration-tests/gradle/projects/it-wasm-basic/settings.gradle.kts
new file mode 100644
index 00000000..053fcdba
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-basic/settings.gradle.kts
@@ -0,0 +1,6 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+apply(from = "../template.settings.gradle.kts")
+rootProject.name = "it-wasm-basic"
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-basic/src/wasmMain/kotlin/RootPackageClass.kt b/dokka-integration-tests/gradle/projects/it-wasm-basic/src/wasmMain/kotlin/RootPackageClass.kt
new file mode 100644
index 00000000..a2d05dff
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-basic/src/wasmMain/kotlin/RootPackageClass.kt
@@ -0,0 +1,30 @@
+@file:Suppress("unused")
+
+import org.w3c.dom.HTMLAnchorElement
+import kotlinx.coroutines.CoroutineScope
+
+/**
+ * A class that lives inside the root package
+ */
+class RootPackageClass {
+ val description = "I do live in the root package!"
+}
+
+fun test(list: MutableList<Int>) = "list"
+
+@JsModule("is-sorted")
+@JsNonModule
+external fun <T> sorted(a: Array<T>): Boolean
+
+// this declaration can be used to check deserialization of dynamic type
+external interface TextLinkProps: AnchorHTMLAttributes<HTMLAnchorElement>
+
+// this declaration uses external library and external documentation link
+fun CoroutineScope.externalClass() = "some string"
+
+/**
+ * Some external function with JsFun
+ * @see kotlin.JsFun
+ */
+@kotlin.JsFun("xxx")
+external fun externalFun() \ No newline at end of file
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-basic/src/wasmMain/kotlin/it/basic/PublicClass.kt b/dokka-integration-tests/gradle/projects/it-wasm-basic/src/wasmMain/kotlin/it/basic/PublicClass.kt
new file mode 100644
index 00000000..fc4b36bd
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-basic/src/wasmMain/kotlin/it/basic/PublicClass.kt
@@ -0,0 +1,53 @@
+@file:Suppress("unused")
+
+package it.basic
+
+import RootPackageClass
+
+/**
+ * This class, unlike [RootPackageClass] is located in a sub-package
+ */
+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/dokka-integration-tests/gradle/projects/it-wasm-basic/src/wasmMain/kotlin/it/internal/InternalClass.kt b/dokka-integration-tests/gradle/projects/it-wasm-basic/src/wasmMain/kotlin/it/internal/InternalClass.kt
new file mode 100644
index 00000000..7d42b978
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-basic/src/wasmMain/kotlin/it/internal/InternalClass.kt
@@ -0,0 +1,7 @@
+package it.internal
+
+/**
+ * §INTERNAL§
+ * This class is internal and should not be rendered
+ */
+internal class InternalClass
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-basic/src/wasmMain/kotlin/it/suppressedByPackage/SuppressedByPackage.kt b/dokka-integration-tests/gradle/projects/it-wasm-basic/src/wasmMain/kotlin/it/suppressedByPackage/SuppressedByPackage.kt
new file mode 100644
index 00000000..d8dc9cff
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-basic/src/wasmMain/kotlin/it/suppressedByPackage/SuppressedByPackage.kt
@@ -0,0 +1,7 @@
+package it.suppressedByPackage
+
+/**
+ * §SUPPRESSED§
+ * This should not be rendered.
+ */
+class SuppressedByPackage
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-basic/src/wasmMain/kotlin/it/suppressedByPath/SuppressedByPath.kt b/dokka-integration-tests/gradle/projects/it-wasm-basic/src/wasmMain/kotlin/it/suppressedByPath/SuppressedByPath.kt
new file mode 100644
index 00000000..4dda9da4
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-basic/src/wasmMain/kotlin/it/suppressedByPath/SuppressedByPath.kt
@@ -0,0 +1,7 @@
+package it.suppressedByPath
+
+/**
+ * §SUPPRESSED§
+ * This should not be rendered.
+ */
+class SuppressedByPath
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/build.gradle.kts b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/build.gradle.kts
new file mode 100644
index 00000000..7039d483
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/build.gradle.kts
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+import org.jetbrains.dokka.gradle.DokkaTask
+import java.net.URL
+
+plugins {
+ kotlin("multiplatform")
+ id("org.jetbrains.dokka")
+}
+
+apply(from = "../template.root.gradle.kts")
+
+repositories {
+ // Remove it when wasm target will be published into public maven repository
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/wasm/experimental")
+}
+
+kotlin {
+ wasmJs()
+ sourceSets {
+ val wasmJsMain by getting {
+ dependencies {
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-wasm-js:1.7.2-wasm3")
+ implementation("org.jetbrains.kotlinx:atomicfu-wasm-js:0.22.0-wasm2") }
+ }
+ }
+ wasmWasi()
+}
+
+tasks.withType<DokkaTask>().configureEach {
+ dokkaSourceSets {
+ configureEach {
+ externalDocumentationLink {
+ url.set(URL("https://kotlinlang.org/api/kotlinx.coroutines/"))
+ }
+ }
+ }
+}
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/gradle.properties b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/gradle.properties
new file mode 100644
index 00000000..5904fc21
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/gradle.properties
@@ -0,0 +1,5 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+dokka_it_kotlin_version=1.9.20
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/gradle/wrapper/gradle-wrapper.jar b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..f3d88b1c
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/gradle/wrapper/gradle-wrapper.properties b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..1c3c4578
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,9 @@
+#
+# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/gradlew b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/gradlew
new file mode 100755
index 00000000..2fe81a7d
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/gradlew
@@ -0,0 +1,183 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/gradlew.bat b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/gradlew.bat
new file mode 100644
index 00000000..24467a14
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/gradlew.bat
@@ -0,0 +1,100 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/settings.gradle.kts b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/settings.gradle.kts
new file mode 100644
index 00000000..6e268072
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/settings.gradle.kts
@@ -0,0 +1,6 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+apply(from = "../template.settings.gradle.kts")
+rootProject.name = "it-wasm-js-wasi-basic"
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmJsMain/kotlin/RootPackageClass.kt b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmJsMain/kotlin/RootPackageClass.kt
new file mode 100644
index 00000000..a2d05dff
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmJsMain/kotlin/RootPackageClass.kt
@@ -0,0 +1,30 @@
+@file:Suppress("unused")
+
+import org.w3c.dom.HTMLAnchorElement
+import kotlinx.coroutines.CoroutineScope
+
+/**
+ * A class that lives inside the root package
+ */
+class RootPackageClass {
+ val description = "I do live in the root package!"
+}
+
+fun test(list: MutableList<Int>) = "list"
+
+@JsModule("is-sorted")
+@JsNonModule
+external fun <T> sorted(a: Array<T>): Boolean
+
+// this declaration can be used to check deserialization of dynamic type
+external interface TextLinkProps: AnchorHTMLAttributes<HTMLAnchorElement>
+
+// this declaration uses external library and external documentation link
+fun CoroutineScope.externalClass() = "some string"
+
+/**
+ * Some external function with JsFun
+ * @see kotlin.JsFun
+ */
+@kotlin.JsFun("xxx")
+external fun externalFun() \ No newline at end of file
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmJsMain/kotlin/it/basic/PublicClass.kt b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmJsMain/kotlin/it/basic/PublicClass.kt
new file mode 100644
index 00000000..fc4b36bd
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmJsMain/kotlin/it/basic/PublicClass.kt
@@ -0,0 +1,53 @@
+@file:Suppress("unused")
+
+package it.basic
+
+import RootPackageClass
+
+/**
+ * This class, unlike [RootPackageClass] is located in a sub-package
+ */
+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/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmJsMain/kotlin/it/internal/InternalClass.kt b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmJsMain/kotlin/it/internal/InternalClass.kt
new file mode 100644
index 00000000..7d42b978
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmJsMain/kotlin/it/internal/InternalClass.kt
@@ -0,0 +1,7 @@
+package it.internal
+
+/**
+ * §INTERNAL§
+ * This class is internal and should not be rendered
+ */
+internal class InternalClass
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmJsMain/kotlin/it/suppressedByPackage/SuppressedByPackage.kt b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmJsMain/kotlin/it/suppressedByPackage/SuppressedByPackage.kt
new file mode 100644
index 00000000..d8dc9cff
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmJsMain/kotlin/it/suppressedByPackage/SuppressedByPackage.kt
@@ -0,0 +1,7 @@
+package it.suppressedByPackage
+
+/**
+ * §SUPPRESSED§
+ * This should not be rendered.
+ */
+class SuppressedByPackage
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmJsMain/kotlin/it/suppressedByPath/SuppressedByPath.kt b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmJsMain/kotlin/it/suppressedByPath/SuppressedByPath.kt
new file mode 100644
index 00000000..4dda9da4
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmJsMain/kotlin/it/suppressedByPath/SuppressedByPath.kt
@@ -0,0 +1,7 @@
+package it.suppressedByPath
+
+/**
+ * §SUPPRESSED§
+ * This should not be rendered.
+ */
+class SuppressedByPath
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmWasiMain/kotlin/RootPackageClass.kt b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmWasiMain/kotlin/RootPackageClass.kt
new file mode 100644
index 00000000..6735459c
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmWasiMain/kotlin/RootPackageClass.kt
@@ -0,0 +1,10 @@
+@file:Suppress("unused")
+
+/**
+ * A class that lives inside the root package
+ */
+class RootPackageClass {
+ val description = "I do live in the root package!"
+}
+
+fun test(list: MutableList<Int>) = "list" \ No newline at end of file
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmWasiMain/kotlin/it/basic/PublicClass.kt b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmWasiMain/kotlin/it/basic/PublicClass.kt
new file mode 100644
index 00000000..fc4b36bd
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmWasiMain/kotlin/it/basic/PublicClass.kt
@@ -0,0 +1,53 @@
+@file:Suppress("unused")
+
+package it.basic
+
+import RootPackageClass
+
+/**
+ * This class, unlike [RootPackageClass] is located in a sub-package
+ */
+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/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmWasiMain/kotlin/it/internal/InternalClass.kt b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmWasiMain/kotlin/it/internal/InternalClass.kt
new file mode 100644
index 00000000..7d42b978
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmWasiMain/kotlin/it/internal/InternalClass.kt
@@ -0,0 +1,7 @@
+package it.internal
+
+/**
+ * §INTERNAL§
+ * This class is internal and should not be rendered
+ */
+internal class InternalClass
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmWasiMain/kotlin/it/suppressedByPackage/SuppressedByPackage.kt b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmWasiMain/kotlin/it/suppressedByPackage/SuppressedByPackage.kt
new file mode 100644
index 00000000..d8dc9cff
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmWasiMain/kotlin/it/suppressedByPackage/SuppressedByPackage.kt
@@ -0,0 +1,7 @@
+package it.suppressedByPackage
+
+/**
+ * §SUPPRESSED§
+ * This should not be rendered.
+ */
+class SuppressedByPackage
diff --git a/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmWasiMain/kotlin/it/suppressedByPath/SuppressedByPath.kt b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmWasiMain/kotlin/it/suppressedByPath/SuppressedByPath.kt
new file mode 100644
index 00000000..4dda9da4
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/it-wasm-js-wasi-basic/src/wasmWasiMain/kotlin/it/suppressedByPath/SuppressedByPath.kt
@@ -0,0 +1,7 @@
+package it.suppressedByPath
+
+/**
+ * §SUPPRESSED§
+ * This should not be rendered.
+ */
+class SuppressedByPath
diff --git a/dokka-integration-tests/gradle/projects/serialization/kotlinx-serialization b/dokka-integration-tests/gradle/projects/serialization/kotlinx-serialization
new file mode 160000
+Subproject ed1b05707ec27f8864c8b42235b299bdb5e0015
diff --git a/dokka-integration-tests/gradle/projects/serialization/serialization.diff b/dokka-integration-tests/gradle/projects/serialization/serialization.diff
new file mode 100644
index 00000000..cc2eb460
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/serialization/serialization.diff
@@ -0,0 +1,29 @@
+diff --git a/build.gradle b/build.gradle
+index 73b566ae..c7224a7a 100644
+--- a/build.gradle
++++ b/build.gradle
+@@ -76,9 +76,10 @@ buildscript {
+ }
+
+ dependencies {
++ def dokkaVersion = System.getenv('DOKKA_VERSION')
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
+- classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version"
++ classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokkaVersion"
+ classpath "org.jetbrains.kotlinx:kover:$kover_version"
+ classpath "org.jetbrains.kotlinx:binary-compatibility-validator:$validator_version"
+ classpath "org.jetbrains.kotlinx:kotlinx-knit:$knit_version"
+diff --git a/gradle.properties b/gradle.properties
+index 5ef66cd9..7e7323fd 100644
+--- a/gradle.properties
++++ b/gradle.properties
+@@ -13,7 +13,7 @@ kotlin.version.snapshot=1.9.255-SNAPSHOT
+
+ junit_version=4.12
+ jackson_version=2.10.0.pr1
+-dokka_version=1.8.10
++dokka_version=non-existing-sanity-check-SNAPSHOT
+ native.deploy=
+ validator_version=0.13.2
+ knit_version=0.5.0-Beta
diff --git a/dokka-integration-tests/gradle/projects/serialization/template.root.gradle.kts b/dokka-integration-tests/gradle/projects/serialization/template.root.gradle.kts
new file mode 120000
index 00000000..895ca83d
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/serialization/template.root.gradle.kts
@@ -0,0 +1 @@
+../template.root.gradle.kts \ No newline at end of file
diff --git a/dokka-integration-tests/gradle/projects/serialization/template.settings.gradle.kts b/dokka-integration-tests/gradle/projects/serialization/template.settings.gradle.kts
new file mode 120000
index 00000000..7b43b3e7
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/serialization/template.settings.gradle.kts
@@ -0,0 +1 @@
+../template.settings.gradle.kts \ No newline at end of file
diff --git a/dokka-integration-tests/gradle/projects/template.root.gradle.kts b/dokka-integration-tests/gradle/projects/template.root.gradle.kts
new file mode 100644
index 00000000..46cb2d6f
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/template.root.gradle.kts
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+allprojects {
+ repositories {
+ mavenLocal {
+ content {
+ includeGroup("org.jetbrains.dokka")
+ }
+ }
+ mavenCentral()
+ google()
+ maven("https://maven.pkg.jetbrains.space/public/p/kotlinx-html/maven") {
+ content {
+ includeGroup("org.jetbrains.kotlinx")
+ }
+ }
+ }
+}
+
+afterEvaluate {
+ logger.quiet("Gradle version: ${gradle.gradleVersion}")
+ logger.quiet("Kotlin version: ${properties["dokka_it_kotlin_version"]}")
+ logger.quiet("Dokka version: ${properties["dokka_it_dokka_version"]}")
+ properties["dokka_it_android_gradle_plugin_version"]?.let { androidVersion ->
+ logger.quiet("Android version: $androidVersion")
+ }
+}
diff --git a/dokka-integration-tests/gradle/projects/template.settings.gradle.kts b/dokka-integration-tests/gradle/projects/template.settings.gradle.kts
new file mode 100644
index 00000000..9cf3abe7
--- /dev/null
+++ b/dokka-integration-tests/gradle/projects/template.settings.gradle.kts
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+@file:Suppress("LocalVariableName", "UnstableApiUsage")
+
+pluginManagement {
+ val dokka_it_kotlin_version: String by settings
+ val dokka_it_dokka_version: String by settings
+ val dokka_it_android_gradle_plugin_version: String? by settings
+
+ plugins {
+ id("org.jetbrains.kotlin.js") version dokka_it_kotlin_version
+ id("org.jetbrains.kotlin.jvm") version dokka_it_kotlin_version
+ id("org.jetbrains.kotlin.android") version dokka_it_kotlin_version
+ id("org.jetbrains.kotlin.multiplatform") version dokka_it_kotlin_version
+ id("org.jetbrains.dokka") version dokka_it_dokka_version
+ }
+
+ resolutionStrategy {
+ eachPlugin {
+ if (requested.id.id == "org.jetbrains.dokka") {
+ useModule("org.jetbrains.dokka:dokka-gradle-plugin:${System.getenv("DOKKA_VERSION")}")
+ }
+
+ if (requested.id.id == "com.android.library") {
+ useModule("com.android.tools.build:gradle:$dokka_it_android_gradle_plugin_version")
+ }
+
+ if (requested.id.id == "com.android.application") {
+ useModule("com.android.tools.build:gradle:$dokka_it_android_gradle_plugin_version")
+ }
+ }
+ }
+ repositories {
+ mavenLocal {
+ content {
+ includeGroup("org.jetbrains.dokka")
+ }
+ }
+ mavenCentral()
+ gradlePluginPortal()
+ google()
+ }
+}
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(moduleJavaPackageDir.isDirectory, "Missing it.basic.java package directory")
+
+ allHtmlFiles().forEach { file ->
+ assertContainsNoErrorClass(file)
+ assertNoUnresolvedLinks(file)
+ assertNoHrefToMissingLocalFileOrDirectory(file)
+ assertNoEmptyLinks(file)
+ assertNoEmptySpans(file)
+ }
+ }
+
+ private fun File.assertJavadocOutputDir() {
+ assertTrue(isDirectory, "Missing dokka javadoc output directory")
+ }
+
+ private fun File.assertGfmOutputDir() {
+ assertTrue(isDirectory, "Missing dokka gfm output directory")
+ }
+
+ private fun File.assertJekyllOutputDir() {
+ assertTrue(isDirectory, "Missing dokka jekyll output directory")
+ }
+}
diff --git a/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Collector0IntegrationTest.kt b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Collector0IntegrationTest.kt
new file mode 100644
index 00000000..f31cf2bb
--- /dev/null
+++ b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Collector0IntegrationTest.kt
@@ -0,0 +1,83 @@
+/*
+ * 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 Collector0IntegrationTest : AbstractGradleIntegrationTest() {
+
+ @BeforeTest
+ fun prepareProjectFiles() {
+ val templateProjectDir = File("projects", "it-collector-0")
+ templateProjectDir.listFiles().orEmpty()
+ .filter { it.isFile }
+ .forEach { topLevelFile -> topLevelFile.copyTo(File(projectDir, topLevelFile.name)) }
+ File(templateProjectDir, "moduleA").copyRecursively(File(projectDir, "moduleA"))
+ }
+
+ @ParameterizedTest(name = "{0}")
+ @ArgumentsSource(AllSupportedTestedVersionsArgumentsProvider::class)
+ fun execute(buildVersions: BuildVersions) {
+ val result = createGradleRunner(
+ buildVersions,
+ ":moduleA:dokkaHtmlCollector",
+ ":moduleA:dokkaJavadocCollector",
+ ":moduleA:dokkaGfmCollector",
+ ":moduleA:dokkaJekyllCollector",
+ "-i", "-s"
+ ).buildRelaxed()
+
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":moduleA:dokkaHtmlCollector")).outcome)
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":moduleA:dokkaJavadocCollector")).outcome)
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":moduleA:dokkaGfmCollector")).outcome)
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":moduleA:dokkaJekyllCollector")).outcome)
+
+ File(projectDir, "moduleA/build/dokka/htmlCollector").assertHtmlOutputDir()
+ File(projectDir, "moduleA/build/dokka/javadocCollector").assertJavadocOutputDir()
+ File(projectDir, "moduleA/build/dokka/gfmCollector").assertGfmOutputDir()
+ File(projectDir, "moduleA/build/dokka/jekyllCollector").assertJekyllOutputDir()
+ }
+
+ private fun File.assertHtmlOutputDir() {
+ assertTrue(isDirectory, "Missing dokka htmlCollector output directory")
+ allHtmlFiles().forEach { file ->
+ assertContainsNoErrorClass(file)
+ assertNoUnresolvedLinks(file)
+ assertNoHrefToMissingLocalFileOrDirectory(file)
+ assertNoEmptyLinks(file)
+ assertNoEmptySpans(file)
+ }
+
+ assertTrue(
+ allHtmlFiles().any { file -> "moduleB" in file.readText() },
+ "Expected moduleB to be present in html"
+ )
+
+ assertTrue(
+ allHtmlFiles().any { file -> "moduleC" in file.readText() },
+ "Expected moduleC to be present in html"
+ )
+ }
+
+ private fun File.assertJavadocOutputDir() {
+ assertTrue(isDirectory, "Missing dokka javadocCollector output directory")
+ }
+
+ private fun File.assertJekyllOutputDir() {
+ assertTrue(isDirectory, "Missing dokka jekyllCollector output directory")
+ }
+
+ private fun File.assertGfmOutputDir() {
+ assertTrue(isDirectory, "Missing dokka gfmCollector output directory")
+ }
+}
+
diff --git a/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/ConfigurationTest.kt b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/ConfigurationTest.kt
new file mode 100644
index 00000000..99031542
--- /dev/null
+++ b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/ConfigurationTest.kt
@@ -0,0 +1,76 @@
+/*
+ * 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
+
+/**
+ * Tests for Dokka's configuration options of the Gradle runner.
+ *
+ * Options can be checked to work in combination with each other:
+ * for instance, you can check that `reportUndocumented` and `failOnWarning`
+ * work in synergy when both set to true.
+ *
+ * Configuration options can be passed as project properties using Gradle CLI arguments.
+ * For example, passing `-Pname=value` to Gradle will create a project-wide property with
+ * key `name` and value `value`, which you can use to set the corresponding option's value
+ * using Dokka's configuration DSL.
+ */
+class ConfigurationTest : AbstractGradleIntegrationTest() {
+
+ @BeforeTest
+ fun prepareProjectFiles() {
+ val templateProjectDir = File("projects", "it-configuration")
+
+ templateProjectDir.listFiles().orEmpty()
+ .filter { it.isFile }
+ .forEach { topLevelFile -> topLevelFile.copyTo(File(projectDir, topLevelFile.name)) }
+
+ File(templateProjectDir, "src").copyRecursively(File(projectDir, "src"))
+ }
+
+ /**
+ * The test project contains some undocumented declarations, so if both `reportUndocumented`
+ * and `failOnWarning` are enabled - it should fail
+ */
+ @ParameterizedTest(name = "{0}")
+ @ArgumentsSource(LatestTestedVersionsArgumentsProvider::class)
+ @Suppress("FunctionName")
+ fun `should fail with DokkaException and readable message if failOnWarning is triggered`(
+ buildVersions: BuildVersions
+ ) {
+ val result = createGradleRunner(
+ buildVersions,
+ "-info",
+ "-stacktrace",
+ "-Preport_undocumented=true",
+ "-Pfail_on_warning=true",
+ "dokkaHtml"
+ ).buildAndFail()
+
+ assertEquals(TaskOutcome.FAILED, assertNotNull(result.task(":dokkaHtml")).outcome)
+
+ result.output.contains("> Task :dokkaHtml FAILED")
+ result.output.contains(
+ """
+ FAILURE: Build failed with an exception\\.
+
+ \* What went wrong:
+ Execution failed for task ':dokkaHtml'\\.
+ > Failed with warningCount=\d and errorCount=\d
+ """.trimIndent().toRegex()
+ )
+
+ result.output.contains(
+ "Caused by: org\\.jetbrains\\.dokka\\.DokkaException: Failed with warningCount=\\d and errorCount=\\d".toRegex()
+ )
+ }
+}
diff --git a/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/GradleRelocatedCachingIntegrationTest.kt b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/GradleRelocatedCachingIntegrationTest.kt
new file mode 100644
index 00000000..edfdea32
--- /dev/null
+++ b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/GradleRelocatedCachingIntegrationTest.kt
@@ -0,0 +1,38 @@
+/*
+ * 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
+
+class GradleRelocatedCachingIntegrationTest : AbstractGradleCachingIntegrationTest() {
+
+ @ParameterizedTest(name = "{0}")
+ @ArgumentsSource(AllSupportedTestedVersionsArgumentsProvider::class)
+ fun execute(buildVersions: BuildVersions) {
+ setupProject(buildVersions, projectFolder(1))
+ setupProject(buildVersions, projectFolder(2))
+
+ runAndAssertOutcomeAndContents(buildVersions, projectFolder(1), TaskOutcome.SUCCESS)
+ runAndAssertOutcomeAndContents(buildVersions, projectFolder(2), TaskOutcome.FROM_CACHE)
+ }
+
+ private fun runAndAssertOutcomeAndContents(buildVersions: BuildVersions, project: File, expectedOutcome: TaskOutcome) {
+ val result = createGradleRunner(
+ buildVersions,
+ "clean", "dokkaHtml", "-i", "-s", "-Dorg.gradle.caching.debug=true", "--build-cache"
+ ).withProjectDir(project).buildRelaxed()
+
+ assertEquals(expectedOutcome, assertNotNull(result.task(":dokkaHtml")).outcome)
+
+ File(project, "build/dokka/html").assertHtmlOutputDir()
+ }
+
+ private fun projectFolder(index: Int) = File(projectDir.absolutePath + index)
+}
diff --git a/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/JsIRGradleIntegrationTest.kt b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/JsIRGradleIntegrationTest.kt
new file mode 100644
index 00000000..f097807b
--- /dev/null
+++ b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/JsIRGradleIntegrationTest.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package org.jetbrains.dokka.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 JsIRGradleIntegrationTest : AbstractGradleIntegrationTest() {
+
+ private val ignoredKotlinVersions = setOf(
+ // There were some breaking refactoring changes in kotlin react wrapper libs in 1.4.0 -> 1.5.0,
+ // some core react classes were moved from `react-router-dom` to `react` artifacts.
+ // Writing an integration test project that would work for both 1.4.0 and 1.5.0 would involve
+ // ugly solutions, so these versions are ignored. Not a big loss given they are deprecated as of this moment.
+ "1.4.0", "1.4.32"
+ )
+
+ @BeforeTest
+ fun prepareProjectFiles() {
+ val templateProjectDir = File("projects", "it-js-ir-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(AllSupportedTestedVersionsArgumentsProvider::class)
+ fun execute(buildVersions: BuildVersions) {
+ if (ignoredKotlinVersions.contains(buildVersions.kotlinVersion)) {
+ return
+ }
+
+ val reactVersion = TestedVersions.KT_REACT_WRAPPER_MAPPING[buildVersions.kotlinVersion]
+ ?: throw IllegalStateException("Unspecified version of react for kotlin " + buildVersions.kotlinVersion)
+ val result = createGradleRunner(buildVersions, "-Preact_version=$reactVersion", "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)
+ assertNoHrefToMissingLocalFileOrDirectory(file)
+ assertNoUnresolvedLinks(file)
+ assertNoEmptyLinks(file)
+ assertNoEmptySpans(file)
+ }
+ }
+}
diff --git a/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/MultiModule0IntegrationTest.kt b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/MultiModule0IntegrationTest.kt
new file mode 100644
index 00000000..ac97ff9f
--- /dev/null
+++ b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/MultiModule0IntegrationTest.kt
@@ -0,0 +1,103 @@
+/*
+ * 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 MultiModule0IntegrationTest : AbstractGradleIntegrationTest() {
+
+ @BeforeTest
+ fun prepareProjectFiles() {
+ val templateProjectDir = File("projects", "it-multimodule-0")
+ templateProjectDir.listFiles().orEmpty()
+ .filter { it.isFile }
+ .forEach { topLevelFile -> topLevelFile.copyTo(File(projectDir, topLevelFile.name)) }
+ File(templateProjectDir, "moduleA").copyRecursively(File(projectDir, "moduleA"))
+ }
+
+ @ParameterizedTest(name = "{0}")
+ @ArgumentsSource(AllSupportedTestedVersionsArgumentsProvider::class)
+ fun execute(buildVersions: BuildVersions) {
+ val result = createGradleRunner(
+ buildVersions,
+ ":moduleA:dokkaHtmlMultiModule",
+ ":moduleA:dokkaGfmMultiModule",
+ ":moduleA:dokkaJekyllMultiModule",
+ "-i", "-s"
+ ).buildRelaxed()
+
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":moduleA:dokkaHtmlMultiModule")).outcome)
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":moduleA:dokkaGfmMultiModule")).outcome)
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":moduleA:dokkaJekyllMultiModule")).outcome)
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":moduleA:moduleB:dokkaHtmlPartial")).outcome)
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":moduleA:moduleC:dokkaHtmlPartial")).outcome)
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":moduleA:moduleB:dokkaGfmPartial")).outcome)
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":moduleA:moduleC:dokkaGfmPartial")).outcome)
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":moduleA:moduleB:dokkaJekyllPartial")).outcome)
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":moduleA:moduleC:dokkaJekyllPartial")).outcome)
+
+
+ val outputDir = File(projectDir, "moduleA/build/dokka/htmlMultiModule")
+ assertTrue(outputDir.isDirectory, "Missing dokka output directory")
+
+ assertTrue(
+ outputDir.allHtmlFiles().any(),
+ "Expected at least one html file being generated"
+ )
+
+ outputDir.allHtmlFiles().forEach { file ->
+ assertContainsNoErrorClass(file)
+ assertNoUnresolvedLinks(file)
+ assertNoHrefToMissingLocalFileOrDirectory(file)
+ assertNoEmptyLinks(file)
+ assertNoEmptySpans(file)
+ assertNoUnsubstitutedTemplatesInHtml(file)
+ }
+
+ val modulesFile = File(outputDir, "index.html")
+ assertTrue(modulesFile.isFile, "Missing index.html file")
+
+ val modulesFileText = modulesFile.readText()
+ assertTrue(
+ "moduleB" in modulesFileText,
+ "Expected moduleB being mentioned in -modules.html"
+ )
+ assertTrue(
+ "moduleC" in modulesFileText,
+ "Expected moduleC being mentioned in -modules.html"
+ )
+
+ val htmlsWithHomepageLink = outputDir.walkTopDown().filter {
+ it.isFile && it.extension == "html" && it.name != "navigation.html"
+ }.toList()
+
+ assertEquals(16, htmlsWithHomepageLink.size)
+
+ htmlsWithHomepageLink.forEach {
+ assertTrue(
+ it.readText().contains(
+ """https://github.com/Kotlin/dokka/tree/master/dokka-integration-tests/gradle/projects/it-multimodule-0/"""
+ ),
+ "File ${it.absolutePath} doesn't contain link to homepage"
+ )
+ }
+
+ val gfmOutputDir = File(projectDir, "moduleA/build/dokka/gfmMultiModule")
+ assertTrue(gfmOutputDir.isDirectory, "Missing dokka GFM output directory")
+
+ assertTrue(
+ gfmOutputDir.allGfmFiles().any(),
+ "Expected at least one md file being generated"
+ )
+
+ gfmOutputDir.allGfmFiles().forEach { file ->
+ assertFalse("GfmCommand" in file.readText())
+ }
+ }
+}
diff --git a/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/MultiModule1IntegrationTest.kt b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/MultiModule1IntegrationTest.kt
new file mode 100644
index 00000000..59736344
--- /dev/null
+++ b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/MultiModule1IntegrationTest.kt
@@ -0,0 +1,58 @@
+/*
+ * 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
+
+/**
+ * This tests mainly checks if linking to relocated methods with no package works
+ */
+class MultiModule1IntegrationTest : AbstractGradleIntegrationTest() {
+
+ @BeforeTest
+ fun prepareProjectFiles() {
+ val templateProjectDir = File("projects", "it-multimodule-1")
+ templateProjectDir.listFiles().orEmpty()
+ .filter { it.isFile }
+ .forEach { topLevelFile -> topLevelFile.copyTo(File(projectDir, topLevelFile.name)) }
+ File(templateProjectDir, "first").copyRecursively(File(projectDir, "first"))
+ File(templateProjectDir, "second").copyRecursively(File(projectDir, "second"))
+ }
+
+ @ParameterizedTest(name = "{0}")
+ @ArgumentsSource(AllSupportedTestedVersionsArgumentsProvider::class)
+ fun execute(buildVersions: BuildVersions) {
+ val result = createGradleRunner(
+ buildVersions,
+ ":second:dokkaHtml",
+ "-i", "-s"
+ ).buildRelaxed()
+
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":second:dokkaHtml")).outcome)
+
+ val outputDir = File(projectDir, "second/build/dokka/html")
+ assertTrue(outputDir.isDirectory, "Missing dokka output directory")
+
+ assertTrue(
+ outputDir.allHtmlFiles().any(),
+ "Expected at least one html file being generated"
+ )
+
+ outputDir.allHtmlFiles().forEach { file ->
+ assertContainsNoErrorClass(file)
+ assertNoUnresolvedLinks(file)
+ assertNoHrefToMissingLocalFileOrDirectory(file)
+ assertNoEmptyLinks(file)
+ assertNoEmptySpans(file)
+ }
+ }
+}
diff --git a/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Multiplatform0GradleIntegrationTest.kt b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Multiplatform0GradleIntegrationTest.kt
new file mode 100644
index 00000000..d8f5cee2
--- /dev/null
+++ b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Multiplatform0GradleIntegrationTest.kt
@@ -0,0 +1,57 @@
+/*
+ * 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 Multiplatform0GradleIntegrationTest : AbstractGradleIntegrationTest() {
+
+ @BeforeTest
+ fun prepareProjectFiles() {
+ val templateProjectDir = File("projects", "it-multiplatform-0")
+ 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) {
+ // `enableGranularSourceSetsMetadata` and `enableDependencyPropagation` flags are enabled by default since 1.6.20.
+ // remove when this test is executed with Kotlin >= 1.6.20
+ val result = if (buildVersions.kotlinVersion < "1.6.20")
+ createGradleRunner(
+ buildVersions,
+ "dokkaHtml",
+ "-i",
+ "-s",
+ "-Pkotlin.mpp.enableGranularSourceSetsMetadata=true",
+ "-Pkotlin.native.enableDependencyPropagation=false"
+ ).buildRelaxed()
+ else
+ createGradleRunner(buildVersions, "dokkaHtml", "-i", "-s").buildRelaxed()
+
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":dokkaHtml")).outcome)
+
+ val dokkaOutputDir = File(projectDir, "build/dokka/html")
+ assertTrue(dokkaOutputDir.isDirectory, "Missing dokka output directory")
+
+ dokkaOutputDir.allHtmlFiles().forEach { file ->
+ assertContainsNoErrorClass(file)
+ assertNoUnresolvedLinks(file)
+ assertNoHrefToMissingLocalFileOrDirectory(file)
+ assertNoEmptyLinks(file)
+ assertNoEmptySpans(file)
+ }
+ }
+}
diff --git a/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/SequentialTasksExecutionStressTest.kt b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/SequentialTasksExecutionStressTest.kt
new file mode 100644
index 00000000..f331c95c
--- /dev/null
+++ b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/SequentialTasksExecutionStressTest.kt
@@ -0,0 +1,48 @@
+/*
+ * 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
+
+/**
+ * Creates 100 tasks for the test project and runs them sequentially under low memory settings.
+ *
+ * If the test passes, it's likely there are no noticeable memory leaks.
+ * If it fails, it's likely that memory is leaking somewhere.
+ */
+class SequentialTasksExecutionStressTest : AbstractGradleIntegrationTest() {
+
+ @BeforeTest
+ fun prepareProjectFiles() {
+ val templateProjectDir = File("projects", "it-sequential-tasks-execution-stress")
+
+ 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(LatestTestedVersionsArgumentsProvider::class)
+ fun execute(buildVersions: BuildVersions) {
+ val result = createGradleRunner(
+ buildVersions,
+ "runTasks",
+ "--info",
+ "--stacktrace",
+ "-Ptask_number=100",
+ jvmArgs = listOf("-Xmx1G", "-XX:MaxMetaspaceSize=400m")
+ ).buildRelaxed()
+
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":runTasks")).outcome)
+ }
+}
diff --git a/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/TestedVersions.kt b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/TestedVersions.kt
new file mode 100644
index 00000000..7c3ea4df
--- /dev/null
+++ b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/TestedVersions.kt
@@ -0,0 +1,72 @@
+/*
+ * 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.junit.jupiter.api.extension.ExtensionContext
+import org.junit.jupiter.params.provider.Arguments
+import org.junit.jupiter.params.provider.ArgumentsProvider
+import java.util.stream.Stream
+
+internal class LatestTestedVersionsArgumentsProvider : TestedVersionsArgumentsProvider(listOf(TestedVersions.LATEST))
+internal open class AllSupportedTestedVersionsArgumentsProvider : TestedVersionsArgumentsProvider(TestedVersions.ALL_SUPPORTED)
+
+internal object TestedVersions {
+
+ val LATEST = BuildVersions("7.6.2", "1.9.20")
+
+ /**
+ * All supported Gradle/Kotlin versions, including [LATEST]
+ *
+ * [Kotlin/Gradle compatibility matrix](https://docs.gradle.org/current/userguide/compatibility.html#kotlin)
+ */
+ val ALL_SUPPORTED =
+ BuildVersions.permutations(
+ gradleVersions = listOf("7.6.2"),
+ kotlinVersions = listOf("1.9.10", "1.8.20", "1.7.20", "1.6.21", "1.5.31"),
+ ) + BuildVersions.permutations(
+ gradleVersions = listOf(*ifExhaustive("7.0", "6.1.1")),
+ kotlinVersions = listOf(*ifExhaustive( "1.8.0", "1.7.0", "1.6.0", "1.5.0"))
+ ) + LATEST
+
+ /**
+ * Supported Android/Gradle/Kotlin versions, including [LATEST]
+ *
+ * Starting with version 7, major Android Gradle Plugin versions are aligned
+ * with major Gradle versions, i.e AGP 7.X will only work with Gradle 7.X
+ *
+ * [AGP/Gradle compatibility matrix](https://developer.android.com/studio/releases/gradle-plugin#updating-gradle)
+ */
+ val ANDROID =
+ BuildVersions.permutations(
+ gradleVersions = listOf("7.4.2", *ifExhaustive("7.0")),
+ kotlinVersions = listOf("1.7.20", "1.6.21", "1.5.31", "1.4.32"),
+ androidGradlePluginVersions = listOf("7.2.0")
+ ) + BuildVersions.permutations(
+ gradleVersions = listOf("6.9", *ifExhaustive("6.1.1", "5.6.4")),
+ kotlinVersions = listOf("1.8.0", "1.7.0", "1.6.0", "1.5.0", "1.4.0"),
+ androidGradlePluginVersions = listOf("4.0.0", *ifExhaustive("3.6.3"))
+ ) + LATEST
+
+ // https://mvnrepository.com/artifact/org.jetbrains.kotlin-wrappers/kotlin-react
+ val KT_REACT_WRAPPER_MAPPING = mapOf(
+ "1.5.0" to "17.0.2-pre.204-kotlin-1.5.0",
+ "1.6.0" to "17.0.2-pre.280-kotlin-1.6.0",
+ "1.5.31" to "17.0.2-pre.265-kotlin-1.5.31",
+ "1.6.21" to "18.0.0-pre.332-kotlin-1.6.21",
+ "1.7.20" to "18.2.0-pre.391",
+ "1.8.0" to "18.2.0-pre.467",
+ "1.8.10" to "18.2.0-pre.490",
+ "1.8.20" to "18.2.0-pre.546",
+ "1.9.0" to "18.2.0-pre.597",
+ "1.9.10" to "18.2.0-pre.597",
+ "1.9.20" to "18.2.0-pre.635",
+ )
+}
+
+abstract class TestedVersionsArgumentsProvider(private val buildVersions: List<BuildVersions>) : ArgumentsProvider {
+ override fun provideArguments(context: ExtensionContext?): Stream<out Arguments> {
+ return buildVersions.stream().map { Arguments.of(it) }
+ }
+}
diff --git a/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Versioning0IntegrationTest.kt b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Versioning0IntegrationTest.kt
new file mode 100644
index 00000000..381a10e0
--- /dev/null
+++ b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Versioning0IntegrationTest.kt
@@ -0,0 +1,87 @@
+/*
+ * 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.jsoup.Jsoup
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.ArgumentsSource
+import java.io.File
+import kotlin.test.*
+
+class Versioning0IntegrationTest : AbstractGradleIntegrationTest() {
+
+ @BeforeTest
+ fun prepareProjectFiles() {
+ val templateProjectDir = File("projects", "it-multimodule-versioning-0")
+ templateProjectDir.listFiles().orEmpty()
+ .filter { it.isFile }
+ .forEach { topLevelFile -> topLevelFile.copyTo(File(projectDir, topLevelFile.name)) }
+ File(templateProjectDir, "first").copyRecursively(File(projectDir, "first"))
+ File(templateProjectDir, "second").copyRecursively(File(projectDir, "second"))
+ }
+
+ /**
+ * This test runs versioning 3 times to simulate how users might use it in the real word
+ *
+ * Each version has a separate task that has a different version number from 1.0 to 1.2 and is placed under `builDir/dokkas/<version>`
+ *
+ * Output is produced in a standard build directory under `build/dokka/htmlMultiModule`
+ */
+ @ParameterizedTest(name = "{0}")
+ @ArgumentsSource(AllSupportedTestedVersionsArgumentsProvider::class)
+ fun execute(buildVersions: BuildVersions) {
+ val result = createGradleRunner(
+ buildVersions,
+ ":dokkaHtmlMultiModuleBaseVersion",
+ "-i", "-s"
+ ).buildRelaxed()
+
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":dokkaHtmlMultiModuleBaseVersion")).outcome)
+ val outputDir = File(projectDir, "dokkas/1.0")
+ assertTrue(outputDir.isDirectory, "Missing dokka output directory")
+
+ val result2 = createGradleRunner(
+ buildVersions,
+ "clean",
+ ":dokkaHtmlMultiModuleNextVersion",
+ "-i", "-s"
+ ).buildRelaxed()
+
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result2.task(":dokkaHtmlMultiModuleNextVersion")).outcome)
+ val outputDir2 = File(projectDir, "dokkas/1.1")
+ assertTrue(outputDir2.isDirectory, "Missing dokka output directory")
+
+ val result3 = createGradleRunner(
+ buildVersions,
+ "clean",
+ ":dokkaHtmlMultiModule",
+ "-i", "-s"
+ ).buildRelaxed()
+
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result3.task(":dokkaHtmlMultiModule")).outcome)
+ val outputDirMultiModule = File(projectDir, "build/dokka/htmlMultiModule")
+ assertTrue(outputDirMultiModule.isDirectory, "Missing dokka output directory")
+
+ val version1_0 = outputDirMultiModule.resolve("older").resolve("1.0")
+ val version1_1 = outputDirMultiModule.resolve("older").resolve("1.1")
+
+ assertTrue(version1_0.isDirectory, "Assumed to have 1.0 version in older dir")
+ assertTrue(version1_1.isDirectory, "Assumed to have 1.1 version in older dir")
+
+ assertFalse(version1_0.resolve("older").exists(), "Subversions should not have older directory")
+ assertFalse(version1_1.resolve("older").exists(), "Subversions should not have older directory")
+
+ val parsedIndex = Jsoup.parse(outputDirMultiModule.resolve("index.html").readText())
+ val dropdown = parsedIndex.select("dokka-template-command").firstOrNull()
+ assertNotNull(dropdown)
+ val links = dropdown.select("a")
+ assertEquals(3, links.count(), "Expected 3 versions to be in dropdown: 1.0, 1.1 and 1.2")
+ assertEquals(
+ listOf("1.2" to "index.html", "1.1" to "older/1.1/index.html", "1.0" to "older/1.0/index.html"),
+ links.map { it.text() to it.attr("href") }
+ )
+ }
+}
diff --git a/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/WasmGradleIntegrationTest.kt b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/WasmGradleIntegrationTest.kt
new file mode 100644
index 00000000..4280459c
--- /dev/null
+++ b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/WasmGradleIntegrationTest.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package org.jetbrains.dokka.it.gradle
+
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.jupiter.api.extension.ExtensionContext
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.Arguments
+import org.junit.jupiter.params.provider.ArgumentsSource
+import java.io.File
+import java.util.stream.Stream
+import kotlin.test.BeforeTest
+import kotlin.test.assertEquals
+import kotlin.test.assertNotNull
+import kotlin.test.assertTrue
+
+internal class WasmTestedVersionsArgumentsProvider : AllSupportedTestedVersionsArgumentsProvider() {
+ override fun provideArguments(context: ExtensionContext?): Stream<out Arguments> {
+ return super.provideArguments(context).filter {
+ val buildVersions = it.get().single() as BuildVersions
+ buildVersions.kotlinVersion >= "1.8.20" && // 1.8.20 is the first public version that can be tested with wasm
+ buildVersions.kotlinVersion <= "1.9.10"// in 1.9.20 wasm target was split into `wasm-js` and `wasm-wasi`
+ }
+ }
+}
+
+class WasmGradleIntegrationTest : AbstractGradleIntegrationTest() {
+
+ @BeforeTest
+ fun prepareProjectFiles() {
+ val templateProjectDir = File("projects", "it-wasm-basic")
+
+ 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(WasmTestedVersionsArgumentsProvider::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)
+ assertNoHrefToMissingLocalFileOrDirectory(file)
+ assertNoUnresolvedLinks(file)
+ assertNoEmptyLinks(file)
+ assertNoEmptySpans(file)
+ }
+ }
+}
diff --git a/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/WasmJsWasiGradleIntegrationTest.kt b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/WasmJsWasiGradleIntegrationTest.kt
new file mode 100644
index 00000000..11580e03
--- /dev/null
+++ b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/WasmJsWasiGradleIntegrationTest.kt
@@ -0,0 +1,65 @@
+/*
+ * 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.api.extension.ExtensionContext
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.Arguments
+import org.junit.jupiter.params.provider.ArgumentsSource
+import java.io.File
+import java.util.stream.Stream
+import kotlin.test.BeforeTest
+import kotlin.test.assertEquals
+import kotlin.test.assertNotNull
+import kotlin.test.assertTrue
+
+internal class WasmJsWasiTestedVersionsArgumentsProvider : AllSupportedTestedVersionsArgumentsProvider() {
+ override fun provideArguments(context: ExtensionContext?): Stream<out Arguments> {
+ return super.provideArguments(context).filter {
+ val buildVersions = it.get().single() as BuildVersions
+ buildVersions.kotlinVersion >= "1.9.20" // 1.9.20 is the first public version that can be tested with wasm-js and wasm-wasi
+ }
+ }
+}
+
+class WasmJsWasiGradleIntegrationTest : AbstractGradleIntegrationTest() {
+
+ @BeforeTest
+ fun prepareProjectFiles() {
+ val templateProjectDir = File("projects", "it-wasm-js-wasi-basic")
+
+ 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(WasmJsWasiTestedVersionsArgumentsProvider::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)
+ assertNoHrefToMissingLocalFileOrDirectory(file)
+ assertNoUnresolvedLinks(file)
+ assertNoEmptyLinks(file)
+ assertNoEmptySpans(file)
+ }
+ }
+}
diff --git a/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/kotlin/CoroutinesGradleIntegrationTest.kt b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/kotlin/CoroutinesGradleIntegrationTest.kt
new file mode 100644
index 00000000..6f0d9188
--- /dev/null
+++ b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/kotlin/CoroutinesGradleIntegrationTest.kt
@@ -0,0 +1,70 @@
+/*
+ * 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.kotlin
+
+import org.gradle.testkit.runner.TaskOutcome
+import org.jetbrains.dokka.it.TestOutputCopier
+import org.jetbrains.dokka.it.copyAndApplyGitDiff
+import org.jetbrains.dokka.it.gradle.AbstractGradleIntegrationTest
+import org.jetbrains.dokka.it.gradle.BuildVersions
+import org.junit.jupiter.api.extension.ExtensionContext
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.Arguments
+import org.junit.jupiter.params.provider.ArgumentsProvider
+import org.junit.jupiter.params.provider.ArgumentsSource
+import java.io.File
+import java.util.stream.Stream
+import kotlin.test.BeforeTest
+import kotlin.test.assertEquals
+import kotlin.test.assertNotNull
+import kotlin.test.assertTrue
+
+class CoroutinesBuildVersionsArgumentsProvider : ArgumentsProvider {
+ private val buildVersions = BuildVersions.permutations(
+ gradleVersions = listOf("7.4.2"),
+ kotlinVersions = listOf("1.8.10")
+ )
+
+ override fun provideArguments(context: ExtensionContext?): Stream<out Arguments> {
+ return buildVersions.stream().map { Arguments.of(it) }
+ }
+}
+
+class CoroutinesGradleIntegrationTest : AbstractGradleIntegrationTest(), TestOutputCopier {
+
+ override val projectOutputLocation: File by lazy { File(projectDir, "build/dokka/htmlMultiModule") }
+
+ @BeforeTest
+ fun prepareProjectFiles() {
+ val templateProjectDir = File("projects", "coroutines/kotlinx-coroutines")
+ templateProjectDir.listFiles().orEmpty()
+ .forEach { topLevelFile -> topLevelFile.copyRecursively(File(projectDir, topLevelFile.name)) }
+
+ copyAndApplyGitDiff(File("projects", "coroutines/coroutines.diff"))
+ }
+
+ @ParameterizedTest(name = "{0}")
+ @ArgumentsSource(CoroutinesBuildVersionsArgumentsProvider::class)
+ fun execute(buildVersions: BuildVersions) {
+ val result = createGradleRunner(
+ buildVersions,
+ ":dokkaHtmlMultiModule", "-i", "-s",
+ jvmArgs = listOf("-Xmx2G", "-XX:MaxMetaspaceSize=500m")
+ ).buildRelaxed()
+
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":dokkaHtmlMultiModule")).outcome)
+
+ assertTrue(projectOutputLocation.isDirectory, "Missing dokka output directory")
+
+ projectOutputLocation.allHtmlFiles().forEach { file ->
+// assertContainsNoErrorClass(file)
+// assertNoUnresolvedLinks(file)
+// assertNoHrefToMissingLocalFileOrDirectory(file)
+ assertNoEmptyLinks(file)
+ assertNoEmptySpans(file)
+ assertNoUnsubstitutedTemplatesInHtml(file)
+ }
+ }
+}
diff --git a/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/kotlin/SerializationGradleIntegrationTest.kt b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/kotlin/SerializationGradleIntegrationTest.kt
new file mode 100644
index 00000000..ff2849b8
--- /dev/null
+++ b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/kotlin/SerializationGradleIntegrationTest.kt
@@ -0,0 +1,64 @@
+/*
+ * 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.kotlin
+
+import org.gradle.testkit.runner.TaskOutcome
+import org.jetbrains.dokka.it.TestOutputCopier
+import org.jetbrains.dokka.it.copyAndApplyGitDiff
+import org.jetbrains.dokka.it.gradle.AbstractGradleIntegrationTest
+import org.jetbrains.dokka.it.gradle.BuildVersions
+import org.junit.jupiter.api.extension.ExtensionContext
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.Arguments
+import org.junit.jupiter.params.provider.ArgumentsProvider
+import org.junit.jupiter.params.provider.ArgumentsSource
+import java.io.File
+import java.util.stream.Stream
+import kotlin.test.BeforeTest
+import kotlin.test.assertEquals
+import kotlin.test.assertNotNull
+import kotlin.test.assertTrue
+
+class SerializationBuildVersionsArgumentsProvider : ArgumentsProvider {
+ private val buildVersions = BuildVersions.permutations(
+ gradleVersions = listOf("7.6.1"),
+ kotlinVersions = listOf("1.9.0")
+ )
+
+ override fun provideArguments(context: ExtensionContext?): Stream<out Arguments> {
+ return buildVersions.stream().map { Arguments.of(it) }
+ }
+}
+
+class SerializationGradleIntegrationTest : AbstractGradleIntegrationTest(), TestOutputCopier {
+
+ override val projectOutputLocation: File by lazy { File(projectDir, "build/dokka/htmlMultiModule") }
+
+ @BeforeTest
+ fun prepareProjectFiles() {
+ val templateProjectDir = File("projects", "serialization/kotlinx-serialization")
+ templateProjectDir.listFiles().orEmpty()
+ .forEach { topLevelFile -> topLevelFile.copyRecursively(File(projectDir, topLevelFile.name)) }
+ copyAndApplyGitDiff(File("projects", "serialization/serialization.diff"))
+ }
+
+ @ParameterizedTest(name = "{0}")
+ @ArgumentsSource(SerializationBuildVersionsArgumentsProvider::class)
+ fun execute(buildVersions: BuildVersions) {
+ val result = createGradleRunner(buildVersions, ":dokkaHtmlMultiModule", "-i", "-s").buildRelaxed()
+
+ assertEquals(TaskOutcome.SUCCESS, assertNotNull(result.task(":dokkaHtmlMultiModule")).outcome)
+
+ assertTrue(projectOutputLocation.isDirectory, "Missing dokka output directory")
+
+ projectOutputLocation.allHtmlFiles().forEach { file ->
+ assertContainsNoErrorClass(file)
+ assertNoUnresolvedLinks(file)
+// assertNoHrefToMissingLocalFileOrDirectory(file)
+ assertNoEmptyLinks(file)
+ assertNoEmptySpans(file)
+ }
+ }
+}
diff --git a/dokka-integration-tests/gradle/src/main/kotlin/org/jetbrains/dokka/it/gradle/AbstractGradleIntegrationTest.kt b/dokka-integration-tests/gradle/src/main/kotlin/org/jetbrains/dokka/it/gradle/AbstractGradleIntegrationTest.kt
new file mode 100644
index 00000000..5c5d1892
--- /dev/null
+++ b/dokka-integration-tests/gradle/src/main/kotlin/org/jetbrains/dokka/it/gradle/AbstractGradleIntegrationTest.kt
@@ -0,0 +1,84 @@
+/*
+ * 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.BuildResult
+import org.gradle.testkit.runner.GradleRunner
+import org.gradle.testkit.runner.internal.DefaultGradleRunner
+import org.gradle.tooling.GradleConnectionException
+import org.gradle.util.GradleVersion
+import org.jetbrains.dokka.it.AbstractIntegrationTest
+import java.io.File
+import java.net.URI
+import kotlin.test.BeforeTest
+
+public abstract class AbstractGradleIntegrationTest : AbstractIntegrationTest() {
+
+ @BeforeTest
+ public fun copyTemplates() {
+ File("projects").listFiles().orEmpty()
+ .filter { it.isFile }
+ .filter { it.name.startsWith("template.") }
+ .forEach { file -> file.copyTo(File(tempFolder, file.name)) }
+ }
+
+ public fun createGradleRunner(
+ buildVersions: BuildVersions,
+ vararg arguments: String,
+ jvmArgs: List<String> = listOf("-Xmx2G", "-XX:MaxMetaspaceSize=1G")
+ ): GradleRunner {
+ return GradleRunner.create()
+ .withProjectDir(projectDir)
+ .forwardOutput()
+ .withJetBrainsCachedGradleVersion(buildVersions.gradleVersion)
+ .withTestKitDir(File("build", "gradle-test-kit").absoluteFile)
+ .withArguments(
+ listOfNotNull(
+ "-Pdokka_it_dokka_version=${System.getenv("DOKKA_VERSION")}",
+ "-Pdokka_it_kotlin_version=${buildVersions.kotlinVersion}",
+ buildVersions.androidGradlePluginVersion?.let { androidVersion ->
+ "-Pdokka_it_android_gradle_plugin_version=$androidVersion"
+ },
+ * arguments
+ )
+ ).run { this as DefaultGradleRunner }
+ .withJvmArguments(jvmArgs)
+ }
+
+ public fun GradleRunner.buildRelaxed(): BuildResult {
+ return try {
+ build()
+ } catch (e: Throwable) {
+ val gradleConnectionException = e.withAllCauses().find { it is GradleConnectionException }
+ if (gradleConnectionException != null) {
+ gradleConnectionException.printStackTrace()
+ throw IllegalStateException("Assumed Gradle connection", gradleConnectionException)
+
+ }
+ throw e
+ }
+ }
+}
+
+private fun GradleRunner.withJetBrainsCachedGradleVersion(version: GradleVersion): GradleRunner {
+ return withGradleDistribution(
+ URI.create(
+ "https://cache-redirector.jetbrains.com/" +
+ "services.gradle.org/distributions/" +
+ "gradle-${version.version}-bin.zip"
+ )
+ )
+}
+
+private fun Throwable.withAllCauses(): Sequence<Throwable> {
+ val root = this
+ return sequence {
+ yield(root)
+ val cause = root.cause
+ if (cause != null && cause != root) {
+ yieldAll(cause.withAllCauses())
+ }
+ }
+}
diff --git a/dokka-integration-tests/gradle/src/main/kotlin/org/jetbrains/dokka/it/gradle/BuildVersions.kt b/dokka-integration-tests/gradle/src/main/kotlin/org/jetbrains/dokka/it/gradle/BuildVersions.kt
new file mode 100644
index 00000000..ab387420
--- /dev/null
+++ b/dokka-integration-tests/gradle/src/main/kotlin/org/jetbrains/dokka/it/gradle/BuildVersions.kt
@@ -0,0 +1,52 @@
+/*
+ * 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
+
+public data class BuildVersions(
+ val gradleVersion: GradleVersion,
+ val kotlinVersion: String,
+ val androidGradlePluginVersion: String? = null,
+) {
+ public constructor(
+ gradleVersion: String,
+ kotlinVersion: String,
+ androidGradlePluginVersion: String? = null
+ ) : this(
+ gradleVersion = GradleVersion.version(gradleVersion),
+ kotlinVersion = kotlinVersion,
+ androidGradlePluginVersion = androidGradlePluginVersion
+ )
+
+ override fun toString(): String {
+ return buildString {
+ append("Gradle ${gradleVersion.version}, Kotlin $kotlinVersion")
+ if (androidGradlePluginVersion != null) {
+ append(", Android $androidGradlePluginVersion")
+ }
+ }
+ }
+
+ public companion object {
+ public fun permutations(
+ gradleVersions: List<String>,
+ kotlinVersions: List<String>,
+ androidGradlePluginVersions: List<String?> = listOf(null)
+ ): List<BuildVersions> {
+ return gradleVersions.distinct().flatMap { gradleVersion ->
+ kotlinVersions.distinct().flatMap { kotlinVersion ->
+ androidGradlePluginVersions.distinct().map { androidVersion ->
+ BuildVersions(
+ gradleVersion = gradleVersion,
+ kotlinVersion = kotlinVersion,
+ androidGradlePluginVersion = androidVersion
+ )
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/dokka-integration-tests/gradle/src/main/kotlin/org/jetbrains/dokka/it/gradle/TestEnvironment.kt b/dokka-integration-tests/gradle/src/main/kotlin/org/jetbrains/dokka/it/gradle/TestEnvironment.kt
new file mode 100644
index 00000000..174060aa
--- /dev/null
+++ b/dokka-integration-tests/gradle/src/main/kotlin/org/jetbrains/dokka/it/gradle/TestEnvironment.kt
@@ -0,0 +1,18 @@
+/*
+ * 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
+
+public object TestEnvironment {
+ public val isExhaustive: Boolean = checkNotNull(System.getenv("isExhaustive")) {
+ "Missing `isExhaustive` environment variable"
+ }.toBoolean()
+}
+
+/**
+ * Will only return values if [TestEnvironment.isExhaustive] is set to true
+ */
+public inline fun <reified T> ifExhaustive(vararg values: T): Array<out T> {
+ return if (TestEnvironment.isExhaustive) values else emptyArray()
+}
diff --git a/dokka-integration-tests/maven/build.gradle.kts b/dokka-integration-tests/maven/build.gradle.kts
new file mode 100644
index 00000000..6f2acca4
--- /dev/null
+++ b/dokka-integration-tests/maven/build.gradle.kts
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+plugins {
+ id("dokkabuild.test-integration")
+ id("dokkabuild.setup-maven-cli")
+}
+
+dependencies {
+ implementation(projects.utilities)
+
+ implementation(kotlin("test-junit5"))
+ implementation(libs.junit.jupiterApi)
+}
+
+val dokkaSubprojects = gradle.includedBuild("dokka")
+val mavenPlugin = gradle.includedBuild("runner-maven-plugin")
+
+tasks.integrationTest {
+ dependsOn(
+ dokkaSubprojects.task(":publishToMavenLocal"),
+ mavenPlugin.task(":publishToMavenLocal"),
+ )
+
+ dependsOn(tasks.installMavenBinary)
+ val mvn = mavenCliSetup.mvn
+ inputs.file(mvn)
+
+
+ doFirst("workaround for https://github.com/gradle/gradle/issues/24267") {
+ environment("DOKKA_VERSION", project.version)
+ environment("MVN_BINARY_PATH", mvn.get().asFile.invariantSeparatorsPath)
+ }
+}
diff --git a/dokka-integration-tests/maven/projects/biojava/biojava b/dokka-integration-tests/maven/projects/biojava/biojava
new file mode 160000
+Subproject 059fbf1403d0704801df1427b0ec925102a645c
diff --git a/dokka-integration-tests/maven/projects/biojava/biojava.diff b/dokka-integration-tests/maven/projects/biojava/biojava.diff
new file mode 100644
index 00000000..33082722
--- /dev/null
+++ b/dokka-integration-tests/maven/projects/biojava/biojava.diff
@@ -0,0 +1,37 @@
+diff --git a/pom.xml b/pom.xml
+index 7e3e806d1..765b6dea3 100644
+--- a/pom.xml
++++ b/pom.xml
+@@ -31,6 +31,12 @@
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
++ <pluginRepositories>
++ <pluginRepository>
++ <id>space</id>
++ <url>https://maven.pkg.jetbrains.space/public/p/kotlinx-html/maven/</url>
++ </pluginRepository>
++ </pluginRepositories>
+ <properties>
+ <!-- Notice: if using java 9 or 10 jres, it is possible to simply use here "8", "9" or "10". But if using java 8 jre, "8" is not an allowed value but only "1.8"-->
+ <jdk.version>1.8</jdk.version>
+@@ -338,6 +356,19 @@
+
+
+ <plugins>
++ <plugin>
++ <groupId>org.jetbrains.dokka</groupId>
++ <artifactId>dokka-maven-plugin</artifactId>
++ <version>${dokka_version}</version>
++ <executions>
++ <execution>
++ <phase>pre-site</phase>
++ <goals>
++ <goal>javadoc</goal>
++ </goals>
++ </execution>
++ </executions>
++ </plugin>
+
+ <!-- give more memory for junit tests -->
+ <plugin>
diff --git a/dokka-integration-tests/maven/projects/it-maven/customResources/custom-resource.svg b/dokka-integration-tests/maven/projects/it-maven/customResources/custom-resource.svg
new file mode 100644
index 00000000..c4b95383
--- /dev/null
+++ b/dokka-integration-tests/maven/projects/it-maven/customResources/custom-resource.svg
@@ -0,0 +1,7 @@
+<!--
+ - Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ -->
+
+<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M18 9C18 14 14 18 9 18C4 18 0 14 0 9C0 4 4 0 9 0C14 0 18 4 18 9ZM14.2 6.2L12.8 4.8L7.5 10.1L5.3 7.8L3.8 9.2L7.5 13L14.2 6.2Z" fill="#4DBB5F"/>
+</svg>
diff --git a/dokka-integration-tests/maven/projects/it-maven/customResources/custom-style-to-add.css b/dokka-integration-tests/maven/projects/it-maven/customResources/custom-style-to-add.css
new file mode 100644
index 00000000..f949ca1c
--- /dev/null
+++ b/dokka-integration-tests/maven/projects/it-maven/customResources/custom-style-to-add.css
@@ -0,0 +1,5 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+/* custom stylesheet */
diff --git a/dokka-integration-tests/maven/projects/it-maven/customResources/logo-styles.css b/dokka-integration-tests/maven/projects/it-maven/customResources/logo-styles.css
new file mode 100644
index 00000000..c7932753
--- /dev/null
+++ b/dokka-integration-tests/maven/projects/it-maven/customResources/logo-styles.css
@@ -0,0 +1,7 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+:root {
+ --dokka-logo-image-url: url('https://upload.wikimedia.org/wikipedia/commons/9/9d/Ubuntu_logo.svg');
+}
diff --git a/dokka-integration-tests/maven/projects/it-maven/pom.xml b/dokka-integration-tests/maven/projects/it-maven/pom.xml
new file mode 100644
index 00000000..6246e27a
--- /dev/null
+++ b/dokka-integration-tests/maven/projects/it-maven/pom.xml
@@ -0,0 +1,192 @@
+<!--
+ ~ Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.jetbrains.dokka</groupId>
+ <artifactId>it-maven</artifactId>
+ <version>1.0-SNAPSHOT</version>
+
+ <properties>
+ <kotlin.version>1.9.20</kotlin.version>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.jetbrains.kotlin</groupId>
+ <artifactId>kotlin-maven-plugin</artifactId>
+ <version>${kotlin.version}</version>
+ <executions>
+ <execution>
+ <id>compile</id>
+ <goals>
+ <goal>compile</goal>
+ </goals>
+ <configuration>
+ <sourceDirs>
+ <sourceDir>${project.basedir}/src/main/kotlin</sourceDir>
+ <sourceDir>${project.basedir}/src/main/java</sourceDir>
+ </sourceDirs>
+ </configuration>
+ </execution>
+ <execution>
+ <id>test-compile</id>
+ <goals>
+ <goal>test-compile</goal>
+ </goals>
+ <configuration>
+ <sourceDirs>
+ <sourceDir>${project.basedir}/src/test/kotlin</sourceDir>
+ <sourceDir>${project.basedir}/src/test/java</sourceDir>
+ </sourceDirs>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.5.1</version>
+ <executions>
+ <!-- Replacing default-compile as it is treated specially by maven -->
+ <execution>
+ <id>default-compile</id>
+ <phase>none</phase>
+ </execution>
+ <!-- Replacing default-testCompile as it is treated specially by maven -->
+ <execution>
+ <id>default-testCompile</id>
+ <phase>none</phase>
+ </execution>
+ <execution>
+ <id>java-compile</id>
+ <phase>compile</phase>
+ <goals>
+ <goal>compile</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>java-test-compile</id>
+ <phase>test-compile</phase>
+ <goals>
+ <goal>testCompile</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.jetbrains.dokka</groupId>
+ <artifactId>dokka-maven-plugin</artifactId>
+ <version>$dokka_version</version>
+ <executions>
+ <execution>
+ <phase>pre-site</phase>
+ <goals>
+ <goal>dokka</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+
+ <!-- Set to true to skip dokka task, default: false -->
+ <skip>false</skip>
+
+ <!-- Default: ${project.artifactId} -->
+ <moduleName>Maven Integration Test Module</moduleName>
+
+ <!-- Default: ${project.basedir}/target/dokka -->
+ <outputDir>${project.basedir}/output</outputDir>
+
+ <!-- Use default or set to custom path to cache directory to enable package-list caching. -->
+ <!-- When set to default, caches stored in $USER_HOME/.cache/dokka -->
+ <cacheRoot>default</cacheRoot>
+
+
+ <!-- Used for linking to JDK, default: 6 -->
+ <jdkVersion>8</jdkVersion>
+
+ <!-- Do not output deprecated members, applies globally, can be overridden by packageOptions -->
+ <skipDeprecated>false</skipDeprecated>
+ <!-- Emit warnings about not documented members, applies globally, also can be overridden by packageOptions -->
+ <reportUndocumented>true</reportUndocumented>
+ <!-- Do not create index pages for empty packages -->
+ <skipEmptyPackages>true</skipEmptyPackages>
+
+ <!-- Short form list of sourceRoots, by default, set to ${project.compileSourceRoots} -->
+ <sourceDirectories>
+ <dir>${project.basedir}/src/main/kotlin</dir>
+ <dir>${project.basedir}/src/main/java</dir>
+ </sourceDirectories>
+
+ <documentedVisibilities>
+ <visibility>PUBLIC</visibility>
+ <visibility>PROTECTED</visibility>
+ </documentedVisibilities>
+
+ <!-- Disable linking to online kotlin-stdlib documentation -->
+ <noStdlibLink>false</noStdlibLink>
+
+ <!-- Disable linking to online JDK documentation -->
+ <noJdkLink>false</noJdkLink>
+
+ <suppressObviousFunctions>false</suppressObviousFunctions>
+
+ <!-- Allows to customize documentation generation options on a per-package basis -->
+ <perPackageOptions>
+ <packageOptions>
+ <!-- Will match kotlin and all sub-packages of it -->
+ <matchingRegex>kotlin</matchingRegex>
+
+ <!-- All options are optional, default values are below: -->
+ <skipDeprecated>false</skipDeprecated>
+ <!-- Emit warnings about not documented members -->
+ <reportUndocumented>true</reportUndocumented>
+ <includeNonPublic>false</includeNonPublic>
+ </packageOptions>
+
+ <packageOptions>
+ <matchingRegex>it.overriddenVisibility.*</matchingRegex>
+ <documentedVisibilities>
+ <visibility>PRIVATE</visibility>
+ </documentedVisibilities>
+ </packageOptions>
+ </perPackageOptions>
+ <pluginsConfiguration>
+ <org.jetbrains.dokka.base.DokkaBase>
+ <customAssets>
+ <customAsset>${project.basedir}/customResources/custom-resource.svg</customAsset>
+ </customAssets>
+ <customStyleSheets>
+ <customStyleSheet>${project.basedir}/customResources/logo-styles.css</customStyleSheet>
+ <customStyleSheet>${project.basedir}/customResources/custom-style-to-add.css</customStyleSheet>
+ </customStyleSheets>
+ </org.jetbrains.dokka.base.DokkaBase>
+ </pluginsConfiguration>
+ </configuration>
+ </plugin>
+ </plugins>
+ <sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
+ <testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
+ </build>
+
+ <pluginRepositories>
+ <pluginRepository>
+ <id>Space</id>
+ <name>Space</name>
+ <url>https://maven.pkg.jetbrains.space/public/p/kotlinx-html/maven/</url>
+ </pluginRepository>
+ </pluginRepositories>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.jetbrains.kotlin</groupId>
+ <artifactId>kotlin-stdlib</artifactId>
+ <version>${kotlin.version}</version>
+ </dependency>
+ </dependencies>
+
+
+</project>
diff --git a/dokka-integration-tests/maven/projects/it-maven/src/main/java/it/basic/java/SampleJavaClass.java b/dokka-integration-tests/maven/projects/it-maven/src/main/java/it/basic/java/SampleJavaClass.java
new file mode 100644
index 00000000..e08bb66a
--- /dev/null
+++ b/dokka-integration-tests/maven/projects/it-maven/src/main/java/it/basic/java/SampleJavaClass.java
@@ -0,0 +1,22 @@
+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();
+ }
+
+
+ public PublicClass publicUndocumentedFunction() {
+ return new PublicClass();
+ }
+}
diff --git a/dokka-integration-tests/maven/projects/it-maven/src/main/kotlin/it/basic/PublicClass.kt b/dokka-integration-tests/maven/projects/it-maven/src/main/kotlin/it/basic/PublicClass.kt
new file mode 100644
index 00000000..d7a72392
--- /dev/null
+++ b/dokka-integration-tests/maven/projects/it-maven/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/maven/projects/it-maven/src/main/kotlin/it/internal/InternalClass.kt b/dokka-integration-tests/maven/projects/it-maven/src/main/kotlin/it/internal/InternalClass.kt
new file mode 100644
index 00000000..6173d239
--- /dev/null
+++ b/dokka-integration-tests/maven/projects/it-maven/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
diff --git a/dokka-integration-tests/maven/projects/it-maven/src/main/kotlin/it/overriddenVisibility/VisiblePrivateClass.kt b/dokka-integration-tests/maven/projects/it-maven/src/main/kotlin/it/overriddenVisibility/VisiblePrivateClass.kt
new file mode 100644
index 00000000..230f5e0b
--- /dev/null
+++ b/dokka-integration-tests/maven/projects/it-maven/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/maven/projects/it-maven/src/main/kotlin/it/protected/ProtectedClass.kt b/dokka-integration-tests/maven/projects/it-maven/src/main/kotlin/it/protected/ProtectedClass.kt
new file mode 100644
index 00000000..ad19f1a1
--- /dev/null
+++ b/dokka-integration-tests/maven/projects/it-maven/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/maven/src/integrationTest/kotlin/org/jetbrains/dokka/it/maven/BiojavaIntegrationTest.kt b/dokka-integration-tests/maven/src/integrationTest/kotlin/org/jetbrains/dokka/it/maven/BiojavaIntegrationTest.kt
new file mode 100644
index 00000000..7987d45e
--- /dev/null
+++ b/dokka-integration-tests/maven/src/integrationTest/kotlin/org/jetbrains/dokka/it/maven/BiojavaIntegrationTest.kt
@@ -0,0 +1,63 @@
+/*
+ * 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.maven
+
+import org.jetbrains.dokka.it.*
+import java.io.File
+import kotlin.test.BeforeTest
+import kotlin.test.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertTrue
+
+class BiojavaIntegrationTest : AbstractIntegrationTest(), TestOutputCopier {
+
+ private val currentDokkaVersion: String = checkNotNull(System.getenv("DOKKA_VERSION"))
+ private val mavenBinaryFile: File = File(checkNotNull(System.getenv("MVN_BINARY_PATH")))
+ override val projectOutputLocation: File by lazy { File(projectDir, "biojava-core/target/dokkaJavadoc") }
+
+ @BeforeTest
+ fun prepareProjectFiles() {
+ val templateProjectDir = File("projects", "biojava/biojava")
+ templateProjectDir.copyRecursively(projectDir)
+ val customResourcesDir = File(templateProjectDir, "custom Resources")
+ if (customResourcesDir.exists() && customResourcesDir.isDirectory) {
+ customResourcesDir.copyRecursively(File(projectDir, "customResources"), overwrite = true)
+ }
+ copyAndApplyGitDiff(File("projects", "biojava/biojava.diff"))
+ }
+
+ @Test
+ fun `dokka javadoc`() {
+ val result = ProcessBuilder().directory(projectDir)
+ .command(mavenBinaryFile.absolutePath, "dokka:javadoc", "-pl", "biojava-core", "\"-Ddokka_version=$currentDokkaVersion\"", "-U", "-e").start().awaitProcessResult()
+
+ diagnosticAsserts(result)
+
+ assertTrue(projectOutputLocation.isDirectory, "Missing dokka output directory")
+
+ val scriptsDir = File(projectOutputLocation, "jquery")
+ assertTrue(scriptsDir.isDirectory, "Missing jquery directory")
+
+ val stylesDir = File(projectOutputLocation, "resources")
+ assertTrue(stylesDir.isDirectory, "Missing resources directory")
+
+ projectDir.allHtmlFiles().forEach { file ->
+ assertContainsNoErrorClass(file)
+ assertNoUnresolvedLinks(file)
+ }
+ }
+
+ private fun diagnosticAsserts(result: ProcessResult) {
+ 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)"
+ )
+ }
+}
diff --git a/dokka-integration-tests/maven/src/integrationTest/kotlin/org/jetbrains/dokka/it/maven/MavenIntegrationTest.kt b/dokka-integration-tests/maven/src/integrationTest/kotlin/org/jetbrains/dokka/it/maven/MavenIntegrationTest.kt
new file mode 100644
index 00000000..7606072c
--- /dev/null
+++ b/dokka-integration-tests/maven/src/integrationTest/kotlin/org/jetbrains/dokka/it/maven/MavenIntegrationTest.kt
@@ -0,0 +1,219 @@
+/*
+ * 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.maven
+
+import org.intellij.lang.annotations.Language
+import org.jetbrains.dokka.it.AbstractIntegrationTest
+import org.jetbrains.dokka.it.ProcessResult
+import org.jetbrains.dokka.it.awaitProcessResult
+import java.io.File
+import kotlin.test.*
+
+class MavenIntegrationTest : AbstractIntegrationTest() {
+
+ private val currentDokkaVersion: String = checkNotNull(System.getenv("DOKKA_VERSION"))
+
+ private val mavenBinaryFile: File = File(checkNotNull(System.getenv("MVN_BINARY_PATH")))
+
+ @BeforeTest
+ fun prepareProjectFiles() {
+ val templateProjectDir = File("projects", "it-maven")
+ templateProjectDir.copyRecursively(projectDir)
+ val pomXml = File(projectDir, "pom.xml")
+ assertTrue(pomXml.isFile)
+ pomXml.apply {
+ writeText(readText().replace("\$dokka_version", currentDokkaVersion))
+ }
+ val customResourcesDir = File(templateProjectDir, "customResources")
+ if (customResourcesDir.exists() && customResourcesDir.isDirectory) {
+ customResourcesDir.copyRecursively(File(projectDir, "customResources"), overwrite = true)
+ }
+ }
+
+ @Test
+ fun `dokka help`() {
+ val result = ProcessBuilder().directory(projectDir)
+ .command(mavenBinaryFile.absolutePath, "dokka:help", "-U", "-e")
+ .start()
+ .awaitProcessResult()
+
+ // format the output to remove blank lines and make newlines system-independent
+ val output = result.output.lines().filter { it.isNotBlank() }.joinToString("\n")
+
+ assertContains(
+ output,
+ """
+ |This plugin has 4 goals:
+ |dokka:dokka
+ |dokka:help
+ |dokka:javadoc
+ |dokka:javadocJar
+ """.trimMargin()
+ )
+ }
+
+ @Test
+ fun `dokka dokka`() {
+ val result = ProcessBuilder().directory(projectDir)
+ .command(mavenBinaryFile.absolutePath, "dokka:dokka", "-U", "-e").start().awaitProcessResult()
+
+ diagnosticAsserts(result)
+
+ val dokkaOutputDir = File(projectDir, "output")
+ 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)
+ }
+
+ 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)
+ projectDir.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(stylesDir.resolve("custom-style-to-add.css").readText().contains("""/* custom stylesheet */"""))
+ assertTrue(imagesDir.resolve("custom-resource.svg").isFile)
+
+ assertConfiguredVisibility(projectDir)
+ }
+
+ @Test
+ fun `dokka javadoc`() {
+ val result = ProcessBuilder().directory(projectDir)
+ .command(mavenBinaryFile.absolutePath, "dokka:javadoc", "-U", "-e").start().awaitProcessResult()
+
+ diagnosticAsserts(result)
+
+ val dokkaOutputDir = File(projectDir, "output")
+ assertTrue(dokkaOutputDir.isDirectory, "Missing dokka output directory")
+
+ val scriptsDir = File(dokkaOutputDir, "jquery")
+ assertTrue(scriptsDir.isDirectory, "Missing jquery directory")
+
+ val stylesDir = File(dokkaOutputDir, "resources")
+ assertTrue(stylesDir.isDirectory, "Missing resources directory")
+
+ projectDir.allHtmlFiles().forEach { file ->
+ assertContainsNoErrorClass(file)
+ assertNoUnresolvedLinks(file)
+ }
+ }
+
+ @Test
+ fun `dokka javadocJar`() {
+ val result = ProcessBuilder().directory(projectDir)
+ .command(mavenBinaryFile.absolutePath, "dokka:javadocJar", "-U", "-e").start().awaitProcessResult()
+
+ diagnosticAsserts(result)
+
+ val dokkaOutputDir = File(projectDir, "output")
+ assertTrue(dokkaOutputDir.isDirectory, "Missing dokka output directory")
+
+ val scriptsDir = File(dokkaOutputDir, "jquery")
+ assertTrue(scriptsDir.isDirectory, "Missing jquery directory")
+
+ val stylesDir = File(dokkaOutputDir, "resources")
+ assertTrue(stylesDir.isDirectory, "Missing resources directory")
+
+ val dokkaTargetDir = File(projectDir, "target")
+ assertTrue(dokkaOutputDir.isDirectory, "Missing dokka target directory")
+
+ val jarFile = File(dokkaTargetDir, "it-maven-1.0-SNAPSHOT-javadoc.jar")
+ assertTrue(jarFile.isFile, "Missing dokka jar file")
+
+ projectDir.allHtmlFiles().forEach { file ->
+ assertContainsNoErrorClass(file)
+ assertNoUnresolvedLinks(file)
+ }
+ }
+
+ private fun diagnosticAsserts(result: ProcessResult) {
+ 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)"
+ )
+
+ val undocumentedJavaReportRegex = Regex("""Undocumented: it\.basic\.java""")
+ val amountOfUndocumentedJavaReports = undocumentedJavaReportRegex.findAll(result.output).count()
+ assertTrue(
+ amountOfUndocumentedJavaReports > 0,
+ "Expected at least one report of undocumented java code (found $amountOfUndocumentedJavaReports)"
+ )
+ }
+
+ private fun assertConfiguredVisibility(projectDir: File) {
+ val projectHtmlFiles = projectDir.allHtmlFiles().toList()
+
+ assertContentVisibility(
+ contentFiles = projectHtmlFiles,
+ documentPublic = true,
+ documentProtected = true, // sourceSet documentedVisibilities
+ documentInternal = false,
+ documentPrivate = true // for overriddenVisibility package
+ )
+
+ assertContainsFilePaths(
+ outputFiles = projectHtmlFiles,
+ 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"),
+ )
+ )
+ }
+
+ companion object {
+ /*
+ * TODO replace with kotlin.test.assertContains after migrating to Kotlin language version 1.5+
+ */
+ fun assertContains(
+ charSequence: CharSequence,
+ @Language("TEXT") other: CharSequence,
+ ignoreCase: Boolean = false
+ ) {
+ asserter.assertTrue(
+ { "Expected the char sequence to contain the substring.\nCharSequence <$charSequence>, substring <$other>, ignoreCase <$ignoreCase>." },
+ charSequence.contains(other, ignoreCase)
+ )
+ }
+ }
+}
diff --git a/dokka-integration-tests/settings.gradle.kts b/dokka-integration-tests/settings.gradle.kts
new file mode 100644
index 00000000..07f1f59d
--- /dev/null
+++ b/dokka-integration-tests/settings.gradle.kts
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+@file:Suppress("UnstableApiUsage")
+
+rootProject.name = "dokka-integration-tests"
+
+pluginManagement {
+ includeBuild("../build-logic")
+
+ repositories {
+ gradlePluginPortal()
+ mavenCentral()
+ }
+}
+
+dependencyResolutionManagement {
+ repositories {
+ mavenCentral()
+ }
+
+ versionCatalogs {
+ create("libs") {
+ from(files("../gradle/libs.versions.toml"))
+ }
+ }
+}
+
+includeBuild("../dokka-runners/runner-gradle-plugin-classic")
+includeBuild("../dokka-runners/runner-maven-plugin")
+includeBuild("../dokka-runners/runner-cli")
+includeBuild("../.") // include the very root aggregating build so that we can depend on its tasks
+
+include(
+ ":cli",
+ ":gradle",
+ ":maven",
+ ":utilities",
+)
+
+enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
diff --git a/dokka-integration-tests/utilities/build.gradle.kts b/dokka-integration-tests/utilities/build.gradle.kts
new file mode 100644
index 00000000..a0337a40
--- /dev/null
+++ b/dokka-integration-tests/utilities/build.gradle.kts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+plugins {
+ id("dokkabuild.kotlin-jvm")
+}
+
+dependencies {
+ // Classes from src rely on JUnit's @TempDir and Kotlin's @AfterTest,
+ // thus these dependencies are needed. Ideally, they should be removed.
+ implementation(kotlin("test-junit5"))
+
+ implementation(libs.kotlinx.coroutines.core)
+ implementation(libs.jsoup)
+ implementation(libs.eclipse.jgit)
+}
diff --git a/dokka-integration-tests/utilities/src/main/kotlin/org/jetbrains/dokka/it/AbstractIntegrationTest.kt b/dokka-integration-tests/utilities/src/main/kotlin/org/jetbrains/dokka/it/AbstractIntegrationTest.kt
new file mode 100644
index 00000000..ec96ac01
--- /dev/null
+++ b/dokka-integration-tests/utilities/src/main/kotlin/org/jetbrains/dokka/it/AbstractIntegrationTest.kt
@@ -0,0 +1,168 @@
+/*
+ * 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 org.jsoup.Jsoup
+import org.junit.jupiter.api.io.TempDir
+import java.io.File
+import java.net.URL
+import kotlin.test.assertEquals
+import kotlin.test.assertFalse
+import kotlin.test.assertNotNull
+import kotlin.test.assertTrue
+
+public abstract class AbstractIntegrationTest {
+
+ @field:TempDir
+ public lateinit var tempFolder: File
+
+ public val projectDir: File get() = File(tempFolder, "project")
+
+ public fun File.allDescendentsWithExtension(extension: String): Sequence<File> =
+ this.walkTopDown().filter { it.isFile && it.extension == extension }
+
+ public fun File.allHtmlFiles(): Sequence<File> = allDescendentsWithExtension("html")
+
+ public fun File.allGfmFiles(): Sequence<File> = allDescendentsWithExtension("md")
+
+ 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 assertNoEmptyLinks(file: File) {
+ val regex = Regex("[\"']#[\"']")
+ val fileText = file.readText()
+ assertFalse(
+ fileText.contains(regex),
+ "Unexpected empty link in ${file.path}\n" + fileText
+ )
+ }
+
+ protected fun assertNoUnresolvedLinks(file: File, exceptions: Set<String> = emptySet()) {
+ val fileText = file.readText()
+ val regex = Regex("""data-unresolved-link="\[(.+?(?=]"))""")
+ val match = regex.findAll(fileText).map { it.groups[1]!!.value }
+
+ assertTrue(
+ match.filterNot { it in exceptions }.toList().isEmpty(),
+ "Unexpected unresolved link in ${file.path}\n" + fileText
+ )
+ }
+
+ protected fun assertNoHrefToMissingLocalFileOrDirectory(
+ file: File, fileExtensions: Set<String> = setOf("html")
+ ) {
+ val fileText = file.readText()
+ val html = Jsoup.parse(fileText)
+ html.allElements.toList().forEach { element ->
+ val href = element.attr("href")
+ if (href.startsWith("https")) return@forEach
+ if (href.startsWith("http")) return@forEach
+
+ val hrefWithoutAnchors = if (href.contains("#")) {
+ val hrefSplits = href.split("#")
+ if (hrefSplits.count() != 2) return@forEach
+ hrefSplits.first()
+ } else href
+
+ val targetFile = if (href.startsWith("file:/")) {
+ File(URL(hrefWithoutAnchors).path)
+ } else {
+ File(file.parent, hrefWithoutAnchors)
+ }
+
+ if (targetFile.extension.isNotEmpty() && targetFile.extension !in fileExtensions) return@forEach
+
+ if (targetFile.extension.isEmpty() || targetFile.extension == "html" && !href.startsWith("#")) {
+ assertTrue(
+ targetFile.exists(),
+ "${file.relativeTo(projectDir).path}: href=\"$href\"\n" +
+ "file does not exist: ${targetFile.path}"
+ )
+ }
+ }
+ }
+
+ protected fun assertNoSuppressedMarker(file: File) {
+ val fileText = file.readText()
+ assertFalse(
+ fileText.contains("§SUPPRESSED§"),
+ "Unexpected `§SUPPRESSED§` in file ${file.path}"
+ )
+ }
+
+ protected fun assertNoEmptySpans(file: File) {
+ val fileText = file.readText()
+ assertFalse(
+ fileText.contains(Regex("""<span>\s*</span>""")),
+ "Unexpected empty <span></span> in file ${file.path}"
+ )
+ }
+
+ protected fun assertNoUnsubstitutedTemplatesInHtml(file: File) {
+ val parsedFile = Jsoup.parse(file, "UTF-8")
+ assertTrue(
+ parsedFile.select("dokka-template-command").isEmpty(),
+ "Expected all templates to be substituted"
+ )
+ }
+
+ /**
+ * Asserts that [contentFiles] have no pages where content contains special visibility markers,
+ * such as §INTERNAL§ for `internal`, §PROTECTED§ for `protected` and §PRIVATE§ for `private` modifiers
+ *
+ * This can be used to check whether actual documented code corresponds to configured documented visibility
+ *
+ * @param contentFiles any readable content file such as html/md/rst/etc
+ */
+ protected fun assertContentVisibility(
+ contentFiles: List<File>,
+ documentPublic: Boolean,
+ documentProtected: Boolean,
+ documentInternal: Boolean,
+ documentPrivate: Boolean
+ ) {
+ val hasPublic = contentFiles.any { file -> "§PUBLIC§" in file.readText() }
+ assertEquals(documentPublic, hasPublic, "Expected content visibility and file content do not match for public")
+
+ val hasInternal = contentFiles.any { file -> "§INTERNAL§" in file.readText() }
+ assertEquals(
+ documentInternal,
+ hasInternal,
+ "Expected content visibility and file content do not match for internal"
+ )
+
+ val hasProtected = contentFiles.any { file -> "§PROTECTED§" in file.readText() }
+ assertEquals(
+ documentProtected,
+ hasProtected,
+ "Expected content visibility and file content do not match for protected"
+ )
+
+ val hasPrivate = contentFiles.any { file -> "§PRIVATE§" in file.readText() }
+ assertEquals(
+ documentPrivate,
+ hasPrivate,
+ "Expected content visibility and file content do not match for private"
+ )
+ }
+
+ /**
+ * Check that [outputFiles] contain specific file paths provided in [expectedFilePaths].
+ * Can be used for checking whether expected folders/pages have been created.
+ */
+ protected fun assertContainsFilePaths(outputFiles: List<File>, expectedFilePaths: List<Regex>) {
+ expectedFilePaths.forEach { pathRegex ->
+ assertNotNull(
+ outputFiles.any { it.absolutePath.contains(pathRegex) },
+ "Expected to find a file with path regex $pathRegex, but found nothing"
+ )
+ }
+ }
+}
diff --git a/dokka-integration-tests/utilities/src/main/kotlin/org/jetbrains/dokka/it/TestOutputCopier.kt b/dokka-integration-tests/utilities/src/main/kotlin/org/jetbrains/dokka/it/TestOutputCopier.kt
new file mode 100644
index 00000000..2e2113a9
--- /dev/null
+++ b/dokka-integration-tests/utilities/src/main/kotlin/org/jetbrains/dokka/it/TestOutputCopier.kt
@@ -0,0 +1,20 @@
+/*
+ * 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.io.File
+import kotlin.test.AfterTest
+
+public interface TestOutputCopier {
+ public val projectOutputLocation: File
+
+ @AfterTest
+ public fun copyToLocation() {
+ System.getenv("DOKKA_TEST_OUTPUT_PATH")?.also { location ->
+ println("Copying to ${File(location).absolutePath}")
+ projectOutputLocation.copyRecursively(File(location))
+ } ?: println("No path via env. variable 'DOKKA_TEST_OUTPUT_PATH' provided, skipping copying")
+ }
+}
diff --git a/dokka-integration-tests/utilities/src/main/kotlin/org/jetbrains/dokka/it/gitSubmoduleUtils.kt b/dokka-integration-tests/utilities/src/main/kotlin/org/jetbrains/dokka/it/gitSubmoduleUtils.kt
new file mode 100644
index 00000000..f8f103be
--- /dev/null
+++ b/dokka-integration-tests/utilities/src/main/kotlin/org/jetbrains/dokka/it/gitSubmoduleUtils.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package org.jetbrains.dokka.it
+
+import org.eclipse.jgit.api.Git
+import org.eclipse.jgit.storage.file.FileRepositoryBuilder
+import java.io.File
+import java.nio.file.Path
+
+public fun AbstractIntegrationTest.copyAndApplyGitDiff(diffFile: File) {
+ copyGitDiffFileToParent(diffFile).let(::applyGitDiffFromFile)
+}
+
+public fun AbstractIntegrationTest.copyGitDiffFileToParent(originalDiffFile: File): File =
+ originalDiffFile.copyTo(File(projectDir.parent, originalDiffFile.name))
+
+public fun AbstractIntegrationTest.applyGitDiffFromFile(diffFile: File) {
+ val projectGitFile = projectDir.resolve(".git")
+ val git = if (projectGitFile.exists()) {
+ if (projectGitFile.isFile) {
+ println(".git file inside project directory exists, removing")
+ removeGitFile(projectDir.toPath())
+ Git.init().setDirectory(projectDir).call()
+ } else {
+ println(".git directory inside project directory exists, reusing")
+ FileRepositoryBuilder().apply {
+ isMustExist = true
+ gitDir = projectDir
+ }.let { Git(it.build()) }
+ }
+ } else {
+ Git.init().setDirectory(projectDir).call()
+ }
+ git.apply().setPatch(diffFile.inputStream()).call()
+}
+
+private fun removeGitFile(repository: Path) =
+ repository.toFile()
+ .listFiles().orEmpty()
+ .filter { it.name.equals(".git", ignoreCase = true) }
+ .forEach { it.delete() }
diff --git a/dokka-integration-tests/utilities/src/main/kotlin/org/jetbrains/dokka/it/processUtils.kt b/dokka-integration-tests/utilities/src/main/kotlin/org/jetbrains/dokka/it/processUtils.kt
new file mode 100644
index 00000000..06b8b1e3
--- /dev/null
+++ b/dokka-integration-tests/utilities/src/main/kotlin/org/jetbrains/dokka/it/processUtils.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package org.jetbrains.dokka.it
+
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.async
+import kotlinx.coroutines.runBlocking
+import kotlin.concurrent.thread
+
+public class ProcessResult(
+ public val exitCode: Int,
+ public val output: String
+)
+
+public fun Process.awaitProcessResult(): ProcessResult = 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()
+}