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::flag_info::{FlagInfoHeader, FlagInfoList, FlagInfoNode};
18 use crate::flag_table::{FlagTable, FlagTableHeader, FlagTableNode};
19 use crate::flag_value::{FlagValueHeader, FlagValueList};
20 use crate::package_table::{PackageTable, PackageTableHeader, PackageTableNode};
21 use crate::{AconfigStorageError, StorageFileType, StoredFlagType};
22 
23 use anyhow::anyhow;
24 use std::io::Write;
25 use tempfile::NamedTempFile;
26 
create_test_package_table() -> PackageTable27 pub fn create_test_package_table() -> PackageTable {
28     let header = PackageTableHeader {
29         version: 1,
30         container: String::from("mockup"),
31         file_type: StorageFileType::PackageMap as u8,
32         file_size: 209,
33         num_packages: 3,
34         bucket_offset: 31,
35         node_offset: 59,
36     };
37     let buckets: Vec<Option<u32>> = vec![Some(59), None, None, Some(109), None, None, None];
38     let first_node = PackageTableNode {
39         package_name: String::from("com.android.aconfig.storage.test_2"),
40         package_id: 1,
41         boolean_start_index: 3,
42         next_offset: None,
43     };
44     let second_node = PackageTableNode {
45         package_name: String::from("com.android.aconfig.storage.test_1"),
46         package_id: 0,
47         boolean_start_index: 0,
48         next_offset: Some(159),
49     };
50     let third_node = PackageTableNode {
51         package_name: String::from("com.android.aconfig.storage.test_4"),
52         package_id: 2,
53         boolean_start_index: 6,
54         next_offset: None,
55     };
56     let nodes = vec![first_node, second_node, third_node];
57     PackageTable { header, buckets, nodes }
58 }
59 
60 impl FlagTableNode {
61     // create test baseline, syntactic sugar
new_expected( package_id: u32, flag_name: &str, flag_type: u16, flag_index: u16, next_offset: Option<u32>, ) -> Self62     fn new_expected(
63         package_id: u32,
64         flag_name: &str,
65         flag_type: u16,
66         flag_index: u16,
67         next_offset: Option<u32>,
68     ) -> Self {
69         Self {
70             package_id,
71             flag_name: flag_name.to_string(),
72             flag_type: StoredFlagType::try_from(flag_type).unwrap(),
73             flag_index,
74             next_offset,
75         }
76     }
77 }
78 
create_test_flag_table() -> FlagTable79 pub fn create_test_flag_table() -> FlagTable {
80     let header = FlagTableHeader {
81         version: 1,
82         container: String::from("mockup"),
83         file_type: StorageFileType::FlagMap as u8,
84         file_size: 321,
85         num_flags: 8,
86         bucket_offset: 31,
87         node_offset: 99,
88     };
89     let buckets: Vec<Option<u32>> = vec![
90         Some(99),
91         Some(125),
92         None,
93         None,
94         None,
95         None,
96         Some(177),
97         Some(204),
98         None,
99         Some(262),
100         None,
101         None,
102         None,
103         None,
104         None,
105         Some(294),
106         None,
107     ];
108     let nodes = vec![
109         FlagTableNode::new_expected(0, "enabled_ro", 1, 1, None),
110         FlagTableNode::new_expected(0, "enabled_rw", 0, 2, Some(151)),
111         FlagTableNode::new_expected(2, "enabled_rw", 0, 1, None),
112         FlagTableNode::new_expected(1, "disabled_rw", 0, 0, None),
113         FlagTableNode::new_expected(1, "enabled_fixed_ro", 2, 1, Some(236)),
114         FlagTableNode::new_expected(1, "enabled_ro", 1, 2, None),
115         FlagTableNode::new_expected(2, "enabled_fixed_ro", 2, 0, None),
116         FlagTableNode::new_expected(0, "disabled_rw", 0, 0, None),
117     ];
118     FlagTable { header, buckets, nodes }
119 }
120 
create_test_flag_value_list() -> FlagValueList121 pub fn create_test_flag_value_list() -> FlagValueList {
122     let header = FlagValueHeader {
123         version: 1,
124         container: String::from("mockup"),
125         file_type: StorageFileType::FlagVal as u8,
126         file_size: 35,
127         num_flags: 8,
128         boolean_value_offset: 27,
129     };
130     let booleans: Vec<bool> = vec![false, true, true, false, true, true, true, true];
131     FlagValueList { header, booleans }
132 }
133 
create_test_flag_info_list() -> FlagInfoList134 pub fn create_test_flag_info_list() -> FlagInfoList {
135     let header = FlagInfoHeader {
136         version: 1,
137         container: String::from("mockup"),
138         file_type: StorageFileType::FlagInfo as u8,
139         file_size: 35,
140         num_flags: 8,
141         boolean_flag_offset: 27,
142     };
143     let is_flag_rw = [true, false, true, true, false, false, false, true];
144     let nodes = is_flag_rw.iter().map(|&rw| FlagInfoNode::create(rw)).collect();
145     FlagInfoList { header, nodes }
146 }
147 
write_bytes_to_temp_file(bytes: &[u8]) -> Result<NamedTempFile, AconfigStorageError>148 pub fn write_bytes_to_temp_file(bytes: &[u8]) -> Result<NamedTempFile, AconfigStorageError> {
149     let mut file = NamedTempFile::new().map_err(|_| {
150         AconfigStorageError::FileCreationFail(anyhow!("Failed to create temp file"))
151     })?;
152     let _ = file.write_all(&bytes);
153     Ok(file)
154 }
155