1 /*
2  * Copyright (C) 2021 Square, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * https://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.squareup.kotlinpoet.javapoet
17 
18 import com.google.common.truth.Truth.assertThat
19 import com.squareup.javapoet.ArrayTypeName
20 import com.squareup.kotlinpoet.ANY
21 import com.squareup.kotlinpoet.ARRAY
22 import com.squareup.kotlinpoet.BOOLEAN
23 import com.squareup.kotlinpoet.BYTE
24 import com.squareup.kotlinpoet.CHAR
25 import com.squareup.kotlinpoet.DOUBLE
26 import com.squareup.kotlinpoet.ENUM
27 import com.squareup.kotlinpoet.FLOAT
28 import com.squareup.kotlinpoet.INT
29 import com.squareup.kotlinpoet.INT_ARRAY
30 import com.squareup.kotlinpoet.LIST
31 import com.squareup.kotlinpoet.LONG
32 import com.squareup.kotlinpoet.MAP
33 import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
34 import com.squareup.kotlinpoet.SET
35 import com.squareup.kotlinpoet.SHORT
36 import com.squareup.kotlinpoet.STAR
37 import com.squareup.kotlinpoet.STRING
38 import com.squareup.kotlinpoet.U_BYTE
39 import com.squareup.kotlinpoet.U_INT
40 import com.squareup.kotlinpoet.U_LONG
41 import com.squareup.kotlinpoet.U_SHORT
42 import com.squareup.kotlinpoet.asClassName
43 import com.squareup.kotlinpoet.typeNameOf
44 import org.junit.Test
45 
46 @OptIn(KotlinPoetJavaPoetPreview::class)
47 class PoetInteropTest {
48 
49   @Test
classNamesMatchnull50   fun classNamesMatch() {
51     val kotlinPoetCN = PoetInteropTest::class.asClassName()
52     val javapoetCN = kotlinPoetCN.toJClassName()
53 
54     assertThat(javapoetCN.toKTypeName()).isEqualTo(kotlinPoetCN)
55     assertThat(JClassName.get(PoetInteropTest::class.java)).isEqualTo(javapoetCN)
56   }
57 
58   @Test
nestedClassNamesMatchnull59   fun nestedClassNamesMatch() {
60     val kotlinPoetCN = PoetInteropTest::class.asClassName().nestedClass("Foo").nestedClass("Bar")
61     val javapoetCN = kotlinPoetCN.toJClassName()
62 
63     assertThat(javapoetCN.toKTypeName()).isEqualTo(kotlinPoetCN)
64     assertThat(JClassName.get(PoetInteropTest::class.java).nestedClass("Foo").nestedClass("Bar"))
65       .isEqualTo(javapoetCN)
66   }
67 
68   @Test
kotlinIntrinsicsMapCorrectlyToJavanull69   fun kotlinIntrinsicsMapCorrectlyToJava() {
70     // To Java
71     assertThat(LIST.toJTypeName()).isEqualTo(PoetInterop.CN_JAVA_LIST)
72     assertThat(SET.toJTypeName()).isEqualTo(PoetInterop.CN_JAVA_SET)
73     assertThat(MAP.toJTypeName()).isEqualTo(PoetInterop.CN_JAVA_MAP)
74     assertThat(STRING.toJTypeName()).isEqualTo(PoetInterop.CN_JAVA_STRING)
75     assertThat(ANY.toJTypeName()).isEqualTo(JTypeName.OBJECT)
76 
77     // To Kotlin
78     assertThat(PoetInterop.CN_JAVA_LIST.toKTypeName()).isEqualTo(LIST)
79     assertThat(PoetInterop.CN_JAVA_SET.toKTypeName()).isEqualTo(SET)
80     assertThat(PoetInterop.CN_JAVA_MAP.toKTypeName()).isEqualTo(MAP)
81     assertThat(PoetInterop.CN_JAVA_STRING.toKTypeName()).isEqualTo(STRING)
82     assertThat(JTypeName.OBJECT.toKTypeName()).isEqualTo(ANY)
83   }
84 
85   @Test
boxIfPrimitiveRequestReturnsBoxedPrimitivenull86   fun boxIfPrimitiveRequestReturnsBoxedPrimitive() {
87     assertThat(BOOLEAN.toJTypeName(boxIfPrimitive = true)).isEqualTo(JTypeName.BOOLEAN.box())
88     assertThat(BYTE.toJTypeName(boxIfPrimitive = true)).isEqualTo(JTypeName.BYTE.box())
89     assertThat(CHAR.toJTypeName(boxIfPrimitive = true)).isEqualTo(JTypeName.CHAR.box())
90     assertThat(SHORT.toJTypeName(boxIfPrimitive = true)).isEqualTo(JTypeName.SHORT.box())
91     assertThat(INT.toJTypeName(boxIfPrimitive = true)).isEqualTo(JTypeName.INT.box())
92     assertThat(LONG.toJTypeName(boxIfPrimitive = true)).isEqualTo(JTypeName.LONG.box())
93     assertThat(FLOAT.toJTypeName(boxIfPrimitive = true)).isEqualTo(JTypeName.FLOAT.box())
94     assertThat(DOUBLE.toJTypeName(boxIfPrimitive = true)).isEqualTo(JTypeName.DOUBLE.box())
95   }
96 
97   @Test
primitivesAreUnboxedByDefaultnull98   fun primitivesAreUnboxedByDefault() {
99     assertThat(BOOLEAN.toJTypeName()).isEqualTo(JTypeName.BOOLEAN)
100     assertThat(BYTE.toJTypeName()).isEqualTo(JTypeName.BYTE)
101     assertThat(CHAR.toJTypeName()).isEqualTo(JTypeName.CHAR)
102     assertThat(SHORT.toJTypeName()).isEqualTo(JTypeName.SHORT)
103     assertThat(INT.toJTypeName()).isEqualTo(JTypeName.INT)
104     assertThat(LONG.toJTypeName()).isEqualTo(JTypeName.LONG)
105     assertThat(FLOAT.toJTypeName()).isEqualTo(JTypeName.FLOAT)
106     assertThat(DOUBLE.toJTypeName()).isEqualTo(JTypeName.DOUBLE)
107   }
108 
109   @Test
nullablePrimitiveBoxedByDefaultnull110   fun nullablePrimitiveBoxedByDefault() {
111     assertThat(BOOLEAN.copy(nullable = true).toJTypeName()).isEqualTo(JTypeName.BOOLEAN.box())
112     assertThat(BYTE.copy(nullable = true).toJTypeName()).isEqualTo(JTypeName.BYTE.box())
113     assertThat(CHAR.copy(nullable = true).toJTypeName()).isEqualTo(JTypeName.CHAR.box())
114     assertThat(SHORT.copy(nullable = true).toJTypeName()).isEqualTo(JTypeName.SHORT.box())
115     assertThat(INT.copy(nullable = true).toJTypeName()).isEqualTo(JTypeName.INT.box())
116     assertThat(LONG.copy(nullable = true).toJTypeName()).isEqualTo(JTypeName.LONG.box())
117     assertThat(FLOAT.copy(nullable = true).toJTypeName()).isEqualTo(JTypeName.FLOAT.box())
118     assertThat(DOUBLE.copy(nullable = true).toJTypeName()).isEqualTo(JTypeName.DOUBLE.box())
119   }
120 
121   @Test
arrayTypesConversionnull122   fun arrayTypesConversion() {
123     assertThat(ARRAY.parameterizedBy(INT).toJParameterizedOrArrayTypeName())
124       .isEqualTo(ArrayTypeName.of(JTypeName.INT))
125     assertThat(ARRAY.parameterizedBy(INT.copy(nullable = true)).toJParameterizedOrArrayTypeName())
126       .isEqualTo(ArrayTypeName.of(JTypeName.INT.box()))
127     assertThat(ArrayTypeName.of(JTypeName.INT).toKTypeName()).isEqualTo(INT_ARRAY)
128     assertThat(ArrayTypeName.of(JTypeName.INT.box()).toKTypeName())
129       .isEqualTo(ARRAY.parameterizedBy(INT))
130   }
131 
132   class GenericType<T>
133 
134   @Test
wildcardsnull135   fun wildcards() {
136     val inKType = typeNameOf<GenericType<in String>>()
137     val superJType = JParameterizedTypeName.get(
138       JClassName.get(GenericType::class.java),
139       JWildcardTypeName.supertypeOf(String::class.java),
140     )
141     assertThat(inKType.toJTypeName()).isEqualTo(superJType)
142     assertThat(superJType.toKTypeName().toString()).isEqualTo(inKType.toString())
143 
144     val outKType = typeNameOf<GenericType<out String>>()
145     val extendsJType = JParameterizedTypeName.get(
146       JClassName.get(GenericType::class.java),
147       JWildcardTypeName.subtypeOf(String::class.java),
148     )
149     assertThat(outKType.toJTypeName()).isEqualTo(extendsJType)
150     assertThat(extendsJType.toKTypeName().toString()).isEqualTo(outKType.toString())
151 
152     val star = typeNameOf<GenericType<*>>()
153     val extendsObjectJType = JParameterizedTypeName.get(
154       JClassName.get(GenericType::class.java),
155       JWildcardTypeName.subtypeOf(JTypeName.OBJECT),
156     )
157     assertThat(star.toJTypeName()).isEqualTo(extendsObjectJType)
158     assertThat(extendsObjectJType.toKTypeName().toString()).isEqualTo(star.toString())
159     assertThat(STAR.toJTypeName()).isEqualTo(JWildcardTypeName.subtypeOf(JTypeName.OBJECT))
160     assertThat(JWildcardTypeName.subtypeOf(JTypeName.OBJECT).toKTypeName()).isEqualTo(STAR)
161   }
162 
163   @Test
complexnull164   fun complex() {
165     val complexType = typeNameOf<Map<String?, List<MutableMap<Int, IntArray>>>>()
166     val jType = JParameterizedTypeName.get(
167       JClassName.get(Map::class.java),
168       JClassName.get(String::class.java),
169       JParameterizedTypeName.get(
170         JClassName.get(List::class.java),
171         JParameterizedTypeName.get(
172           JClassName.get(Map::class.java),
173           JClassName.INT.box(),
174           ArrayTypeName.of(JClassName.INT),
175         ),
176       ),
177     )
178     assertThat(complexType.toJTypeName()).isEqualTo(jType)
179 
180     assertThat(jType.toKTypeName())
181       .isEqualTo(typeNameOf<Map<String, List<MutableMap<Int, IntArray>>>>())
182   }
183 
184   @Test
uTypesAreJustNormalTypesInJavanull185   fun uTypesAreJustNormalTypesInJava() {
186     assertThat(U_BYTE.toJTypeName()).isEqualTo(JTypeName.BYTE)
187     assertThat(U_SHORT.toJTypeName()).isEqualTo(JTypeName.SHORT)
188     assertThat(U_INT.toJTypeName()).isEqualTo(JTypeName.INT)
189     assertThat(U_LONG.toJTypeName()).isEqualTo(JTypeName.LONG)
190   }
191 
192   @Test
enumsnull193   fun enums() {
194     assertThat(ENUM.toJTypeName()).isEqualTo(PoetInterop.CN_JAVA_ENUM)
195     assertThat(PoetInterop.CN_JAVA_ENUM.toKTypeName()).isEqualTo(ENUM)
196   }
197 }
198