aboutsummaryrefslogtreecommitdiff
path: root/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet
diff options
context:
space:
mode:
Diffstat (limited to 'interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet')
-rw-r--r--interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/FacadeFile.kt96
-rw-r--r--interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/FacadeFileTest.kt394
-rw-r--r--interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/JvmNameWithKtFacadeFile.kt20
-rw-r--r--interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/KmAnnotationsTest.kt260
-rw-r--r--interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/KotlinPoetMetadataSpecsTest.kt2250
-rw-r--r--interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/MultiClassInspectorTest.kt119
-rw-r--r--interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/NoJvmNameFacadeFile.kt18
-rw-r--r--interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/ReflectiveClassInspectorTest.kt90
-rw-r--r--interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/classinspectors/ClassInspectorUtilTest.kt96
9 files changed, 3343 insertions, 0 deletions
diff --git a/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/FacadeFile.kt b/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/FacadeFile.kt
new file mode 100644
index 00000000..6eb40a88
--- /dev/null
+++ b/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/FacadeFile.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2021 Square, Inc.
+ *
+ * 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.
+ */
+@file:JvmName("FacadeFile")
+@file:FileAnnotation("file annotations!")
+
+package com.squareup.kotlinpoet.metadata.specs
+
+import kotlin.annotation.AnnotationTarget.FILE
+
+@Target(FILE)
+annotation class FileAnnotation(val value: String)
+
+@JvmName("jvmStaticFunction")
+fun jvmNameFunction() {
+}
+
+fun regularFun() {
+}
+
+@Synchronized
+fun synchronizedFun() {
+}
+
+@JvmOverloads
+fun jvmOverloads(
+ param1: String,
+ optionalParam2: String = "",
+ nullableParam3: String? = null,
+) {
+}
+
+val BOOL_PROP = false
+val BINARY_PROP = 0b00001011
+val INT_PROP = 1
+val UNDERSCORES_PROP = 1_000_000
+val HEX_PROP = 0x0F
+val UNDERSCORES_HEX_PROP = 0xFF_EC_DE_5E
+val LONG_PROP = 1L
+val FLOAT_PROP = 1.0f
+val DOUBLE_PROP = 1.0
+val STRING_PROP = "prop"
+var VAR_BOOL_PROP = false
+var VAR_BINARY_PROP = 0b00001011
+var VAR_INT_PROP = 1
+var VAR_UNDERSCORES_PROP = 1_000_000
+var VAR_HEX_PROP = 0x0F
+var VAR_UNDERSCORES_HEX_PROP = 0xFF_EC_DE_5E
+var VAR_LONG_PROP = 1L
+var VAR_FLOAT_PROP = 1.0f
+var VAR_DOUBLE_PROP = 1.0
+var VAR_STRING_PROP = "prop"
+
+const val CONST_BOOL_PROP = false
+const val CONST_BINARY_PROP = 0b00001011
+const val CONST_INT_PROP = 1
+const val CONST_UNDERSCORES_PROP = 1_000_000
+const val CONST_HEX_PROP = 0x0F
+const val CONST_UNDERSCORES_HEX_PROP = 0xFF_EC_DE_5E
+const val CONST_LONG_PROP = 1L
+const val CONST_FLOAT_PROP = 1.0f
+const val CONST_DOUBLE_PROP = 1.0
+const val CONST_STRING_PROP = "prop"
+
+@JvmField
+@JvmSynthetic
+val syntheticFieldProperty: kotlin.String? = null
+
+@field:JvmSynthetic
+val syntheticProperty: kotlin.String? = null
+
+@get:JvmSynthetic
+val syntheticPropertyGet: kotlin.String? = null
+
+@get:JvmSynthetic
+@set:JvmSynthetic
+var syntheticPropertyGetAndSet: kotlin.String? = null
+
+@set:JvmSynthetic
+var syntheticPropertySet: kotlin.String? = null
+
+typealias FacadeTypeAliasName = String
+typealias FacadeGenericTypeAlias = List<String>
+typealias FacadeNestedTypeAlias = List<GenericTypeAlias>
diff --git a/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/FacadeFileTest.kt b/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/FacadeFileTest.kt
new file mode 100644
index 00000000..adea853f
--- /dev/null
+++ b/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/FacadeFileTest.kt
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) 2021 Square, Inc.
+ *
+ * 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.
+ */
+package com.squareup.kotlinpoet.metadata.specs
+
+import com.google.common.truth.Truth.assertThat
+import com.squareup.kotlinpoet.FileSpec
+import com.squareup.kotlinpoet.metadata.KotlinPoetMetadataPreview
+import com.squareup.kotlinpoet.metadata.specs.MultiClassInspectorTest.ClassInspectorType.ELEMENTS
+import com.squareup.kotlinpoet.metadata.specs.MultiClassInspectorTest.ClassInspectorType.REFLECTIVE
+import org.junit.Test
+
+@KotlinPoetMetadataPreview
+class FacadeFileTest : MultiClassInspectorTest() {
+
+ @IgnoreForHandlerType(
+ handlerType = ELEMENTS,
+ reason = "Elements can detect JvmOverloads, JvmName not possible in reflection",
+ )
+ @Test
+ fun facadeFile_reflective() {
+ val fileSpec = Class.forName(
+ "com.squareup.kotlinpoet.metadata.specs.FacadeFile",
+ ).kotlin.toFileSpecWithTestHandler()
+ assertThat(fileSpec.name).isEqualTo("FacadeFile")
+ //language=kotlin
+ assertThat(fileSpec.trimmedToString()).isEqualTo(
+ """
+ @file:JvmName(name = "FacadeFile")
+ @file:FileAnnotation(value = "file annotations!")
+
+ package com.squareup.kotlinpoet.metadata.specs
+
+ import com.squareup.kotlinpoet.metadata.specs.FileAnnotation
+ import kotlin.Boolean
+ import kotlin.Double
+ import kotlin.Float
+ import kotlin.Int
+ import kotlin.Long
+ import kotlin.String
+ import kotlin.Unit
+ import kotlin.collections.List
+ import kotlin.jvm.JvmField
+ import kotlin.jvm.JvmName
+ import kotlin.jvm.JvmSynthetic
+ import kotlin.jvm.Synchronized
+
+ @JvmName(name = "jvmStaticFunction")
+ public fun jvmNameFunction(): Unit {
+ }
+
+ public fun jvmOverloads(
+ param1: String,
+ optionalParam2: String = throw NotImplementedError("Stub!"),
+ nullableParam3: String? = throw NotImplementedError("Stub!"),
+ ): Unit {
+ }
+
+ public fun regularFun(): Unit {
+ }
+
+ @Synchronized
+ public fun synchronizedFun(): Unit {
+ }
+
+ public val BINARY_PROP: Int = 11
+
+ public val BOOL_PROP: Boolean = false
+
+ public const val CONST_BINARY_PROP: Int = 11
+
+ public const val CONST_BOOL_PROP: Boolean = false
+
+ public const val CONST_DOUBLE_PROP: Double = 1.0
+
+ public const val CONST_FLOAT_PROP: Float = 1.0F
+
+ public const val CONST_HEX_PROP: Int = 15
+
+ public const val CONST_INT_PROP: Int = 1
+
+ public const val CONST_LONG_PROP: Long = 1L
+
+ public const val CONST_STRING_PROP: String = "prop"
+
+ public const val CONST_UNDERSCORES_HEX_PROP: Long = 4_293_713_502L
+
+ public const val CONST_UNDERSCORES_PROP: Int = 1_000_000
+
+ public val DOUBLE_PROP: Double = 1.0
+
+ public val FLOAT_PROP: Float = 1.0F
+
+ public val HEX_PROP: Int = 15
+
+ public val INT_PROP: Int = 1
+
+ public val LONG_PROP: Long = 1L
+
+ public val STRING_PROP: String = "prop"
+
+ public val UNDERSCORES_HEX_PROP: Long = 4_293_713_502L
+
+ public val UNDERSCORES_PROP: Int = 1_000_000
+
+ public var VAR_BINARY_PROP: Int = throw NotImplementedError("Stub!")
+
+ public var VAR_BOOL_PROP: Boolean = throw NotImplementedError("Stub!")
+
+ public var VAR_DOUBLE_PROP: Double = throw NotImplementedError("Stub!")
+
+ public var VAR_FLOAT_PROP: Float = throw NotImplementedError("Stub!")
+
+ public var VAR_HEX_PROP: Int = throw NotImplementedError("Stub!")
+
+ public var VAR_INT_PROP: Int = throw NotImplementedError("Stub!")
+
+ public var VAR_LONG_PROP: Long = throw NotImplementedError("Stub!")
+
+ public var VAR_STRING_PROP: String = throw NotImplementedError("Stub!")
+
+ public var VAR_UNDERSCORES_HEX_PROP: Long = throw NotImplementedError("Stub!")
+
+ public var VAR_UNDERSCORES_PROP: Int = throw NotImplementedError("Stub!")
+
+ @field:JvmSynthetic
+ @JvmField
+ public val syntheticFieldProperty: String? = null
+
+ @field:JvmSynthetic
+ public val syntheticProperty: String? = null
+
+ @get:JvmSynthetic
+ public val syntheticPropertyGet: String? = null
+
+ @get:JvmSynthetic
+ @set:JvmSynthetic
+ public var syntheticPropertyGetAndSet: String? = null
+
+ @set:JvmSynthetic
+ public var syntheticPropertySet: String? = null
+
+ public typealias FacadeGenericTypeAlias = List<String>
+
+ public typealias FacadeNestedTypeAlias = List<GenericTypeAlias>
+
+ public typealias FacadeTypeAliasName = String
+ """.trimIndent(),
+ )
+ }
+
+ @IgnoreForHandlerType(
+ handlerType = REFLECTIVE,
+ reason = "Elements can detect JvmOverloads, JvmName not possible in reflection",
+ )
+ @Test
+ fun facadeFile_elements() {
+ val fileSpec = Class.forName(
+ "com.squareup.kotlinpoet.metadata.specs.FacadeFile",
+ ).kotlin.toFileSpecWithTestHandler()
+ assertThat(fileSpec.name).isEqualTo("FacadeFile")
+ //language=kotlin
+ assertThat(fileSpec.trimmedToString()).isEqualTo(
+ """
+ @file:FileAnnotation(value = "file annotations!")
+ @file:JvmName(name = "FacadeFile")
+
+ package com.squareup.kotlinpoet.metadata.specs
+
+ import com.squareup.kotlinpoet.metadata.specs.FileAnnotation
+ import kotlin.Boolean
+ import kotlin.Double
+ import kotlin.Float
+ import kotlin.Int
+ import kotlin.Long
+ import kotlin.String
+ import kotlin.Unit
+ import kotlin.collections.List
+ import kotlin.jvm.JvmName
+ import kotlin.jvm.JvmOverloads
+ import kotlin.jvm.JvmSynthetic
+ import kotlin.jvm.Synchronized
+
+ @JvmName(name = "jvmStaticFunction")
+ public fun jvmNameFunction(): Unit {
+ }
+
+ @JvmOverloads
+ public fun jvmOverloads(
+ param1: String,
+ optionalParam2: String = throw NotImplementedError("Stub!"),
+ nullableParam3: String? = throw NotImplementedError("Stub!"),
+ ): Unit {
+ }
+
+ public fun regularFun(): Unit {
+ }
+
+ @Synchronized
+ public fun synchronizedFun(): Unit {
+ }
+
+ public val BINARY_PROP: Int = throw NotImplementedError("Stub!")
+
+ public val BOOL_PROP: Boolean = throw NotImplementedError("Stub!")
+
+ public const val CONST_BINARY_PROP: Int = 11
+
+ public const val CONST_BOOL_PROP: Boolean = false
+
+ public const val CONST_DOUBLE_PROP: Double = 1.0
+
+ public const val CONST_FLOAT_PROP: Float = 1.0F
+
+ public const val CONST_HEX_PROP: Int = 15
+
+ public const val CONST_INT_PROP: Int = 1
+
+ public const val CONST_LONG_PROP: Long = 1L
+
+ public const val CONST_STRING_PROP: String = "prop"
+
+ public const val CONST_UNDERSCORES_HEX_PROP: Long = 4_293_713_502L
+
+ public const val CONST_UNDERSCORES_PROP: Int = 1_000_000
+
+ public val DOUBLE_PROP: Double = throw NotImplementedError("Stub!")
+
+ public val FLOAT_PROP: Float = throw NotImplementedError("Stub!")
+
+ public val HEX_PROP: Int = throw NotImplementedError("Stub!")
+
+ public val INT_PROP: Int = throw NotImplementedError("Stub!")
+
+ public val LONG_PROP: Long = throw NotImplementedError("Stub!")
+
+ public val STRING_PROP: String = throw NotImplementedError("Stub!")
+
+ public val UNDERSCORES_HEX_PROP: Long = throw NotImplementedError("Stub!")
+
+ public val UNDERSCORES_PROP: Int = throw NotImplementedError("Stub!")
+
+ public var VAR_BINARY_PROP: Int = throw NotImplementedError("Stub!")
+
+ public var VAR_BOOL_PROP: Boolean = throw NotImplementedError("Stub!")
+
+ public var VAR_DOUBLE_PROP: Double = throw NotImplementedError("Stub!")
+
+ public var VAR_FLOAT_PROP: Float = throw NotImplementedError("Stub!")
+
+ public var VAR_HEX_PROP: Int = throw NotImplementedError("Stub!")
+
+ public var VAR_INT_PROP: Int = throw NotImplementedError("Stub!")
+
+ public var VAR_LONG_PROP: Long = throw NotImplementedError("Stub!")
+
+ public var VAR_STRING_PROP: String = throw NotImplementedError("Stub!")
+
+ public var VAR_UNDERSCORES_HEX_PROP: Long = throw NotImplementedError("Stub!")
+
+ public var VAR_UNDERSCORES_PROP: Int = throw NotImplementedError("Stub!")
+
+ @field:JvmSynthetic
+ public val syntheticFieldProperty: String? = null
+
+ @field:JvmSynthetic
+ public val syntheticProperty: String? = null
+
+ @get:JvmSynthetic
+ public val syntheticPropertyGet: String? = null
+
+ @get:JvmSynthetic
+ @set:JvmSynthetic
+ public var syntheticPropertyGetAndSet: String? = null
+
+ @set:JvmSynthetic
+ public var syntheticPropertySet: String? = null
+
+ public typealias FacadeGenericTypeAlias = List<String>
+
+ public typealias FacadeNestedTypeAlias = List<GenericTypeAlias>
+
+ public typealias FacadeTypeAliasName = String
+ """.trimIndent(),
+ )
+ }
+
+ @IgnoreForHandlerType(
+ handlerType = ELEMENTS,
+ reason = "JvmName not possible in reflection",
+ )
+ @Test
+ fun noJvmName_reflective() {
+ val fileSpec = Class.forName(
+ "com.squareup.kotlinpoet.metadata.specs.NoJvmNameFacadeFileKt",
+ ).kotlin.toFileSpecWithTestHandler()
+ assertThat(fileSpec.name).isEqualTo("NoJvmNameFacadeFile")
+ //language=kotlin
+ assertThat(fileSpec.trimmedToString()).isEqualTo(
+ """
+ package com.squareup.kotlinpoet.metadata.specs
+
+ import kotlin.String
+
+ public val prop: String = ""
+ """.trimIndent(),
+ )
+ }
+
+ @IgnoreForHandlerType(
+ handlerType = REFLECTIVE,
+ reason = "JvmName not possible in reflection",
+ )
+ @Test
+ fun noJvmName_elements() {
+ val fileSpec = Class.forName(
+ "com.squareup.kotlinpoet.metadata.specs.NoJvmNameFacadeFileKt",
+ ).kotlin.toFileSpecWithTestHandler()
+ assertThat(fileSpec.name).isEqualTo("NoJvmNameFacadeFile")
+ //language=kotlin
+ assertThat(fileSpec.trimmedToString()).isEqualTo(
+ """
+ package com.squareup.kotlinpoet.metadata.specs
+
+ import kotlin.String
+
+ public val prop: String = throw NotImplementedError("Stub!")
+ """.trimIndent(),
+ )
+ }
+
+ @IgnoreForHandlerType(
+ handlerType = ELEMENTS,
+ reason = "JvmName not possible in reflection",
+ )
+ @Test
+ fun jvmName_with_kt_reflective() {
+ val fileSpec = Class.forName(
+ "com.squareup.kotlinpoet.metadata.specs.JvmNameKt",
+ ).kotlin.toFileSpecWithTestHandler()
+ assertThat(fileSpec.name).isEqualTo("JvmName")
+ //language=kotlin
+ assertThat(fileSpec.trimmedToString()).isEqualTo(
+ """
+ package com.squareup.kotlinpoet.metadata.specs
+
+ import kotlin.String
+
+ public val prop2: String = ""
+ """.trimIndent(),
+ )
+ }
+
+ @IgnoreForHandlerType(
+ handlerType = REFLECTIVE,
+ reason = "JvmName not possible in reflection",
+ )
+ @Test
+ fun jvmName_with_kt_elements() {
+ val fileSpec = Class.forName(
+ "com.squareup.kotlinpoet.metadata.specs.JvmNameKt",
+ ).kotlin.toFileSpecWithTestHandler()
+ assertThat(fileSpec.name).isEqualTo("JvmName")
+ //language=kotlin
+ assertThat(fileSpec.trimmedToString()).isEqualTo(
+ """
+ @file:JvmName(name = "JvmNameKt")
+
+ package com.squareup.kotlinpoet.metadata.specs
+
+ import kotlin.String
+ import kotlin.jvm.JvmName
+
+ public val prop2: String = throw NotImplementedError("Stub!")
+ """.trimIndent(),
+ )
+ }
+}
+
+private fun FileSpec.trimmedToString(): String {
+ return buildString { writeTo(this) }.trim()
+}
diff --git a/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/JvmNameWithKtFacadeFile.kt b/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/JvmNameWithKtFacadeFile.kt
new file mode 100644
index 00000000..008b36f1
--- /dev/null
+++ b/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/JvmNameWithKtFacadeFile.kt
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2021 Square, Inc.
+ *
+ * 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.
+ */
+@file:JvmName("JvmNameKt")
+
+package com.squareup.kotlinpoet.metadata.specs
+
+val prop2: String = ""
diff --git a/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/KmAnnotationsTest.kt b/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/KmAnnotationsTest.kt
new file mode 100644
index 00000000..c7928b4e
--- /dev/null
+++ b/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/KmAnnotationsTest.kt
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2021 Square, Inc.
+ *
+ * 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.
+ */
+package com.squareup.kotlinpoet.metadata.specs
+
+import com.google.common.truth.Truth.assertThat
+import com.squareup.kotlinpoet.metadata.KotlinPoetMetadataPreview
+import kotlin.test.Test
+import kotlinx.metadata.KmAnnotation
+import kotlinx.metadata.KmAnnotationArgument.AnnotationValue
+import kotlinx.metadata.KmAnnotationArgument.ArrayValue
+import kotlinx.metadata.KmAnnotationArgument.BooleanValue
+import kotlinx.metadata.KmAnnotationArgument.ByteValue
+import kotlinx.metadata.KmAnnotationArgument.CharValue
+import kotlinx.metadata.KmAnnotationArgument.DoubleValue
+import kotlinx.metadata.KmAnnotationArgument.EnumValue
+import kotlinx.metadata.KmAnnotationArgument.FloatValue
+import kotlinx.metadata.KmAnnotationArgument.IntValue
+import kotlinx.metadata.KmAnnotationArgument.KClassValue
+import kotlinx.metadata.KmAnnotationArgument.LongValue
+import kotlinx.metadata.KmAnnotationArgument.ShortValue
+import kotlinx.metadata.KmAnnotationArgument.StringValue
+import kotlinx.metadata.KmAnnotationArgument.UByteValue
+import kotlinx.metadata.KmAnnotationArgument.UIntValue
+import kotlinx.metadata.KmAnnotationArgument.ULongValue
+import kotlinx.metadata.KmAnnotationArgument.UShortValue
+
+@OptIn(ExperimentalUnsignedTypes::class)
+@KotlinPoetMetadataPreview
+class KmAnnotationsTest {
+
+ @Test fun noMembers() {
+ val annotation = KmAnnotation("test/NoMembersAnnotation", emptyMap())
+ assertThat(annotation.toAnnotationSpec().toString()).isEqualTo(
+ """
+ @test.NoMembersAnnotation
+ """.trimIndent(),
+ )
+ }
+
+ @Test fun byteValue() {
+ val annotation = KmAnnotation(
+ "test/ByteValueAnnotation",
+ mapOf("value" to ByteValue(2)),
+ )
+ assertThat(annotation.toAnnotationSpec().toString()).isEqualTo(
+ """
+ @test.ByteValueAnnotation(value = 2)
+ """.trimIndent(),
+ )
+ }
+
+ @Test fun charValue() {
+ val annotation = KmAnnotation(
+ "test/CharValueAnnotation",
+ mapOf("value" to CharValue('2')),
+ )
+ assertThat(annotation.toAnnotationSpec().toString()).isEqualTo(
+ """
+ @test.CharValueAnnotation(value = '2')
+ """.trimIndent(),
+ )
+ }
+
+ @Test fun shortValue() {
+ val annotation = KmAnnotation(
+ "test/ShortValueAnnotation",
+ mapOf("value" to ShortValue(2)),
+ )
+ assertThat(annotation.toAnnotationSpec().toString()).isEqualTo(
+ """
+ @test.ShortValueAnnotation(value = 2)
+ """.trimIndent(),
+ )
+ }
+
+ @Test fun intValue() {
+ val annotation = KmAnnotation(
+ "test/IntValueAnnotation",
+ mapOf("value" to IntValue(2)),
+ )
+ assertThat(annotation.toAnnotationSpec().toString()).isEqualTo(
+ """
+ @test.IntValueAnnotation(value = 2)
+ """.trimIndent(),
+ )
+ }
+
+ @Test fun longValue() {
+ val annotation = KmAnnotation(
+ "test/LongValueAnnotation",
+ mapOf("value" to LongValue(2L)),
+ )
+ assertThat(annotation.toAnnotationSpec().toString()).isEqualTo(
+ """
+ @test.LongValueAnnotation(value = 2L)
+ """.trimIndent(),
+ )
+ }
+
+ @Test fun floatValue() {
+ val annotation = KmAnnotation(
+ "test/FloatValueAnnotation",
+ mapOf("value" to FloatValue(2.0F)),
+ )
+ assertThat(annotation.toAnnotationSpec().toString()).isEqualTo(
+ """
+ @test.FloatValueAnnotation(value = 2.0F)
+ """.trimIndent(),
+ )
+ }
+
+ @Test fun doubleValue() {
+ val annotation = KmAnnotation(
+ "test/DoubleValueAnnotation",
+ mapOf("value" to DoubleValue(2.0)),
+ )
+ assertThat(annotation.toAnnotationSpec().toString()).isEqualTo(
+ """
+ @test.DoubleValueAnnotation(value = 2.0)
+ """.trimIndent(),
+ )
+ }
+
+ @Test fun booleanValue() {
+ val annotation = KmAnnotation(
+ "test/BooleanValueAnnotation",
+ mapOf("value" to BooleanValue(true)),
+ )
+ assertThat(annotation.toAnnotationSpec().toString()).isEqualTo(
+ """
+ @test.BooleanValueAnnotation(value = true)
+ """.trimIndent(),
+ )
+ }
+
+ @Test fun uByteValue() {
+ val annotation = KmAnnotation(
+ "test/UByteValueAnnotation",
+ mapOf("value" to UByteValue(2u)),
+ )
+ assertThat(annotation.toAnnotationSpec().toString()).isEqualTo(
+ """
+ @test.UByteValueAnnotation(value = 2u)
+ """.trimIndent(),
+ )
+ }
+
+ @Test fun uShortValue() {
+ val annotation = KmAnnotation(
+ "test/UShortValueAnnotation",
+ mapOf("value" to UShortValue(2u)),
+ )
+ assertThat(annotation.toAnnotationSpec().toString()).isEqualTo(
+ """
+ @test.UShortValueAnnotation(value = 2u)
+ """.trimIndent(),
+ )
+ }
+
+ @Test fun uIntValue() {
+ val annotation = KmAnnotation(
+ "test/UIntValueAnnotation",
+ mapOf("value" to UIntValue(2u)),
+ )
+ assertThat(annotation.toAnnotationSpec().toString()).isEqualTo(
+ """
+ @test.UIntValueAnnotation(value = 2u)
+ """.trimIndent(),
+ )
+ }
+
+ @Test fun uLongValue() {
+ val annotation = KmAnnotation(
+ "test/ULongValueAnnotation",
+ mapOf("value" to ULongValue(2u)),
+ )
+ assertThat(annotation.toAnnotationSpec().toString()).isEqualTo(
+ """
+ @test.ULongValueAnnotation(value = 2u)
+ """.trimIndent(),
+ )
+ }
+
+ @Test fun stringValue() {
+ val annotation = KmAnnotation(
+ "test/StringValueAnnotation",
+ mapOf("value" to StringValue("taco")),
+ )
+ assertThat(annotation.toAnnotationSpec().toString()).isEqualTo(
+ """
+ @test.StringValueAnnotation(value = "taco")
+ """.trimIndent(),
+ )
+ }
+
+ @Test fun kClassValue() {
+ val annotation = KmAnnotation(
+ "test/KClassValueAnnotation",
+ mapOf("value" to KClassValue("test/OtherClass", 0)),
+ )
+ assertThat(annotation.toAnnotationSpec().toString()).isEqualTo(
+ """
+ @test.KClassValueAnnotation(value = test.OtherClass::class)
+ """.trimIndent(),
+ )
+ }
+
+ @Test fun enumValue() {
+ val annotation = KmAnnotation(
+ "test/EnumValueAnnotation",
+ mapOf("value" to EnumValue("test/OtherClass", "VALUE")),
+ )
+ assertThat(annotation.toAnnotationSpec().toString()).isEqualTo(
+ """
+ @test.EnumValueAnnotation(value = test.OtherClass.VALUE)
+ """.trimIndent(),
+ )
+ }
+
+ @Test fun annotationValue() {
+ val annotation = KmAnnotation(
+ "test/AnnotationValueAnnotation",
+ mapOf(
+ "value" to AnnotationValue(
+ KmAnnotation("test/OtherAnnotation", mapOf("value" to StringValue("Hello!"))),
+ ),
+ ),
+ )
+ assertThat(annotation.toAnnotationSpec().toString()).isEqualTo(
+ """
+ @test.AnnotationValueAnnotation(value = test.OtherAnnotation(value = "Hello!"))
+ """.trimIndent(),
+ )
+ }
+
+ @Test fun arrayValue() {
+ val annotation = KmAnnotation(
+ "test/ArrayValueAnnotation",
+ mapOf("value" to ArrayValue(listOf(IntValue(1), IntValue(2), IntValue(3)))),
+ )
+ assertThat(annotation.toAnnotationSpec().toString()).isEqualTo(
+ """
+ @test.ArrayValueAnnotation(value = [1, 2, 3])
+ """.trimIndent(),
+ )
+ }
+}
diff --git a/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/KotlinPoetMetadataSpecsTest.kt b/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/KotlinPoetMetadataSpecsTest.kt
new file mode 100644
index 00000000..9198dbcb
--- /dev/null
+++ b/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/KotlinPoetMetadataSpecsTest.kt
@@ -0,0 +1,2250 @@
+/*
+ * Copyright (C) 2019 Square, Inc.
+ *
+ * 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.
+ */
+@file:OptIn(KotlinPoetMetadataPreview::class)
+@file:Suppress(
+ "DEPRECATION",
+ "NOTHING_TO_INLINE",
+ "RedundantSuspendModifier",
+ "RedundantUnitReturnType",
+ "RedundantVisibilityModifier",
+ "RemoveEmptyPrimaryConstructor",
+ "RemoveRedundantQualifierName",
+ "UNUSED_PARAMETER",
+ "unused",
+)
+
+package com.squareup.kotlinpoet.metadata.specs
+
+import com.google.common.truth.Truth.assertThat
+import com.squareup.kotlinpoet.LIST
+import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
+import com.squareup.kotlinpoet.STRING
+import com.squareup.kotlinpoet.TypeSpec
+import com.squareup.kotlinpoet.metadata.KotlinPoetMetadataPreview
+import com.squareup.kotlinpoet.metadata.specs.MultiClassInspectorTest.ClassInspectorType.ELEMENTS
+import com.squareup.kotlinpoet.metadata.specs.MultiClassInspectorTest.ClassInspectorType.REFLECTIVE
+import com.squareup.kotlinpoet.tag
+import com.squareup.kotlinpoet.tags.TypeAliasTag
+import kotlin.annotation.AnnotationRetention.RUNTIME
+import kotlin.annotation.AnnotationTarget.TYPE
+import kotlin.annotation.AnnotationTarget.TYPE_PARAMETER
+import kotlin.properties.Delegates
+import kotlin.test.fail
+import kotlinx.metadata.KmClass
+import kotlinx.metadata.KmConstructor
+import kotlinx.metadata.KmFunction
+import kotlinx.metadata.KmProperty
+import kotlinx.metadata.KmTypeParameter
+import kotlinx.metadata.KmValueParameter
+import org.junit.Ignore
+import org.junit.Test
+
+class KotlinPoetMetadataSpecsTest : MultiClassInspectorTest() {
+
+ @Test
+ fun constructorData() {
+ val typeSpec = ConstructorClass::class.toTypeSpecWithTestHandler()
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class ConstructorClass(
+ public val foo: kotlin.String,
+ vararg bar: kotlin.Int,
+ ) {
+ public constructor(bar: kotlin.Int)
+ }
+ """.trimIndent(),
+ )
+ }
+
+ class ConstructorClass(val foo: String, vararg bar: Int) {
+ // Secondary constructors are ignored, so we expect this constructor to not be the one picked
+ // up in the test.
+ constructor(bar: Int) : this("defaultFoo")
+ }
+
+ @Test
+ fun supertype() {
+ val typeSpec = Supertype::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class Supertype() : com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.BaseType(), com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.BaseInterface
+ """.trimIndent(),
+ )
+ }
+
+ abstract class BaseType
+ interface BaseInterface
+ class Supertype : BaseType(), BaseInterface
+
+ @IgnoreForHandlerType(
+ reason = "Elements properly resolves the string constant",
+ handlerType = ELEMENTS,
+ )
+ @Test
+ fun propertiesReflective() {
+ val typeSpec = Properties::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class Properties() {
+ public var aList: kotlin.collections.List<kotlin.Int> = throw NotImplementedError("Stub!")
+
+ public val bar: kotlin.String? = null
+
+ public var baz: kotlin.Int = throw NotImplementedError("Stub!")
+
+ public val foo: kotlin.String = throw NotImplementedError("Stub!")
+ }
+ """.trimIndent(),
+ )
+ }
+
+ @IgnoreForHandlerType(
+ reason = "Elements properly resolves the string constant",
+ handlerType = REFLECTIVE,
+ )
+ @Test
+ fun propertiesElements() {
+ val typeSpec = Properties::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class Properties() {
+ public var aList: kotlin.collections.List<kotlin.Int> = throw NotImplementedError("Stub!")
+
+ public val bar: kotlin.String? = null
+
+ public var baz: kotlin.Int = throw NotImplementedError("Stub!")
+
+ public val foo: kotlin.String = throw NotImplementedError("Stub!")
+ }
+ """.trimIndent(),
+ )
+ }
+
+ class Properties {
+ val foo: String = ""
+ val bar: String? = null
+ var baz: Int = 0
+ var aList: List<Int> = emptyList()
+ }
+
+ @Test
+ fun companionObject() {
+ val typeSpec = CompanionObject::class.toTypeSpecWithTestHandler()
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class CompanionObject() {
+ public companion object
+ }
+ """.trimIndent(),
+ )
+ }
+
+ class CompanionObject {
+ companion object
+ }
+
+ @Test
+ fun namedCompanionObject() {
+ val typeSpec = NamedCompanionObject::class.toTypeSpecWithTestHandler()
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class NamedCompanionObject() {
+ public companion object Named
+ }
+ """.trimIndent(),
+ )
+ }
+
+ class NamedCompanionObject {
+ companion object Named
+ }
+
+ @Test
+ fun generics() {
+ val typeSpec = Generics::class.toTypeSpecWithTestHandler()
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class Generics<out T, in R, V>(
+ public val genericInput: T,
+ )
+ """.trimIndent(),
+ )
+ }
+
+ class Generics<out T, in R, V>(val genericInput: T)
+
+ @Test
+ fun typeAliases() {
+ val typeSpec = TypeAliases::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class TypeAliases(
+ public val foo: com.squareup.kotlinpoet.metadata.specs.TypeAliasName,
+ public val bar: com.squareup.kotlinpoet.metadata.specs.GenericTypeAlias,
+ )
+ """.trimIndent(),
+ )
+
+ val fooPropertyType = typeSpec.propertySpecs.first { it.name == "foo" }.type
+ val fooAliasData = fooPropertyType.tag<TypeAliasTag>()
+ checkNotNull(fooAliasData)
+ assertThat(fooAliasData.abbreviatedType).isEqualTo(STRING)
+
+ val barPropertyType = typeSpec.propertySpecs.first { it.name == "bar" }.type
+ val barAliasData = barPropertyType.tag<TypeAliasTag>()
+ checkNotNull(barAliasData)
+ assertThat(barAliasData.abbreviatedType).isEqualTo(LIST.parameterizedBy(STRING))
+ }
+
+ class TypeAliases(val foo: TypeAliasName, val bar: GenericTypeAlias)
+
+ @Test
+ fun propertyMutability() {
+ val typeSpec = PropertyMutability::class.toTypeSpecWithTestHandler()
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class PropertyMutability(
+ public val foo: kotlin.String,
+ public var mutableFoo: kotlin.String,
+ )
+ """.trimIndent(),
+ )
+ }
+
+ class PropertyMutability(val foo: String, var mutableFoo: String)
+
+ @Test
+ fun collectionMutability() {
+ val typeSpec = CollectionMutability::class.toTypeSpecWithTestHandler()
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class CollectionMutability(
+ public val immutableList: kotlin.collections.List<kotlin.String>,
+ public val mutableList: kotlin.collections.MutableList<kotlin.String>,
+ )
+ """.trimIndent(),
+ )
+ }
+
+ class CollectionMutability(val immutableList: List<String>, val mutableList: MutableList<String>)
+
+ @Test
+ fun suspendTypes() {
+ val typeSpec = SuspendTypes::class.toTypeSpecWithTestHandler()
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class SuspendTypes() {
+ public val testProp: suspend (kotlin.Int, kotlin.Long) -> kotlin.String = throw NotImplementedError("Stub!")
+
+ public suspend fun testComplexSuspendFun(body: suspend (kotlin.Int, suspend (kotlin.Long) -> kotlin.String) -> kotlin.String): kotlin.Unit {
+ }
+
+ public fun testFun(body: suspend (kotlin.Int, kotlin.Long) -> kotlin.String): kotlin.Unit {
+ }
+
+ public suspend fun testSuspendFun(param1: kotlin.String): kotlin.Unit {
+ }
+ }
+ """.trimIndent(),
+ )
+ }
+
+ class SuspendTypes {
+ val testProp: suspend (Int, Long) -> String = { _, _ -> "" }
+
+ fun testFun(body: suspend (Int, Long) -> String) {
+ }
+
+ suspend fun testSuspendFun(param1: String) {
+ }
+
+ suspend fun testComplexSuspendFun(body: suspend (Int, suspend (Long) -> String) -> String) {
+ }
+ }
+
+ @Test
+ fun parameters() {
+ val typeSpec = Parameters::class.toTypeSpecWithTestHandler()
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class Parameters() {
+ public inline fun hasDefault(param1: kotlin.String = throw NotImplementedError("Stub!")): kotlin.Unit {
+ }
+
+ public inline fun `inline`(crossinline param1: () -> kotlin.String): kotlin.Unit {
+ }
+
+ public inline fun `noinline`(noinline param1: () -> kotlin.String): kotlin.String = throw NotImplementedError("Stub!")
+ }
+ """.trimIndent(),
+ )
+ }
+
+ class Parameters {
+ inline fun inline(crossinline param1: () -> String) {
+ }
+
+ inline fun noinline(noinline param1: () -> String): String {
+ return ""
+ }
+
+ inline fun hasDefault(param1: String = "Nope") {
+ }
+ }
+
+ @Test
+ fun lambdaReceiver() {
+ val typeSpec = LambdaReceiver::class.toTypeSpecWithTestHandler()
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class LambdaReceiver() {
+ public fun lambdaReceiver(block: kotlin.String.() -> kotlin.Unit): kotlin.Unit {
+ }
+
+ public fun lambdaReceiver2(block: kotlin.String.(kotlin.Int) -> kotlin.Unit): kotlin.Unit {
+ }
+
+ public fun lambdaReceiver3(block: kotlin.String.(kotlin.Int, kotlin.String) -> kotlin.Unit): kotlin.Unit {
+ }
+ }
+ """.trimIndent(),
+ )
+ }
+
+ class LambdaReceiver {
+ fun lambdaReceiver(block: String.() -> Unit) {
+ }
+ fun lambdaReceiver2(block: String.(Int) -> Unit) {
+ }
+ fun lambdaReceiver3(block: String.(Int, String) -> Unit) {
+ }
+ }
+
+ @Test
+ fun nestedTypeAlias() {
+ val typeSpec = NestedTypeAliasTest::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class NestedTypeAliasTest() {
+ public val prop: com.squareup.kotlinpoet.metadata.specs.NestedTypeAlias = throw NotImplementedError("Stub!")
+ }
+ """.trimIndent(),
+ )
+ }
+
+ class NestedTypeAliasTest {
+ val prop: NestedTypeAlias = listOf(listOf(""))
+ }
+
+ @Test
+ fun inlineClass() {
+ val typeSpec = InlineClass::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ @kotlin.jvm.JvmInline
+ public value class InlineClass(
+ public val `value`: kotlin.String,
+ )
+ """.trimIndent(),
+ )
+ }
+
+ @Test
+ fun valueClass() {
+ val typeSpec = ValueClass::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ @kotlin.jvm.JvmInline
+ public value class ValueClass(
+ public val `value`: kotlin.String,
+ )
+ """.trimIndent(),
+ )
+ }
+
+ @Test
+ fun functionReferencingTypeParam() {
+ val typeSpec = FunctionsReferencingTypeParameters::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class FunctionsReferencingTypeParameters<T>() {
+ public fun test(`param`: T): kotlin.Unit {
+ }
+ }
+ """.trimIndent(),
+ )
+ }
+
+ class FunctionsReferencingTypeParameters<T> {
+ fun test(param: T) {
+ }
+ }
+
+ @Test
+ fun overriddenThings() {
+ val typeSpec = OverriddenThings::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public abstract class OverriddenThings() : com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.OverriddenThingsBase(), com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.OverriddenThingsInterface {
+ public override var openProp: kotlin.String = throw NotImplementedError("Stub!")
+
+ public override var openPropInterface: kotlin.String = throw NotImplementedError("Stub!")
+
+ public override fun openFunction(): kotlin.Unit {
+ }
+
+ public override fun openFunctionInterface(): kotlin.Unit {
+ }
+ }
+ """.trimIndent(),
+ )
+ }
+
+ abstract class OverriddenThingsBase {
+ abstract var openProp: String
+
+ abstract fun openFunction()
+ }
+
+ interface OverriddenThingsInterface {
+ var openPropInterface: String
+
+ fun openFunctionInterface()
+ }
+
+ abstract class OverriddenThings : OverriddenThingsBase(), OverriddenThingsInterface {
+ override var openProp: String = ""
+ override var openPropInterface: String = ""
+
+ override fun openFunction() {
+ }
+
+ override fun openFunctionInterface() {
+ }
+ }
+
+ @Test
+ fun delegatedProperties() {
+ val typeSpec = DelegatedProperties::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class DelegatedProperties() {
+ /**
+ * Note: delegation is ABI stub only and not guaranteed to match source code.
+ */
+ public val immutable: kotlin.String by kotlin.lazy { throw NotImplementedError("Stub!") }
+
+ /**
+ * Note: delegation is ABI stub only and not guaranteed to match source code.
+ */
+ public val immutableNullable: kotlin.String? by kotlin.lazy { throw NotImplementedError("Stub!") }
+
+ /**
+ * Note: delegation is ABI stub only and not guaranteed to match source code.
+ */
+ public var mutable: kotlin.String by kotlin.properties.Delegates.notNull()
+
+ /**
+ * Note: delegation is ABI stub only and not guaranteed to match source code.
+ */
+ public var mutableNullable: kotlin.String? by kotlin.properties.Delegates.observable(null) { _, _, _ -> }
+ }
+ """.trimIndent(),
+ )
+ }
+
+ class DelegatedProperties {
+ val immutable: String by lazy { "" }
+ val immutableNullable: String? by lazy { "" }
+ var mutable: String by Delegates.notNull()
+ var mutableNullable: String? by Delegates.observable(null) { _, _, _ -> }
+ }
+
+ @Ignore("Need to be able to know about class delegation in metadata")
+ @Test
+ fun classDelegation() {
+ val typeSpec = ClassDelegation::class.toTypeSpecWithTestHandler()
+
+ // TODO Assert this also excludes functions handled by the delegate
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class ClassDelegation<T>(
+ delegate: List<T>
+ ): List<T> by delegate
+ """.trimIndent(),
+ )
+ }
+
+ class ClassDelegation<T>(delegate: List<T>) : List<T> by delegate
+
+ @Test
+ fun simpleEnum() {
+ val typeSpec = SimpleEnum::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public enum class SimpleEnum() {
+ FOO,
+ BAR,
+ BAZ,
+ }
+ """.trimIndent(),
+ )
+ }
+
+ enum class SimpleEnum {
+ FOO, BAR, BAZ
+ }
+
+ @Test
+ fun complexEnum() {
+ val typeSpec = ComplexEnum::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public enum class ComplexEnum(
+ public val `value`: kotlin.String,
+ ) {
+ FOO {
+ public override fun toString(): kotlin.String = throw NotImplementedError("Stub!")
+ },
+ BAR {
+ public override fun toString(): kotlin.String = throw NotImplementedError("Stub!")
+ },
+ BAZ {
+ public override fun toString(): kotlin.String = throw NotImplementedError("Stub!")
+ },
+ ;
+ }
+ """.trimIndent(),
+ )
+ }
+
+ enum class ComplexEnum(val value: String) {
+ FOO("foo") {
+ override fun toString(): String {
+ return "foo1"
+ }
+ },
+ BAR("bar") {
+ override fun toString(): String {
+ return "bar1"
+ }
+ },
+ BAZ("baz") {
+ override fun toString(): String {
+ return "baz1"
+ }
+ },
+ }
+
+ @Test
+ fun enumWithAnnotation() {
+ val typeSpec = EnumWithAnnotation::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public enum class EnumWithAnnotation() {
+ FOO,
+ @com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.FieldAnnotation
+ BAR,
+ BAZ,
+ }
+ """.trimIndent(),
+ )
+ }
+
+ enum class EnumWithAnnotation {
+ FOO, @FieldAnnotation
+ BAR, BAZ
+ }
+
+ @Test
+ fun complexEnumWithAnnotation() {
+ val typeSpec = ComplexEnumWithAnnotation::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public enum class ComplexEnumWithAnnotation(
+ public val `value`: kotlin.String,
+ ) {
+ FOO {
+ public override fun toString(): kotlin.String = throw NotImplementedError("Stub!")
+ },
+ @com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.FieldAnnotation
+ BAR {
+ public override fun toString(): kotlin.String = throw NotImplementedError("Stub!")
+ },
+ BAZ {
+ public override fun toString(): kotlin.String = throw NotImplementedError("Stub!")
+ },
+ ;
+ }
+ """.trimIndent(),
+ )
+ }
+
+ enum class ComplexEnumWithAnnotation(val value: String) {
+ FOO("foo") {
+ override fun toString(): String {
+ return "foo1"
+ }
+ },
+
+ @FieldAnnotation
+ BAR("bar") {
+ override fun toString(): String {
+ return "bar1"
+ }
+ },
+ BAZ("baz") {
+ override fun toString(): String {
+ return "baz1"
+ }
+ },
+ }
+
+ @Test
+ fun interfaces() {
+ val testInterfaceSpec = TestInterface::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(testInterfaceSpec.trimmedToString()).isEqualTo(
+ """
+ public interface TestInterface {
+ public fun complex(input: kotlin.String, input2: kotlin.String = throw NotImplementedError("Stub!")): kotlin.String = throw NotImplementedError("Stub!")
+
+ public fun hasDefault(): kotlin.Unit {
+ }
+
+ public fun hasDefaultMultiParam(input: kotlin.String, input2: kotlin.String): kotlin.String = throw NotImplementedError("Stub!")
+
+ public fun hasDefaultSingleParam(input: kotlin.String): kotlin.String = throw NotImplementedError("Stub!")
+
+ @kotlin.jvm.JvmDefault
+ public fun hasJvmDefault(): kotlin.Unit {
+ }
+
+ public fun noDefault(): kotlin.Unit
+
+ public fun noDefaultWithInput(input: kotlin.String): kotlin.Unit
+
+ public fun noDefaultWithInputDefault(input: kotlin.String = throw NotImplementedError("Stub!")): kotlin.Unit
+ }
+ """.trimIndent(),
+ )
+
+ val subInterfaceSpec = SubInterface::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(subInterfaceSpec.trimmedToString()).isEqualTo(
+ """
+ public interface SubInterface : com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.TestInterface {
+ public override fun hasDefault(): kotlin.Unit {
+ }
+
+ @kotlin.jvm.JvmDefault
+ public override fun hasJvmDefault(): kotlin.Unit {
+ }
+
+ public fun subInterfaceFunction(): kotlin.Unit {
+ }
+ }
+ """.trimIndent(),
+ )
+
+ val implSpec = TestSubInterfaceImpl::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(implSpec.trimmedToString()).isEqualTo(
+ """
+ public class TestSubInterfaceImpl() : com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.SubInterface {
+ public override fun noDefault(): kotlin.Unit {
+ }
+
+ public override fun noDefaultWithInput(input: kotlin.String): kotlin.Unit {
+ }
+
+ public override fun noDefaultWithInputDefault(input: kotlin.String): kotlin.Unit {
+ }
+ }
+ """.trimIndent(),
+ )
+ }
+
+ interface TestInterface {
+
+ fun noDefault()
+
+ fun noDefaultWithInput(input: String)
+
+ fun noDefaultWithInputDefault(input: String = "")
+
+ @JvmDefault
+ fun hasJvmDefault() {
+ }
+
+ fun hasDefault() {
+ }
+
+ fun hasDefaultSingleParam(input: String): String {
+ return "1234"
+ }
+
+ fun hasDefaultMultiParam(input: String, input2: String): String {
+ return "1234"
+ }
+
+ fun complex(input: String, input2: String = ""): String {
+ return "5678"
+ }
+ }
+
+ interface SubInterface : TestInterface {
+ fun subInterfaceFunction() {
+ }
+
+ @JvmDefault
+ override fun hasJvmDefault() {
+ super.hasJvmDefault()
+ }
+
+ override fun hasDefault() {
+ super.hasDefault()
+ }
+ }
+
+ class TestSubInterfaceImpl : SubInterface {
+ override fun noDefault() {
+ }
+
+ override fun noDefaultWithInput(input: String) {
+ }
+
+ override fun noDefaultWithInputDefault(input: String) {
+ }
+ }
+
+ @Test
+ fun backwardReferencingTypeVars() {
+ val typeSpec = BackwardReferencingTypeVars::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public interface BackwardReferencingTypeVars<T> : kotlin.collections.List<kotlin.collections.Set<T>>
+ """.trimIndent(),
+ )
+ }
+
+ interface BackwardReferencingTypeVars<T> : List<Set<T>>
+
+ @Test
+ fun taggedTypes() {
+ val typeSpec = TaggedTypes::class.toTypeSpecWithTestHandler()
+ assertThat(typeSpec.tag<KmClass>()).isNotNull()
+
+ val constructorSpec = typeSpec.primaryConstructor ?: fail("No constructor found!")
+ assertThat(constructorSpec.tag<KmConstructor>()).isNotNull()
+
+ val parameterSpec = constructorSpec.parameters[0]
+ assertThat(parameterSpec.tag<KmValueParameter>()).isNotNull()
+
+ val typeVar = typeSpec.typeVariables[0]
+ assertThat(typeVar.tag<KmTypeParameter>()).isNotNull()
+
+ val funSpec = typeSpec.funSpecs[0]
+ assertThat(funSpec.tag<KmFunction>()).isNotNull()
+
+ val propertySpec = typeSpec.propertySpecs[0]
+ assertThat(propertySpec.tag<KmProperty>()).isNotNull()
+ }
+
+ class TaggedTypes<T>(val param: T) {
+ val property: String = ""
+
+ fun function() {
+ }
+ }
+
+ @Test
+ fun annotations() {
+ val typeSpec = MyAnnotation::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public annotation class MyAnnotation(
+ public val `value`: kotlin.String,
+ )
+ """.trimIndent(),
+ )
+ }
+
+ annotation class MyAnnotation(val value: String)
+
+ @Test
+ fun functionTypeArgsSupersedeClass() {
+ val typeSpec = GenericClass::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class GenericClass<T>() {
+ public fun <T> functionAlsoWithT(`param`: T): kotlin.Unit {
+ }
+
+ public fun <R> functionWithADifferentType(`param`: R): kotlin.Unit {
+ }
+
+ public fun functionWithT(`param`: T): kotlin.Unit {
+ }
+
+ /**
+ * Note: Since this is a synthetic function, some JVM information (annotations, modifiers) may be missing.
+ */
+ public inline fun <reified T> `reified`(`param`: T): kotlin.Unit {
+ }
+ }
+ """.trimIndent(),
+ )
+
+ val func1TypeVar = typeSpec.funSpecs.find { it.name == "functionAlsoWithT" }!!.typeVariables.first()
+ val classTypeVar = typeSpec.typeVariables.first()
+
+ assertThat(func1TypeVar).isNotSameInstanceAs(classTypeVar)
+ }
+
+ class GenericClass<T> {
+ fun functionWithT(param: T) {
+ }
+ fun <T> functionAlsoWithT(param: T) {
+ }
+ fun <R> functionWithADifferentType(param: R) {
+ }
+
+ // Regression for https://github.com/square/kotlinpoet/issues/829
+ inline fun <reified T> reified(param: T) {
+ }
+ }
+
+ @Test
+ fun complexCompanionObject() {
+ val typeSpec = ComplexCompanionObject::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class ComplexCompanionObject() {
+ public companion object ComplexObject : com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.CompanionBase(), com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.CompanionInterface
+ }
+ """.trimIndent(),
+ )
+ }
+
+ interface CompanionInterface
+ open class CompanionBase
+
+ class ComplexCompanionObject {
+ companion object ComplexObject : CompanionBase(), CompanionInterface
+ }
+
+ @IgnoreForHandlerType(
+ reason = "TODO Synthetic methods that hold annotations aren't visible in these tests",
+ handlerType = ELEMENTS,
+ )
+ @Test
+ fun annotationsAreCopied() {
+ val typeSpec = AnnotationHolders::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class AnnotationHolders @com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.ConstructorAnnotation constructor() {
+ @field:com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.FieldAnnotation
+ public var `field`: kotlin.String? = null
+
+ @get:com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.GetterAnnotation
+ public var getter: kotlin.String? = null
+
+ @com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.HolderAnnotation
+ @kotlin.jvm.JvmField
+ public var holder: kotlin.String? = null
+
+ @set:com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.SetterAnnotation
+ public var setter: kotlin.String? = null
+
+ @com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.ConstructorAnnotation
+ public constructor(`value`: kotlin.String)
+
+ @com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.FunctionAnnotation
+ public fun function(): kotlin.Unit {
+ }
+ }
+ """.trimIndent(),
+ )
+ }
+
+ class AnnotationHolders @ConstructorAnnotation constructor() {
+
+ @ConstructorAnnotation
+ constructor(value: String) : this()
+
+ @field:FieldAnnotation
+ var field: String? = null
+
+ @get:GetterAnnotation
+ var getter: String? = null
+
+ @set:SetterAnnotation
+ var setter: String? = null
+
+ @HolderAnnotation
+ @JvmField
+ var holder: String? = null
+
+ @FunctionAnnotation
+ fun function() {
+ }
+ }
+
+ @Retention(RUNTIME)
+ annotation class ConstructorAnnotation
+
+ @Retention(RUNTIME)
+ annotation class FieldAnnotation
+
+ @Retention(RUNTIME)
+ annotation class GetterAnnotation
+
+ @Retention(RUNTIME)
+ annotation class SetterAnnotation
+
+ @Retention(RUNTIME)
+ annotation class HolderAnnotation
+
+ @Retention(RUNTIME)
+ annotation class FunctionAnnotation
+
+ @IgnoreForHandlerType(
+ reason = "Elements properly resolves the regular properties + JvmStatic, but reflection will not",
+ handlerType = REFLECTIVE,
+ )
+ @Test
+ fun constantValuesElements() {
+ val typeSpec = Constants::class.toTypeSpecWithTestHandler()
+
+ // Note: formats like hex/binary/underscore are not available as formatted at runtime
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class Constants(
+ public val `param`: kotlin.String = throw NotImplementedError("Stub!"),
+ ) {
+ public val binaryProp: kotlin.Int = throw NotImplementedError("Stub!")
+
+ public val boolProp: kotlin.Boolean = throw NotImplementedError("Stub!")
+
+ public val doubleProp: kotlin.Double = throw NotImplementedError("Stub!")
+
+ public val floatProp: kotlin.Float = throw NotImplementedError("Stub!")
+
+ public val hexProp: kotlin.Int = throw NotImplementedError("Stub!")
+
+ public val intProp: kotlin.Int = throw NotImplementedError("Stub!")
+
+ public val longProp: kotlin.Long = throw NotImplementedError("Stub!")
+
+ public val stringProp: kotlin.String = throw NotImplementedError("Stub!")
+
+ public val underscoresHexProp: kotlin.Long = throw NotImplementedError("Stub!")
+
+ public val underscoresProp: kotlin.Int = throw NotImplementedError("Stub!")
+
+ public companion object {
+ public const val CONST_BINARY_PROP: kotlin.Int = 11
+
+ public const val CONST_BOOL_PROP: kotlin.Boolean = false
+
+ public const val CONST_DOUBLE_PROP: kotlin.Double = 1.0
+
+ public const val CONST_FLOAT_PROP: kotlin.Float = 1.0F
+
+ public const val CONST_HEX_PROP: kotlin.Int = 15
+
+ public const val CONST_INT_PROP: kotlin.Int = 1
+
+ public const val CONST_LONG_PROP: kotlin.Long = 1L
+
+ public const val CONST_STRING_PROP: kotlin.String = "prop"
+
+ public const val CONST_UNDERSCORES_HEX_PROP: kotlin.Long = 4_293_713_502L
+
+ public const val CONST_UNDERSCORES_PROP: kotlin.Int = 1_000_000
+
+ @kotlin.jvm.JvmStatic
+ public val STATIC_CONST_BINARY_PROP: kotlin.Int = throw NotImplementedError("Stub!")
+
+ @kotlin.jvm.JvmStatic
+ public val STATIC_CONST_BOOL_PROP: kotlin.Boolean = throw NotImplementedError("Stub!")
+
+ @kotlin.jvm.JvmStatic
+ public val STATIC_CONST_DOUBLE_PROP: kotlin.Double = throw NotImplementedError("Stub!")
+
+ @kotlin.jvm.JvmStatic
+ public val STATIC_CONST_FLOAT_PROP: kotlin.Float = throw NotImplementedError("Stub!")
+
+ @kotlin.jvm.JvmStatic
+ public val STATIC_CONST_HEX_PROP: kotlin.Int = throw NotImplementedError("Stub!")
+
+ @kotlin.jvm.JvmStatic
+ public val STATIC_CONST_INT_PROP: kotlin.Int = throw NotImplementedError("Stub!")
+
+ @kotlin.jvm.JvmStatic
+ public val STATIC_CONST_LONG_PROP: kotlin.Long = throw NotImplementedError("Stub!")
+
+ @kotlin.jvm.JvmStatic
+ public val STATIC_CONST_STRING_PROP: kotlin.String = throw NotImplementedError("Stub!")
+
+ @kotlin.jvm.JvmStatic
+ public val STATIC_CONST_UNDERSCORES_HEX_PROP: kotlin.Long = throw NotImplementedError("Stub!")
+
+ @kotlin.jvm.JvmStatic
+ public val STATIC_CONST_UNDERSCORES_PROP: kotlin.Int = throw NotImplementedError("Stub!")
+ }
+ }
+ """.trimIndent(),
+ )
+
+ // TODO check with objects
+ }
+
+ @IgnoreForHandlerType(
+ reason = "Elements properly resolves the regular properties + JvmStatic, but reflection will not",
+ handlerType = ELEMENTS,
+ )
+ @Test
+ fun constantValuesReflective() {
+ val typeSpec = Constants::class.toTypeSpecWithTestHandler()
+
+ // Note: formats like hex/binary/underscore are not available as formatted in elements
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class Constants(
+ public val `param`: kotlin.String = throw NotImplementedError("Stub!"),
+ ) {
+ public val binaryProp: kotlin.Int = throw NotImplementedError("Stub!")
+
+ public val boolProp: kotlin.Boolean = throw NotImplementedError("Stub!")
+
+ public val doubleProp: kotlin.Double = throw NotImplementedError("Stub!")
+
+ public val floatProp: kotlin.Float = throw NotImplementedError("Stub!")
+
+ public val hexProp: kotlin.Int = throw NotImplementedError("Stub!")
+
+ public val intProp: kotlin.Int = throw NotImplementedError("Stub!")
+
+ public val longProp: kotlin.Long = throw NotImplementedError("Stub!")
+
+ public val stringProp: kotlin.String = throw NotImplementedError("Stub!")
+
+ public val underscoresHexProp: kotlin.Long = throw NotImplementedError("Stub!")
+
+ public val underscoresProp: kotlin.Int = throw NotImplementedError("Stub!")
+
+ public companion object {
+ public const val CONST_BINARY_PROP: kotlin.Int = 11
+
+ public const val CONST_BOOL_PROP: kotlin.Boolean = false
+
+ public const val CONST_DOUBLE_PROP: kotlin.Double = 1.0
+
+ public const val CONST_FLOAT_PROP: kotlin.Float = 1.0F
+
+ public const val CONST_HEX_PROP: kotlin.Int = 15
+
+ public const val CONST_INT_PROP: kotlin.Int = 1
+
+ public const val CONST_LONG_PROP: kotlin.Long = 1L
+
+ public const val CONST_STRING_PROP: kotlin.String = "prop"
+
+ public const val CONST_UNDERSCORES_HEX_PROP: kotlin.Long = 4_293_713_502L
+
+ public const val CONST_UNDERSCORES_PROP: kotlin.Int = 1_000_000
+
+ @kotlin.jvm.JvmStatic
+ public val STATIC_CONST_BINARY_PROP: kotlin.Int = 11
+
+ @kotlin.jvm.JvmStatic
+ public val STATIC_CONST_BOOL_PROP: kotlin.Boolean = false
+
+ @kotlin.jvm.JvmStatic
+ public val STATIC_CONST_DOUBLE_PROP: kotlin.Double = 1.0
+
+ @kotlin.jvm.JvmStatic
+ public val STATIC_CONST_FLOAT_PROP: kotlin.Float = 1.0F
+
+ @kotlin.jvm.JvmStatic
+ public val STATIC_CONST_HEX_PROP: kotlin.Int = 15
+
+ @kotlin.jvm.JvmStatic
+ public val STATIC_CONST_INT_PROP: kotlin.Int = 1
+
+ @kotlin.jvm.JvmStatic
+ public val STATIC_CONST_LONG_PROP: kotlin.Long = 1L
+
+ @kotlin.jvm.JvmStatic
+ public val STATIC_CONST_STRING_PROP: kotlin.String = "prop"
+
+ @kotlin.jvm.JvmStatic
+ public val STATIC_CONST_UNDERSCORES_HEX_PROP: kotlin.Long = 4_293_713_502L
+
+ @kotlin.jvm.JvmStatic
+ public val STATIC_CONST_UNDERSCORES_PROP: kotlin.Int = 1_000_000
+ }
+ }
+ """.trimIndent(),
+ )
+ }
+
+ class Constants(
+ val param: String = "param",
+ ) {
+ val boolProp = false
+ val binaryProp = 0b00001011
+ val intProp = 1
+ val underscoresProp = 1_000_000
+ val hexProp = 0x0F
+ val underscoresHexProp = 0xFF_EC_DE_5E
+ val longProp = 1L
+ val floatProp = 1.0F
+ val doubleProp = 1.0
+ val stringProp = "prop"
+
+ companion object {
+ @JvmStatic val STATIC_CONST_BOOL_PROP = false
+
+ @JvmStatic val STATIC_CONST_BINARY_PROP = 0b00001011
+
+ @JvmStatic val STATIC_CONST_INT_PROP = 1
+
+ @JvmStatic val STATIC_CONST_UNDERSCORES_PROP = 1_000_000
+
+ @JvmStatic val STATIC_CONST_HEX_PROP = 0x0F
+
+ @JvmStatic val STATIC_CONST_UNDERSCORES_HEX_PROP = 0xFF_EC_DE_5E
+
+ @JvmStatic val STATIC_CONST_LONG_PROP = 1L
+
+ @JvmStatic val STATIC_CONST_FLOAT_PROP = 1.0f
+
+ @JvmStatic val STATIC_CONST_DOUBLE_PROP = 1.0
+
+ @JvmStatic val STATIC_CONST_STRING_PROP = "prop"
+
+ const val CONST_BOOL_PROP = false
+ const val CONST_BINARY_PROP = 0b00001011
+ const val CONST_INT_PROP = 1
+ const val CONST_UNDERSCORES_PROP = 1_000_000
+ const val CONST_HEX_PROP = 0x0F
+ const val CONST_UNDERSCORES_HEX_PROP = 0xFF_EC_DE_5E
+ const val CONST_LONG_PROP = 1L
+ const val CONST_FLOAT_PROP = 1.0f
+ const val CONST_DOUBLE_PROP = 1.0
+ const val CONST_STRING_PROP = "prop"
+ }
+ }
+
+ @Test
+ fun jvmAnnotations() {
+ val typeSpec = JvmAnnotations::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class JvmAnnotations() {
+ @get:kotlin.jvm.Synchronized
+ public val synchronizedGetProp: kotlin.String? = null
+
+ @set:kotlin.jvm.Synchronized
+ public var synchronizedSetProp: kotlin.String? = null
+
+ @kotlin.jvm.Transient
+ public val transientProp: kotlin.String? = null
+
+ @kotlin.jvm.Volatile
+ public var volatileProp: kotlin.String? = null
+
+ @kotlin.jvm.Synchronized
+ public fun synchronizedFun(): kotlin.Unit {
+ }
+ }
+ """.trimIndent(),
+ )
+
+ val interfaceSpec = JvmAnnotationsInterface::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(interfaceSpec.trimmedToString()).isEqualTo(
+ """
+ public interface JvmAnnotationsInterface {
+ @kotlin.jvm.JvmDefault
+ public fun defaultMethod(): kotlin.Unit {
+ }
+
+ public fun notDefaultMethod(): kotlin.Unit
+ }
+ """.trimIndent(),
+ )
+ }
+
+ class JvmAnnotations {
+ @Transient val transientProp: String? = null
+
+ @Volatile var volatileProp: String? = null
+
+ @get:Synchronized val synchronizedGetProp: String? = null
+
+ @set:Synchronized var synchronizedSetProp: String? = null
+
+ @Synchronized
+ fun synchronizedFun() {
+ }
+ }
+
+ interface JvmAnnotationsInterface {
+ @JvmDefault
+ fun defaultMethod() {
+ }
+ fun notDefaultMethod()
+ }
+
+ @Test
+ fun nestedClasses() {
+ val typeSpec = NestedClasses::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class NestedClasses() {
+ public abstract class NestedClass<T>() : kotlin.collections.List<T>
+
+ public inner class NestedInnerClass()
+ }
+ """.trimIndent(),
+ )
+ }
+
+ class NestedClasses {
+ abstract class NestedClass<T> : List<T>
+ inner class NestedInnerClass
+ }
+
+ @IgnoreForHandlerType(
+ reason = "Reflection properly resolves companion properties + JvmStatic + JvmName, but " +
+ "elements will not",
+ handlerType = ELEMENTS,
+ )
+ @Test
+ fun jvmNamesReflective() {
+ val typeSpec = JvmNameData::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class JvmNameData(
+ @get:kotlin.jvm.JvmName(name = "jvmParam")
+ public val `param`: kotlin.String,
+ ) {
+ @get:kotlin.jvm.JvmName(name = "jvmPropertyGet")
+ public val propertyGet: kotlin.String? = null
+
+ @get:kotlin.jvm.JvmName(name = "jvmPropertyGetAndSet")
+ @set:kotlin.jvm.JvmName(name = "jvmPropertyGetAndSet")
+ public var propertyGetAndSet: kotlin.String? = null
+
+ @set:kotlin.jvm.JvmName(name = "jvmPropertySet")
+ public var propertySet: kotlin.String? = null
+
+ @kotlin.jvm.JvmName(name = "jvmFunction")
+ public fun function(): kotlin.Unit {
+ }
+
+ public interface InterfaceWithJvmName {
+ public companion object {
+ @get:kotlin.jvm.JvmName(name = "fooBoolJvm")
+ @kotlin.jvm.JvmStatic
+ public val FOO_BOOL: kotlin.Boolean = false
+
+ @kotlin.jvm.JvmName(name = "jvmStaticFunction")
+ @kotlin.jvm.JvmStatic
+ public fun staticFunction(): kotlin.Unit {
+ }
+ }
+ }
+ }
+ """.trimIndent(),
+ )
+ }
+
+ @IgnoreForHandlerType(
+ reason = "Reflection properly resolves companion properties + JvmStatic + JvmName, but " +
+ "elements will not",
+ handlerType = REFLECTIVE,
+ )
+ @Test
+ fun jvmNamesElements() {
+ val typeSpec = JvmNameData::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class JvmNameData(
+ @get:kotlin.jvm.JvmName(name = "jvmParam")
+ public val `param`: kotlin.String,
+ ) {
+ @get:kotlin.jvm.JvmName(name = "jvmPropertyGet")
+ public val propertyGet: kotlin.String? = null
+
+ @get:kotlin.jvm.JvmName(name = "jvmPropertyGetAndSet")
+ @set:kotlin.jvm.JvmName(name = "jvmPropertyGetAndSet")
+ public var propertyGetAndSet: kotlin.String? = null
+
+ @set:kotlin.jvm.JvmName(name = "jvmPropertySet")
+ public var propertySet: kotlin.String? = null
+
+ @kotlin.jvm.JvmName(name = "jvmFunction")
+ public fun function(): kotlin.Unit {
+ }
+
+ public interface InterfaceWithJvmName {
+ public companion object {
+ @get:kotlin.jvm.JvmName(name = "fooBoolJvm")
+ @kotlin.jvm.JvmStatic
+ public val FOO_BOOL: kotlin.Boolean = throw NotImplementedError("Stub!")
+
+ @kotlin.jvm.JvmName(name = "jvmStaticFunction")
+ @kotlin.jvm.JvmStatic
+ public fun staticFunction(): kotlin.Unit {
+ }
+ }
+ }
+ }
+ """.trimIndent(),
+ )
+ }
+
+ class JvmNameData(
+ @get:JvmName("jvmParam") val param: String,
+ ) {
+
+ @get:JvmName("jvmPropertyGet")
+ val propertyGet: String? = null
+
+ @set:JvmName("jvmPropertySet")
+ var propertySet: String? = null
+
+ @set:JvmName("jvmPropertyGetAndSet")
+ @get:JvmName("jvmPropertyGetAndSet")
+ var propertyGetAndSet: String? = null
+
+ @JvmName("jvmFunction")
+ fun function() {
+ }
+
+ // Interfaces can't have JvmName, but covering a potential edge case of having a companion
+ // object with JvmName elements. Also covers an edge case where constants have getters
+ interface InterfaceWithJvmName {
+ companion object {
+ @JvmStatic
+ @get:JvmName("fooBoolJvm")
+ val FOO_BOOL = false
+
+ @JvmName("jvmStaticFunction")
+ @JvmStatic
+ fun staticFunction() {
+ }
+ }
+ }
+ }
+
+ @IgnoreForHandlerType(
+ reason = "JvmOverloads is not runtime retained and thus not visible to reflection.",
+ handlerType = REFLECTIVE,
+ )
+ @Test
+ fun overloads() {
+ val typeSpec = Overloads::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class Overloads @kotlin.jvm.JvmOverloads constructor(
+ public val param1: kotlin.String,
+ public val optionalParam2: kotlin.String = throw NotImplementedError("Stub!"),
+ public val nullableParam3: kotlin.String? = throw NotImplementedError("Stub!"),
+ ) {
+ @kotlin.jvm.JvmOverloads
+ public fun testFunction(
+ param1: kotlin.String,
+ optionalParam2: kotlin.String = throw NotImplementedError("Stub!"),
+ nullableParam3: kotlin.String? = throw NotImplementedError("Stub!"),
+ ): kotlin.Unit {
+ }
+ }
+ """.trimIndent(),
+ )
+ }
+
+ class Overloads @JvmOverloads constructor(
+ val param1: String,
+ val optionalParam2: String = "",
+ val nullableParam3: String? = null,
+ ) {
+ @JvmOverloads
+ fun testFunction(
+ param1: String,
+ optionalParam2: String = "",
+ nullableParam3: String? = null,
+ ) {
+ }
+ }
+
+ @IgnoreForHandlerType(
+ reason = "Elements generates initializer values.",
+ handlerType = ELEMENTS,
+ )
+ @Test
+ fun jvmFields_reflective() {
+ val typeSpec = Fields::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class Fields(
+ @property:kotlin.jvm.JvmField
+ public val param1: kotlin.String,
+ ) {
+ @kotlin.jvm.JvmField
+ public val fieldProp: kotlin.String = throw NotImplementedError("Stub!")
+
+ public companion object {
+ @kotlin.jvm.JvmField
+ public val companionProp: kotlin.String = ""
+
+ public const val constCompanionProp: kotlin.String = ""
+
+ @kotlin.jvm.JvmStatic
+ public val staticCompanionProp: kotlin.String = ""
+ }
+ }
+ """.trimIndent(),
+ )
+ }
+
+ @IgnoreForHandlerType(
+ reason = "Elements generates initializer values.",
+ handlerType = REFLECTIVE,
+ )
+ @Test
+ fun jvmFields_elements() {
+ val typeSpec = Fields::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class Fields(
+ @property:kotlin.jvm.JvmField
+ public val param1: kotlin.String,
+ ) {
+ @kotlin.jvm.JvmField
+ public val fieldProp: kotlin.String = throw NotImplementedError("Stub!")
+
+ public companion object {
+ @kotlin.jvm.JvmField
+ public val companionProp: kotlin.String = throw NotImplementedError("Stub!")
+
+ public const val constCompanionProp: kotlin.String = ""
+
+ @kotlin.jvm.JvmStatic
+ public val staticCompanionProp: kotlin.String = throw NotImplementedError("Stub!")
+ }
+ }
+ """.trimIndent(),
+ )
+ }
+
+ class Fields(
+ @JvmField val param1: String,
+ ) {
+ @JvmField val fieldProp: String = ""
+
+ companion object {
+ @JvmField val companionProp: String = ""
+
+ @JvmStatic val staticCompanionProp: String = ""
+ const val constCompanionProp: String = ""
+ }
+ }
+
+ @IgnoreForHandlerType(
+ reason = "Synthetic constructs aren't available in elements, so some information like " +
+ "JvmStatic can't be deduced.",
+ handlerType = ELEMENTS,
+ )
+ @Test
+ fun synthetics_reflective() {
+ val typeSpec = Synthetics::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class Synthetics(
+ @get:kotlin.jvm.JvmSynthetic
+ public val `param`: kotlin.String,
+ ) {
+ @field:kotlin.jvm.JvmSynthetic
+ public val fieldProperty: kotlin.String? = null
+
+ @field:kotlin.jvm.JvmSynthetic
+ public val `property`: kotlin.String? = null
+
+ @get:kotlin.jvm.JvmSynthetic
+ public val propertyGet: kotlin.String? = null
+
+ @get:kotlin.jvm.JvmSynthetic
+ @set:kotlin.jvm.JvmSynthetic
+ public var propertyGetAndSet: kotlin.String? = null
+
+ @set:kotlin.jvm.JvmSynthetic
+ public var propertySet: kotlin.String? = null
+
+ /**
+ * Note: Since this is a synthetic function, some JVM information (annotations, modifiers) may be missing.
+ */
+ @kotlin.jvm.JvmSynthetic
+ public fun function(): kotlin.Unit {
+ }
+
+ public interface InterfaceWithJvmName {
+ /**
+ * Note: Since this is a synthetic function, some JVM information (annotations, modifiers) may be missing.
+ */
+ @kotlin.jvm.JvmSynthetic
+ public fun interfaceFunction(): kotlin.Unit
+
+ public companion object {
+ @get:kotlin.jvm.JvmSynthetic
+ @kotlin.jvm.JvmStatic
+ public val FOO_BOOL: kotlin.Boolean = false
+
+ /**
+ * Note: Since this is a synthetic function, some JVM information (annotations, modifiers) may be missing.
+ */
+ @kotlin.jvm.JvmStatic
+ @kotlin.jvm.JvmSynthetic
+ public fun staticFunction(): kotlin.Unit {
+ }
+ }
+ }
+ }
+ """.trimIndent(),
+ )
+ }
+
+ @IgnoreForHandlerType(
+ reason = "Synthetic constructs aren't available in elements, so some information like " +
+ "JvmStatic can't be deduced.",
+ handlerType = REFLECTIVE,
+ )
+ @Test
+ fun synthetics_elements() {
+ val typeSpec = Synthetics::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class Synthetics(
+ @get:kotlin.jvm.JvmSynthetic
+ public val `param`: kotlin.String,
+ ) {
+ @field:kotlin.jvm.JvmSynthetic
+ public val fieldProperty: kotlin.String? = null
+
+ @field:kotlin.jvm.JvmSynthetic
+ public val `property`: kotlin.String? = null
+
+ @get:kotlin.jvm.JvmSynthetic
+ public val propertyGet: kotlin.String? = null
+
+ @get:kotlin.jvm.JvmSynthetic
+ @set:kotlin.jvm.JvmSynthetic
+ public var propertyGetAndSet: kotlin.String? = null
+
+ @set:kotlin.jvm.JvmSynthetic
+ public var propertySet: kotlin.String? = null
+
+ /**
+ * Note: Since this is a synthetic function, some JVM information (annotations, modifiers) may be missing.
+ */
+ @kotlin.jvm.JvmSynthetic
+ public fun function(): kotlin.Unit {
+ }
+
+ public interface InterfaceWithJvmName {
+ /**
+ * Note: Since this is a synthetic function, some JVM information (annotations, modifiers) may be missing.
+ */
+ @kotlin.jvm.JvmSynthetic
+ public fun interfaceFunction(): kotlin.Unit
+
+ public companion object {
+ @get:kotlin.jvm.JvmSynthetic
+ @kotlin.jvm.JvmStatic
+ public val FOO_BOOL: kotlin.Boolean = throw NotImplementedError("Stub!")
+
+ /**
+ * Note: Since this is a synthetic function, some JVM information (annotations, modifiers) may be missing.
+ */
+ @kotlin.jvm.JvmSynthetic
+ public fun staticFunction(): kotlin.Unit {
+ }
+ }
+ }
+ }
+ """.trimIndent(),
+ )
+ }
+
+ class Synthetics(
+ @get:JvmSynthetic val param: String,
+ ) {
+
+ @JvmSynthetic
+ val property: String? = null
+
+ @field:JvmSynthetic
+ val fieldProperty: String? = null
+
+ @get:JvmSynthetic
+ val propertyGet: String? = null
+
+ @set:JvmSynthetic
+ var propertySet: String? = null
+
+ @set:JvmSynthetic
+ @get:JvmSynthetic
+ var propertyGetAndSet: String? = null
+
+ @JvmSynthetic
+ fun function() {
+ }
+
+ // Interfaces can have JvmSynthetic, so covering a potential edge case of having a companion
+ // object with JvmSynthetic elements. Also covers an edge case where constants have getters
+ interface InterfaceWithJvmName {
+ @JvmSynthetic
+ fun interfaceFunction()
+
+ companion object {
+ @JvmStatic
+ @get:JvmSynthetic
+ val FOO_BOOL = false
+
+ @JvmSynthetic
+ @JvmStatic
+ fun staticFunction() {
+ }
+ }
+ }
+ }
+
+ @Test
+ fun throws() {
+ val typeSpec = Throwing::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class Throwing @kotlin.jvm.Throws(exceptionClasses = [java.lang.IllegalStateException::class]) constructor() {
+ @get:kotlin.jvm.Throws(exceptionClasses = [java.lang.IllegalStateException::class])
+ @set:kotlin.jvm.Throws(exceptionClasses = [java.lang.IllegalStateException::class])
+ public var getterAndSetterThrows: kotlin.String? = null
+
+ @get:kotlin.jvm.Throws(exceptionClasses = [java.lang.IllegalStateException::class])
+ public val getterThrows: kotlin.String? = null
+
+ @set:kotlin.jvm.Throws(exceptionClasses = [java.lang.IllegalStateException::class])
+ public var setterThrows: kotlin.String? = null
+
+ @kotlin.jvm.Throws(exceptionClasses = [java.lang.IllegalStateException::class])
+ public fun testFunction(): kotlin.Unit {
+ }
+ }
+ """.trimIndent(),
+ )
+ }
+
+ class Throwing
+ @Throws(IllegalStateException::class)
+ constructor() {
+
+ @get:Throws(IllegalStateException::class)
+ val getterThrows: String? = null
+
+ @set:Throws(IllegalStateException::class)
+ var setterThrows: String? = null
+
+ @get:Throws(IllegalStateException::class)
+ @set:Throws(IllegalStateException::class)
+ var getterAndSetterThrows: String? = null
+
+ @Throws(IllegalStateException::class)
+ fun testFunction() {
+ }
+ }
+
+ // The meta-ist of metadata meta-tests.
+ @IgnoreForHandlerType(
+ reason = "Reflection can't parse non-runtime retained annotations",
+ handlerType = REFLECTIVE,
+ )
+ @Test
+ fun metaTest_elements() {
+ val typeSpec = Metadata::class.toTypeSpecWithTestHandler()
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ @kotlin.SinceKotlin(version = "1.3")
+ @kotlin.`annotation`.Retention(value = kotlin.`annotation`.AnnotationRetention.RUNTIME)
+ @kotlin.`annotation`.Target(allowedTargets = arrayOf(kotlin.`annotation`.AnnotationTarget.CLASS))
+ public annotation class Metadata(
+ @get:kotlin.jvm.JvmName(name = "k")
+ public val kind: kotlin.Int = throw NotImplementedError("Stub!"),
+ @get:kotlin.jvm.JvmName(name = "mv")
+ public val metadataVersion: kotlin.IntArray = throw NotImplementedError("Stub!"),
+ @get:kotlin.jvm.JvmName(name = "bv")
+ public val bytecodeVersion: kotlin.IntArray = throw NotImplementedError("Stub!"),
+ @get:kotlin.jvm.JvmName(name = "d1")
+ public val data1: kotlin.Array<kotlin.String> = throw NotImplementedError("Stub!"),
+ @get:kotlin.jvm.JvmName(name = "d2")
+ public val data2: kotlin.Array<kotlin.String> = throw NotImplementedError("Stub!"),
+ @get:kotlin.jvm.JvmName(name = "xs")
+ public val extraString: kotlin.String = throw NotImplementedError("Stub!"),
+ @get:kotlin.jvm.JvmName(name = "pn")
+ public val packageName: kotlin.String = throw NotImplementedError("Stub!"),
+ @get:kotlin.jvm.JvmName(name = "xi")
+ public val extraInt: kotlin.Int = throw NotImplementedError("Stub!"),
+ )
+ """.trimIndent(),
+ )
+ }
+
+ // The meta-ist of metadata meta-tests.
+ @IgnoreForHandlerType(
+ reason = "Reflection can't parse non-runtime retained annotations",
+ handlerType = ELEMENTS,
+ )
+ @Test
+ fun metaTest_reflection() {
+ val typeSpec = Metadata::class.toTypeSpecWithTestHandler()
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ @kotlin.`annotation`.Retention(value = kotlin.`annotation`.AnnotationRetention.RUNTIME)
+ @kotlin.`annotation`.Target(allowedTargets = arrayOf(kotlin.`annotation`.AnnotationTarget.CLASS))
+ public annotation class Metadata(
+ @get:kotlin.jvm.JvmName(name = "k")
+ public val kind: kotlin.Int = throw NotImplementedError("Stub!"),
+ @get:kotlin.jvm.JvmName(name = "mv")
+ public val metadataVersion: kotlin.IntArray = throw NotImplementedError("Stub!"),
+ @get:kotlin.jvm.JvmName(name = "bv")
+ public val bytecodeVersion: kotlin.IntArray = throw NotImplementedError("Stub!"),
+ @get:kotlin.jvm.JvmName(name = "d1")
+ public val data1: kotlin.Array<kotlin.String> = throw NotImplementedError("Stub!"),
+ @get:kotlin.jvm.JvmName(name = "d2")
+ public val data2: kotlin.Array<kotlin.String> = throw NotImplementedError("Stub!"),
+ @get:kotlin.jvm.JvmName(name = "xs")
+ public val extraString: kotlin.String = throw NotImplementedError("Stub!"),
+ @get:kotlin.jvm.JvmName(name = "pn")
+ public val packageName: kotlin.String = throw NotImplementedError("Stub!"),
+ @get:kotlin.jvm.JvmName(name = "xi")
+ public val extraInt: kotlin.Int = throw NotImplementedError("Stub!"),
+ )
+ """.trimIndent(),
+ )
+ }
+
+ @Test
+ fun classNamesAndNesting() {
+ // Make sure we parse class names correctly at all levels
+ val typeSpec = ClassNesting::class.toTypeSpecWithTestHandler()
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class ClassNesting() {
+ public class NestedClass() {
+ public class SuperNestedClass() {
+ public inner class SuperDuperInnerClass()
+ }
+ }
+ }
+ """.trimIndent(),
+ )
+ }
+
+ @IgnoreForHandlerType(
+ reason = "compile-testing can't handle class names with dashes, will throw " +
+ "\"class file for com.squareup.kotlinpoet.metadata.specs.Fuzzy\$ClassNesting\$-Nested not found\"",
+ handlerType = ELEMENTS,
+ )
+ @Test
+ fun classNamesAndNesting_pathological() {
+ // Make sure we parse class names correctly at all levels
+ val typeSpec = `Fuzzy$ClassNesting`::class.toTypeSpecWithTestHandler()
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class `Fuzzy${'$'}ClassNesting`() {
+ public class `-Nested`() {
+ public class SuperNestedClass() {
+ public inner class `-${'$'}Fuzzy${'$'}Super${'$'}Weird-Nested${'$'}Name`()
+ }
+ }
+ }
+ """.trimIndent(),
+ )
+ }
+
+ @IgnoreForHandlerType(
+ reason = "Property site-target annotations are always stored on the synthetic annotations " +
+ "method, which is not accessible in the elements API",
+ handlerType = ELEMENTS,
+ )
+ @Test
+ fun parameterAnnotations_reflective() {
+ val typeSpec = ParameterAnnotations::class.toTypeSpecWithTestHandler()
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class ParameterAnnotations(
+ @property:com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.CustomAnnotation(name = "${'$'}{'${'$'}'}a")
+ @com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.CustomAnnotation(name = "b")
+ public val param1: kotlin.String,
+ @com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.CustomAnnotation(name = "2")
+ param2: kotlin.String,
+ ) {
+ public fun function(@com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.CustomAnnotation(name = "woo") param1: kotlin.String): kotlin.Unit {
+ }
+ }
+ """.trimIndent(),
+ )
+ }
+
+ @IgnoreForHandlerType(
+ reason = "Property site-target annotations are always stored on the synthetic annotations " +
+ "method, which is not accessible in the elements API",
+ handlerType = REFLECTIVE,
+ )
+ @Test
+ fun parameterAnnotations_elements() {
+ val typeSpec = ParameterAnnotations::class.toTypeSpecWithTestHandler()
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class ParameterAnnotations(
+ @com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.CustomAnnotation(name = "b")
+ public val param1: kotlin.String,
+ @com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.CustomAnnotation(name = "2")
+ param2: kotlin.String,
+ ) {
+ public fun function(@com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.CustomAnnotation(name = "woo") param1: kotlin.String): kotlin.Unit {
+ }
+ }
+ """.trimIndent(),
+ )
+ }
+
+ annotation class CustomAnnotation(val name: String)
+
+ class ParameterAnnotations(
+ @property:CustomAnnotation("\$a")
+ @param:CustomAnnotation("b")
+ val param1: String,
+ @CustomAnnotation("2") param2: String,
+ ) {
+ fun function(@CustomAnnotation("woo") param1: String) {
+ }
+ }
+
+ @IgnoreForHandlerType(
+ reason = "Non-runtime annotations are not present for reflection.",
+ handlerType = ELEMENTS,
+ )
+ @Test
+ fun classAnnotations_reflective() {
+ val typeSpec = ClassAnnotations::class.toTypeSpecWithTestHandler()
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ @com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.RuntimeCustomClassAnnotation(name = "Runtime")
+ public class ClassAnnotations()
+ """.trimIndent(),
+ )
+ }
+
+ @IgnoreForHandlerType(
+ reason = "Non-runtime annotations are not present for reflection.",
+ handlerType = REFLECTIVE,
+ )
+ @Test
+ fun classAnnotations_elements() {
+ val typeSpec = ClassAnnotations::class.toTypeSpecWithTestHandler()
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ @com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.BinaryCustomClassAnnotation(name = "Binary")
+ @com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.RuntimeCustomClassAnnotation(name = "Runtime")
+ public class ClassAnnotations()
+ """.trimIndent(),
+ )
+ }
+
+ @Retention(AnnotationRetention.SOURCE)
+ annotation class SourceCustomClassAnnotation(val name: String)
+
+ @Retention(AnnotationRetention.BINARY)
+ annotation class BinaryCustomClassAnnotation(val name: String)
+
+ @Retention(AnnotationRetention.RUNTIME)
+ annotation class RuntimeCustomClassAnnotation(val name: String)
+
+ @SourceCustomClassAnnotation("Source")
+ @BinaryCustomClassAnnotation("Binary")
+ @RuntimeCustomClassAnnotation("Runtime")
+ class ClassAnnotations
+
+ @Test
+ fun typeAnnotations() {
+ val typeSpec = TypeAnnotations::class.toTypeSpecWithTestHandler()
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class TypeAnnotations() {
+ public val foo: kotlin.collections.List<@com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.TypeAnnotation kotlin.String> = throw NotImplementedError("Stub!")
+
+ public fun <T> bar(input: @com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.TypeAnnotation kotlin.String, input2: @com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.TypeAnnotation (@com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.TypeAnnotation kotlin.Int) -> @com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.TypeAnnotation kotlin.String): kotlin.Unit {
+ }
+ }
+ """.trimIndent(),
+ )
+ }
+
+ @Target(TYPE, TYPE_PARAMETER)
+ annotation class TypeAnnotation
+
+ class TypeAnnotations {
+ val foo: List<@TypeAnnotation String> = emptyList()
+
+ fun <@TypeAnnotation T> bar(
+ input: @TypeAnnotation String,
+ input2: @TypeAnnotation (@TypeAnnotation Int) -> @TypeAnnotation String,
+ ) {
+ }
+ }
+
+ // Regression test for https://github.com/square/kotlinpoet/issues/812
+ @Test
+ fun backwardTypeVarReferences() {
+ val typeSpec = Asset::class.toTypeSpecWithTestHandler()
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public class Asset<A : com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.Asset<A>>() {
+ public fun <D : com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.Asset<D>, C : com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.Asset<A>> function(): kotlin.Unit {
+ }
+
+ public class AssetIn<in C : com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.Asset.AssetIn<C>>()
+
+ public class AssetOut<out B : com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.Asset.AssetOut<B>>()
+ }
+ """.trimIndent(),
+ )
+ }
+
+ class Asset<A : Asset<A>> {
+ fun <D : Asset<D>, C : Asset<A>> function() {
+ }
+
+ class AssetOut<out B : AssetOut<B>>
+ class AssetIn<in C : AssetIn<C>>
+ }
+
+ // Regression test for https://github.com/square/kotlinpoet/issues/821
+ @Test
+ fun abstractClass() {
+ val typeSpec = AbstractClass::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public abstract class AbstractClass() {
+ public val baz: kotlin.String? = null
+
+ public abstract val foo: kotlin.String
+
+ public abstract fun bar(): kotlin.Unit
+
+ public abstract fun barWithReturn(): kotlin.String
+
+ public fun fuz(): kotlin.Unit {
+ }
+
+ public fun fuzWithReturn(): kotlin.String = throw NotImplementedError("Stub!")
+ }
+ """.trimIndent(),
+ )
+ }
+
+ abstract class AbstractClass {
+ abstract val foo: String
+ abstract fun bar()
+ abstract fun barWithReturn(): String
+
+ val baz: String? = null
+ fun fuz() {}
+ fun fuzWithReturn(): String {
+ return ""
+ }
+ }
+
+ // Regression test for https://github.com/square/kotlinpoet/issues/820
+ @Test
+ fun internalAbstractProperty() {
+ val typeSpec = InternalAbstractPropertyHolder::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public abstract class InternalAbstractPropertyHolder() {
+ internal abstract val valProp: kotlin.String
+
+ internal abstract var varProp: kotlin.String
+ }
+ """.trimIndent(),
+ )
+ }
+
+ abstract class InternalAbstractPropertyHolder {
+ internal abstract val valProp: String
+ internal abstract var varProp: String
+ }
+
+ @Test
+ fun modalities() {
+ val abstractModalities = AbstractModalities::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(abstractModalities.trimmedToString()).isEqualTo(
+ """
+ public abstract class AbstractModalities() : com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.ModalitiesInterface {
+ public val implicitFinalProp: kotlin.String? = null
+
+ public override val interfaceProp: kotlin.String? = null
+
+ public open val openProp: kotlin.String? = null
+
+ public fun implicitFinalFun(): kotlin.Unit {
+ }
+
+ public override fun interfaceFun(): kotlin.Unit {
+ }
+
+ public open fun openFun(): kotlin.Unit {
+ }
+ }
+ """.trimIndent(),
+ )
+
+ val finalAbstractModalities = FinalAbstractModalities::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(finalAbstractModalities.trimmedToString()).isEqualTo(
+ """
+ public abstract class FinalAbstractModalities() : com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.ModalitiesInterface {
+ public final override val interfaceProp: kotlin.String? = null
+
+ public final override fun interfaceFun(): kotlin.Unit {
+ }
+ }
+ """.trimIndent(),
+ )
+
+ val modalities = Modalities::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(modalities.trimmedToString()).isEqualTo(
+ """
+ public class Modalities() : com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.AbstractModalities() {
+ public override val interfaceProp: kotlin.String? = null
+
+ public override val openProp: kotlin.String? = null
+
+ public override fun interfaceFun(): kotlin.Unit {
+ }
+
+ public override fun openFun(): kotlin.Unit {
+ }
+ }
+ """.trimIndent(),
+ )
+ }
+
+ interface ModalitiesInterface {
+ val interfaceProp: String?
+ fun interfaceFun()
+ }
+ abstract class AbstractModalities : ModalitiesInterface {
+ override val interfaceProp: String? = null
+ override fun interfaceFun() {
+ }
+ val implicitFinalProp: String? = null
+ fun implicitFinalFun() {
+ }
+ open val openProp: String? = null
+ open fun openFun() {
+ }
+ }
+ abstract class FinalAbstractModalities : ModalitiesInterface {
+ final override val interfaceProp: String? = null
+ final override fun interfaceFun() {
+ }
+ }
+ class Modalities : AbstractModalities() {
+ override val interfaceProp: String? = null
+ override fun interfaceFun() {
+ }
+
+ override val openProp: String? = null
+ override fun openFun() {
+ }
+ }
+
+ @Test
+ fun funClass() {
+ val funInterface = FunInterface::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(funInterface.trimmedToString()).isEqualTo(
+ """
+ public fun interface FunInterface {
+ public fun example(): kotlin.Unit
+ }
+ """.trimIndent(),
+ )
+ }
+
+ fun interface FunInterface {
+ fun example()
+ }
+
+ @Test
+ fun selfReferencingTypeParams() {
+ val typeSpec = Node::class.toTypeSpecWithTestHandler()
+
+ //language=kotlin
+ assertThat(typeSpec.trimmedToString()).isEqualTo(
+ """
+ public open class Node<T : com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.Node<T, R>, R : com.squareup.kotlinpoet.metadata.specs.KotlinPoetMetadataSpecsTest.Node<R, T>>() {
+ public var r: R? = null
+
+ public var t: T? = null
+ }
+ """.trimIndent(),
+ )
+ }
+
+ open class Node<T : Node<T, R>, R : Node<R, T>> {
+ var t: T? = null
+ var r: R? = null
+ }
+}
+
+class ClassNesting {
+ class NestedClass {
+ class SuperNestedClass {
+ inner class SuperDuperInnerClass
+ }
+ }
+}
+
+class `Fuzzy$ClassNesting` {
+ class `-Nested` {
+ class SuperNestedClass {
+ inner class `-$Fuzzy$Super$Weird-Nested$Name`
+ }
+ }
+}
+
+private fun TypeSpec.trimmedToString(): String {
+ return toString().trim()
+}
+
+inline class InlineClass(val value: String)
+
+@JvmInline
+value class ValueClass(val value: String)
+
+typealias TypeAliasName = String
+typealias GenericTypeAlias = List<String>
+typealias NestedTypeAlias = List<GenericTypeAlias>
diff --git a/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/MultiClassInspectorTest.kt b/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/MultiClassInspectorTest.kt
new file mode 100644
index 00000000..cb7c21d6
--- /dev/null
+++ b/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/MultiClassInspectorTest.kt
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2019 Square, Inc.
+ *
+ * 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.
+ */
+package com.squareup.kotlinpoet.metadata.specs
+
+import com.google.testing.compile.CompilationRule
+import com.squareup.kotlinpoet.FileSpec
+import com.squareup.kotlinpoet.TypeSpec
+import com.squareup.kotlinpoet.asClassName
+import com.squareup.kotlinpoet.metadata.KotlinPoetMetadataPreview
+import com.squareup.kotlinpoet.metadata.classinspectors.ElementsClassInspector
+import com.squareup.kotlinpoet.metadata.classinspectors.ReflectiveClassInspector
+import com.squareup.kotlinpoet.metadata.specs.MultiClassInspectorTest.ClassInspectorType
+import com.squareup.kotlinpoet.metadata.toKotlinClassMetadata
+import java.lang.annotation.Inherited
+import kotlin.annotation.AnnotationRetention.RUNTIME
+import kotlin.reflect.KClass
+import kotlinx.metadata.jvm.KotlinClassMetadata.FileFacade
+import org.junit.Assume
+import org.junit.Rule
+import org.junit.rules.TestRule
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.junit.runners.Parameterized.Parameter
+import org.junit.runners.model.Statement
+
+/** Base test class that runs all tests with multiple [ClassInspectorTypes][ClassInspectorType]. */
+@RunWith(Parameterized::class)
+@KotlinPoetMetadataPreview
+abstract class MultiClassInspectorTest {
+ companion object {
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun data(): Collection<Array<ClassInspectorType>> {
+ return listOf(
+ arrayOf(ClassInspectorType.REFLECTIVE),
+ arrayOf(ClassInspectorType.ELEMENTS),
+ )
+ }
+ }
+
+ enum class ClassInspectorType {
+ NONE {
+ override fun create(testInstance: MultiClassInspectorTest): ClassInspector {
+ throw IllegalStateException("Should not be called, just here to default the jvmfield to something.")
+ }
+ },
+ REFLECTIVE {
+ override fun create(testInstance: MultiClassInspectorTest): ClassInspector {
+ return ReflectiveClassInspector.create()
+ }
+ },
+ ELEMENTS {
+ override fun create(testInstance: MultiClassInspectorTest): ClassInspector {
+ return ElementsClassInspector.create(testInstance.compilation.elements, testInstance.compilation.types)
+ }
+ },
+ ;
+
+ abstract fun create(testInstance: MultiClassInspectorTest): ClassInspector
+ }
+
+ @Retention(RUNTIME)
+ @Target(AnnotationTarget.FUNCTION)
+ @Inherited
+ annotation class IgnoreForHandlerType(
+ val reason: String,
+ val handlerType: ClassInspectorType,
+ )
+
+ @JvmField
+ @Parameter
+ var classInspectorType: ClassInspectorType = ClassInspectorType.NONE
+
+ @Rule
+ @JvmField
+ val compilation = CompilationRule()
+
+ @Rule
+ @JvmField
+ val ignoreForElementsRule = TestRule { base, description ->
+ object : Statement() {
+ override fun evaluate() {
+ val annotation = description.getAnnotation(
+ IgnoreForHandlerType::class.java,
+ )
+ val shouldIgnore = annotation?.handlerType == classInspectorType
+ Assume.assumeTrue(
+ "Ignoring ${description.methodName}: ${annotation?.reason}",
+ !shouldIgnore,
+ )
+ base.evaluate()
+ }
+ }
+ }
+
+ protected fun KClass<*>.toTypeSpecWithTestHandler(): TypeSpec {
+ return toTypeSpec(classInspectorType.create(this@MultiClassInspectorTest))
+ }
+
+ protected fun KClass<*>.toFileSpecWithTestHandler(): FileSpec {
+ val classInspector = classInspectorType.create(this@MultiClassInspectorTest)
+ return java.annotations.filterIsInstance<Metadata>().first().toKotlinClassMetadata<FileFacade>()
+ .toKmPackage()
+ .toFileSpec(classInspector, asClassName())
+ }
+}
diff --git a/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/NoJvmNameFacadeFile.kt b/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/NoJvmNameFacadeFile.kt
new file mode 100644
index 00000000..6347108d
--- /dev/null
+++ b/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/NoJvmNameFacadeFile.kt
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2021 Square, Inc.
+ *
+ * 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.
+ */
+package com.squareup.kotlinpoet.metadata.specs
+
+val prop: String = ""
diff --git a/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/ReflectiveClassInspectorTest.kt b/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/ReflectiveClassInspectorTest.kt
new file mode 100644
index 00000000..a4ecc3de
--- /dev/null
+++ b/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/ReflectiveClassInspectorTest.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2021 Square, Inc.
+ *
+ * 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.
+ */
+package com.squareup.kotlinpoet.metadata.specs
+
+import com.squareup.kotlinpoet.ClassName
+import com.squareup.kotlinpoet.asClassName
+import com.squareup.kotlinpoet.metadata.KotlinPoetMetadataPreview
+import com.squareup.kotlinpoet.metadata.classinspectors.ReflectiveClassInspector
+import com.tschuchort.compiletesting.KotlinCompilation
+import com.tschuchort.compiletesting.SourceFile
+import kotlin.test.assertEquals
+import kotlin.test.assertNotNull
+import org.junit.Test
+
+/**
+ * Class to test the new functionality of Issue#1036.
+ * @see <a href="https://github.com/square/kotlinpoet/issues/1036">issue</a>
+ * @author oberstrike
+ */
+@KotlinPoetMetadataPreview
+class ReflectiveClassInspectorTest {
+
+ data class Person(val name: String)
+
+ /**
+ * Tests if the [ReflectiveClassInspector] can be created without a
+ * custom ClassLoader and still works.
+ */
+ @Test
+ fun standardClassLoaderTest() {
+ val classInspector = ReflectiveClassInspector.create()
+ val className = Person::class.asClassName()
+ val declarationContainer = classInspector.declarationContainerFor(className)
+ assertNotNull(declarationContainer)
+ }
+
+ /**
+ * Tests if the [ReflectiveClassInspector] can be created with a
+ * custom ClassLoader.
+ */
+ @Test
+ fun useACustomClassLoaderTest() {
+ val testClass = "Person"
+ val testPropertyName = "name"
+ val testPropertyType = "String"
+ val testPackageName = "com.test"
+ val testClassName = ClassName(testPackageName, testClass)
+ val testKtFileName = "KClass.kt"
+
+ val kotlinSource = SourceFile.kotlin(
+ testKtFileName,
+ """
+ package $testPackageName
+ data class $testClass(val $testPropertyName: $testPropertyType)
+ """.trimIndent(),
+ )
+
+ val result = KotlinCompilation().apply {
+ sources = listOf(kotlinSource)
+ }.compile()
+
+ assertEquals(KotlinCompilation.ExitCode.OK, result.exitCode)
+ val classLoader = result.classLoader
+ val classInspector = ReflectiveClassInspector.create(classLoader)
+
+ val declarationContainer = classInspector.declarationContainerFor(testClassName)
+
+ val properties = declarationContainer.properties
+ assertEquals(1, properties.size)
+
+ val testProperty = properties.findLast { it.name == testPropertyName }
+ assertNotNull(testProperty)
+
+ val returnType = testProperty.returnType
+ assertNotNull(returnType)
+ }
+}
diff --git a/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/classinspectors/ClassInspectorUtilTest.kt b/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/classinspectors/ClassInspectorUtilTest.kt
new file mode 100644
index 00000000..4e1c268b
--- /dev/null
+++ b/interop/kotlinx-metadata/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/classinspectors/ClassInspectorUtilTest.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2021 Square, Inc.
+ *
+ * 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.
+ */
+package com.squareup.kotlinpoet.metadata.specs.classinspectors
+
+import com.google.common.truth.Truth.assertThat
+import com.squareup.kotlinpoet.AnnotationSpec
+import com.squareup.kotlinpoet.ClassName
+import com.squareup.kotlinpoet.asClassName
+import com.squareup.kotlinpoet.metadata.KotlinPoetMetadataPreview
+import com.squareup.kotlinpoet.metadata.classinspectors.ClassInspectorUtil
+import kotlin.test.Test
+
+@KotlinPoetMetadataPreview
+class ClassInspectorUtilTest {
+
+ @Test fun createClassName_simple() {
+ assertThat(ClassInspectorUtil.createClassName("some/path/Foo"))
+ .isEqualTo(ClassName("some.path", "Foo"))
+ }
+
+ @Test fun createClassName_nested() {
+ assertThat(ClassInspectorUtil.createClassName("some/path/Foo.Nested"))
+ .isEqualTo(ClassName("some.path", "Foo", "Nested"))
+ }
+
+ @Test fun createClassName_simple_dollarNameStart() {
+ assertThat(ClassInspectorUtil.createClassName("some/path/Foo$"))
+ .isEqualTo(ClassName("some.path", "Foo$"))
+ }
+
+ @Test fun createClassName_simple_dollarNameMiddle() {
+ assertThat(ClassInspectorUtil.createClassName("some/path/Fo${'$'}o"))
+ .isEqualTo(ClassName("some.path", "Fo${'$'}o"))
+ }
+
+ @Test fun createClassName_simple_dollarNameEnd() {
+ assertThat(ClassInspectorUtil.createClassName("some/path/Nested.${'$'}Foo"))
+ .isEqualTo(ClassName("some.path", "Nested", "${'$'}Foo"))
+ }
+
+ @Test fun createClassName_nested_dollarNameStart() {
+ assertThat(ClassInspectorUtil.createClassName("some/path/Nested.Foo$"))
+ .isEqualTo(ClassName("some.path", "Nested", "Foo$"))
+ }
+
+ @Test fun createClassName_nested_dollarNameMiddle() {
+ assertThat(ClassInspectorUtil.createClassName("some/path/Nested.Fo${'$'}o"))
+ .isEqualTo(ClassName("some.path", "Nested", "Fo${'$'}o"))
+ }
+
+ @Test fun createClassName_nested_dollarNameEnd() {
+ assertThat(ClassInspectorUtil.createClassName("some/path/Nested.${'$'}Foo"))
+ .isEqualTo(ClassName("some.path", "Nested", "${'$'}Foo"))
+ }
+
+ @Test fun createClassName_noPackageName() {
+ assertThat(ClassInspectorUtil.createClassName("ClassWithNoPackage"))
+ .isEqualTo(ClassName("", "ClassWithNoPackage"))
+ }
+
+ // Regression test for avoiding https://github.com/square/kotlinpoet/issues/795
+ @Test fun createClassName_noEmptyNames() {
+ val noPackage = ClassInspectorUtil.createClassName("ClassWithNoPackage")
+ assertThat(noPackage.simpleNames.any { it.isEmpty() }).isFalse()
+
+ val withPackage = ClassInspectorUtil.createClassName("path/to/ClassWithNoPackage")
+ assertThat(withPackage.simpleNames.any { it.isEmpty() }).isFalse()
+ }
+
+ @Test fun createClassName_packageWithCaps() {
+ assertThat(ClassInspectorUtil.createClassName("some/Path/Foo.Nested"))
+ .isEqualTo(ClassName("some.Path", "Foo", "Nested"))
+ }
+
+ @Test fun throwsSpec_normal() {
+ assertThat(ClassInspectorUtil.createThrowsSpec(listOf(Exception::class.asClassName())))
+ .isEqualTo(
+ AnnotationSpec.builder(Throws::class.asClassName())
+ .addMember("exceptionClasses = [%T::class]", Exception::class.asClassName())
+ .build(),
+ )
+ }
+}