blob: ee5aaf15cb57d34fbdecbbb58d7dcc5c9b4abaf5 [file] [log] [blame]
Yiming Pan823c15d2024-04-01 07:30:27 +00001/*
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 */
16
17package android.platform.coverage
18
19import com.google.common.truth.extensions.proto.ProtoTruth.assertThat
20import com.google.protobuf.TextFormat
21import java.nio.file.Files
22import java.nio.file.Path
23import java.nio.file.StandardOpenOption
24import org.junit.After
25import org.junit.Before
26import org.junit.Test
27import org.junit.runner.RunWith
28import org.junit.runners.JUnit4
29
30@RunWith(JUnit4::class)
31class ExtractFlaggedApisTest {
32
33 companion object {
34 const val COMMAND = "java -jar extract-flagged-apis.jar %s %s"
35 }
36
37 private var apiTextFile: Path = Files.createTempFile("current", ".txt")
38 private var flagToApiMap: Path = Files.createTempFile("flag_api_map", ".textproto")
39
40 @Before
41 fun setup() {
42 apiTextFile = Files.createTempFile("current", ".txt")
43 flagToApiMap = Files.createTempFile("flag_api_map", ".textproto")
44 }
45
46 @After
47 fun cleanup() {
48 Files.deleteIfExists(apiTextFile)
49 Files.deleteIfExists(flagToApiMap)
50 }
51
52 @Test
53 fun extractFlaggedApis_onlyMethodFlag_useMethodFlag() {
54 val apiText =
55 """
56 // Signature format: 2.0
57 package android.net.ipsec.ike {
58 public final class IkeSession implements java.lang.AutoCloseable {
59 method @FlaggedApi("com.android.ipsec.flags.dumpsys_api") public void dump(@NonNull java.io.PrintWriter);
60 }
61 }
62 """
63 .trimIndent()
64 Files.write(apiTextFile, apiText.toByteArray(Charsets.UTF_8), StandardOpenOption.APPEND)
65
66 val process = Runtime.getRuntime().exec(createCommand())
67 process.waitFor()
68
69 val content = Files.readAllBytes(flagToApiMap).toString(Charsets.UTF_8)
70 val result = TextFormat.parse(content, FlagApiMap::class.java)
71
72 val expected = FlagApiMap.newBuilder()
73 val api =
74 JavaMethod.newBuilder()
75 .setPackageName("android.net.ipsec.ike")
76 .setClassName("IkeSession")
77 .setMethodName("dump")
78 api.addParameters("java.io.PrintWriter")
79 addFlaggedApi(expected, api, "com.android.ipsec.flags.dumpsys_api")
80 assertThat(result).isEqualTo(expected.build())
81 }
82
83 @Test
84 fun extractFlaggedApis_onlyClassFlag_useClassFlag() {
85 val apiText =
86 """
87 // Signature format: 2.0
88 package android.net.ipsec.ike {
89 @FlaggedApi("com.android.ipsec.flags.dumpsys_api") public final class IkeSession implements java.lang.AutoCloseable {
90 method public void dump(@NonNull java.io.PrintWriter);
91 }
92 }
93 """
94 .trimIndent()
95 Files.write(apiTextFile, apiText.toByteArray(Charsets.UTF_8), StandardOpenOption.APPEND)
96
97 val process = Runtime.getRuntime().exec(createCommand())
98 process.waitFor()
99
100 val content = Files.readAllBytes(flagToApiMap).toString(Charsets.UTF_8)
101 val result = TextFormat.parse(content, FlagApiMap::class.java)
102
103 val expected = FlagApiMap.newBuilder()
104 val api =
105 JavaMethod.newBuilder()
106 .setPackageName("android.net.ipsec.ike")
107 .setClassName("IkeSession")
108 .setMethodName("dump")
109 api.addParameters("java.io.PrintWriter")
110 addFlaggedApi(expected, api, "com.android.ipsec.flags.dumpsys_api")
111 assertThat(result).isEqualTo(expected.build())
112 }
113
114 @Test
115 fun extractFlaggedApis_flaggedConstructorsAreFlaggedApis() {
116 val apiText =
117 """
118 // Signature format: 2.0
119 package android.app.pinner {
120 @FlaggedApi("android.app.pinner_service_client_api") public class PinnerServiceClient {
121 ctor @FlaggedApi("android.app.pinner_service_client_api") public PinnerServiceClient();
122 }
123 }
124 """
125 .trimIndent()
126 Files.write(apiTextFile, apiText.toByteArray(Charsets.UTF_8), StandardOpenOption.APPEND)
127
128 val process = Runtime.getRuntime().exec(createCommand())
129 process.waitFor()
130
131 val content = Files.readAllBytes(flagToApiMap).toString(Charsets.UTF_8)
132 val result = TextFormat.parse(content, FlagApiMap::class.java)
133
134 val expected = FlagApiMap.newBuilder()
135 val api =
136 JavaMethod.newBuilder()
137 .setPackageName("android.app.pinner")
138 .setClassName("PinnerServiceClient")
139 .setMethodName("PinnerServiceClient")
140 addFlaggedApi(expected, api, "android.app.pinner_service_client_api")
141 assertThat(result).isEqualTo(expected.build())
142 }
143
144 private fun addFlaggedApi(builder: FlagApiMap.Builder, api: JavaMethod.Builder, flag: String) {
145 if (builder.containsFlagToApi(flag)) {
146 val updatedApis =
147 builder.getFlagToApiOrThrow(flag).toBuilder().addJavaMethods(api).build()
148 builder.putFlagToApi(flag, updatedApis)
149 } else {
150 val apis = FlaggedApis.newBuilder().addJavaMethods(api).build()
151 builder.putFlagToApi(flag, apis)
152 }
153 }
154
155 private fun createCommand(): Array<String> {
156 val command =
157 String.format(COMMAND, apiTextFile.toAbsolutePath(), flagToApiMap.toAbsolutePath())
158 return command.split(" ").toTypedArray()
159 }
160}