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