Skip to content

Commit

Permalink
Compare DokkaSourceSetImpl by DokkaSourceSetID only (#3568)
Browse files Browse the repository at this point in the history
* Make SourceSet equals/hashCode use only it's ID
* Add checker that all sourceSet ids are unique during generation
* `verificationStage` should always run in tests
* `verificationStage` should run as a first step as in `SingleModuleGeneration::generate` in tests
* Add structural assertions over `DokkaSourceSet` and `DokkaConfiguration` for tests
* rename `dokka-test-api` Gradle project name for composite builds support
  • Loading branch information
whyoleg committed Apr 19, 2024
1 parent ff4c2d0 commit f524273
Show file tree
Hide file tree
Showing 36 changed files with 285 additions and 42 deletions.
Expand Up @@ -161,5 +161,13 @@ internal fun parseSourceSet(moduleName: String, args: Array<String>): DokkaConfi
override val suppressedFiles = suppressedFiles.toMutableSet()
override val documentedVisibilities: Set<DokkaConfiguration.Visibility> = documentedVisibilities.toSet()
.ifEmpty { DokkaDefaults.documentedVisibilities }

override fun equals(other: Any?): Boolean {
return sourceSetID == (other as? DokkaConfiguration.DokkaSourceSet)?.sourceSetID
}

override fun hashCode(): Int {
return sourceSetID.hashCode()
}
}
}
Expand Up @@ -25,6 +25,7 @@ dependencies {
testImplementation(libs.gradlePlugin.kotlin)
testImplementation(libs.gradlePlugin.kotlin.klibCommonizerApi)
testImplementation(libs.gradlePlugin.android)
testImplementation("org.jetbrains.dokka:dokka-test-api:$version")
}

@Suppress("UnstableApiUsage")
Expand Down
Expand Up @@ -12,6 +12,7 @@ import org.jetbrains.dokka.PluginConfigurationImpl
import org.jetbrains.dokka.gradle.utils.create_
import org.jetbrains.dokka.gradle.utils.externalDocumentationLink_
import org.jetbrains.dokka.gradle.utils.withDependencies_
import org.jetbrains.dokka.testApi.assertDokkaConfigurationEquals
import org.jetbrains.dokka.toCompactJsonString
import java.io.File
import java.net.URI
Expand Down Expand Up @@ -66,7 +67,7 @@ class DokkaConfigurationJsonTest {
val configurationJson = sourceConfiguration.toCompactJsonString()
val parsedConfiguration = DokkaConfigurationImpl(configurationJson)

assertEquals(sourceConfiguration, parsedConfiguration)
assertDokkaConfigurationEquals(sourceConfiguration, parsedConfiguration)
println(parsedConfiguration)
}
}
Expand Up @@ -11,6 +11,7 @@ import org.jetbrains.dokka.PluginConfigurationImpl
import org.jetbrains.dokka.gradle.utils.create_
import org.jetbrains.dokka.gradle.utils.externalDocumentationLink_
import org.jetbrains.dokka.gradle.utils.withDependencies_
import org.jetbrains.dokka.testApi.assertDokkaConfigurationEquals
import org.junit.jupiter.api.io.TempDir
import java.io.File
import java.io.ObjectInputStream
Expand Down Expand Up @@ -73,6 +74,6 @@ class DokkaConfigurationSerializableTest {
stream.readObject() as DokkaConfiguration
}

assertEquals(sourceConfiguration, parsedConfiguration)
assertDokkaConfigurationEquals(sourceConfiguration, parsedConfiguration)
}
}
Expand Up @@ -16,6 +16,7 @@ import org.jetbrains.dokka.gradle.utils.all_
import org.jetbrains.dokka.gradle.utils.allprojects_
import org.jetbrains.dokka.gradle.utils.configureEach_
import org.jetbrains.dokka.gradle.utils.withDependencies_
import org.jetbrains.dokka.testApi.assertDokkaConfigurationEquals
import java.io.File
import kotlin.test.*

Expand Down Expand Up @@ -52,7 +53,7 @@ class DokkaCollectorTaskTest {

collectorTasks.forEach { task ->
val dokkaConfiguration = task.buildDokkaConfiguration()
assertEquals(
assertDokkaConfigurationEquals(
DokkaConfigurationImpl(
moduleName = "custom Module Name",
outputDir = rootProject.projectDir.resolve("customOutputDirectory"),
Expand Down
Expand Up @@ -137,6 +137,13 @@ private fun TestDokkaSourceSet.toDokkaSourceSet(relativeToDir: File): DokkaConfi
override val apiVersion: String?
get() = apiVersion

override fun equals(other: Any?): Boolean {
return sourceSetID == (other as? DokkaConfiguration.DokkaSourceSet)?.sourceSetID
}

override fun hashCode(): Int {
return sourceSetID.hashCode()
}

/*
* The properties below are not used by the analysis modules,
Expand Down
Expand Up @@ -17,7 +17,7 @@ dependencies {

testImplementation(kotlin("test"))
testImplementation(projects.dokkaSubprojects.coreContentMatcherTestUtils)
testImplementation(projects.dokkaSubprojects.coreTestApi)
testImplementation(projects.dokkaSubprojects.dokkaTestApi)
testImplementation(projects.dokkaSubprojects.analysisKotlinApi)

// TODO [beresnev] get rid of it
Expand Down
Expand Up @@ -7,7 +7,7 @@ plugins {
}

dependencies {
implementation(projects.dokkaSubprojects.coreTestApi)
implementation(projects.dokkaSubprojects.dokkaTestApi)

implementation(kotlin("reflect"))
implementation(kotlin("test"))
Expand Down
@@ -1,3 +1,8 @@
public final class org/jetbrains/dokka/testApi/ConfigurationKt {
public static final fun assertDokkaConfigurationEquals (Lorg/jetbrains/dokka/DokkaConfiguration;Lorg/jetbrains/dokka/DokkaConfiguration;)V
public static final fun assertDokkaSourceSetEquals (Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)V
}

public final class org/jetbrains/dokka/testApi/context/MockContext : org/jetbrains/dokka/plugability/DokkaContext {
public fun <init> ([Lkotlin/Pair;Lorg/jetbrains/dokka/DokkaConfiguration;Ljava/util/List;)V
public synthetic fun <init> ([Lkotlin/Pair;Lorg/jetbrains/dokka/DokkaConfiguration;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
Expand Down
3 changes: 3 additions & 0 deletions dokka-subprojects/core-test-api/build.gradle.kts
Expand Up @@ -13,6 +13,9 @@ overridePublicationArtifactId("dokka-test-api")

dependencies {
api(projects.dokkaSubprojects.dokkaCore)
// for assertions over `DokkaConfiguration/DokkaSourceSet`
// it's compileOnly, so it should be able to handle both `junit` and `junit5`
compileOnly(kotlin("test"))

implementation(kotlin("reflect"))
}
@@ -0,0 +1,82 @@
/*
* Copyright 2014-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package org.jetbrains.dokka.testApi

import org.jetbrains.dokka.DokkaConfiguration
import kotlin.test.assertEquals

public fun assertDokkaConfigurationEquals(
expected: DokkaConfiguration,
actual: DokkaConfiguration
) {
assertEquals(expected.moduleName, actual.moduleName, "DokkaConfiguration.moduleName")
assertEquals(expected.moduleVersion, actual.moduleVersion, "DokkaConfiguration.moduleVersion")
assertEquals(expected.outputDir, actual.outputDir, "DokkaConfiguration.outputDir")
assertEquals(expected.cacheRoot, actual.cacheRoot, "DokkaConfiguration.cacheRoot")
assertEquals(expected.offlineMode, actual.offlineMode, "DokkaConfiguration.offlineMode")
assertEquals(expected.pluginsClasspath, actual.pluginsClasspath, "DokkaConfiguration.pluginsClasspath")
assertEquals(expected.pluginsConfiguration, actual.pluginsConfiguration, "DokkaConfiguration.pluginsConfiguration")
assertEquals(expected.modules, actual.modules, "DokkaConfiguration.modules")
assertEquals(expected.failOnWarning, actual.failOnWarning, "DokkaConfiguration.failOnWarning")
assertEquals(
expected.delayTemplateSubstitution,
actual.delayTemplateSubstitution,
"DokkaConfiguration.delayTemplateSubstitution"
)
assertEquals(
expected.suppressObviousFunctions,
actual.suppressObviousFunctions,
"DokkaConfiguration.suppressObviousFunctions"
)
assertEquals(expected.includes, actual.includes, "DokkaConfiguration.includes")
assertEquals(
expected.suppressInheritedMembers,
actual.suppressInheritedMembers,
"DokkaConfiguration.suppressInheritedMembers"
)
assertEquals(expected.finalizeCoroutines, actual.finalizeCoroutines, "DokkaConfiguration.finalizeCoroutines")

assertEquals(expected.sourceSets.size, actual.sourceSets.size, "DokkaConfiguration.sourceSets.size")
expected.sourceSets.zip(actual.sourceSets) { expectedSourceSet, actualSourceSet ->
assertDokkaSourceSetEquals(expectedSourceSet, actualSourceSet)
}
}

public fun assertDokkaSourceSetEquals(
expected: DokkaConfiguration.DokkaSourceSet,
actual: DokkaConfiguration.DokkaSourceSet
) {
assertEquals(expected.sourceSetID, actual.sourceSetID, "DokkaSourceSet.sourceSetID")
assertEquals(expected.displayName, actual.displayName, "DokkaSourceSet.displayName")
assertEquals(expected.classpath, actual.classpath, "DokkaSourceSet.classpath")
assertEquals(expected.sourceRoots, actual.sourceRoots, "DokkaSourceSet.sourceRoots")
assertEquals(expected.dependentSourceSets, actual.dependentSourceSets, "DokkaSourceSet.dependentSourceSets")
assertEquals(expected.samples, actual.samples, "DokkaSourceSet.samples")
assertEquals(expected.includes, actual.includes, "DokkaSourceSet.includes")
@Suppress("DEPRECATION")
assertEquals(expected.includeNonPublic, actual.includeNonPublic, "DokkaSourceSet.includeNonPublic")
assertEquals(expected.reportUndocumented, actual.reportUndocumented, "DokkaSourceSet.reportUndocumented")
assertEquals(expected.skipEmptyPackages, actual.skipEmptyPackages, "DokkaSourceSet.skipEmptyPackages")
assertEquals(expected.skipDeprecated, actual.skipDeprecated, "DokkaSourceSet.skipDeprecated")
assertEquals(expected.jdkVersion, actual.jdkVersion, "DokkaSourceSet.jdkVersion")
assertEquals(expected.sourceLinks, actual.sourceLinks, "DokkaSourceSet.sourceLinks")
assertEquals(expected.perPackageOptions, actual.perPackageOptions, "DokkaSourceSet.perPackageOptions")
assertEquals(
expected.externalDocumentationLinks,
actual.externalDocumentationLinks,
"DokkaSourceSet.externalDocumentationLinks"
)
assertEquals(expected.languageVersion, actual.languageVersion, "DokkaSourceSet.languageVersion")
assertEquals(expected.apiVersion, actual.apiVersion, "DokkaSourceSet.apiVersion")
assertEquals(expected.noStdlibLink, actual.noStdlibLink, "DokkaSourceSet.noStdlibLink")
assertEquals(expected.noJdkLink, actual.noJdkLink, "DokkaSourceSet.noJdkLink")
assertEquals(expected.suppressedFiles, actual.suppressedFiles, "DokkaSourceSet.suppressedFiles")
assertEquals(expected.analysisPlatform, actual.analysisPlatform, "DokkaSourceSet.analysisPlatform")
assertEquals(
expected.documentedVisibilities,
actual.documentedVisibilities,
"DokkaSourceSet.documentedVisibilities"
)
}
2 changes: 1 addition & 1 deletion dokka-subprojects/core/build.gradle.kts
Expand Up @@ -23,7 +23,7 @@ dependencies {
}

testImplementation(kotlin("test"))
testImplementation(projects.dokkaSubprojects.coreTestApi)
testImplementation(projects.dokkaSubprojects.dokkaTestApi)
}

tasks.processResources {
Expand Down
Expand Up @@ -78,15 +78,18 @@ public fun interface DokkaConfigurationBuilder<T : Any> {

public fun <T : Any> Iterable<DokkaConfigurationBuilder<T>>.build(): List<T> = this.map { it.build() }

/**
* Represents a unique identifier for a [DokkaConfiguration.DokkaSourceSet].
* It should be unique across the whole project.
*
* @property scopeId The unique identifier of the scope that this source set is placed in.
* Each scope provides only unique source set names.
* E.g. One DokkaTask inside the Gradle plugin represents one source set scope, since there cannot be multiple
* source sets with the same name. However, a Gradle project will not be a proper scope, since there can be
* multiple DokkaTasks that contain source sets with the same name (but different configuration)
* @property sourceSetName The name of the source set.
*/
public data class DokkaSourceSetID(
/**
* Unique identifier of the scope that this source set is placed in.
* Each scope provide only unique source set names.
*
* E.g. One DokkaTask inside the Gradle plugin represents one source set scope, since there cannot be multiple
* source sets with the same name. However, a Gradle project will not be a proper scope, since there can be
* multple DokkaTasks that contain source sets with the same name (but different configuration)
*/
val scopeId: String,
val sourceSetName: String
) : Serializable {
Expand Down Expand Up @@ -170,6 +173,13 @@ public interface DokkaConfiguration : Serializable {
public val values: String
}

/**
* Each [DokkaSourceSet] is uniquely identified by its [sourceSetID].
* This means that if two [DokkaSourceSet]s will have the same [sourceSetID] they will be interchangeable.
* [equals] and [hashCode] must be defined only based on [sourceSetID].
*
* **See Also:** [Dokka#3246](https://github.com/Kotlin/dokka/issues/3246)
*/
public interface DokkaSourceSet : Serializable {
public val sourceSetID: DokkaSourceSetID
public val displayName: String
Expand Down
Expand Up @@ -57,7 +57,15 @@ public data class DokkaSourceSetImpl(
override val suppressedFiles: Set<File> = emptySet(),
override val analysisPlatform: Platform = DokkaDefaults.analysisPlatform,
override val documentedVisibilities: Set<DokkaConfiguration.Visibility> = DokkaDefaults.documentedVisibilities,
) : DokkaSourceSet
) : DokkaSourceSet {
override fun equals(other: Any?): Boolean {
return sourceSetID == (other as? DokkaSourceSet)?.sourceSetID
}

override fun hashCode(): Int {
return sourceSetID.hashCode()
}
}

public data class DokkaModuleDescriptionImpl(
override val name: String,
Expand Down
Expand Up @@ -7,10 +7,10 @@ package utilities
import org.jetbrains.dokka.DokkaConfigurationImpl
import org.jetbrains.dokka.DokkaSourceSetID
import org.jetbrains.dokka.DokkaSourceSetImpl
import org.jetbrains.dokka.testApi.assertDokkaConfigurationEquals
import org.jetbrains.dokka.toCompactJsonString
import java.io.File
import kotlin.test.Test
import kotlin.test.assertEquals

class DokkaConfigurationJsonTest {
@Test
Expand All @@ -29,7 +29,7 @@ class DokkaConfigurationJsonTest {

val jsonString = configuration.toCompactJsonString()
val parsedConfiguration = DokkaConfigurationImpl(jsonString)
assertEquals(configuration, parsedConfiguration)
assertDokkaConfigurationEquals(configuration, parsedConfiguration)
}

@Test
Expand All @@ -53,7 +53,7 @@ class DokkaConfigurationJsonTest {
""".trimIndent()

val parsedConfiguration = DokkaConfigurationImpl(json)
assertEquals(
assertDokkaConfigurationEquals(
DokkaConfigurationImpl(
moduleName = "moduleName",
outputDir = File("customOutputDir"),
Expand All @@ -66,7 +66,7 @@ class DokkaConfigurationJsonTest {
)
)
),
parsedConfiguration
parsedConfiguration,
)
}
}
2 changes: 1 addition & 1 deletion dokka-subprojects/plugin-all-modules-page/build.gradle.kts
Expand Up @@ -28,5 +28,5 @@ dependencies {
testImplementation(projects.dokkaSubprojects.pluginGfm)
testImplementation(projects.dokkaSubprojects.pluginGfmTemplateProcessing)
testImplementation(projects.dokkaSubprojects.coreContentMatcherTestUtils)
testImplementation(projects.dokkaSubprojects.coreTestApi)
testImplementation(projects.dokkaSubprojects.dokkaTestApi)
}
Expand Up @@ -21,7 +21,7 @@ dependencies {

testImplementation(kotlin("test"))
testImplementation(projects.dokkaSubprojects.pluginBase)
testImplementation(projects.dokkaSubprojects.coreTestApi)
testImplementation(projects.dokkaSubprojects.dokkaTestApi)

symbolsTestImplementation(project(path = ":dokka-subprojects:analysis-kotlin-symbols", configuration = "shadow"))
descriptorsTestImplementation(project(path = ":dokka-subprojects:analysis-kotlin-descriptors", configuration = "shadow"))
Expand Down
4 changes: 2 additions & 2 deletions dokka-subprojects/plugin-base-test-utils/build.gradle.kts
Expand Up @@ -25,8 +25,8 @@ dependencies {
implementation(libs.jsoup)

implementation(kotlin("test"))
implementation(projects.dokkaSubprojects.coreTestApi)
implementation(projects.dokkaSubprojects.dokkaTestApi)

testImplementation(kotlin("test"))
testImplementation(projects.dokkaSubprojects.coreTestApi)
testImplementation(projects.dokkaSubprojects.dokkaTestApi)
}
Expand Up @@ -38,11 +38,11 @@ public class BaseDokkaTestGenerator(

val singleModuleGeneration = context.single(CoreExtensions.generation) as SingleModuleGeneration

verificationStage { singleModuleGeneration.validityCheck(context) }

val modulesFromPlatforms = singleModuleGeneration.createDocumentationModels()
documentablesCreationStage(modulesFromPlatforms)

verificationStage { singleModuleGeneration.validityCheck(context) }

val filteredModules = singleModuleGeneration.transformDocumentationModelBeforeMerge(modulesFromPlatforms)
documentablesFirstTransformationStep(filteredModules)

Expand Down Expand Up @@ -91,7 +91,7 @@ public data class BaseTestMethods(

public class BaseTestBuilder : TestBuilder<BaseTestMethods>() {
public var pluginsSetupStage: (DokkaContext) -> Unit = {}
public var verificationStage: (() -> Unit) -> Unit = {}
public var verificationStage: (() -> Unit) -> Unit = { it() }
public var documentablesCreationStage: (List<DModule>) -> Unit = {}
public var preMergeDocumentablesTransformationStage: (List<DModule>) -> Unit = {}
public var documentablesMergingStage: (DModule) -> Unit = {}
Expand Down
2 changes: 1 addition & 1 deletion dokka-subprojects/plugin-base/build.gradle.kts
Expand Up @@ -47,7 +47,7 @@ dependencies {
exclude(module = "analysis-kotlin-descriptors")
}
testImplementation(projects.dokkaSubprojects.coreContentMatcherTestUtils)
testImplementation(projects.dokkaSubprojects.coreTestApi)
testImplementation(projects.dokkaSubprojects.dokkaTestApi)
testImplementation(projects.dokkaSubprojects.analysisKotlinApi)

dokkaHtmlFrontendFiles(projects.dokkaSubprojects.pluginBaseFrontend) {
Expand Down
Expand Up @@ -6,6 +6,7 @@ package org.jetbrains.dokka.base

import org.jetbrains.dokka.CoreExtensions
import org.jetbrains.dokka.base.generation.SingleModuleGeneration
import org.jetbrains.dokka.base.generation.SourceSetIdUniquenessChecker
import org.jetbrains.dokka.base.renderers.*
import org.jetbrains.dokka.base.renderers.html.*
import org.jetbrains.dokka.base.renderers.html.command.consumers.PathToRootConsumer
Expand Down Expand Up @@ -262,6 +263,10 @@ public class DokkaBase : DokkaPlugin() {
htmlPreprocessors providing ::SearchbarDataInstaller order { after(sourceLinksTransformer) }
}

internal val sourceSetIdUniquenessChecker by extending {
CoreExtensions.preGenerationCheck providing ::SourceSetIdUniquenessChecker
}

//<editor-fold desc="Deprecated API left for compatibility">
@Suppress("DEPRECATION_ERROR")
@Deprecated(message = org.jetbrains.dokka.base.deprecated.ANALYSIS_API_DEPRECATION_MESSAGE, level = DeprecationLevel.ERROR)
Expand Down

0 comments on commit f524273

Please sign in to comment.