1 /*
2  * Copyright 2022 The Android Open Source Project
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  *      http://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 
17 package androidx.build.lint
18 
19 import org.junit.Test
20 import org.junit.runner.RunWith
21 import org.junit.runners.JUnit4
22 
23 @RunWith(JUnit4::class)
24 class MissingJvmDefaultWithCompatibilityDetectorTest :
25     AbstractLintDetectorTest(
26         useDetector = MissingJvmDefaultWithCompatibilityDetector(),
27         useIssues = listOf(MissingJvmDefaultWithCompatibilityDetector.ISSUE),
28     ) {
29     @Test
Test lint for interface with stable default methodnull30     fun `Test lint for interface with stable default method`() {
31         val input =
32             arrayOf(
33                 kotlin(
34                     """
35                 package java.androidx
36 
37                 interface InterfaceWithDefaultMethod {
38                     fun methodWithoutDefaultImplementation(foo: Int): String
39                     fun methodWithDefaultImplementation(): Int = 3
40                 }
41             """
42                 )
43             )
44 
45         val expected =
46             """
47 src/java/androidx/InterfaceWithDefaultMethod.kt:4: Error: This interface must be annotated with @JvmDefaultWithCompatibility because it has a stable method with a default implementation [MissingJvmDefaultWithCompatibility]
48                 interface InterfaceWithDefaultMethod {
49                 ^
50 1 errors, 0 warnings
51         """
52 
53         val expectedFixDiffs =
54             """
55 Autofix for src/java/androidx/InterfaceWithDefaultMethod.kt line 4: Annotate with @JvmDefaultWithCompatibility:
56 @@ -4 +4
57 +                 @JvmDefaultWithCompatibility
58         """
59 
60         check(*input).expect(expected).expectFixDiffs(expectedFixDiffs)
61     }
62 
63     @Test
Test lint for interface with stable method with default parameternull64     fun `Test lint for interface with stable method with default parameter`() {
65         val input =
66             arrayOf(
67                 kotlin(
68                     """
69                 package java.androidx
70 
71                 interface InterfaceWithMethodWithDefaultParameterValue {
72                     fun methodWithDefaultParameterValue(foo: Int = 3): Int
73                 }
74             """
75                 )
76             )
77 
78         val expected =
79             """
80 src/java/androidx/InterfaceWithMethodWithDefaultParameterValue.kt:4: Error: This interface must be annotated with @JvmDefaultWithCompatibility because it has a stable method with a parameter with a default value [MissingJvmDefaultWithCompatibility]
81                 interface InterfaceWithMethodWithDefaultParameterValue {
82                 ^
83 1 errors, 0 warnings
84         """
85 
86         val expectedFixDiffs =
87             """
88 Autofix for src/java/androidx/InterfaceWithMethodWithDefaultParameterValue.kt line 4: Annotate with @JvmDefaultWithCompatibility:
89 @@ -4 +4
90 +                 @JvmDefaultWithCompatibility
91         """
92 
93         check(*input).expect(expected).expectFixDiffs(expectedFixDiffs)
94     }
95 
96     @Test
Test lint for interface implementing @JvmDefaultWithCompatibility interfacenull97     fun `Test lint for interface implementing @JvmDefaultWithCompatibility interface`() {
98         val input =
99             arrayOf(
100                 kotlin(
101                     """
102                 package java.androidx
103 
104                 import kotlin.jvm.JvmDefaultWithCompatibility
105 
106                 @JvmDefaultWithCompatibility
107                 interface InterfaceWithAnnotation {
108                     fun foo(bar: Int = 3): Int
109                 }
110             """
111                 ),
112                 kotlin(
113                     """
114                 package java.androidx
115 
116                 interface InterfaceWithoutAnnotation: InterfaceWithAnnotation {
117                     fun baz(): Int
118                 }
119             """
120                 ),
121                 Stubs.JvmDefaultWithCompatibility
122             )
123 
124         val expected =
125             """
126 src/java/androidx/InterfaceWithoutAnnotation.kt:4: Error: This interface must be annotated with @JvmDefaultWithCompatibility because it implements an interface which uses this annotation [MissingJvmDefaultWithCompatibility]
127                 interface InterfaceWithoutAnnotation: InterfaceWithAnnotation {
128                 ^
129 1 errors, 0 warnings
130         """
131 
132         val expectedFixDiffs =
133             """
134 Autofix for src/java/androidx/InterfaceWithoutAnnotation.kt line 4: Annotate with @JvmDefaultWithCompatibility:
135 @@ -4 +4
136 +                 @JvmDefaultWithCompatibility
137         """
138                 .trimIndent()
139 
140         check(*input).expect(expected).expectFixDiffs(expectedFixDiffs)
141     }
142 
143     @Test
Test lint does not apply to interface implementing @JvmDefaultWithCompatibilitynull144     fun `Test lint does not apply to interface implementing @JvmDefaultWithCompatibility`() {
145         val input =
146             arrayOf(
147                 kotlin(
148                     """
149                 package java.androidx
150 
151                 import kotlin.jvm.JvmDefaultWithCompatibility
152 
153                 @JvmDefaultWithCompatibility
154                 interface InterfaceWithAnnotation {
155                     fun foo(bar: Int = 3): Int = 4
156                 }
157             """
158                 ),
159                 Stubs.JvmDefaultWithCompatibility
160             )
161 
162         check(*input).expectClean()
163     }
164 
165     @Test
Test lint does not apply to unstable interfacenull166     fun `Test lint does not apply to unstable interface`() {
167         val input =
168             arrayOf(
169                 kotlin(
170                     """
171                 package java.androidx
172 
173                 @RequiresOptIn
174                 interface UnstableInterface {
175                     fun foo(bar: Int = 3): Int = 4
176                 }
177             """
178                 ),
179                 Stubs.OptIn
180             )
181 
182         check(*input).expectClean()
183     }
184 
185     @Test
Test lint does not apply to interface with no stable methodsnull186     fun `Test lint does not apply to interface with no stable methods`() {
187         val input =
188             arrayOf(
189                 kotlin(
190                     """
191                 package java.androidx
192 
193                 interface InterfaceWithoutStableMethods {
194                     @RequiresOptIn
195                     fun unstableMethod(foo: Int = 3): Int = 4
196                 }
197             """
198                 ),
199                 Stubs.OptIn
200             )
201 
202         check(*input).expectClean()
203     }
204 
205     @Test
Test lint does apply to interface with one unstable method and one stable methodnull206     fun `Test lint does apply to interface with one unstable method and one stable method`() {
207         val input =
208             arrayOf(
209                 kotlin(
210                     """
211                 package java.androidx
212 
213                 interface InterfaceWithStableAndUnstableMethods {
214                     @RequiresOptIn
215                     fun unstableMethod(foo: Int = 3): Int = 4
216                     fun stableMethod(foo: Int = 3): Int = 4
217                 }
218             """
219                 ),
220                 Stubs.OptIn
221             )
222 
223         val expected =
224             """
225 src/java/androidx/InterfaceWithStableAndUnstableMethods.kt:4: Error: This interface must be annotated with @JvmDefaultWithCompatibility because it has a stable method with a default implementation [MissingJvmDefaultWithCompatibility]
226                 interface InterfaceWithStableAndUnstableMethods {
227                 ^
228 1 errors, 0 warnings
229         """
230 
231         val expectedFixDiffs =
232             """
233 Autofix for src/java/androidx/InterfaceWithStableAndUnstableMethods.kt line 4: Annotate with @JvmDefaultWithCompatibility:
234 @@ -4 +4
235 +                 @JvmDefaultWithCompatibility
236         """
237                 .trimIndent()
238 
239         check(*input).expect(expected).expectFixDiffs(expectedFixDiffs)
240     }
241 
242     @Test
Test lint does not apply to interface with no default methodsnull243     fun `Test lint does not apply to interface with no default methods`() {
244         val input =
245             arrayOf(
246                 kotlin(
247                     """
248                 package java.androidx
249 
250                 interface InterfaceWithoutDefaults {
251                     fun methodWithoutDefaults(foo: Int): Int
252                 }
253             """
254                 )
255             )
256 
257         check(*input).expectClean()
258     }
259 
260     @Test
Test lint does not apply to Java filenull261     fun `Test lint does not apply to Java file`() {
262         val input =
263             arrayOf(
264                 java(
265                     """
266                 package java.androidx;
267 
268                 interface JavaInterface {
269                     static int staticMethodInInterface() {
270                         return 3;
271                     }
272                 }
273             """
274                 )
275             )
276 
277         check(*input).expectClean()
278     }
279 }
280