blob: cd859448b0a28a54f0284060ec9fef710f2c4e6d [file] [log] [blame]
Mårten Kongstadf242ec82024-04-16 17:12:26 +02001/*
2 * Copyright (C) 2024 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 */
16package com.android.checkflaggedapis
17
Mårten Kongstad387ff6c2024-04-16 12:42:14 +020018import android.aconfig.Aconfig
Mårten Kongstad18ff19a2024-04-26 05:48:57 +020019import android.aconfig.Aconfig.flag_state.DISABLED
20import android.aconfig.Aconfig.flag_state.ENABLED
Mårten Kongstad387ff6c2024-04-16 12:42:14 +020021import java.io.ByteArrayInputStream
22import java.io.ByteArrayOutputStream
Mårten Kongstad9238a3a2024-04-16 13:19:50 +020023import java.io.InputStream
Mårten Kongstad20de4052024-04-16 11:33:56 +020024import org.junit.Assert.assertEquals
Mårten Kongstadf242ec82024-04-16 17:12:26 +020025import org.junit.Test
26import org.junit.runner.RunWith
Mårten Kongstad7cc21742024-04-18 10:23:20 +020027import org.junit.runners.JUnit4
Mårten Kongstadf242ec82024-04-16 17:12:26 +020028
Mårten Kongstad20de4052024-04-16 11:33:56 +020029private val API_SIGNATURE =
30 """
31 // Signature format: 2.0
32 package android {
Mårten Kongstad18ff19a2024-04-26 05:48:57 +020033 @FlaggedApi("android.flag.foo") public final class Clazz {
Mårten Kongstad40da9702024-04-27 01:42:51 +020034 ctor @FlaggedApi("android.flag.foo") public Clazz();
Mårten Kongstad20de4052024-04-16 11:33:56 +020035 field @FlaggedApi("android.flag.foo") public static final int FOO = 1; // 0x1
Mårten Kongstad40da9702024-04-27 01:42:51 +020036 method @FlaggedApi("android.flag.foo") public int getErrorCode();
Mårten Kongstadb4a14bf2024-04-28 00:21:11 +020037 method @FlaggedApi("android.flag.foo") public boolean setData(int, int[][], @NonNull android.util.Utility<T, U>);
38 method @FlaggedApi("android.flag.foo") public boolean setVariableData(int, android.util.Atom...);
39 method @FlaggedApi("android.flag.foo") public boolean innerClassArg(android.Clazz.Builder);
Mårten Kongstad20de4052024-04-16 11:33:56 +020040 }
Mårten Kongstad18ff19a2024-04-26 05:48:57 +020041 @FlaggedApi("android.flag.bar") public static class Clazz.Builder {
42 }
Mårten Kongstad20de4052024-04-16 11:33:56 +020043 }
44"""
45 .trim()
46
Mårten Kongstadb673d3b2024-04-16 18:34:20 +020047private val API_VERSIONS =
48 """
49 <?xml version="1.0" encoding="utf-8"?>
50 <api version="3">
51 <class name="android/Clazz" since="1">
Mårten Kongstadc3f05a62024-05-06 21:42:15 +020052 <extends name="java/lang/Object"/>
Mårten Kongstadb673d3b2024-04-16 18:34:20 +020053 <method name="&lt;init>()V"/>
54 <field name="FOO"/>
Mårten Kongstad40da9702024-04-27 01:42:51 +020055 <method name="getErrorCode()I"/>
Mårten Kongstadb4a14bf2024-04-28 00:21:11 +020056 <method name="setData(I[[ILandroid/util/Utility;)Z"/>
57 <method name="setVariableData(I[Landroid/util/Atom;)Z"/>
58 <method name="innerClassArg(Landroid/Clazz${"$"}Builder;)"/>
Mårten Kongstadb673d3b2024-04-16 18:34:20 +020059 </class>
Mårten Kongstad18ff19a2024-04-26 05:48:57 +020060 <class name="android/Clazz${"$"}Builder" since="2">
Mårten Kongstadc3f05a62024-05-06 21:42:15 +020061 <extends name="java/lang/Object"/>
Mårten Kongstad18ff19a2024-04-26 05:48:57 +020062 </class>
Mårten Kongstadb673d3b2024-04-16 18:34:20 +020063 </api>
64"""
65 .trim()
66
Mårten Kongstad18ff19a2024-04-26 05:48:57 +020067private fun generateFlagsProto(
68 fooState: Aconfig.flag_state,
69 barState: Aconfig.flag_state
70): InputStream {
71 val fooFlag =
Mårten Kongstad9238a3a2024-04-16 13:19:50 +020072 Aconfig.parsed_flag
73 .newBuilder()
74 .setPackage("android.flag")
75 .setName("foo")
76 .setState(fooState)
77 .setPermission(Aconfig.flag_permission.READ_ONLY)
78 .build()
Mårten Kongstad18ff19a2024-04-26 05:48:57 +020079 val barFlag =
80 Aconfig.parsed_flag
81 .newBuilder()
82 .setPackage("android.flag")
83 .setName("bar")
84 .setState(barState)
85 .setPermission(Aconfig.flag_permission.READ_ONLY)
86 .build()
87 val flags =
88 Aconfig.parsed_flags.newBuilder().addParsedFlag(fooFlag).addParsedFlag(barFlag).build()
Mårten Kongstad9238a3a2024-04-16 13:19:50 +020089 val binaryProto = ByteArrayOutputStream()
Mårten Kongstad18ff19a2024-04-26 05:48:57 +020090 flags.writeTo(binaryProto)
Mårten Kongstad9238a3a2024-04-16 13:19:50 +020091 return ByteArrayInputStream(binaryProto.toByteArray())
92}
93
Mårten Kongstad7cc21742024-04-18 10:23:20 +020094@RunWith(JUnit4::class)
95class CheckFlaggedApisTest {
Mårten Kongstad20de4052024-04-16 11:33:56 +020096 @Test
97 fun testParseApiSignature() {
Mårten Kongstad18ff19a2024-04-26 05:48:57 +020098 val expected =
99 setOf(
Mårten Kongstadc3f05a62024-05-06 21:42:15 +0200100 Pair(
101 Symbol.createClass("android/Clazz", "java/lang/Object", setOf()),
102 Flag("android.flag.foo")),
Mårten Kongstada1fe3712024-05-06 13:46:21 +0200103 Pair(Symbol.createMethod("android/Clazz", "Clazz()"), Flag("android.flag.foo")),
104 Pair(Symbol.createField("android/Clazz", "FOO"), Flag("android.flag.foo")),
105 Pair(Symbol.createMethod("android/Clazz", "getErrorCode()"), Flag("android.flag.foo")),
Mårten Kongstadb4a14bf2024-04-28 00:21:11 +0200106 Pair(
Mårten Kongstada1fe3712024-05-06 13:46:21 +0200107 Symbol.createMethod("android/Clazz", "setData(I[[ILandroid/util/Utility;)"),
Mårten Kongstadb4a14bf2024-04-28 00:21:11 +0200108 Flag("android.flag.foo")),
109 Pair(
Mårten Kongstada1fe3712024-05-06 13:46:21 +0200110 Symbol.createMethod("android/Clazz", "setVariableData(I[Landroid/util/Atom;)"),
Mårten Kongstadb4a14bf2024-04-28 00:21:11 +0200111 Flag("android.flag.foo")),
112 Pair(
Mårten Kongstada1fe3712024-05-06 13:46:21 +0200113 Symbol.createMethod("android/Clazz", "innerClassArg(Landroid/Clazz/Builder;)"),
Mårten Kongstadb4a14bf2024-04-28 00:21:11 +0200114 Flag("android.flag.foo")),
Mårten Kongstadc3f05a62024-05-06 21:42:15 +0200115 Pair(
116 Symbol.createClass("android/Clazz/Builder", "java/lang/Object", setOf()),
117 Flag("android.flag.bar")),
Mårten Kongstad18ff19a2024-04-26 05:48:57 +0200118 )
Mårten Kongstad20de4052024-04-16 11:33:56 +0200119 val actual = parseApiSignature("in-memory", API_SIGNATURE.byteInputStream())
120 assertEquals(expected, actual)
121 }
Mårten Kongstad387ff6c2024-04-16 12:42:14 +0200122
123 @Test
124 fun testParseFlagValues() {
Mårten Kongstad18ff19a2024-04-26 05:48:57 +0200125 val expected: Map<Flag, Boolean> =
126 mapOf(Flag("android.flag.foo") to true, Flag("android.flag.bar") to true)
127 val actual = parseFlagValues(generateFlagsProto(ENABLED, ENABLED))
Mårten Kongstad387ff6c2024-04-16 12:42:14 +0200128 assertEquals(expected, actual)
129 }
Mårten Kongstadb673d3b2024-04-16 18:34:20 +0200130
131 @Test
132 fun testParseApiVersions() {
Mårten Kongstad18ff19a2024-04-26 05:48:57 +0200133 val expected: Set<Symbol> =
134 setOf(
Mårten Kongstadc3f05a62024-05-06 21:42:15 +0200135 Symbol.createClass("android/Clazz", "java/lang/Object", setOf()),
Mårten Kongstada1fe3712024-05-06 13:46:21 +0200136 Symbol.createMethod("android/Clazz", "Clazz()"),
137 Symbol.createField("android/Clazz", "FOO"),
138 Symbol.createMethod("android/Clazz", "getErrorCode()"),
139 Symbol.createMethod("android/Clazz", "setData(I[[ILandroid/util/Utility;)"),
140 Symbol.createMethod("android/Clazz", "setVariableData(I[Landroid/util/Atom;)"),
141 Symbol.createMethod("android/Clazz", "innerClassArg(Landroid/Clazz/Builder;)"),
Mårten Kongstadc3f05a62024-05-06 21:42:15 +0200142 Symbol.createClass("android/Clazz/Builder", "java/lang/Object", setOf()),
Mårten Kongstad18ff19a2024-04-26 05:48:57 +0200143 )
Mårten Kongstadb673d3b2024-04-16 18:34:20 +0200144 val actual = parseApiVersions(API_VERSIONS.byteInputStream())
145 assertEquals(expected, actual)
146 }
Mårten Kongstad9238a3a2024-04-16 13:19:50 +0200147
148 @Test
Mårten Kongstad02525a82024-05-06 10:28:02 +0200149 fun testParseApiVersionsNestedClasses() {
150 val apiVersions =
151 """
152 <?xml version="1.0" encoding="utf-8"?>
153 <api version="3">
154 <class name="android/Clazz${'$'}Foo${'$'}Bar" since="1">
Mårten Kongstadc3f05a62024-05-06 21:42:15 +0200155 <extends name="java/lang/Object"/>
Mårten Kongstad02525a82024-05-06 10:28:02 +0200156 <method name="&lt;init>()V"/>
157 </class>
158 </api>
159 """
160 .trim()
161 val expected: Set<Symbol> =
162 setOf(
Mårten Kongstadc3f05a62024-05-06 21:42:15 +0200163 Symbol.createClass("android/Clazz/Foo/Bar", "java/lang/Object", setOf()),
Mårten Kongstada1fe3712024-05-06 13:46:21 +0200164 Symbol.createMethod("android/Clazz/Foo/Bar", "Bar()"),
Mårten Kongstad02525a82024-05-06 10:28:02 +0200165 )
166 val actual = parseApiVersions(apiVersions.byteInputStream())
167 assertEquals(expected, actual)
168 }
169
170 @Test
Mårten Kongstad9238a3a2024-04-16 13:19:50 +0200171 fun testFindErrorsNoErrors() {
172 val expected = setOf<ApiError>()
173 val actual =
174 findErrors(
175 parseApiSignature("in-memory", API_SIGNATURE.byteInputStream()),
Mårten Kongstad18ff19a2024-04-26 05:48:57 +0200176 parseFlagValues(generateFlagsProto(ENABLED, ENABLED)),
Mårten Kongstad9238a3a2024-04-16 13:19:50 +0200177 parseApiVersions(API_VERSIONS.byteInputStream()))
178 assertEquals(expected, actual)
179 }
180
181 @Test
Mårten Kongstadd2c70762024-05-06 14:58:18 +0200182 fun testFindErrorsVerifyImplements() {
183 val apiSignature =
184 """
185 // Signature format: 2.0
186 package android {
187 @FlaggedApi("android.flag.foo") public final class Clazz implements android.Interface {
188 method @FlaggedApi("android.flag.foo") public boolean foo();
189 method @FlaggedApi("android.flag.foo") public boolean bar();
190 }
191 public interface Interface {
192 method public boolean bar();
193 }
194 }
195 """
196 .trim()
197
198 val apiVersions =
199 """
200 <?xml version="1.0" encoding="utf-8"?>
201 <api version="3">
202 <class name="android/Clazz" since="1">
Mårten Kongstadc3f05a62024-05-06 21:42:15 +0200203 <extends name="java/lang/Object"/>
Mårten Kongstadd2c70762024-05-06 14:58:18 +0200204 <implements name="android/Interface"/>
205 <method name="foo()Z"/>
206 </class>
207 <class name="android/Interface" since="1">
208 <method name="bar()Z"/>
209 </class>
210 </api>
211 """
212 .trim()
213
214 val expected = setOf<ApiError>()
215 val actual =
216 findErrors(
217 parseApiSignature("in-memory", apiSignature.byteInputStream()),
218 parseFlagValues(generateFlagsProto(ENABLED, ENABLED)),
219 parseApiVersions(apiVersions.byteInputStream()))
220 assertEquals(expected, actual)
221 }
222
223 @Test
Mårten Kongstade8120392024-05-06 21:32:34 +0200224 fun testFindErrorsVerifySuperclass() {
225 val apiSignature =
226 """
227 // Signature format: 2.0
228 package android {
229 @FlaggedApi("android.flag.foo") public final class C extends android.B {
230 method @FlaggedApi("android.flag.foo") public boolean c();
231 method @FlaggedApi("android.flag.foo") public boolean b();
232 method @FlaggedApi("android.flag.foo") public boolean a();
233 }
234 public final class B extends android.A {
235 method public boolean b();
236 }
237 public final class A {
238 method public boolean a();
239 }
240 }
241 """
242 .trim()
243
244 val apiVersions =
245 """
246 <?xml version="1.0" encoding="utf-8"?>
247 <api version="3">
248 <class name="android/C" since="1">
249 <extends name="android/B"/>
250 <method name="c()Z"/>
251 </class>
252 <class name="android/B" since="1">
253 <extends name="android/A"/>
254 <method name="b()Z"/>
255 </class>
256 <class name="android/A" since="1">
257 <method name="a()Z"/>
258 </class>
259 </api>
260 """
261 .trim()
262
263 val expected = setOf<ApiError>()
264 val actual =
265 findErrors(
266 parseApiSignature("in-memory", apiSignature.byteInputStream()),
267 parseFlagValues(generateFlagsProto(ENABLED, ENABLED)),
268 parseApiVersions(apiVersions.byteInputStream()))
269 assertEquals(expected, actual)
270 }
271
272 @Test
Mårten Kongstad9238a3a2024-04-16 13:19:50 +0200273 fun testFindErrorsDisabledFlaggedApiIsPresent() {
274 val expected =
275 setOf<ApiError>(
Mårten Kongstad40da9702024-04-27 01:42:51 +0200276 DisabledFlaggedApiIsPresentError(
Mårten Kongstadc3f05a62024-05-06 21:42:15 +0200277 Symbol.createClass("android/Clazz", "java/lang/Object", setOf()),
278 Flag("android.flag.foo")),
Mårten Kongstad18ff19a2024-04-26 05:48:57 +0200279 DisabledFlaggedApiIsPresentError(
Mårten Kongstada1fe3712024-05-06 13:46:21 +0200280 Symbol.createMethod("android/Clazz", "Clazz()"), Flag("android.flag.foo")),
Mårten Kongstad40da9702024-04-27 01:42:51 +0200281 DisabledFlaggedApiIsPresentError(
Mårten Kongstada1fe3712024-05-06 13:46:21 +0200282 Symbol.createField("android/Clazz", "FOO"), Flag("android.flag.foo")),
283 DisabledFlaggedApiIsPresentError(
284 Symbol.createMethod("android/Clazz", "getErrorCode()"), Flag("android.flag.foo")),
285 DisabledFlaggedApiIsPresentError(
286 Symbol.createMethod("android/Clazz", "setData(I[[ILandroid/util/Utility;)"),
Mårten Kongstadb4a14bf2024-04-28 00:21:11 +0200287 Flag("android.flag.foo")),
288 DisabledFlaggedApiIsPresentError(
Mårten Kongstada1fe3712024-05-06 13:46:21 +0200289 Symbol.createMethod("android/Clazz", "setVariableData(I[Landroid/util/Atom;)"),
Mårten Kongstadb4a14bf2024-04-28 00:21:11 +0200290 Flag("android.flag.foo")),
291 DisabledFlaggedApiIsPresentError(
Mårten Kongstada1fe3712024-05-06 13:46:21 +0200292 Symbol.createMethod("android/Clazz", "innerClassArg(Landroid/Clazz/Builder;)"),
Mårten Kongstadb4a14bf2024-04-28 00:21:11 +0200293 Flag("android.flag.foo")),
294 DisabledFlaggedApiIsPresentError(
Mårten Kongstadc3f05a62024-05-06 21:42:15 +0200295 Symbol.createClass("android/Clazz/Builder", "java/lang/Object", setOf()),
296 Flag("android.flag.bar")),
Mårten Kongstad18ff19a2024-04-26 05:48:57 +0200297 )
Mårten Kongstad9238a3a2024-04-16 13:19:50 +0200298 val actual =
299 findErrors(
300 parseApiSignature("in-memory", API_SIGNATURE.byteInputStream()),
Mårten Kongstad18ff19a2024-04-26 05:48:57 +0200301 parseFlagValues(generateFlagsProto(DISABLED, DISABLED)),
Mårten Kongstad9238a3a2024-04-16 13:19:50 +0200302 parseApiVersions(API_VERSIONS.byteInputStream()))
303 assertEquals(expected, actual)
304 }
Mårten Kongstadf242ec82024-04-16 17:12:26 +0200305}