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.assertTrue 25 import org.junit.Test 26 import java.io.File 27 import java.lang.reflect.Modifier 28 import java.net.URLClassLoader 29 import kotlin.text.Charsets.UTF_8 30 31 class RewriteAnnotationsTest : DriverTest() { 32 @Test Test copying private annotations from one of the stubsnull33 fun `Test copying private annotations from one of the stubs`() { 34 val source = File("stub-annotations".replace('/', File.separatorChar)) 35 assertTrue(source.path, source.isDirectory) 36 val target = temporaryFolder.newFolder() 37 runDriver( 38 ARG_NO_COLOR, 39 ARG_NO_BANNER, 40 41 ARG_COPY_ANNOTATIONS, 42 source.path, 43 target.path 44 ) 45 46 // Source retention: Shouldn't exist 47 val nonNull = File(target, "androidx/annotation/NonNull.java") 48 assertFalse("${nonNull.path} exists", nonNull.isFile) 49 50 // Class retention: Should be converted 51 52 val recentlyNull = File(target, "androidx/annotation/RecentlyNullable.java") 53 assertTrue("${recentlyNull.path} doesn't exist", recentlyNull.isFile) 54 assertEquals( 55 """ 56 /* 57 * Copyright (C) 2018 The Android Open Source Project 58 * 59 * Licensed under the Apache License, Version 2.0 (the "License"); 60 * you may not use this file except in compliance with the License. 61 * You may obtain a copy of the License at 62 * 63 * http://www.apache.org/licenses/LICENSE-2.0 64 * 65 * Unless required by applicable law or agreed to in writing, software 66 * distributed under the License is distributed on an "AS IS" BASIS, 67 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 68 * See the License for the specific language governing permissions and 69 * limitations under the License. 70 */ 71 package androidx.annotation; 72 73 import static java.lang.annotation.ElementType.FIELD; 74 import static java.lang.annotation.ElementType.METHOD; 75 import static java.lang.annotation.ElementType.PARAMETER; 76 import static java.lang.annotation.ElementType.TYPE_USE; 77 import static java.lang.annotation.RetentionPolicy.CLASS; 78 79 import java.lang.annotation.Retention; 80 import java.lang.annotation.Target; 81 82 /** Stub only annotation. Do not use directly. */ 83 @Retention(CLASS) 84 @Target({METHOD, PARAMETER, FIELD}) 85 @interface RecentlyNullable {} 86 """.trimIndent().trim(), recentlyNull.readText(UTF_8).trim().replace("\r\n", "\n") 87 ) 88 } 89 90 @Test Test rewriting the bytecode for one of the public annotationsnull91 fun `Test rewriting the bytecode for one of the public annotations`() { 92 val bytecode = base64gzip( 93 "androidx/annotation/CallSuper.class", "" + 94 "H4sIAAAAAAAAAIWPsU4CQRRF70NhEQWxJMZoLCjdxs6KIMYCA2E3NlbD8kKG" + 95 "DDNkmSXwaxZ+gB9FfGMBFps4yczc5J53kve9//wC8IirCK0IlxHahEbiijzj" + 96 "F22Y0OorY5JixfnDQm0UoTMprNdLftdrPTXcs9Z55bWza8LdMDCxUXYeq0MR" + 97 "T9izDemJUN0oU4i3+w86dkZnuzDQH/aShHBTPpCqfM5euPvyfmB4KcZ0t2KB" + 98 "am+D9HX0LDZlZ7nTs+1f9rAqoX2UjaYLzjzhttR/3L9LIFTkniCcCk5/3ypq" + 99 "8l9LiqSrM87QwHmIHyDGBZo/ObYRQoUBAAA=" 100 ) 101 102 val compiledStubs = temporaryFolder.newFolder("compiled-stubs") 103 bytecode.createFile(compiledStubs) 104 105 runDriver( 106 ARG_NO_COLOR, 107 ARG_NO_BANNER, 108 109 ARG_REWRITE_ANNOTATIONS, 110 compiledStubs.path 111 ) 112 113 // Load the class to make sure it's legit 114 val url = compiledStubs.toURI().toURL() 115 val loader = URLClassLoader(arrayOf(url), null) 116 val annotationClass = loader.loadClass("androidx.annotation.CallSuper") 117 val modifiers = annotationClass.modifiers 118 assertEquals(0, modifiers and Modifier.PUBLIC) 119 assertTrue(annotationClass.isAnnotation) 120 } 121 122 @Test Test rewriting the bytecode for one of the public annotations in a jar filenull123 fun `Test rewriting the bytecode for one of the public annotations in a jar file`() { 124 val bytecode = base64gzip( 125 "androidx/annotation/CallSuper.class", "" + 126 "H4sIAAAAAAAAAIWPsU4CQRRF70NhEQWxJMZoLCjdxs6KIMYCA2E3NlbD8kKG" + 127 "DDNkmSXwaxZ+gB9FfGMBFps4yczc5J53kve9//wC8IirCK0IlxHahEbiijzj" + 128 "F22Y0OorY5JixfnDQm0UoTMprNdLftdrPTXcs9Z55bWza8LdMDCxUXYeq0MR" + 129 "T9izDemJUN0oU4i3+w86dkZnuzDQH/aShHBTPpCqfM5euPvyfmB4KcZ0t2KB" + 130 "am+D9HX0LDZlZ7nTs+1f9rAqoX2UjaYLzjzhttR/3L9LIFTkniCcCk5/3ypq" + 131 "8l9LiqSrM87QwHmIHyDGBZo/ObYRQoUBAAA=" 132 ) 133 134 val jarDesc = jar( 135 "myjar.jar", 136 bytecode, 137 xml("foo/bar/baz.xml", "<hello-world/>") 138 ) 139 140 val jarFile = jarDesc.createFile(temporaryFolder.root) 141 142 runDriver( 143 ARG_NO_COLOR, 144 ARG_NO_BANNER, 145 146 ARG_REWRITE_ANNOTATIONS, 147 jarFile.path 148 ) 149 150 // Load the class to make sure it's legit 151 val url = jarFile.toURI().toURL() 152 val loader = URLClassLoader(arrayOf(url), null) 153 val annotationClass = loader.loadClass("androidx.annotation.CallSuper") 154 val modifiers = annotationClass.modifiers 155 assertEquals(0, modifiers and Modifier.PUBLIC) 156 assertTrue(annotationClass.isAnnotation) 157 } 158 }