diff options
| author | Ignat Beresnev <ignat.beresnev@jetbrains.com> | 2023-11-10 11:46:54 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-11-10 11:46:54 +0100 |
| commit | 8e5c63d035ef44a269b8c43430f43f5c8eebfb63 (patch) | |
| tree | 1b915207b2b9f61951ddbf0ff2e687efd053d555 /dokka-subprojects/plugin-javadoc/src/test/kotlin/org/jetbrains | |
| parent | a44efd4ba0c2e4ab921ff75e0f53fc9335aa79db (diff) | |
| download | dokka-8e5c63d035ef44a269b8c43430f43f5c8eebfb63.tar.gz dokka-8e5c63d035ef44a269b8c43430f43f5c8eebfb63.tar.bz2 dokka-8e5c63d035ef44a269b8c43430f43f5c8eebfb63.zip | |
Restructure the project to utilize included builds (#3174)
* Refactor and simplify artifact publishing
* Update Gradle to 8.4
* Refactor and simplify convention plugins and build scripts
Fixes #3132
---------
Co-authored-by: Adam <897017+aSemy@users.noreply.github.com>
Co-authored-by: Oleg Yukhnevich <whyoleg@gmail.com>
Diffstat (limited to 'dokka-subprojects/plugin-javadoc/src/test/kotlin/org/jetbrains')
17 files changed, 2230 insertions, 0 deletions
diff --git a/dokka-subprojects/plugin-javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/AbstractJavadocTemplateMapTest.kt b/dokka-subprojects/plugin-javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/AbstractJavadocTemplateMapTest.kt new file mode 100644 index 00000000..60265e33 --- /dev/null +++ b/dokka-subprojects/plugin-javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/AbstractJavadocTemplateMapTest.kt @@ -0,0 +1,132 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package org.jetbrains.dokka.javadoc + +import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.DokkaConfigurationImpl +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.javadoc.location.JavadocLocationProvider +import org.jetbrains.dokka.javadoc.pages.JavadocPageNode +import org.jetbrains.dokka.javadoc.renderer.JavadocContentToTemplateMapTranslator +import org.jetbrains.dokka.jdk +import org.jetbrains.dokka.kotlinStdlib +import org.jetbrains.dokka.model.withDescendants +import org.jetbrains.dokka.pages.RootPageNode +import org.jetbrains.dokka.plugability.* + +internal abstract class AbstractJavadocTemplateMapTest : BaseAbstractTest() { + protected var config: DokkaConfigurationImpl = dokkaConfiguration { + format = "javadoc" + suppressObviousFunctions = false + sourceSets { + sourceSet { + sourceRoots = listOf("src") + analysisPlatform = "jvm" + externalDocumentationLinks = listOf( + DokkaConfiguration.ExternalDocumentationLink.jdk(8), + DokkaConfiguration.ExternalDocumentationLink.kotlinStdlib() + ) + classpath = listOfNotNull(jvmStdlibPath) + } + } + } + + data class Result( + val rootPageNode: RootPageNode, + val context: DokkaContext + ) { + + val translator: JavadocContentToTemplateMapTranslator by lazy { + val locationProvider = context.plugin<JavadocPlugin>() + .querySingle { locationProviderFactory } + .getLocationProvider(rootPageNode) as JavadocLocationProvider + + JavadocContentToTemplateMapTranslator(locationProvider, context) + } + + val JavadocPageNode.templateMap: Map<String, Any?> get() = translator.templateMapForPageNode(this) + + inline fun <reified T : JavadocPageNode> allPagesOfType(): List<T> { + return rootPageNode.withDescendants().filterIsInstance<T>().toList() + } + + inline fun <reified T : JavadocPageNode> firstPageOfType(): T { + return rootPageNode.withDescendants().filterIsInstance<T>().first() + } + + inline fun <reified T : JavadocPageNode> firstPageOfTypeOrNull(): T? { + return rootPageNode.withDescendants().filterIsInstance<T>().firstOrNull() + } + + inline fun <reified T : JavadocPageNode> singlePageOfType(): T { + return rootPageNode.withDescendants().filterIsInstance<T>().single() + } + } + + fun testTemplateMapInline( + query: String, + configuration: DokkaConfigurationImpl = config, + pluginsOverride: List<DokkaPlugin> = emptyList(), + assertions: Result.() -> Unit + ) { + testInline(query, configuration, pluginOverrides = pluginsOverride) { + renderingStage = { rootPageNode, dokkaContext -> + val preprocessors = dokkaContext.plugin<JavadocPlugin>().query { javadocPreprocessors } + val transformedRootPageNode = preprocessors.fold(rootPageNode) { acc, pageTransformer -> + pageTransformer(acc) + } + + Result(transformedRootPageNode, dokkaContext).assertions() + } + } + } + + fun dualTestTemplateMapInline( + kotlin: String? = null, + java: String? = null, + configuration: DokkaConfigurationImpl = config, + pluginsOverride: List<DokkaPlugin> = emptyList(), + assertions: Result.() -> Unit + ) { + val kotlinException = kotlin?.let { + runCatching { + testTemplateMapInline( + query = kotlin, + configuration = configuration, + pluginsOverride = pluginsOverride, + assertions = assertions + ) + }.exceptionOrNull() + } + + val javaException = java?.let { + runCatching { + testTemplateMapInline( + query = java, + configuration = configuration, + pluginsOverride = pluginsOverride, + assertions = assertions + ) + }.exceptionOrNull() + } + + if (kotlinException != null && javaException != null) { + throw AssertionError( + "Kotlin and Java Code failed assertions\n" + + "Kotlin: ${kotlinException.message}\n" + + "Java : ${javaException.message}", + kotlinException + ) + } + + if (kotlinException != null) { + throw AssertionError("Kotlin Code failed assertions", kotlinException) + } + + if (javaException != null) { + throw AssertionError("Java Code failed assertions", javaException) + } + } +} diff --git a/dokka-subprojects/plugin-javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/Asserts.kt b/dokka-subprojects/plugin-javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/Asserts.kt new file mode 100644 index 00000000..2854ac7c --- /dev/null +++ b/dokka-subprojects/plugin-javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/Asserts.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 org.jetbrains.dokka.javadoc + +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract + +// TODO replace with assertIs<T> from kotlin-test as part of #2924 +@OptIn(ExperimentalContracts::class) +inline fun <reified T> assertIsInstance(obj: Any?): T { + contract { + returns() implies (obj is T) + } + + if (obj is T) { + return obj + } + + throw AssertionError("Expected instance of type ${T::class.qualifiedName} but found $obj") +} diff --git a/dokka-subprojects/plugin-javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/JavadocAccessorNamingTest.kt b/dokka-subprojects/plugin-javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/JavadocAccessorNamingTest.kt new file mode 100644 index 00000000..95ce4d27 --- /dev/null +++ b/dokka-subprojects/plugin-javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/JavadocAccessorNamingTest.kt @@ -0,0 +1,93 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package org.jetbrains.dokka.javadoc + +import org.jsoup.Jsoup +import utils.TestOutputWriterPlugin +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +internal class JavadocAccessorNamingTest : AbstractJavadocTemplateMapTest() { + + val configuration = dokkaConfiguration { + suppressObviousFunctions = true + sourceSets { + sourceSet { + sourceRoots = listOf("src/main/kotlin") + classpath = listOfNotNull(jvmStdlibPath) + } + } + } + + /** + * This is a quick sanity check for the AccessorMethodNamingTest + */ + @Test + fun verifySpecialIsRuleIsApplied() { + val writerPlugin = TestOutputWriterPlugin() + + testInline( + """ + /src/main/kotlin/sample/TestCase.kt + package sample + + /** + * Test links: + * - [TestCase.issuesFetched] + * - [TestCase.isFoo] + */ + data class TestCase( + var issuesFetched: Int, + var isFoo: String, + ) + """.trimIndent(), + configuration, + cleanupOutput = false, + pluginOverrides = listOf(writerPlugin, JavadocPlugin()) + ) { + renderingStage = { _, _ -> + val html = writerPlugin.writer.contents.getValue("sample/TestCase.html").let { Jsoup.parse(it) } + val props = html + .select("#memberSummary_tabpanel") + .select("th[scope=row].colSecond") + .select("code") + .map { it.text() } + .toSet() + // In K2 name of accessors parameter is `value` + assertTrue( + setOf( + "getIssuesFetched()", + "setIssuesFetched(Integer issuesFetched)", + "isFoo()", + "setFoo(String isFoo)", + ) == props || setOf( + "getIssuesFetched()", + "setIssuesFetched(Integer value)", + "isFoo()", + "setFoo(String value)", + ) == props + ) + + val descriptionLinks = html + .select("div.description") + .select("p") + .select("a") + .eachAttr("href") + .map { a -> a.takeLastWhile { it != '#' } } + + assertEquals(setOf( + "issuesFetched", + "isFoo()", + ), descriptionLinks.toSet()) + + // Make sure that the ids from above actually exist + assertEquals(1, html.select("[id = isFoo()]").size) + // Bug! Nothing in the doc has the right id + assertEquals(0, html.select("[id = issuesFetched]").size) + } + } + } +} diff --git a/dokka-subprojects/plugin-javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/JavadocAllClassesTemplateMapTest.kt b/dokka-subprojects/plugin-javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/JavadocAllClassesTemplateMapTest.kt new file mode 100644 index 00000000..8d7ff1ea --- /dev/null +++ b/dokka-subprojects/plugin-javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/JavadocAllClassesTemplateMapTest.kt @@ -0,0 +1,54 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package org.jetbrains.dokka.javadoc + +import org.jetbrains.dokka.javadoc.pages.AllClassesPage +import org.jetbrains.dokka.javadoc.pages.LinkJavadocListEntry +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.pages.ContentKind +import org.junit.jupiter.api.Tag +import kotlin.test.Test +import kotlin.test.assertEquals + +internal class JavadocAllClassesTemplateMapTest : AbstractJavadocTemplateMapTest() { + @Test + @Tag("onlyDescriptors") // https://github.com/Kotlin/dokka/issues/3250 + fun `two classes from different packages`() { + dualTestTemplateMapInline( + """ + /src/source0.kt + package package0 + /** + * Documentation for ClassA + */ + class ClassA + + /src/source1.kt + package package1 + /** + * Documentation for ClassB + */ + class ClassB + """ + ) { + val map = singlePageOfType<AllClassesPage>().templateMap + assertEquals("main", map["kind"]) + assertEquals("All Classes", map["title"]) + + val list = assertIsInstance<List<*>>(map["list"]) + assertEquals(2, list.size, "Expected two classes") + + val classA = assertIsInstance<LinkJavadocListEntry>(list[0]) + assertEquals("ClassA", classA.name) + assertEquals(DRI("package0", "ClassA"), classA.dri.single()) + assertEquals(ContentKind.Classlikes, classA.kind) + + val classB = assertIsInstance<LinkJavadocListEntry>(list[1]) + assertEquals("ClassB", classB.name) + assertEquals(DRI("package1", "ClassB"), classB.dri.single()) + assertEquals(ContentKind.Classlikes, classB.kind) + } + } +} diff --git a/dokka-subprojects/plugin-javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/JavadocClasslikeTemplateMapTest.kt b/dokka-subprojects/plugin-javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/JavadocClasslikeTemplateMapTest.kt new file mode 100644 index 00000000..fd382d42 --- /dev/null +++ b/dokka-subprojects/plugin-javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/JavadocClasslikeTemplateMapTest.kt @@ -0,0 +1,461 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package org.jetbrains.dokka.javadoc + +import org.jetbrains.dokka.javadoc.pages.JavadocClasslikePageNode +import kotlin.test.Test +import kotlin.test.assertEquals + +internal class JavadocClasslikeTemplateMapTest : AbstractJavadocTemplateMapTest() { + + @Test + fun `empty class`() { + dualTestTemplateMapInline( + kotlin = + """ + /src/source0.kt + package com.test.package0 + /** + * Documentation for TestClass + */ + class TestClass + """, + java = + """ + /src/com/test/package0/TestClass.java + package com.test.package0; + /** + * Documentation for TestClass + */ + public final class TestClass {} + """ + ) { + val map = singlePageOfType<JavadocClasslikePageNode>().templateMap + assertEquals("TestClass", map["name"]) + assertEquals("TestClass", map["title"]) + assertEquals("com.test.package0", map["packageName"]) + assertEquals("<p>Documentation for TestClass</p>", map["classlikeDocumentation"]) + assertEquals("Documentation for TestClass", map["subtitle"]) + assertEquals("public final class <a href=TestClass.html>TestClass</a>", map.signatureWithModifiers()) + } + } + + @Test + fun `single function`() { + dualTestTemplateMapInline( + kotlin = + """ + /src/source0.kt + package com.test.package0 + /** + * Documentation for TestClass + */ + class TestClass { + /** + * Documentation for testFunction + */ + fun testFunction(): String = "" + } + """, + java = + """ + /src/com/test/package0/TestClass.java + package com.test.package0 + /** + * Documentation for TestClass + */ + public final class TestClass { + /** + * Documentation for testFunction + */ + public final String testFunction() { + return ""; + } + } + """ + ) { + val map = singlePageOfType<JavadocClasslikePageNode>().templateMap + + assertEquals("TestClass", map["name"]) + assertEquals("TestClass", map["title"]) + assertEquals("com.test.package0", map["packageName"]) + assertEquals("<p>Documentation for TestClass</p>", map["classlikeDocumentation"]) + assertEquals("Documentation for TestClass", map["subtitle"]) + assertEquals("public final class", map.modifiers()) + assertEquals("<a href=TestClass.html>TestClass</a>", map.signatureWithoutModifiers()) + + val methods = assertIsInstance<Map<Any, Any?>>(map["methods"]) + val ownMethods = assertIsInstance<List<*>>(methods["own"]) + assertEquals(1, ownMethods.size, "Expected only one method") + val method = assertIsInstance<Map<String, Any?>>(ownMethods.single()) + assertEquals("Documentation for testFunction", method["brief"]) + assertEquals("testFunction", method["name"]) + assertEquals( + 0, assertIsInstance<List<*>>(method["parameters"]).size, + "Expected no parameters" + ) + assertEquals("final <a href=https://docs.oracle.com/javase/8/docs/api/java/lang/String.html>String</a>", method.modifiers()) + assertEquals("<a href=TestClass.html#testFunction()>testFunction</a>()", method.signatureWithoutModifiers()) + } + } + + @Test + fun `class with annotation`(){ + dualTestTemplateMapInline( + kotlin = + """ + /src/source0.kt + package com.test.package0 + @MustBeDocumented + annotation class Author(val name: String) + + @Author( + name = "Benjamin Franklin" + ) + class TestClass {` + + @Author( + name = "Franklin D. Roosevelt" + ) + fun testFunction(): String = "" + } + """, + java = + """ + /src/com/test/package0/Author.java + package com.test.package0 + import java.lang.annotation.Documented; + + @Documented + public @interface Author { + String name(); + } + /src/com/test/package0/TestClass.java + package com.test.package0 + + @Author( + name = "Benjamin Franklin" + ) + public final class TestClass { + + @Author( + name = "Franklin D. Roosevelt" + ) + public final String testFunction() { + return ""; + } + } + """ + ){ + val map = allPagesOfType<JavadocClasslikePageNode>().first { it.name == "TestClass" }.templateMap + assertEquals("TestClass", map["name"]) + val signature = assertIsInstance<Map<String, Any?>>(map["signature"]) + assertEquals("@<a href=Author.html>Author</a>(name = "Benjamin Franklin")", signature["annotations"]) + + val methods = assertIsInstance<Map<Any, Any?>>(map["methods"]) + val ownMethods = assertIsInstance<List<*>>(methods["own"]) + val method = assertIsInstance<Map<String, Any?>>(ownMethods.single()) + val methodSignature = assertIsInstance<Map<String, Any?>>(method["signature"]) + assertEquals("@<a href=Author.html>Author</a>(name = "Franklin D. Roosevelt")", methodSignature["annotations"]) + } + } + + @Test + fun `simple enum`(){ + dualTestTemplateMapInline( + kotlin = + """ + /src/source0.kt + package com.test.package0 + enum class ClockDays { + /** + * Sample docs for first + */ + FIRST, + /** + * Sample docs for second + */ + SECOND + } + """, + java = + """ + /src/com/test/package0/TestClass.java + package com.test.package0; + public enum ClockDays { + /** + * Sample docs for first + */ + FIRST, + /** + * Sample docs for second + */ + SECOND + } + """ + ){ + val map = singlePageOfType<JavadocClasslikePageNode>().templateMap + assertEquals("ClockDays", map["name"]) + assertEquals("enum", map["kind"]) + val entries = assertIsInstance<List<Map<String, Any?>>>(map["entries"]) + assertEquals(2, entries.size) + + val (first, second) = entries.sortedBy { it["brief"] as String } + assertEquals("<p>Sample docs for first</p>", first["brief"]) + assertEquals("<p>Sample docs for second</p>", second["brief"]) + + assertEquals("<a href=ClockDays.html#FIRST>FIRST</a>", first.signatureWithoutModifiers()) + assertEquals("<a href=ClockDays.html#SECOND>SECOND</a>", second.signatureWithoutModifiers()) + } + } + + @Test + fun `documented function parameters`(){ + dualTestTemplateMapInline( + kotlin = + """ + /src/source0.kt + package com.test.package0 + class TestClass { + /** + * Simple parameters list to check out + * @param simple simple String parameter + * @param parameters simple Integer parameter + * @param list simple Boolean parameter + * @return just a String + */ + fun testFunction(simple: String?, parameters: Int?, list: Boolean?): String { + return "" + } + } + """, + java = + """ + /src/com/test/package0/TestClass.java + package com.test.package0; + public final class TestClass { + /** + * Simple parameters list to check out + * @param simple simple String parameter + * @param parameters simple Integer parameter + * @param list simple Boolean parameter + * @return just a String + */ + public final String testFunction(String simple, Integer parameters, Boolean list) { + return ""; + } + } + """ + ) { + val map = singlePageOfType<JavadocClasslikePageNode>().templateMap + assertEquals("TestClass", map["name"]) + + val methods = assertIsInstance<Map<String, Any?>>(map["methods"]) + val testFunction = assertIsInstance<List<Map<String, Any?>>>(methods["own"]).single() + assertEquals("Simple parameters list to check out", testFunction["brief"]) + + val (first, second, third) = assertIsInstance<List<Map<String, Any?>>>(testFunction["parameters"]) + assertParameterNode( + node = first, + expectedName = "simple", + expectedType = "<a href=https://docs.oracle.com/javase/8/docs/api/java/lang/String.html>String</a>", + expectedDescription = "simple String parameter" + ) + assertParameterNode( + node = second, + expectedName = "parameters", + expectedType = "<a href=https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html>Integer</a>", + expectedDescription = "simple Integer parameter" + ) + assertParameterNode( + node = third, + expectedName = "list", + expectedType = "<a href=https://docs.oracle.com/javase/8/docs/api/java/lang/Boolean.html>Boolean</a>", + expectedDescription = "simple Boolean parameter" + ) + } + } + + @Test + fun `with generic parameters`(){ + dualTestTemplateMapInline( + kotlin = + """ + /src/source0.kt + package com.test.package0 + import java.io.Serializable + + class Generic<T : Serializable?> { + fun <D : T> sampleFunction(): D = TODO() + } + """, + java = + """ + /src/com/test/package0/Generic.java + package com.test.package0; + import java.io.Serializable; + + public final class Generic<T extends Serializable> { + public final <D extends T> D sampleFunction(){ + return null; + } + } + """ + ) { + val map = singlePageOfType<JavadocClasslikePageNode>().templateMap + assertEquals("Generic", map["name"]) + + assertEquals( + "public final class <a href=Generic.html>Generic</a><T extends <a href=https://docs.oracle.com/javase/8/docs/api/java/io/Serializable.html>Serializable</a>>", + map.signatureWithModifiers() + ) + val methods = assertIsInstance<Map<Any, Any?>>(map["methods"]) + val ownMethods = assertIsInstance<List<*>>(methods["own"]).first() + val sampleFunction = assertIsInstance<Map<String, Any?>>(ownMethods) + + assertEquals("final <D extends <a href=Generic.html>T</a>> <a href=Generic.html#sampleFunction()>D</a> <a href=Generic.html#sampleFunction()>sampleFunction</a>()", sampleFunction.signatureWithModifiers()) + } + } + + @Test + fun `class with top-level const`() { + dualTestTemplateMapInline( + kotlin = + """ + /src/Test.kt + package com.test.package0 + + const val TEST_VAL = "test" + """, + java = + """ + /src/com/test/package0/TestKt.java + package com.test.package0; + + public final class TestKt { + public static final String TEST_VAL = "test"; + } + """ + ) { + val map = singlePageOfType<JavadocClasslikePageNode>().templateMap + val properties = assertIsInstance<List<*>>(map["properties"]) + val property = assertIsInstance<Map<String, Any?>>(properties.first()) + assertEquals("public final static <a href=https://docs.oracle.com/javase/8/docs/api/java/lang/String.html>String</a> <a href=TestKt.html#TEST_VAL>TEST_VAL</a>", "${property["modifiers"]} ${property["signature"]}") + } + } + + @Test + fun `@author @since @return method tags`(){ + dualTestTemplateMapInline( + kotlin = + """ + /src/source0.kt + package com.test.package0 + class TestClass { + /** + * Testing @author @since @return method tags + * @since 1.2 + * @since 08 april 2023 + * @return parameter's value in lower case + */ + fun testFunction(testParam: String?): String { + return testParam?.lowercase() ?: "" + } + } + """, + java = + """ + /src/com/test/package0/TestClass.java + package com.test.package0; + public final class TestClass { + /** + * Testing @author @since @return method tags + * @since 1.2 + * @since 08 april 2023 + * @return parameter's value in lower case + */ + public final String testFunction(String testParam) { + return testParam.toLowerCase(); + } + } + """ + ) { + val map = singlePageOfType<JavadocClasslikePageNode>().templateMap + assertEquals("TestClass", map["name"]) + + val methods = assertIsInstance<Map<String, Any?>>(map["methods"]) + val testFunction = assertIsInstance<List<Map<String, Any?>>>(methods["own"]).single() + assertEquals("Testing @author @since @return method tags", testFunction["brief"]) + + assertEquals("testFunction", testFunction["name"]) + assertEquals(listOf("<p>1.2</p>", "<p>08 april 2023</p>"), testFunction["sinceTagContent"]) + assertEquals("<p>parameter's value in lower case</p>", testFunction["returnTagContent"]) + } + } + + @Test + fun `@author @since class tags`(){ + dualTestTemplateMapInline( + kotlin = + """ + /src/source0.kt + package com.test.package0 + /** + * Testing @author @since class tags + * @author Test Author + * @author Test Author2 + * @author Test Author3 + * @since 1.2 + * @since 08 april 2023 + */ + class TestClass { + fun testFunction(testParam: String?): String { + return testParam?.lowercase() ?: "" + } + } + """, + java = + """ + /src/com/test/package0/TestClass.java + package com.test.package0; + /** + * Testing @author @since class tags + * @author Test Author + * @author Test Author2 + * @author Test Author3 + * @since 1.2 + |
