xref: /aosp_15_r20/tools/metalava/metalava/src/test/java/com/android/tools/metalava/CoreApiTest.kt (revision 115816f9299ab6ddd6b9673b81f34e707f6bacab)
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