• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package com.android.tools.metalava
18 
19 import com.android.tools.lint.checks.infrastructure.TestFiles.base64gzip
20 import com.android.tools.lint.checks.infrastructure.TestFiles.jar
21 import com.android.tools.lint.checks.infrastructure.TestFiles.xml
22 import org.junit.Assert.assertEquals
23 import org.junit.Assert.assertFalse
24 import org.junit.Assert.assertThrows
25 import org.junit.Assert.assertTrue
26 import org.junit.Test
27 import java.io.File
28 import java.lang.reflect.Modifier
29 import java.net.URLClassLoader
30 import kotlin.text.Charsets.UTF_8
31 
32 class RewriteAnnotationsTest : DriverTest() {
33     @Test
Test copying private annotations from one of the stubsnull34     fun `Test copying private annotations from one of the stubs`() {
35         val source = File("stub-annotations")
36         assertTrue(source.path, source.isDirectory)
37         val target = temporaryFolder.newFolder()
38         runDriver(
39             ARG_NO_COLOR,
40             ARG_NO_BANNER,
41 
42             ARG_COPY_ANNOTATIONS,
43             source.path,
44             target.path,
45 
46             ARG_CLASS_PATH,
47             getAndroidJar().path
48         )
49         // Source retention explicitly listed: Shouldn't exist
50         val nullable = File(target, "android/annotation/SdkConstant.java")
51         assertFalse("${nullable.path} exists", nullable.isFile)
52 
53         // Source retention androidx: Shouldn't exist
54         val nonNull = File(target, "androidx/annotation/NonNull.java")
55         assertFalse("${nonNull.path} exists", nonNull.isFile)
56 
57         // Class retention: Should be converted
58 
59         val recentlyNull = File(target, "androidx/annotation/RecentlyNullable.java")
60         assertTrue("${recentlyNull.path} doesn't exist", recentlyNull.isFile)
61         assertEquals(
62             """
63             /*
64              * Copyright (C) 2018 The Android Open Source Project
65              *
66              * Licensed under the Apache License, Version 2.0 (the "License");
67              * you may not use this file except in compliance with the License.
68              * You may obtain a copy of the License at
69              *
70              *      http://www.apache.org/licenses/LICENSE-2.0
71              *
72              * Unless required by applicable law or agreed to in writing, software
73              * distributed under the License is distributed on an "AS IS" BASIS,
74              * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
75              * See the License for the specific language governing permissions and
76              * limitations under the License.
77              */
78             package androidx.annotation;
79 
80             import static java.lang.annotation.ElementType.FIELD;
81             import static java.lang.annotation.ElementType.METHOD;
82             import static java.lang.annotation.ElementType.PARAMETER;
83             import static java.lang.annotation.ElementType.TYPE_USE;
84             import static java.lang.annotation.RetentionPolicy.CLASS;
85 
86             import java.lang.annotation.Retention;
87             import java.lang.annotation.Target;
88 
89             /** Stub only annotation. Do not use directly. */
90             @Retention(CLASS)
91             @Target({METHOD, PARAMETER, FIELD})
92             @interface RecentlyNullable {}
93             """.trimIndent().trim(),
94             recentlyNull.readText(UTF_8).trim().replace("\r\n", "\n")
95         )
96     }
97 
98     @Test
Test stub-annotations containing unknown annotationnull99     fun `Test stub-annotations containing unknown annotation`() {
100         val source = temporaryFolder.newFolder()
101         File("stub-annotations").copyRecursively(source)
102         assertTrue(source.path, source.isDirectory)
103         val target = temporaryFolder.newFolder()
104 
105         val fooSource =
106             """
107             package android.annotation;
108 
109             import static java.lang.annotation.ElementType.FIELD;
110             import static java.lang.annotation.ElementType.METHOD;
111             import static java.lang.annotation.ElementType.PARAMETER;
112             import static java.lang.annotation.RetentionPolicy.SOURCE;
113 
114             import java.lang.annotation.Retention;
115             import java.lang.annotation.Target;
116 
117             /** Stub only annotation. Do not use directly. */
118             @Retention(SOURCE)
119             @Target({METHOD, PARAMETER, FIELD})
120             public @interface Foo {}
121             """
122 
123         File(source, "src/main/java/android/annotation/Unknown.java").writeText(fooSource)
124         assertThrows(IllegalStateException::class.java) {
125             runDriver(
126                 ARG_NO_COLOR,
127                 ARG_NO_BANNER,
128 
129                 ARG_COPY_ANNOTATIONS,
130                 source.path,
131                 target.path,
132 
133                 ARG_CLASS_PATH,
134                 getAndroidJar().path
135             )
136         }
137     }
138 
139     @Test
Test rewriting the bytecode for one of the public annotationsnull140     fun `Test rewriting the bytecode for one of the public annotations`() {
141         val bytecode = base64gzip(
142             "androidx/annotation/CallSuper.class",
143             "" +
144                 "H4sIAAAAAAAAAIWPsU4CQRRF70NhEQWxJMZoLCjdxs6KIMYCA2E3NlbD8kKG" +
145                 "DDNkmSXwaxZ+gB9FfGMBFps4yczc5J53kve9//wC8IirCK0IlxHahEbiijzj" +
146                 "F22Y0OorY5JixfnDQm0UoTMprNdLftdrPTXcs9Z55bWza8LdMDCxUXYeq0MR" +
147                 "T9izDemJUN0oU4i3+w86dkZnuzDQH/aShHBTPpCqfM5euPvyfmB4KcZ0t2KB" +
148                 "am+D9HX0LDZlZ7nTs+1f9rAqoX2UjaYLzjzhttR/3L9LIFTkniCcCk5/3ypq" +
149                 "8l9LiqSrM87QwHmIHyDGBZo/ObYRQoUBAAA="
150         )
151 
152         val compiledStubs = temporaryFolder.newFolder("compiled-stubs")
153         bytecode.createFile(compiledStubs)
154 
155         runDriver(
156             ARG_NO_COLOR,
157             ARG_NO_BANNER,
158 
159             ARG_REWRITE_ANNOTATIONS,
160             compiledStubs.path,
161 
162             ARG_CLASS_PATH,
163             getAndroidJar().path
164         )
165 
166         // Load the class to make sure it's legit
167         val url = compiledStubs.toURI().toURL()
168         val loader = URLClassLoader(arrayOf(url), null)
169         val annotationClass = loader.loadClass("androidx.annotation.CallSuper")
170         val modifiers = annotationClass.modifiers
171         assertEquals(0, modifiers and Modifier.PUBLIC)
172         assertTrue(annotationClass.isAnnotation)
173     }
174 
175     @Test
Test rewriting the bytecode for one of the public annotations in a jar filenull176     fun `Test rewriting the bytecode for one of the public annotations in a jar file`() {
177         val bytecode = base64gzip(
178             "androidx/annotation/CallSuper.class",
179             "" +
180                 "H4sIAAAAAAAAAIWPsU4CQRRF70NhEQWxJMZoLCjdxs6KIMYCA2E3NlbD8kKG" +
181                 "DDNkmSXwaxZ+gB9FfGMBFps4yczc5J53kve9//wC8IirCK0IlxHahEbiijzj" +
182                 "F22Y0OorY5JixfnDQm0UoTMprNdLftdrPTXcs9Z55bWza8LdMDCxUXYeq0MR" +
183                 "T9izDemJUN0oU4i3+w86dkZnuzDQH/aShHBTPpCqfM5euPvyfmB4KcZ0t2KB" +
184                 "am+D9HX0LDZlZ7nTs+1f9rAqoX2UjaYLzjzhttR/3L9LIFTkniCcCk5/3ypq" +
185                 "8l9LiqSrM87QwHmIHyDGBZo/ObYRQoUBAAA="
186         )
187 
188         val jarDesc = jar(
189             "myjar.jar",
190             bytecode,
191             xml("foo/bar/baz.xml", "<hello-world/>")
192         )
193 
194         val jarFile = jarDesc.createFile(temporaryFolder.root)
195 
196         runDriver(
197             ARG_NO_COLOR,
198             ARG_NO_BANNER,
199 
200             ARG_REWRITE_ANNOTATIONS,
201             jarFile.path,
202 
203             ARG_CLASS_PATH,
204             getAndroidJar().path
205         )
206 
207         // Load the class to make sure it's legit
208         val url = jarFile.toURI().toURL()
209         val loader = URLClassLoader(arrayOf(url), null)
210         val annotationClass = loader.loadClass("androidx.annotation.CallSuper")
211         val modifiers = annotationClass.modifiers
212         assertEquals(0, modifiers and Modifier.PUBLIC)
213         assertTrue(annotationClass.isAnnotation)
214     }
215 }
216