Merge "check-flagged-apis: create list of @FlaggedApi errors" into main
This commit is contained in:
commit
fde34c3b65
2 changed files with 108 additions and 21 deletions
|
@ -20,6 +20,7 @@ import com.android.tradefed.testtype.DeviceJUnit4ClassRunner
|
|||
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 @@ private val API_SIGNATURE =
|
|||
"""
|
||||
.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 @@ private val API_VERSIONS =
|
|||
"""
|
||||
.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 @@ class CheckFlaggedApisTest : BaseHostJUnit4Test() {
|
|||
@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 @@ class CheckFlaggedApisTest : BaseHostJUnit4Test() {
|
|||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,6 +81,36 @@ internal value class Flag(val name: String) {
|
|||
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 @@ The tool will exit with a non-zero exit code if any flagged APIs are found to be
|
|||
.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 @@ internal fun parseApiVersions(input: InputStream): Set<Symbol> {
|
|||
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)
|
||||
|
|
Loading…
Reference in a new issue