blob: ba38699e4d8b47626248335f36b443610650e2fa [file]
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
mod build_flags;
mod sdk_version;
#[cfg(test)]
mod tests {
use crate::build_flags::{ReleaseConfigs, FLAGS_WE_CARE_ABOUT};
use crate::sdk_version::SdkVersion;
use std::sync::LazyLock;
// the subset of build flags relevant for SDK finalization
static RELEASE_CONFIGS: LazyLock<ReleaseConfigs> = LazyLock::new(ReleaseConfigs::init);
fn sdk_version(release_config: &str) -> SdkVersion {
// use SDK_INT_FULL if set, otherwise fall back to SDK_INT
let s = &RELEASE_CONFIGS.flags[release_config]["RELEASE_PLATFORM_SDK_VERSION_FULL"];
if !s.is_empty() {
s.parse::<SdkVersion>().unwrap_or_else(|_| {
panic!(
"failed to parse RELEASE_PLATFORM_SDK_VERSION_FULL for {release_config} ({s}) as SdkVersion"
)
})
} else {
let s = &RELEASE_CONFIGS.flags[release_config]["RELEASE_PLATFORM_SDK_VERSION"];
s.parse::<SdkVersion>().unwrap_or_else(|_| {
panic!(
"failed to parse RELEASE_PLATFORM_SDK_VERSION for {release_config} ({s}) as SdkVersion"
)
})
}
}
#[test]
fn test_build_flags_in_trunk_and_trunk_staging_are_equal() {
// invariant: the values of the flags (that this test cares about) in RELEASE_CONFIGS.flags are equal
// across trunk and trunk_staging release configs
//
// this means that the rest of the tests can focus on trunk and ignore trunk_staging
for flag in FLAGS_WE_CARE_ABOUT {
assert_eq!(
RELEASE_CONFIGS.flags["trunk"][flag], RELEASE_CONFIGS.flags["trunk_staging"][flag],
"flag {flag} differenct across trunk and trunk_staging",
);
}
}
#[test]
fn test_trunk_is_never_rel() {
// invariant: the codename in trunk is never REL: trunk is always bleeding edge and thus
// always something later than the latest finalized (REL) platform
assert_ne!(RELEASE_CONFIGS.flags["trunk"]["RELEASE_PLATFORM_VERSION_CODENAME"], "REL");
}
#[test]
fn test_version_parity_if_next_is_not_rel() {
// invariant: the version code of trunk and next are identical, unless next is REL: then
// the version in trunk can be one less than the version in next (during the intermediate
// state where next is REL but we haven't created prebuilts/sdk/<new-version> yet), or the
// version in trunk is identical to the one in next
let next = &RELEASE_CONFIGS.aliases["next"];
if RELEASE_CONFIGS.flags[next]["RELEASE_PLATFORM_VERSION_CODENAME"] != "REL" {
// expect the versions to be identical
assert_eq!(
RELEASE_CONFIGS.flags[next]["RELEASE_PLATFORM_SDK_VERSION_FULL"],
RELEASE_CONFIGS.flags["trunk"]["RELEASE_PLATFORM_SDK_VERSION_FULL"]
);
} else {
// make sure the version in trunk is less or equal to that of next
//
// ideally this should check that trunk is at most one version behind next, but we
// can't tell what that means, so let's settle for the weaker guarantee of "less or
// equal"
assert!(sdk_version("trunk") <= sdk_version(next));
}
}
#[test]
fn test_version_and_version_full_parity() {
// invariant: for the release configs that set RELEASE_PLATFORM_SDK_VERSION_FULL:
// - the value can be parsed as a float
// - the value contains a decimal separator
// - the value before the decimal separator is identical to RELEASE_PLATFORM_SDK_VERSION
// (e.g. 36.0 and 36)
for release_config in RELEASE_CONFIGS.flags.keys() {
let version_full =
&RELEASE_CONFIGS.flags[release_config]["RELEASE_PLATFORM_SDK_VERSION_FULL"];
if version_full.is_empty() {
// skip this release config if it doesn't set RELEASE_PLATFORM_SDK_VERSION_FULL
continue;
}
assert!(
version_full.parse::<f32>().is_ok(),
"failed to convert value ({version_full}) of RELEASE_PLATFORM_SDK_VERSION_FULL for {release_config} to f32"
);
let (integer_part, _) = version_full.split_once(".").unwrap_or_else(|| panic!("value of RELEASE_PLATFORM_SDK_VERSION_FULL ({version_full}) for {release_config} doesn't have expected format"));
assert_eq!(
integer_part,
RELEASE_CONFIGS.flags[release_config]["RELEASE_PLATFORM_SDK_VERSION"]
);
}
}
#[test]
fn test_release_hidden_api_exportable_stubs_is_enabled_in_next() {
// invariant: RELEASE_HIDDEN_API_EXPORTABLE_STUBS is set to `true` in `next`, because we'll
// cut an Android release from this release config (the flag is too expensive in terms of
// build performance to enable everywhere)
let next = &RELEASE_CONFIGS.aliases["next"];
let value = &RELEASE_CONFIGS.flags[next]["RELEASE_HIDDEN_API_EXPORTABLE_STUBS"];
assert_eq!(
value, "true",
"expected RELEASE_HIDDEN_API_EXPORTABLE_STUBS to be 'true' in next ({next}) but was '{value}'"
);
}
#[test]
fn test_only_canary_release_config_has_codename_canary() {
// invariant: only the canary release config ("canary", aliased to "zp11") sets codename to
// CANARY; no release config inherits from the canary release config
let canary = &RELEASE_CONFIGS.aliases["canary"];
let value = &RELEASE_CONFIGS.flags[canary]["RELEASE_PLATFORM_VERSION_CODENAME"];
assert_eq!(value, "CANARY");
for release_config in RELEASE_CONFIGS.flags.keys().filter(|key| *key != canary) {
let value = &RELEASE_CONFIGS.flags[release_config]["RELEASE_PLATFORM_VERSION_CODENAME"];
assert_ne!(value, "CANARY");
}
}
#[test]
fn test_prospective_sdk_version() {
// invariants:
// - if the codename is REL, RELEASE_PLATFORM_PROSPECTIVE_SDK_VERSION_FULL should not be set
// - if set, RELEASE_PROSPECTIVE_SDK_VERSION_FULL is greater or equal to the current SDK version
for release_config in RELEASE_CONFIGS.flags.keys() {
let codename =
&RELEASE_CONFIGS.flags[release_config]["RELEASE_PLATFORM_VERSION_CODENAME"];
let prospective_version = &RELEASE_CONFIGS.flags[release_config]
["RELEASE_PLATFORM_PROSPECTIVE_SDK_VERSION_FULL"];
if codename == "REL" {
assert!(prospective_version.is_empty(), "in release config {release_config}, codename is REL, expected RELEASE_PLATFORM_PROSPECTIVE_SDK_VERSION_FULL to be empty, but is {prospective_version}");
} else if !prospective_version.is_empty() {
let prospective_version = prospective_version.parse::<SdkVersion>().unwrap();
let sdk_version = sdk_version(release_config);
assert!(prospective_version > sdk_version, "in release config {release_config}, expected RELEASE_PROSPECTIVE_SDK_VERSION_FULL ({prospective_version}) to not be set, or to be greater than SDK version ({sdk_version})");
}
}
}
#[test]
fn test_preview_sdk_int() {
// invariants: if codename is REL, RELEASE_PLATFORM_PREVIEW_SDK_INT must be 0, else it
// should be non-zero (but old release configs from before we resurrected PREVIEW_SDK_INT,
// may still set it to 0)
for release_config in RELEASE_CONFIGS.flags.keys() {
let codename =
&RELEASE_CONFIGS.flags[release_config]["RELEASE_PLATFORM_VERSION_CODENAME"];
if codename == "REL" {
let preview_sdk_int =
&RELEASE_CONFIGS.flags[release_config]["RELEASE_PLATFORM_PREVIEW_SDK_INT"];
let preview_sdk_int = preview_sdk_int.parse::<u32>().unwrap();
assert_eq!(preview_sdk_int, 0, "in release config {release_config}, expected RELEASE_PLATFORM_PREVIEW_SDK_INT to be 0 but was {preview_sdk_int}");
}
}
}
}