Merge "check-flagged-apis: create list of @FlaggedApi errors" into main
diff --git a/tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt b/tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt
index 9e6a6e3..d2b75d4 100644
--- a/tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt
+++ b/tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt
@@ -20,6 +20,7 @@
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
+import java.io.InputStream
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
@@ -36,22 +37,6 @@
"""
.trim()
-private val PARSED_FLAGS =
- {
- val parsed_flag =
- Aconfig.parsed_flag
- .newBuilder()
- .setPackage("android.flag")
- .setName("foo")
- .setState(Aconfig.flag_state.ENABLED)
- .setPermission(Aconfig.flag_permission.READ_ONLY)
- .build()
- val parsed_flags = Aconfig.parsed_flags.newBuilder().addParsedFlag(parsed_flag).build()
- val binaryProto = ByteArrayOutputStream()
- parsed_flags.writeTo(binaryProto)
- ByteArrayInputStream(binaryProto.toByteArray())
- }()
-
private val API_VERSIONS =
"""
<?xml version="1.0" encoding="utf-8"?>
@@ -64,6 +49,21 @@
"""
.trim()
+private fun generateFlagsProto(fooState: Aconfig.flag_state): InputStream {
+ val parsed_flag =
+ Aconfig.parsed_flag
+ .newBuilder()
+ .setPackage("android.flag")
+ .setName("foo")
+ .setState(fooState)
+ .setPermission(Aconfig.flag_permission.READ_ONLY)
+ .build()
+ val parsed_flags = Aconfig.parsed_flags.newBuilder().addParsedFlag(parsed_flag).build()
+ val binaryProto = ByteArrayOutputStream()
+ parsed_flags.writeTo(binaryProto)
+ return ByteArrayInputStream(binaryProto.toByteArray())
+}
+
@RunWith(DeviceJUnit4ClassRunner::class)
class CheckFlaggedApisTest : BaseHostJUnit4Test() {
@Test
@@ -76,7 +76,7 @@
@Test
fun testParseFlagValues() {
val expected: Map<Flag, Boolean> = mapOf(Flag("android.flag.foo") to true)
- val actual = parseFlagValues(PARSED_FLAGS)
+ val actual = parseFlagValues(generateFlagsProto(Aconfig.flag_state.ENABLED))
assertEquals(expected, actual)
}
@@ -86,4 +86,28 @@
val actual = parseApiVersions(API_VERSIONS.byteInputStream())
assertEquals(expected, actual)
}
+
+ @Test
+ fun testFindErrorsNoErrors() {
+ val expected = setOf<ApiError>()
+ val actual =
+ findErrors(
+ parseApiSignature("in-memory", API_SIGNATURE.byteInputStream()),
+ parseFlagValues(generateFlagsProto(Aconfig.flag_state.ENABLED)),
+ parseApiVersions(API_VERSIONS.byteInputStream()))
+ assertEquals(expected, actual)
+ }
+
+ @Test
+ fun testFindErrorsDisabledFlaggedApiIsPresent() {
+ val expected =
+ setOf<ApiError>(
+ DisabledFlaggedApiIsPresentError(Symbol("android.Clazz.FOO"), Flag("android.flag.foo")))
+ val actual =
+ findErrors(
+ parseApiSignature("in-memory", API_SIGNATURE.byteInputStream()),
+ parseFlagValues(generateFlagsProto(Aconfig.flag_state.DISABLED)),
+ parseApiVersions(API_VERSIONS.byteInputStream()))
+ assertEquals(expected, actual)
+ }
}
diff --git a/tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt b/tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt
index e7eff17..84564ba 100644
--- a/tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt
+++ b/tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt
@@ -81,6 +81,36 @@
override fun toString(): String = name.toString()
}
+internal sealed class ApiError {
+ abstract val symbol: Symbol
+ abstract val flag: Flag
+}
+
+internal data class EnabledFlaggedApiNotPresentError(
+ override val symbol: Symbol,
+ override val flag: Flag
+) : ApiError() {
+ override fun toString(): String {
+ return "error: enabled @FlaggedApi not present in built artifact: symbol=$symbol flag=$flag"
+ }
+}
+
+internal data class DisabledFlaggedApiIsPresentError(
+ override val symbol: Symbol,
+ override val flag: Flag
+) : ApiError() {
+ override fun toString(): String {
+ return "error: disabled @FlaggedApi is present in built artifact: symbol=$symbol flag=$flag"
+ }
+}
+
+internal data class UnknownFlagError(override val symbol: Symbol, override val flag: Flag) :
+ ApiError() {
+ override fun toString(): String {
+ return "error: unknown flag: symbol=$symbol flag=$flag"
+ }
+}
+
class CheckCommand :
CliktCommand(
help =
@@ -122,16 +152,17 @@
.required()
override fun run() {
- @Suppress("UNUSED_VARIABLE")
val flaggedSymbols =
apiSignaturePath.toFile().inputStream().use {
parseApiSignature(apiSignaturePath.toString(), it)
}
- @Suppress("UNUSED_VARIABLE")
val flags = flagValuesPath.toFile().inputStream().use { parseFlagValues(it) }
- @Suppress("UNUSED_VARIABLE")
val exportedSymbols = apiVersionsPath.toFile().inputStream().use { parseApiVersions(it) }
- throw ProgramResult(0)
+ val errors = findErrors(flaggedSymbols, flags, exportedSymbols)
+ for (e in errors) {
+ println(e)
+ }
+ throw ProgramResult(errors.size)
}
}
@@ -185,4 +216,36 @@
return output
}
+/**
+ * Find errors in the given data.
+ *
+ * @param flaggedSymbolsInSource the set of symbols that are flagged in the source code
+ * @param flags the set of flags and their values
+ * @param symbolsInOutput the set of symbols that are present in the output
+ * @return the set of errors found
+ */
+internal fun findErrors(
+ flaggedSymbolsInSource: Set<Pair<Symbol, Flag>>,
+ flags: Map<Flag, Boolean>,
+ symbolsInOutput: Set<Symbol>
+): Set<ApiError> {
+ val errors = mutableSetOf<ApiError>()
+ for ((symbol, flag) in flaggedSymbolsInSource) {
+ try {
+ if (flags.getValue(flag)) {
+ if (!symbolsInOutput.contains(symbol)) {
+ errors.add(EnabledFlaggedApiNotPresentError(symbol, flag))
+ }
+ } else {
+ if (symbolsInOutput.contains(symbol)) {
+ errors.add(DisabledFlaggedApiIsPresentError(symbol, flag))
+ }
+ }
+ } catch (e: NoSuchElementException) {
+ errors.add(UnknownFlagError(symbol, flag))
+ }
+ }
+ return errors
+}
+
fun main(args: Array<String>) = CheckCommand().main(args)