blob: 773f4339f0169b33321e39dcf8e1be9a2ac38f92 [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 Kongstad9238a3a2024-04-16 13:19:50 +0200224 fun testFindErrorsDisabledFlaggedApiIsPresent() {
225 val expected =
226 setOf<ApiError>(
Mårten Kongstad40da9702024-04-27 01:42:51 +0200227 DisabledFlaggedApiIsPresentError(
Mårten Kongstadc3f05a62024-05-06 21:42:15 +0200228 Symbol.createClass("android/Clazz", "java/lang/Object", setOf()),
229 Flag("android.flag.foo")),
Mårten Kongstad18ff19a2024-04-26 05:48:57 +0200230 DisabledFlaggedApiIsPresentError(
Mårten Kongstada1fe3712024-05-06 13:46:21 +0200231 Symbol.createMethod("android/Clazz", "Clazz()"), Flag("android.flag.foo")),
Mårten Kongstad40da9702024-04-27 01:42:51 +0200232 DisabledFlaggedApiIsPresentError(
Mårten Kongstada1fe3712024-05-06 13:46:21 +0200233 Symbol.createField("android/Clazz", "FOO"), Flag("android.flag.foo")),
234 DisabledFlaggedApiIsPresentError(
235 Symbol.createMethod("android/Clazz", "getErrorCode()"), Flag("android.flag.foo")),
236 DisabledFlaggedApiIsPresentError(
237 Symbol.createMethod("android/Clazz", "setData(I[[ILandroid/util/Utility;)"),
Mårten Kongstadb4a14bf2024-04-28 00:21:11 +0200238 Flag("android.flag.foo")),
239 DisabledFlaggedApiIsPresentError(
Mårten Kongstada1fe3712024-05-06 13:46:21 +0200240 Symbol.createMethod("android/Clazz", "setVariableData(I[Landroid/util/Atom;)"),
Mårten Kongstadb4a14bf2024-04-28 00:21:11 +0200241 Flag("android.flag.foo")),
242 DisabledFlaggedApiIsPresentError(
Mårten Kongstada1fe3712024-05-06 13:46:21 +0200243 Symbol.createMethod("android/Clazz", "innerClassArg(Landroid/Clazz/Builder;)"),
Mårten Kongstadb4a14bf2024-04-28 00:21:11 +0200244 Flag("android.flag.foo")),
245 DisabledFlaggedApiIsPresentError(
Mårten Kongstadc3f05a62024-05-06 21:42:15 +0200246 Symbol.createClass("android/Clazz/Builder", "java/lang/Object", setOf()),
247 Flag("android.flag.bar")),
Mårten Kongstad18ff19a2024-04-26 05:48:57 +0200248 )
Mårten Kongstad9238a3a2024-04-16 13:19:50 +0200249 val actual =
250 findErrors(
251 parseApiSignature("in-memory", API_SIGNATURE.byteInputStream()),
Mårten Kongstad18ff19a2024-04-26 05:48:57 +0200252 parseFlagValues(generateFlagsProto(DISABLED, DISABLED)),
Mårten Kongstad9238a3a2024-04-16 13:19:50 +0200253 parseApiVersions(API_VERSIONS.byteInputStream()))
254 assertEquals(expected, actual)
255 }
Mårten Kongstadf242ec82024-04-16 17:12:26 +0200256}