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 //! flag value query module defines the flag value file read from mapped bytes
18 
19 use crate::{AconfigStorageError, FILE_VERSION};
20 use aconfig_storage_file::{flag_value::FlagValueHeader, read_u8_from_bytes};
21 use anyhow::anyhow;
22 
23 /// Query flag value
find_boolean_flag_value(buf: &[u8], flag_index: u32) -> Result<bool, AconfigStorageError>24 pub fn find_boolean_flag_value(buf: &[u8], flag_index: u32) -> Result<bool, AconfigStorageError> {
25     let interpreted_header = FlagValueHeader::from_bytes(buf)?;
26     if interpreted_header.version > crate::FILE_VERSION {
27         return Err(AconfigStorageError::HigherStorageFileVersion(anyhow!(
28             "Cannot read storage file with a higher version of {} with lib version {}",
29             interpreted_header.version,
30             FILE_VERSION
31         )));
32     }
33 
34     // Find byte offset to the flag value, each boolean flag cost one byte to store
35     let mut head = (interpreted_header.boolean_value_offset + flag_index) as usize;
36     if head >= interpreted_header.file_size as usize {
37         return Err(AconfigStorageError::InvalidStorageFileOffset(anyhow!(
38             "Flag value offset goes beyond the end of the file."
39         )));
40     }
41 
42     let val = read_u8_from_bytes(buf, &mut head)?;
43     Ok(val == 1)
44 }
45 
46 #[cfg(test)]
47 mod tests {
48     use super::*;
49     use aconfig_storage_file::test_utils::create_test_flag_value_list;
50 
51     #[test]
52     // this test point locks down flag value query
test_flag_value_query()53     fn test_flag_value_query() {
54         let flag_value_list = create_test_flag_value_list().into_bytes();
55         let baseline: Vec<bool> = vec![false, true, true, false, true, true, true, true];
56         for (offset, expected_value) in baseline.into_iter().enumerate() {
57             let flag_value = find_boolean_flag_value(&flag_value_list[..], offset as u32).unwrap();
58             assert_eq!(flag_value, expected_value);
59         }
60     }
61 
62     #[test]
63     // this test point locks down query beyond the end of boolean section
test_boolean_out_of_range()64     fn test_boolean_out_of_range() {
65         let flag_value_list = create_test_flag_value_list().into_bytes();
66         let error = find_boolean_flag_value(&flag_value_list[..], 8).unwrap_err();
67         assert_eq!(
68             format!("{:?}", error),
69             "InvalidStorageFileOffset(Flag value offset goes beyond the end of the file.)"
70         );
71     }
72 
73     #[test]
74     // this test point locks down query error when file has a higher version
test_higher_version_storage_file()75     fn test_higher_version_storage_file() {
76         let mut value_list = create_test_flag_value_list();
77         value_list.header.version = crate::FILE_VERSION + 1;
78         let flag_value = value_list.into_bytes();
79         let error = find_boolean_flag_value(&flag_value[..], 4).unwrap_err();
80         assert_eq!(
81             format!("{:?}", error),
82             format!(
83                 "HigherStorageFileVersion(Cannot read storage file with a higher version of {} with lib version {})",
84                 crate::FILE_VERSION + 1,
85                 crate::FILE_VERSION
86             )
87         );
88     }
89 }
90