From 8e5c63d035ef44a269b8c43430f43f5c8eebfb63 Mon Sep 17 00:00:00 2001 From: Ignat Beresnev Date: Fri, 10 Nov 2023 11:46:54 +0100 Subject: Restructure the project to utilize included builds (#3174) * Refactor and simplify artifact publishing * Update Gradle to 8.4 * Refactor and simplify convention plugins and build scripts Fixes #3132 --------- Co-authored-by: Adam <897017+aSemy@users.noreply.github.com> Co-authored-by: Oleg Yukhnevich --- .../AbortGracefullyOnMissingDocumentablesTest.kt | 22 ++ .../plugin-base/src/test/kotlin/basic/DRITest.kt | 351 +++++++++++++++++++++ .../src/test/kotlin/basic/DokkaBasicTests.kt | 46 +++ .../src/test/kotlin/basic/FailOnWarningTest.kt | 128 ++++++++ .../src/test/kotlin/basic/LoggerTest.kt | 48 +++ 5 files changed, 595 insertions(+) create mode 100644 dokka-subprojects/plugin-base/src/test/kotlin/basic/AbortGracefullyOnMissingDocumentablesTest.kt create mode 100644 dokka-subprojects/plugin-base/src/test/kotlin/basic/DRITest.kt create mode 100644 dokka-subprojects/plugin-base/src/test/kotlin/basic/DokkaBasicTests.kt create mode 100644 dokka-subprojects/plugin-base/src/test/kotlin/basic/FailOnWarningTest.kt create mode 100644 dokka-subprojects/plugin-base/src/test/kotlin/basic/LoggerTest.kt (limited to 'dokka-subprojects/plugin-base/src/test/kotlin/basic') diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/basic/AbortGracefullyOnMissingDocumentablesTest.kt b/dokka-subprojects/plugin-base/src/test/kotlin/basic/AbortGracefullyOnMissingDocumentablesTest.kt new file mode 100644 index 00000000..693174ec --- /dev/null +++ b/dokka-subprojects/plugin-base/src/test/kotlin/basic/AbortGracefullyOnMissingDocumentablesTest.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package basic + +import org.jetbrains.dokka.DokkaGenerator +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import kotlin.test.Test +import kotlin.test.assertTrue + +class AbortGracefullyOnMissingDocumentablesTest: BaseAbstractTest() { + @Test + fun `Generation aborts Gracefully with no Documentables`() { + DokkaGenerator(dokkaConfiguration { }, logger).generate() + + assertTrue( + logger.progressMessages.any { message -> "Exiting Generation: Nothing to document" == message }, + "Expected graceful exit message. Found: ${logger.progressMessages}" + ) + } +} diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/basic/DRITest.kt b/dokka-subprojects/plugin-base/src/test/kotlin/basic/DRITest.kt new file mode 100644 index 00000000..6fd9d4b0 --- /dev/null +++ b/dokka-subprojects/plugin-base/src/test/kotlin/basic/DRITest.kt @@ -0,0 +1,351 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package basic + +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.links.* +import org.jetbrains.dokka.links.Callable +import org.jetbrains.dokka.links.Nullable +import org.jetbrains.dokka.links.TypeConstructor +import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.pages.ClasslikePageNode +import org.jetbrains.dokka.pages.ContentPage +import org.jetbrains.dokka.pages.MemberPageNode +import kotlin.test.Test +import kotlin.test.assertEquals + +class DRITest : BaseAbstractTest() { + @Test + fun issue634() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + } + } + } + + testInline( + """ + |/src/main/kotlin/basic/Test.kt + |package toplevel + | + |inline fun > Array.mySortBy( + | crossinline selector: (T) -> R?): Array = TODO() + |} + """.trimMargin(), + configuration + ) { + documentablesMergingStage = { module -> + val expected = TypeConstructor( + "kotlin.Function1", listOf( + TypeParam(listOf(Nullable(TypeConstructor("kotlin.Any", emptyList())))), + Nullable(TypeParam(listOf(TypeConstructor("kotlin.Comparable", listOf(RecursiveType(0)))))) + ) + ) + val actual = module.packages.single() + .functions.single() + .dri.callable?.params?.single() + assertEquals(expected, actual) + } + } + } + + @Test + fun issue634WithImmediateNullableSelf() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + } + } + } + + testInline( + """ + |/src/main/kotlin/basic/Test.kt + |package toplevel + | + |fun > Array.doSomething(t: T?): Array = TODO() + |} + """.trimMargin(), + configuration + ) { + documentablesMergingStage = { module -> + val expected = Nullable(TypeParam(listOf(TypeConstructor("kotlin.Comparable", listOf(RecursiveType(0)))))) + val actual = module.packages.single() + .functions.single() + .dri.callable?.params?.single() + assertEquals(expected, actual) + } + } + } + + @Test + fun issue634WithGenericNullableReceiver() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + } + } + } + + testInline( + """ + |/src/main/kotlin/basic/Test.kt + |package toplevel + | + |fun > T?.doSomethingWithNullable() = TODO() + |} + """.trimMargin(), + configuration + ) { + documentablesMergingStage = { module -> + val expected = Nullable(TypeParam(listOf(TypeConstructor("kotlin.Comparable", listOf(RecursiveType(0)))))) + val actual = module.packages.single() + .functions.single() + .dri.callable?.receiver + assertEquals(expected, actual) + } + } + } + + @Test + fun issue642WithStarAndAny() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + analysisPlatform = "js" + sourceRoots = listOf("src/") + } + } + } + + testInline( + """ + |/src/main/kotlin/Test.kt + | + |open class Bar + |class ReBarBar : Bar() + |class Foo, R : List>> + | + |fun > Foo.qux(): String = TODO() + |fun > Foo.qux(): String = TODO() + | + """.trimMargin(), + configuration + ) { + pagesGenerationStage = { module -> + // DRI(//qux/Foo[TypeParam(bounds=[kotlin.Comparable[kotlin.Any?]]),*]#/PointingToFunctionOrClasslike/) + val expectedDRI = DRI( + "", + null, + Callable( + "qux", TypeConstructor( + "Foo", listOf( + TypeParam( + listOf( + TypeConstructor( + "kotlin.Comparable", listOf( + Nullable(TypeConstructor("kotlin.Any", emptyList())) + ) + ) + ) + ), + StarProjection + ) + ), + emptyList() + ) + ) + + val driCount = module + .withDescendants() + .filterIsInstance() + .sumBy { it.dri.count { dri -> dri == expectedDRI } } + + assertEquals(1, driCount) + } + } + } + + @Test + fun driForGenericClass(){ + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + } + } + } + testInline( + """ + |/src/main/kotlin/Test.kt + |package example + | + |class Sample(first: S){ } + | + | + """.trimMargin(), + configuration + ) { + pagesGenerationStage = { module -> + val sampleClass = module.dfs { it.name == "Sample" } as ClasslikePageNode + val classDocumentable = sampleClass.documentables.firstOrNull() as DClass + + assertEquals( "example/Sample///PointingToDeclaration/", sampleClass.dri.first().toString()) + assertEquals("example/Sample///PointingToGenericParameters(0)/", classDocumentable.generics.first().dri.toString()) + } + } + } + + @Test + fun driForGenericFunction(){ + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + classpath = listOfNotNull(jvmStdlibPath) + } + } + } + testInline( + """ + |/src/main/kotlin/Test.kt + |package example + | + |class Sample(first: S){ + | fun genericFun(param1: String): Tuple = TODO() + |} + | + | + """.trimMargin(), + configuration + ) { + pagesGenerationStage = { module -> + val sampleClass = module.dfs { it.name == "Sample" } as ClasslikePageNode + val functionNode = sampleClass.children.first { it.name == "genericFun" } as MemberPageNode + val functionDocumentable = functionNode.documentables.firstOrNull() as DFunction + val parameter = functionDocumentable.parameters.first() + + assertEquals("example/Sample/genericFun/#kotlin.String/PointingToDeclaration/", functionNode.dri.first().toString()) + + assertEquals(1, functionDocumentable.parameters.size) + assertEquals("example/Sample/genericFun/#kotlin.String/PointingToCallableParameters(0)/", parameter.dri.toString()) + //1 since from the function's perspective there is only 1 new generic declared + //The other one is 'inherited' from class + assertEquals( 1, functionDocumentable.generics.size) + assertEquals( "T", functionDocumentable.generics.first().name) + assertEquals( "example/Sample/genericFun/#kotlin.String/PointingToGenericParameters(0)/", functionDocumentable.generics.first().dri.toString()) + } + } + } + + @Test + fun driForFunctionNestedInsideInnerClass() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + classpath = listOfNotNull(jvmStdlibPath) + } + } + } + testInline( + """ + |/src/main/kotlin/Test.kt + |package example + | + |class Sample(first: S){ + | inner class SampleInner { + | fun foo(): S = TODO() + | } + |} + | + | + """.trimMargin(), + configuration + ) { + pagesGenerationStage = { module -> + val sampleClass = module.dfs { it.name == "Sample" } as ClasslikePageNode + val sampleInner = sampleClass.children.first { it.name == "SampleInner" } as ClasslikePageNode + val foo = sampleInner.children.first { it.name == "foo" } as MemberPageNode + val documentable = foo.documentables.firstOrNull() as DFunction + + val generics = (sampleClass.documentables.firstOrNull() as WithGenerics).generics + assertEquals(generics.first().dri.toString(), (documentable.type as TypeParameter).dri.toString()) + assertEquals(0, documentable.generics.size) + } + } + } + + @Test + fun driForGenericExtensionFunction(){ + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + } + } + } + testInline( + """ + |/src/main/kotlin/Test.kt + |package example + | + | fun List.extensionFunction(): String = "" + | + """.trimMargin(), + configuration + ) { + pagesGenerationStage = { module -> + val extensionFunction = module.dfs { it.name == "extensionFunction" } as MemberPageNode + val documentable = extensionFunction.documentables.firstOrNull() as DFunction + + assertEquals( + "example//extensionFunction/kotlin.collections.List[TypeParam(bounds=[kotlin.Any?])]#/PointingToDeclaration/", + extensionFunction.dri.first().toString() + ) + assertEquals(1, documentable.generics.size) + assertEquals("T", documentable.generics.first().name) + assertEquals( + "example//extensionFunction/kotlin.collections.List[TypeParam(bounds=[kotlin.Any?])]#/PointingToGenericParameters(0)/", + documentable.generics.first().dri.toString() + ) + + } + } + } + + @Test + fun `deep recursive typebound #1342`() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + } + } + } + testInline( + """ + |/src/main/kotlin/Test.kt + |package example + | + | fun recursiveBound(t: T, s: S, r: R) where T: List, S: List, R: List = Unit + | + """.trimMargin(), + configuration + ) { + documentablesMergingStage = { module -> + val function = module.dfs { it.name == "recursiveBound" } + assertEquals( + "example//recursiveBound/#TypeParam(bounds=[kotlin.collections.List[TypeParam(bounds=[kotlin.collections.List[TypeParam(bounds=[kotlin.collections.List[^^]])]])]])#TypeParam(bounds=[kotlin.collections.List[TypeParam(bounds=[kotlin.collections.List[^]])]])#TypeParam(bounds=[kotlin.collections.List[TypeParam(bounds=[kotlin.collections.List[^]])]])/PointingToDeclaration/", + function?.dri?.toString(), + ) + } + } + } +} diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/basic/DokkaBasicTests.kt b/dokka-subprojects/plugin-base/src/test/kotlin/basic/DokkaBasicTests.kt new file mode 100644 index 00000000..2b353ad8 --- /dev/null +++ b/dokka-subprojects/plugin-base/src/test/kotlin/basic/DokkaBasicTests.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package basic + +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.pages.ClasslikePageNode +import org.jetbrains.dokka.pages.ModulePageNode +import kotlin.test.Test +import kotlin.test.assertEquals + +class DokkaBasicTests : BaseAbstractTest() { + + @Test + fun basic1() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/main/kotlin/basic/Test.kt") + } + } + } + + testInline( + """ + |/src/main/kotlin/basic/Test.kt + |package basic + | + |class Test { + | val tI = 1 + | fun tF() = 2 + |} + """.trimMargin(), + configuration + ) { + pagesGenerationStage = { + val root = it as ModulePageNode + assertEquals(3, root.getClasslikeToMemberMap().filterKeys { it.name == "Test" }.entries.firstOrNull()?.value?.size) + } + } + } + + private fun ModulePageNode.getClasslikeToMemberMap() = + this.parentMap.filterValues { it is ClasslikePageNode }.entries.groupBy({ it.value }) { it.key } +} diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/basic/FailOnWarningTest.kt b/dokka-subprojects/plugin-base/src/test/kotlin/basic/FailOnWarningTest.kt new file mode 100644 index 00000000..ebdf7860 --- /dev/null +++ b/dokka-subprojects/plugin-base/src/test/kotlin/basic/FailOnWarningTest.kt @@ -0,0 +1,128 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package basic + +import org.jetbrains.dokka.DokkaException +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.testApi.logger.TestLogger +import org.jetbrains.dokka.utilities.DokkaConsoleLogger +import org.jetbrains.dokka.utilities.DokkaLogger +import org.jetbrains.dokka.utilities.LoggingLevel +import kotlin.test.Test +import kotlin.test.assertFailsWith + +class FailOnWarningTest : BaseAbstractTest() { + + @Test + fun `throws exception if one or more warnings were emitted`() { + val configuration = dokkaConfiguration { + failOnWarning = true + sourceSets { + sourceSet { + sourceRoots = listOf("src/main/kotlin") + } + } + } + + assertFailsWith { + testInline( + """ + |/src/main/kotlin/Bar.kt + |package sample + |class Bar {} + """.trimIndent(), configuration + ) { + pluginsSetupStage = { + logger.warn("Warning!") + } + } + } + } + + @Test + fun `throws exception if one or more error were emitted`() { + val configuration = dokkaConfiguration { + failOnWarning = true + sourceSets { + sourceSet { + sourceRoots = listOf("src/main/kotlin") + } + } + } + + assertFailsWith { + testInline( + """ + |/src/main/kotlin/Bar.kt + |package sample + |class Bar {} + """.trimIndent(), configuration + ) { + pluginsSetupStage = { + logger.error("Error!") + } + } + } + } + + @Test + fun `does not throw if now warning or error was emitted`() { + + val configuration = dokkaConfiguration { + failOnWarning = true + sourceSets { + sourceSet { + sourceRoots = listOf("src/main/kotlin") + } + } + } + + + testInline( + """ + |/src/main/kotlin/Bar.kt + |package sample + |class Bar {} + """.trimIndent(), + configuration, + loggerForTest = TestLogger(ZeroErrorOrWarningCountDokkaLogger()) + ) { + /* We expect no Exception */ + } + } + + @Test + fun `does not throw if disabled`() { + val configuration = dokkaConfiguration { + failOnWarning = false + sourceSets { + sourceSet { + sourceRoots = listOf("src/main/kotlin") + } + } + } + + + testInline( + """ + |/src/main/kotlin/Bar.kt + |package sample + |class Bar {} + """.trimIndent(), configuration + ) { + pluginsSetupStage = { + logger.warn("Error!") + logger.error("Error!") + } + } + } +} + +private class ZeroErrorOrWarningCountDokkaLogger( + logger: DokkaLogger = DokkaConsoleLogger(LoggingLevel.DEBUG) +) : DokkaLogger by logger { + override var warningsCount: Int = 0 + override var errorsCount: Int = 0 +} diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/basic/LoggerTest.kt b/dokka-subprojects/plugin-base/src/test/kotlin/basic/LoggerTest.kt new file mode 100644 index 00000000..12c39690 --- /dev/null +++ b/dokka-subprojects/plugin-base/src/test/kotlin/basic/LoggerTest.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 basic + +import org.jetbrains.dokka.utilities.DokkaConsoleLogger +import org.jetbrains.dokka.utilities.LoggingLevel +import org.jetbrains.dokka.utilities.MessageEmitter +import kotlin.test.Test +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +class LoggerTest { + class AccumulatingEmitter : MessageEmitter { + val messages: MutableList = mutableListOf() + override fun invoke(message: String) { + messages.add(message) + } + } + + @Test + fun `should display info messages if logging is info`(){ + val emitter = AccumulatingEmitter() + val logger = DokkaConsoleLogger(LoggingLevel.INFO, emitter) + + logger.debug("Debug!") + logger.info("Info!") + + assertTrue(emitter.messages.size > 0) + assertTrue(emitter.messages.any { it == "Info!" }) + assertFalse(emitter.messages.any { it == "Debug!" }) + } + + @Test + fun `should not display info messages if logging is warn`(){ + val emitter = AccumulatingEmitter() + val logger = DokkaConsoleLogger(LoggingLevel.WARN, emitter) + + logger.warn("Warning!") + logger.info("Info!") + + + assertTrue(emitter.messages.size > 0) + assertFalse(emitter.messages.any { it.contains("Info!") }) + assertTrue(emitter.messages.any { it.contains("Warning!") }) + } +} -- cgit