1 /*
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
17 use crate::commands::assign_flag_ids;
18 use crate::storage::FlagPackage;
19 use aconfig_protos::ProtoFlagState;
20 use aconfig_storage_file::{FlagValueHeader, FlagValueList, StorageFileType, FILE_VERSION};
21 use anyhow::{anyhow, Result};
22
new_header(container: &str, num_flags: u32) -> FlagValueHeader23 fn new_header(container: &str, num_flags: u32) -> FlagValueHeader {
24 FlagValueHeader {
25 version: FILE_VERSION,
26 container: String::from(container),
27 file_type: StorageFileType::FlagVal as u8,
28 file_size: 0,
29 num_flags,
30 boolean_value_offset: 0,
31 }
32 }
33
create_flag_value(container: &str, packages: &[FlagPackage]) -> Result<FlagValueList>34 pub fn create_flag_value(container: &str, packages: &[FlagPackage]) -> Result<FlagValueList> {
35 // create list
36 let num_flags = packages.iter().map(|pkg| pkg.boolean_flags.len() as u32).sum();
37
38 let mut list = FlagValueList {
39 header: new_header(container, num_flags),
40 booleans: vec![false; num_flags as usize],
41 };
42
43 for pkg in packages.iter() {
44 let start_index = pkg.boolean_start_index as usize;
45 let flag_ids = assign_flag_ids(pkg.package_name, pkg.boolean_flags.iter().copied())?;
46 for pf in pkg.boolean_flags.iter() {
47 let fid = flag_ids
48 .get(pf.name())
49 .ok_or(anyhow!(format!("missing flag id for {}", pf.name())))?;
50
51 list.booleans[start_index + (*fid as usize)] = pf.state() == ProtoFlagState::ENABLED;
52 }
53 }
54
55 // initialize all header fields
56 list.header.boolean_value_offset = list.header.into_bytes().len() as u32;
57 list.header.file_size = list.header.boolean_value_offset + num_flags;
58
59 Ok(list)
60 }
61
62 #[cfg(test)]
63 mod tests {
64 use super::*;
65 use crate::storage::{group_flags_by_package, tests::parse_all_test_flags};
66
create_test_flag_value_list_from_source() -> Result<FlagValueList>67 pub fn create_test_flag_value_list_from_source() -> Result<FlagValueList> {
68 let caches = parse_all_test_flags();
69 let packages = group_flags_by_package(caches.iter());
70 create_flag_value("mockup", &packages)
71 }
72
73 #[test]
74 // this test point locks down the flag value creation and each field
test_list_contents()75 fn test_list_contents() {
76 let flag_value_list = create_test_flag_value_list_from_source();
77 assert!(flag_value_list.is_ok());
78 let expected_flag_value_list =
79 aconfig_storage_file::test_utils::create_test_flag_value_list();
80 assert_eq!(flag_value_list.unwrap(), expected_flag_value_list);
81 }
82 }
83