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