1 /*
2  * Copyright 2023 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 DeprecationMismatchDetectorTest :
25     AbstractLintDetectorTest(
26         useDetector = DeprecationMismatchDetector(),
27         useIssues = listOf(DeprecationMismatchDetector.ISSUE),
28     ) {
29     @Test
Test correctly matched @deprecated and @Deprecatednull30     fun `Test correctly matched @deprecated and @Deprecated`() {
31         val input =
32             arrayOf(
33                 java(
34                     """
35                     package java.androidx;
36 
37                     /**
38                      * @deprecated Foo is deprecated
39                      */
40                     @Deprecated
41                     public class Foo {
42                         /**
43                          * @deprecated foo is deprecated
44                          */
45                         @Deprecated
46                         public void foo() {}
47 
48                         /**
49                          * @deprecated FOO is deprecated
50                          */
51                         @Deprecated
52                         public static int FOO = 0;
53 
54                         /**
55                          * @deprecated InnerFoo is deprecated
56                          */
57                         @Deprecated
58                         public interface InnerFoo {}
59                     }
60                 """
61                         .trimIndent()
62                 )
63             )
64 
65         check(*input).expectClean()
66     }
67 
68     @Test
Test @deprecated missing @Deprecatednull69     fun `Test @deprecated missing @Deprecated`() {
70         val input =
71             arrayOf(
72                 java(
73                     """
74                     package java.androidx;
75 
76                     /**
77                      * @deprecated Foo is deprecated
78                      */
79                     public class Foo {
80                         /**
81                          * @deprecated foo is deprecated
82                          */
83                         public void foo() {}
84 
85                         /**
86                          * @deprecated FOO is deprecated
87                          */
88                         public static int FOO = 0;
89 
90                         /**
91                          * @deprecated InnerFoo is deprecated
92                          */
93                         public interface InnerFoo {}
94                     }
95                 """
96                         .trimIndent()
97                 )
98             )
99 
100         val expected =
101             """
102             src/java/androidx/Foo.java:6: Error: Items with a @deprecated doc tag must be annotated with @Deprecated [DeprecationMismatch]
103             public class Foo {
104                          ~~~
105             src/java/androidx/Foo.java:10: Error: Items with a @deprecated doc tag must be annotated with @Deprecated [DeprecationMismatch]
106                 public void foo() {}
107                             ~~~
108             src/java/androidx/Foo.java:15: Error: Items with a @deprecated doc tag must be annotated with @Deprecated [DeprecationMismatch]
109                 public static int FOO = 0;
110                                   ~~~
111             src/java/androidx/Foo.java:20: Error: Items with a @deprecated doc tag must be annotated with @Deprecated [DeprecationMismatch]
112                 public interface InnerFoo {}
113                                  ~~~~~~~~
114             4 errors, 0 warnings
115         """
116                 .trimIndent()
117 
118         val expectedFixDiffs =
119             """
120             Autofix for src/java/androidx/Foo.java line 6: Annotate with @Deprecated:
121             @@ -6 +6
122             + @Deprecated
123             Autofix for src/java/androidx/Foo.java line 10: Annotate with @Deprecated:
124             @@ -10 +10
125             +     @Deprecated
126             Autofix for src/java/androidx/Foo.java line 15: Annotate with @Deprecated:
127             @@ -15 +15
128             +     @Deprecated
129             Autofix for src/java/androidx/Foo.java line 20: Annotate with @Deprecated:
130             @@ -20 +20
131             +     @Deprecated
132         """
133                 .trimIndent()
134 
135         check(*input).expect(expected).expectFixDiffs(expectedFixDiffs)
136     }
137 
138     @Test
Test @Deprecated missing @deprecatednull139     fun `Test @Deprecated missing @deprecated`() {
140         val input =
141             arrayOf(
142                 java(
143                     """
144                     package java.androidx;
145 
146                     @Deprecated
147                     public class Foo {
148                         @Deprecated
149                         public void foo() {}
150 
151                         @Deprecated
152                         public static int FOO = 0;
153 
154                         @Deprecated
155                         public interface InnerFoo {}
156                     }
157                 """
158                         .trimIndent()
159                 )
160             )
161 
162         val expected =
163             """
164             src/java/androidx/Foo.java:4: Error: Items annotated with @Deprecated must have a @deprecated doc tag [DeprecationMismatch]
165             public class Foo {
166                          ~~~
167             src/java/androidx/Foo.java:6: Error: Items annotated with @Deprecated must have a @deprecated doc tag [DeprecationMismatch]
168                 public void foo() {}
169                             ~~~
170             src/java/androidx/Foo.java:9: Error: Items annotated with @Deprecated must have a @deprecated doc tag [DeprecationMismatch]
171                 public static int FOO = 0;
172                                   ~~~
173             src/java/androidx/Foo.java:12: Error: Items annotated with @Deprecated must have a @deprecated doc tag [DeprecationMismatch]
174                 public interface InnerFoo {}
175                                  ~~~~~~~~
176             4 errors, 0 warnings
177         """
178                 .trimIndent()
179 
180         check(*input).expect(expected)
181     }
182 
183     @Test
Test @deprecated not required for private APIsnull184     fun `Test @deprecated not required for private APIs`() {
185         val input =
186             arrayOf(
187                 java(
188                     """
189                     package java.androidx;
190 
191                     @Deprecated
192                     private class Foo {
193                         @Deprecated
194                         private void foo() {}
195 
196                         @Deprecated
197                         private static int FOO = 0;
198 
199                         @Deprecated
200                         private interface InnerFoo {}
201                     }
202                 """
203                         .trimIndent()
204                 )
205             )
206         check(*input).expectClean()
207     }
208 
209     @Test
Test @deprecated not required for proto-generated APIsnull210     fun `Test @deprecated not required for proto-generated APIs`() {
211         val input =
212             arrayOf(
213                 java(
214                     """
215                     // Generated by the protocol buffer compiler.  DO NOT EDIT!
216                     package java.androidx.proto;
217 
218                     @Deprecated
219                     public class Foo {
220                         @Deprecated
221                         public void foo() {}
222 
223                         @Deprecated
224                         public static int FOO = 0;
225 
226                         @Deprecated
227                         public interface InnerFoo {}
228                     }
229                 """
230                         .trimIndent()
231                 )
232             )
233         check(*input).expectClean()
234     }
235 
236     @Test
Test anonymous classes don't need @deprecatednull237     fun `Test anonymous classes don't need @deprecated`() {
238         val input =
239             arrayOf(
240                 java(
241                     """
242                     package java.androidx;
243 
244                     /**
245                      * @deprecated Foo is deprecated
246                      */
247                     @Deprecated
248                     public abstract class Foo<T> {
249                         /**
250                          * @deprecated foo is deprecated
251                          */
252                         @Deprecated
253                         public void foo();
254                     }
255                 """
256                         .trimIndent()
257                 ),
258                 java(
259                     """
260                     package java.androidx;
261 
262                     public class Bar {
263                         public static void bar() {
264                             new Foo<String>() {
265                                 @Override
266                                 public void foo() {}
267                             }.foo();
268                         }
269                     }
270                 """
271                         .trimIndent()
272                 )
273             )
274 
275         check(*input).expectClean()
276     }
277 
278     @Test
279     fun `Test @RestrictTo APIs don't need @deprecated`() {
280         val input =
281             arrayOf(
282                 java(
283                     """
284                     package java.androidx;
285 
286                     import androidx.annotation.RestrictTo;
287 
288                     @RestrictTo(RestrictTo.Scope.LIBRARY)
289                     @Deprecated
290                     public class Foo {
291                         @Deprecated
292                         private void foo() {}
293 
294                         @Deprecated
295                         private static int FOO = 0;
296 
297                         @Deprecated
298                         private interface InnerFoo {}
299                     }
300                 """
301                         .trimIndent()
302                 ),
303                 Stubs.RestrictTo
304             )
305         check(*input).expectClean()
306     }
307 
308     @Test
Test overriding methods don't need @deprecatednull309     fun `Test overriding methods don't need @deprecated`() {
310         val input =
311             arrayOf(
312                 java(
313                     """
314                     package java.androidX;
315 
316                     public interface MyInterface {
317                         /** @deprecated Use XYZ instead. */
318                         @Deprecated
319                         void inheritedNoComment();
320 
321                         /** @deprecated Use XYZ instead. */
322                         @Deprecated
323                         void inheritedWithComment();
324 
325                         /** @deprecated Use XYZ instead. */
326                         @Deprecated
327                         void inheritedWithInheritDoc();
328                     }
329                 """,
330                 ),
331                 java(
332                     """
333                     package test.pkg;
334 
335                     public class MyClass implements MyInterface {
336                         @Deprecated
337                         @Override
338                         public void inheritedNoComment() {}
339 
340                         /** @deprecated Use XYZ instead. */
341                         @Deprecated
342                         @Override
343                         public void inheritedWithComment() {}
344 
345                         /** {@inheritDoc} */
346                         @Deprecated
347                         @Override
348                         public void inheritedWithInheritDoc() {}
349                     }
350                 """
351                 )
352             )
353         check(*input).expectClean()
354     }
355 }
356