1 /* 2 * Copyright (C) 2018 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 @file:Suppress("JavaDoc", "DanglingJavadoc") 18 19 package com.android.tools.metalava 20 21 import com.android.tools.lint.checks.infrastructure.TestFile 22 import com.android.tools.lint.checks.infrastructure.TestFiles 23 import com.android.tools.metalava.lint.DefaultLintErrorMessage 24 import com.android.tools.metalava.model.text.FileFormat 25 import com.android.tools.metalava.testing.java 26 import org.junit.Test 27 28 /** Test to explore hidden versus public APIs via annotations */ 29 class CoreApiTest : DriverTest() { 30 @Test Hidden with --hide-annotationnull31 fun `Hidden with --hide-annotation`() { 32 check( 33 format = FileFormat.V2, 34 sourceFiles = 35 arrayOf( 36 java( 37 """ 38 /** 39 * Hide everything in this package: 40 */ 41 @libcore.api.LibCoreHidden 42 package test.pkg; 43 """ 44 ) 45 .indented(), 46 java( 47 """ 48 package test.pkg; 49 // Not included: hidden by default from package annotation 50 public class NotExposed { 51 } 52 """ 53 ) 54 .indented(), 55 java( 56 """ 57 package test.pkg; 58 import libcore.api.IntraCoreApi; 59 60 /** 61 * Included because it is annotated with a --show-single-annotation 62 */ 63 @libcore.api.LibCoreHidden 64 @IntraCoreApi 65 public class Exposed { 66 public void stillHidden() { } 67 public String stillHidden; 68 @IntraCoreApi 69 public void exposed() { } 70 @IntraCoreApi 71 public String exposed; 72 73 public class StillHidden { 74 } 75 } 76 """ 77 ) 78 .indented(), 79 libcoreCoreApi, 80 libcoreCoreHidden 81 ), 82 api = 83 """ 84 package libcore.api { 85 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.ANNOTATION_TYPE, java.lang.annotation.ElementType.PACKAGE}) @libcore.api.IntraCoreApi public @interface IntraCoreApi { 86 } 87 } 88 package test.pkg { 89 @libcore.api.IntraCoreApi public class Exposed { 90 method @libcore.api.IntraCoreApi public void exposed(); 91 field @libcore.api.IntraCoreApi public String exposed; 92 } 93 } 94 """, 95 stubFiles = 96 arrayOf( 97 java( 98 """ 99 /** 100 * Hide everything in this package: 101 */ 102 package test.pkg; 103 """ 104 ), 105 java( 106 """ 107 package test.pkg; 108 /** 109 * Included because it is annotated with a --show-single-annotation 110 */ 111 @SuppressWarnings({"unchecked", "deprecation", "all"}) 112 public class Exposed { 113 Exposed() { throw new RuntimeException("Stub!"); } 114 public void exposed() { throw new RuntimeException("Stub!"); } 115 public java.lang.String exposed; 116 } 117 """ 118 ) 119 ), 120 extraArguments = 121 arrayOf( 122 ARG_SHOW_SINGLE_ANNOTATION, 123 "libcore.api.IntraCoreApi", 124 ARG_HIDE_ANNOTATION, 125 "libcore.api.LibCoreHidden" 126 ) 127 ) 128 } 129 130 @Test Hidden with package javadoc and hiding default constructor explicitlynull131 fun `Hidden with package javadoc and hiding default constructor explicitly`() { 132 check( 133 format = FileFormat.V2, 134 sourceFiles = 135 arrayOf( 136 java( 137 """ 138 /** 139 * Hide everything in this package: 140 * @hide 141 */ 142 package test.pkg; 143 """ 144 ) 145 .indented(), 146 java( 147 """ 148 package test.pkg; 149 // Not included: hidden by default from package annotation 150 public class NotExposed { 151 } 152 """ 153 ) 154 .indented(), 155 java( 156 """ 157 package test.pkg; 158 import libcore.api.IntraCoreApi; 159 160 /** 161 * Included because it is annotated with a --show-single-annotation 162 * @hide 163 */ 164 @IntraCoreApi 165 public class Exposed { 166 /** @hide */ 167 public Exposed() { } 168 public void stillHidden() { } 169 @IntraCoreApi 170 public void exposed() { } 171 172 public class StillHidden { 173 } 174 } 175 """ 176 ) 177 .indented(), 178 libcoreCoreApi, 179 libcoreCoreHidden 180 ), 181 api = 182 """ 183 package libcore.api { 184 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.ANNOTATION_TYPE, java.lang.annotation.ElementType.PACKAGE}) @libcore.api.IntraCoreApi public @interface IntraCoreApi { 185 } 186 } 187 package test.pkg { 188 @libcore.api.IntraCoreApi public class Exposed { 189 method @libcore.api.IntraCoreApi public void exposed(); 190 } 191 } 192 """, 193 stubFiles = 194 arrayOf( 195 java( 196 """ 197 /** 198 * Hide everything in this package: 199 * @hide 200 */ 201 package test.pkg; 202 """ 203 ), 204 java( 205 """ 206 package test.pkg; 207 /** 208 * Included because it is annotated with a --show-single-annotation 209 * @hide 210 */ 211 @SuppressWarnings({"unchecked", "deprecation", "all"}) 212 public class Exposed { 213 Exposed() { throw new RuntimeException("Stub!"); } 214 public void exposed() { throw new RuntimeException("Stub!"); } 215 } 216 """ 217 ) 218 ), 219 extraArguments = 220 arrayOf( 221 ARG_SHOW_SINGLE_ANNOTATION, 222 "libcore.api.IntraCoreApi", 223 ARG_HIDE_ANNOTATION, 224 "libcore.api.LibCoreHidden" 225 ), 226 docStubs = true 227 ) 228 } 229 230 @Test Complain if annotating a member and the surrounding class is not includednull231 fun `Complain if annotating a member and the surrounding class is not included`() { 232 check( 233 format = FileFormat.V2, 234 sourceFiles = 235 arrayOf( 236 java( 237 """ 238 /** 239 * Hide everything in this package: 240 * @hide 241 */ 242 package test.pkg; 243 """ 244 ) 245 .indented(), 246 java( 247 """ 248 package test.pkg; 249 import libcore.api.IntraCoreApi; 250 251 /** 252 * Included because it is annotated with a --show-single-annotation 253 * @hide 254 */ 255 public class Exposed { 256 public void stillHidden() { } 257 public String stillHidden; 258 @IntraCoreApi // error: can only expose methods in class also exposed 259 public void exposed() { } 260 261 @IntraCoreApi 262 public String exposed; 263 264 @IntraCoreApi // error: can only expose inner classes in exported outer class 265 public class StillHidden { 266 } 267 } 268 """ 269 ) 270 .indented(), 271 libcoreCoreApi, 272 libcoreCoreHidden 273 ), 274 api = 275 """ 276 package libcore.api { 277 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.ANNOTATION_TYPE, java.lang.annotation.ElementType.PACKAGE}) @libcore.api.IntraCoreApi public @interface IntraCoreApi { 278 } 279 } 280 """, 281 extraArguments = 282 arrayOf( 283 ARG_SHOW_SINGLE_ANNOTATION, 284 "libcore.api.IntraCoreApi", 285 ARG_HIDE_ANNOTATION, 286 "libcore.api.LibCoreHidden" 287 ), 288 expectedIssues = 289 """ 290 src/test/pkg/Exposed.java:12: error: Attempting to unhide method test.pkg.Exposed.exposed(), but surrounding class test.pkg.Exposed is hidden and should also be annotated with @libcore.api.IntraCoreApi [ShowingMemberInHiddenClass] 291 src/test/pkg/Exposed.java:15: error: Attempting to unhide field test.pkg.Exposed.exposed, but surrounding class test.pkg.Exposed is hidden and should also be annotated with @libcore.api.IntraCoreApi [ShowingMemberInHiddenClass] 292 src/test/pkg/Exposed.java:18: error: Attempting to unhide class test.pkg.Exposed.StillHidden, but surrounding class test.pkg.Exposed is hidden and should also be annotated with @libcore.api.IntraCoreApi [ShowingMemberInHiddenClass] 293 """, 294 expectedFail = DefaultLintErrorMessage, 295 ) 296 } 297 } 298 299 val libcoreCoreApi: TestFile = 300 TestFiles.java( 301 """ 302 package libcore.api; 303 304 import static java.lang.annotation.ElementType.ANNOTATION_TYPE; 305 import static java.lang.annotation.ElementType.CONSTRUCTOR; 306 import static java.lang.annotation.ElementType.FIELD; 307 import static java.lang.annotation.ElementType.METHOD; 308 import static java.lang.annotation.ElementType.PACKAGE; 309 import static java.lang.annotation.ElementType.TYPE; 310 311 import java.lang.annotation.Retention; 312 import java.lang.annotation.RetentionPolicy; 313 import java.lang.annotation.Target; 314 315 /** 316 * @hide 317 */ 318 @SuppressWarnings("ALL") 319 @IntraCoreApi // @IntraCoreApi is itself part of the intra-core API 320 @Target({TYPE, FIELD, METHOD, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE}) 321 @Retention(RetentionPolicy.SOURCE) 322 public @interface IntraCoreApi { 323 } 324 """ 325 ) 326 .indented() 327 328 val libcoreCoreHidden: TestFile = 329 TestFiles.java( 330 """ 331 package libcore.api; 332 333 import static java.lang.annotation.ElementType.ANNOTATION_TYPE; 334 import static java.lang.annotation.ElementType.CONSTRUCTOR; 335 import static java.lang.annotation.ElementType.FIELD; 336 import static java.lang.annotation.ElementType.METHOD; 337 import static java.lang.annotation.ElementType.PACKAGE; 338 import static java.lang.annotation.ElementType.TYPE; 339 340 import java.lang.annotation.Retention; 341 import java.lang.annotation.RetentionPolicy; 342 import java.lang.annotation.Target; 343 344 /** 345 * @hide 346 */ 347 @Target({TYPE, FIELD, METHOD, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE}) 348 @Retention(RetentionPolicy.SOURCE) 349 public @interface LibCoreHidden { 350 } 351 """ 352 ) 353 .indented() 354 355 /** Annotation whose annotated elements should be hidden. */ 356 val libcoreCoreHiddenFeature: TestFile = 357 TestFiles.java( 358 """ 359 package libcore.api; 360 361 import static java.lang.annotation.ElementType.ANNOTATION_TYPE; 362 import static java.lang.annotation.ElementType.CONSTRUCTOR; 363 import static java.lang.annotation.ElementType.FIELD; 364 import static java.lang.annotation.ElementType.METHOD; 365 import static java.lang.annotation.ElementType.PACKAGE; 366 import static java.lang.annotation.ElementType.TYPE; 367 import static java.lang.annotation.RetentionPolicy.CLASS; 368 369 import java.lang.annotation.Retention; 370 371 @Retention(CLASS) 372 @LibCoreHiddenFeature 373 @LibCoreMetaHidden 374 public @interface LibCoreHiddenFeature { 375 } 376 """ 377 ) 378 .indented() 379 380 /** Meta-annotation used to denote an annotation whose annotated elements should be hidden. */ 381 val libcoreCoreMetaHidden: TestFile = 382 TestFiles.java( 383 """ 384 package libcore.api; 385 386 import static java.lang.annotation.ElementType.ANNOTATION_TYPE; 387 import static java.lang.annotation.RetentionPolicy.CLASS; 388 389 import java.lang.annotation.Retention; 390 import java.lang.annotation.Target; 391 392 @Retention(CLASS) 393 @Target({ANNOTATION_TYPE}) 394 public @interface LibCoreMetaHidden { 395 } 396 """ 397 ) 398 .indented() 399