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-base/src/test/kotlin/model/annotations | |
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-base/src/test/kotlin/model/annotations')
3 files changed, 481 insertions, 0 deletions
diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/model/annotations/JavaAnnotationsForParametersTest.kt b/dokka-subprojects/plugin-base/src/test/kotlin/model/annotations/JavaAnnotationsForParametersTest.kt new file mode 100644 index 00000000..9800006b --- /dev/null +++ b/dokka-subprojects/plugin-base/src/test/kotlin/model/annotations/JavaAnnotationsForParametersTest.kt @@ -0,0 +1,181 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package model.annotations + +import org.jetbrains.dokka.base.signatures.KotlinSignatureUtils.annotations +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.utilities.cast +import utils.AbstractModelTest +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class JavaAnnotationsForParametersTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { + + @Test + fun `function with deprecated parameter`() { + inlineModelTest( + """ + |public class Test { + | public void fn(@Deprecated String name) {} + |} + """.trimIndent() + ) { + with((this / "java" / "Test").cast<DClass>()) { + with((this / "fn").cast<DFunction>()) { + val dri = + parameters.first().extra[Annotations]?.directAnnotations?.flatMap { it.value }?.map { it.dri } + assertEquals(listOf(DRI("java.lang", "Deprecated")), dri) + } + } + } + } + + @Test + fun `function with parameter that has custom annotation`() { + inlineModelTest( + """ + |@Retention(RetentionPolicy.RUNTIME) + |@Target(ElementType.PARAMETER) + |public @interface Hello { + | public String bar() default ""; + |} + |public class Test { + | public void foo(@Hello(bar = "baz") String arg){ } + |} + """.trimIndent() + ) { + with((this / "java" / "Test").cast<DClass>()) { + with((this / "foo").cast<DFunction>()) { + val annotations = + parameters.first().extra[Annotations]?.directAnnotations?.flatMap { it.value } + val driOfHello = DRI("java", "Hello") + val annotationsValues = annotations?.flatMap { it.params.values }?.map { it.toString() }?.toList() + + assertEquals(listOf(driOfHello), annotations?.map { it.dri }) + assertEquals(listOf("baz"), annotationsValues) + } + } + } + } + + @Test + fun `function with annotated generic parameter`() { + inlineModelTest( + """ + |@Retention(RetentionPolicy.RUNTIME) + |@Target(ElementType.TYPE_PARAMETER) + |@interface Hello { + | public String bar() default ""; + |} + |public class Test { + | public <@Hello(bar = "baz") T> List<T> foo() { + | return null; + | } + |} + """.trimIndent() + ) { + with((this / "java" / "Test").cast<DClass>()) { + with((this / "foo").cast<DFunction>()) { + val annotations = generics.first().extra[Annotations]?.directAnnotations?.flatMap { it.value } + val driOfHello = DRI("java", "Hello") + val annotationsValues = annotations?.flatMap { it.params.values }?.map { it.toString() }?.toList() + + assertEquals(listOf(driOfHello), annotations?.map { it.dri }) + assertEquals(listOf("baz"), annotationsValues) + } + } + } + } + + @Test + fun `function with generic parameter that has annotated bounds`() { + inlineModelTest( + """ + |@Retention(RetentionPolicy.RUNTIME) + |@Target({ElementType.TYPE_USE}) + |@interface Hello { + | public String bar() default ""; + |} + |public class Test { + | public <T extends @Hello(bar = "baz") String> List<T> foo() { + | return null; + | } + |} + """.trimIndent() + ) { + with((this / "java" / "Test").cast<DClass>()) { + with((this / "foo").cast<DFunction>()) { + val annotations = ((generics.first().bounds.first() as Nullable).inner as GenericTypeConstructor) + .extra[Annotations]?.directAnnotations?.flatMap { it.value } + val driOfHello = DRI("java", "Hello") + val annotationsValues = annotations?.flatMap { it.params.values }?.map { it.toString() }?.toList() + + assertEquals(listOf(driOfHello), annotations?.map { it.dri }) + assertEquals(listOf("baz"), annotationsValues) + } + } + } + } + + @Test + fun `type parameter annotations should be visible even if type declaration has none`() { + inlineModelTest( + """ + |@Retention(RetentionPolicy.RUNTIME) + |@Target(ElementType.PARAMETER) + |public @interface Hello { + | public String bar() default ""; + |} + |public class Test { + | public <T> void foo(java.util.List<@Hello T> param) {} + |} + """.trimIndent() + ) { + with((this / "java" / "Test").cast<DClass>()) { + with((this / "foo").cast<DFunction>()) { + val paramAnnotations = parameters.first() + .type.cast<GenericTypeConstructor>() + .projections.first().cast<TypeParameter>() + .annotations() + .values + .flatten() + + assertEquals(1, paramAnnotations.size) + assertEquals(DRI("java", "Hello"), paramAnnotations[0].dri) + } + } + } + } + + @Test + fun `type parameter annotations should not be propagated from resolved type`() { + inlineModelTest( + """ + |@Retention(RetentionPolicy.RUNTIME) + |@Target(ElementType.PARAMETER) + |public @interface Hello { + | public String bar() default ""; + |} + |public class Test { + | public <@Hello T> void foo(java.util.List<T> param) {} + |} + """.trimIndent() + ) { + with((this / "java" / "Test").cast<DClass>()) { + with((this / "foo").cast<DFunction>()) { + val paramAnnotations = parameters.first() + .type.cast<GenericTypeConstructor>() + .projections.first().cast<TypeParameter>() + .annotations() + + assertTrue(paramAnnotations.isEmpty()) + } + } + } + } +} + diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/model/annotations/JavaAnnotationsTest.kt b/dokka-subprojects/plugin-base/src/test/kotlin/model/annotations/JavaAnnotationsTest.kt new file mode 100644 index 00000000..daab7dc9 --- /dev/null +++ b/dokka-subprojects/plugin-base/src/test/kotlin/model/annotations/JavaAnnotationsTest.kt @@ -0,0 +1,195 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package model.annotations + +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.model.* +import translators.findClasslike +import kotlin.test.* + +class JavaAnnotationsTest : BaseAbstractTest() { + + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/main/java") + } + } + } + + @Test // see https://github.com/Kotlin/dokka/issues/2350 + fun `should hande array used as annotation param value`() { + testInline( + """ + |/src/main/java/annotation/TestClass.java + |package annotation; + |public class TestClass { + | @SimpleAnnotation(clazz = String[].class) + | public boolean simpleAnnotation() { + | return false; + | } + |} + | + |/src/main/java/annotation/SimpleAnnotation.java + |package annotation; + |@Retention(RetentionPolicy.RUNTIME) + |@Target(ElementType.METHOD) + |public @interface SimpleAnnotation { + | Class<?> clazz(); + |} + """.trimIndent(), + configuration + ) { + documentablesTransformationStage = { module -> + val testClass = module.findClasslike("annotation", "TestClass") as DClass + assertNotNull(testClass) + + val annotatedFunction = testClass.functions.single { it.name == "simpleAnnotation" } + val annotation = + annotatedFunction.extra[Annotations]?.directAnnotations?.entries?.single()?.value?.single() + assertNotNull(annotation) { "Expected to find an annotation on simpleAnnotation function, found none" } + assertEquals("annotation", annotation.dri.packageName) + assertEquals("SimpleAnnotation", annotation.dri.classNames) + assertEquals(1, annotation.params.size) + + val param = annotation.params.values.single() + assertTrue(param is ClassValue) + // should probably be Array instead + // String matches parsing of Kotlin sources as of now + assertEquals("String", param.className) + assertEquals("java.lang", param.classDRI.packageName) + assertEquals("String", param.classDRI.classNames) + } + } + } + + @Test // see https://github.com/Kotlin/dokka/issues/2551 + fun `should hande annotation used within annotation params with class param value`() { + testInline( + """ + |/src/main/java/annotation/TestClass.java + |package annotation; + |public class TestClass { + | @XmlElementRefs({ + | @XmlElementRef(name = "NotOffered", namespace = "http://www.gaeb.de/GAEB_DA_XML/DA86/3.3", type = JAXBElement.class, required = false) + | }) + | public List<JAXBElement<Object>> content; + |} + | + |/src/main/java/annotation/XmlElementRefs.java + |package annotation; + |public @interface XmlElementRefs { + | XmlElementRef[] value(); + |} + | + |/src/main/java/annotation/XmlElementRef.java + |package annotation; + |public @interface XmlElementRef { + | String name(); + | + | String namespace(); + | + | boolean required(); + | + | Class<JAXBElement> type(); + |} + | + |/src/main/java/annotation/JAXBElement.java + |package annotation; + |public class JAXBElement<T> { + |} + """.trimIndent(), + configuration + ) { + documentablesTransformationStage = { module -> + val testClass = module.findClasslike("annotation", "TestClass") as DClass + assertNotNull(testClass) + + val contentField = testClass.properties.find { it.name == "content" } + assertNotNull(contentField) + + val annotation = contentField.extra[Annotations]?.directAnnotations?.entries?.single()?.value?.single() + assertNotNull(annotation) { "Expected to find an annotation on content field, found none" } + assertEquals("XmlElementRefs", annotation.dri.classNames) + assertEquals(1, annotation.params.size) + + val arrayParam = annotation.params.values.single() + assertTrue(arrayParam is ArrayValue, "Expected single annotation param to be array") + assertEquals(1, arrayParam.value.size) + + val arrayParamValue = arrayParam.value.single() + assertTrue(arrayParamValue is AnnotationValue) + + val arrayParamAnnotationValue = arrayParamValue.annotation + assertEquals(4, arrayParamAnnotationValue.params.size) + assertEquals("XmlElementRef", arrayParamAnnotationValue.dri.classNames) + + val annotationParams = arrayParamAnnotationValue.params.values.toList() + + val nameParam = annotationParams[0] + assertTrue(nameParam is StringValue) + assertEquals("NotOffered", nameParam.value) + + val namespaceParam = annotationParams[1] + assertTrue(namespaceParam is StringValue) + assertEquals("http://www.gaeb.de/GAEB_DA_XML/DA86/3.3", namespaceParam.value) + + val typeParam = annotationParams[2] + assertTrue(typeParam is ClassValue) + assertEquals("JAXBElement", typeParam.className) + assertEquals("annotation", typeParam.classDRI.packageName) + assertEquals("JAXBElement", typeParam.classDRI.classNames) + + val requiredParam = annotationParams[3] + assertTrue(requiredParam is BooleanValue) + assertFalse(requiredParam.value) + } + } + } + + @Test // see https://github.com/Kotlin/dokka/issues/2509 + fun `should handle generic class in annotation`() { + testInline( + """ + |/src/main/java/annotation/Breaking.java + |package annotation; + |public class Breaking<Y> { + |} + | + |/src/main/java/annotation/TestAnnotate.java + |package annotation; + |public @interface TestAnnotate { + | Class<?> value(); + |} + | + |/src/main/java/annotation/TestClass.java + |package annotation; + |@TestAnnotate(Breaking.class) + |public class TestClass { + |} + """.trimIndent(), + configuration + ) { + documentablesTransformationStage = { module -> + val testClass = module.findClasslike("annotation", "TestClass") as DClass + assertNotNull(testClass) + + val annotation = testClass.extra[Annotations]?.directAnnotations?.entries?.single()?.value?.single() + assertNotNull(annotation) { "Expected to find an annotation on TestClass, found none" } + + assertEquals("TestAnnotate", annotation.dri.classNames) + assertEquals(1, annotation.params.size) + + val valueParameter = annotation.params.values.single() + assertTrue(valueParameter is ClassValue) + + assertEquals("Breaking", valueParameter.className) + + assertEquals("annotation", valueParameter.classDRI.packageName) + assertEquals("Breaking", valueParameter.classDRI.classNames) + } + } + } +} diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/model/annotations/KotlinAnnotationsForParametersTest.kt b/dokka-subprojects/plugin-base/src/test/kotlin/model/annotations/KotlinAnnotationsForParametersTest.kt new file mode 100644 index 00000000..e3b17818 --- /dev/null +++ b/dokka-subprojects/plugin-base/src/test/kotlin/model/annotations/KotlinAnnotationsForParametersTest.kt @@ -0,0 +1,105 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package model.annotations + +import org.jetbrains.dokka.base.signatures.KotlinSignatureUtils.annotations +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.utilities.cast +import utils.AbstractModelTest +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class KotlinAnnotationsForParametersTest : AbstractModelTest("/src/main/kotlin/annotations/Test.kt", "annotations") { + @Test + fun `generic receiver with annotations`() { + inlineModelTest( + """ + |@Target(AnnotationTarget.TYPE_PARAMETER) + |annotation class Hello(val bar: String) + |fun <@Hello("abc") T> foo(arg: String): List<T> = TODO() + """.trimIndent() + ) { + with((this / "annotations" / "foo").cast<DFunction>()) { + val annotations = generics.first().extra[Annotations]?.directAnnotations?.flatMap { it.value } + val driOfHello = DRI("annotations", "Hello") + val annotationsValues = annotations?.flatMap { it.params.values }?.map { it.toString() }?.toList() + + assertEquals(listOf(driOfHello), annotations?.map { it.dri }) + assertEquals(listOf("abc"), annotationsValues) + } + } + } + + @Test + fun `generic receiver with annotated bounds`() { + inlineModelTest( + """ + |@Target(AnnotationTarget.TYPE_PARAMETER) + |annotation class Hello(val bar: String) + |fun <T: @Hello("abc") String> foo(arg: String): List<T> = TODO() + """.trimIndent() + ) { + with((this / "annotations" / "foo").cast<DFunction>()) { + val annotations = (generics.first().bounds.first() as GenericTypeConstructor) + .extra[Annotations]?.directAnnotations?.flatMap { it.value } + val driOfHello = DRI("annotations", "Hello") + val annotationsValues = annotations?.flatMap { it.params.values }?.map { it.toString() }?.toList() + + assertEquals(listOf(driOfHello), annotations?.map { it.dri }) + assertEquals(listOf("abc"), annotationsValues) + } + } + } + + @Test + fun `type parameter annotations should be visible even if type declaration has none`() { + inlineModelTest( + """ + |@Target(AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.TYPE) + |annotation class Hello + | + |fun <T> foo(param: List<@Hello T>) {} + """.trimIndent() + ) { + with((this / "annotations" / "foo").cast<DFunction>()) { + val paramAnnotations = parameters.first() + .type.cast<GenericTypeConstructor>() + .projections + .first().cast<Invariance<TypeParameter>>() + .inner.cast<TypeParameter>() + .annotations() + .values + .flatten() + + assertEquals(1, paramAnnotations.size) + assertEquals(DRI("annotations", "Hello"), paramAnnotations[0].dri) + } + } + } + + @Test + fun `type parameter annotations should not be propagated from resolved type`() { + inlineModelTest( + """ + |@Target(AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.TYPE) + |annotation class Hello + | + |fun <@Hello T> foo(param: List<T>) {} + """.trimIndent() + ) { + with((this / "annotations" / "foo").cast<DFunction>()) { + val paramAnnotations = parameters.first() + .type.cast<GenericTypeConstructor>() + .projections.first().cast<Invariance<TypeParameter>>() + .inner.cast<TypeParameter>() + .annotations() + + assertTrue(paramAnnotations.isEmpty()) + } + } + } +} |