blob: be32bde92c9b127dad790da3758f3b96481d6538 [file] [log] [blame]
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +02001/*
2 * Copyright (C) 2023 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
Mårten Kongstad403658f2023-06-14 09:51:56 +020017use anyhow::{bail, ensure, Context, Result};
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020018use clap::ValueEnum;
Mårten Kongstada1029092023-05-08 11:51:59 +020019use protobuf::Message;
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020020use std::io::Read;
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +020021use std::path::PathBuf;
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020022
Mårten Kongstad12e593c2023-12-08 11:24:54 +010023use crate::codegen::cpp::generate_cpp_code;
24use crate::codegen::java::generate_java_code;
25use crate::codegen::rust::generate_rust_code;
Mårten Kongstad403658f2023-06-14 09:51:56 +020026use crate::protos::{
Mårten Kongstadf3f20ef2023-12-07 10:05:09 +010027 ParsedFlagExt, ProtoFlagMetadata, ProtoFlagPermission, ProtoFlagState, ProtoParsedFlag,
28 ProtoParsedFlags, ProtoTracepoint,
Mårten Kongstad403658f2023-06-14 09:51:56 +020029};
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020030
31pub struct Input {
Mårten Kongstad403658f2023-06-14 09:51:56 +020032 pub source: String,
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020033 pub reader: Box<dyn Read>,
34}
35
Mårten Kongstad403658f2023-06-14 09:51:56 +020036impl Input {
37 fn try_parse_flags(&mut self) -> Result<ProtoParsedFlags> {
38 let mut buffer = Vec::new();
Mårten Kongstadcd414d4c2023-07-27 14:25:33 +020039 self.reader
40 .read_to_end(&mut buffer)
41 .with_context(|| format!("failed to read {}", self.source))?;
Mårten Kongstad403658f2023-06-14 09:51:56 +020042 crate::protos::parsed_flags::try_from_binary_proto(&buffer)
Mårten Kongstadcd414d4c2023-07-27 14:25:33 +020043 .with_context(|| self.error_context())
44 }
45
46 fn error_context(&self) -> String {
47 format!("failed to parse {}", self.source)
Mårten Kongstad403658f2023-06-14 09:51:56 +020048 }
49}
50
Mårten Kongstadd42eeeb2023-05-12 10:01:00 +020051pub struct OutputFile {
52 pub path: PathBuf, // relative to some root directory only main knows about
53 pub contents: Vec<u8>,
54}
55
Zhi Dou24a0b6a2023-08-10 21:39:59 +000056pub const DEFAULT_FLAG_STATE: ProtoFlagState = ProtoFlagState::DISABLED;
57pub const DEFAULT_FLAG_PERMISSION: ProtoFlagPermission = ProtoFlagPermission::READ_WRITE;
Mårten Kongstad403658f2023-06-14 09:51:56 +020058
Zhi Dou24a0b6a2023-08-10 21:39:59 +000059pub fn parse_flags(
60 package: &str,
Oriol Prieto Gasco7afc7e72023-11-22 13:26:02 +000061 container: Option<&str>,
Zhi Dou24a0b6a2023-08-10 21:39:59 +000062 declarations: Vec<Input>,
63 values: Vec<Input>,
64 default_permission: ProtoFlagPermission,
65) -> Result<Vec<u8>> {
Mårten Kongstad403658f2023-06-14 09:51:56 +020066 let mut parsed_flags = ProtoParsedFlags::new();
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020067
Mårten Kongstadfa23d292023-05-11 14:47:02 +020068 for mut input in declarations {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +020069 let mut contents = String::new();
Mårten Kongstadcd414d4c2023-07-27 14:25:33 +020070 input
71 .reader
72 .read_to_string(&mut contents)
73 .with_context(|| format!("failed to read {}", input.source))?;
Mårten Kongstad403658f2023-06-14 09:51:56 +020074
75 let flag_declarations = crate::protos::flag_declarations::try_from_text_proto(&contents)
Mårten Kongstadcd414d4c2023-07-27 14:25:33 +020076 .with_context(|| input.error_context())?;
Mårten Kongstad30950782023-05-09 13:31:29 +020077 ensure!(
Mårten Kongstad403658f2023-06-14 09:51:56 +020078 package == flag_declarations.package(),
Mårten Kongstadcd414d4c2023-07-27 14:25:33 +020079 "failed to parse {}: expected package {}, got {}",
Mårten Kongstad30950782023-05-09 13:31:29 +020080 input.source,
Mårten Kongstad9fb58962023-05-31 13:02:13 +020081 package,
Mårten Kongstad403658f2023-06-14 09:51:56 +020082 flag_declarations.package()
Mårten Kongstad30950782023-05-09 13:31:29 +020083 );
Oriol Prieto Gasco7afc7e72023-11-22 13:26:02 +000084 if let Some(c) = container {
85 ensure!(
86 c == flag_declarations.container(),
87 "failed to parse {}: expected container {}, got {}",
88 input.source,
89 c,
90 flag_declarations.container()
91 );
92 }
Mårten Kongstad403658f2023-06-14 09:51:56 +020093 for mut flag_declaration in flag_declarations.flag.into_iter() {
94 crate::protos::flag_declaration::verify_fields(&flag_declaration)
Mårten Kongstadcd414d4c2023-07-27 14:25:33 +020095 .with_context(|| input.error_context())?;
Mårten Kongstad403658f2023-06-14 09:51:56 +020096
97 // create ParsedFlag using FlagDeclaration and default values
98 let mut parsed_flag = ProtoParsedFlag::new();
Oriol Prieto Gasco7afc7e72023-11-22 13:26:02 +000099 if let Some(c) = container {
100 parsed_flag.set_container(c.to_string());
101 }
Mårten Kongstad403658f2023-06-14 09:51:56 +0200102 parsed_flag.set_package(package.to_string());
103 parsed_flag.set_name(flag_declaration.take_name());
104 parsed_flag.set_namespace(flag_declaration.take_namespace());
105 parsed_flag.set_description(flag_declaration.take_description());
Mårten Kongstad1b8636b2023-06-22 10:12:24 +0200106 parsed_flag.bug.append(&mut flag_declaration.bug);
Mårten Kongstad403658f2023-06-14 09:51:56 +0200107 parsed_flag.set_state(DEFAULT_FLAG_STATE);
Zhi Dou71f1b352023-08-21 22:49:46 +0000108 let flag_permission = if flag_declaration.is_fixed_read_only() {
109 ProtoFlagPermission::READ_ONLY
110 } else {
111 default_permission
112 };
113 parsed_flag.set_permission(flag_permission);
114 parsed_flag.set_is_fixed_read_only(flag_declaration.is_fixed_read_only());
Oriol Prieto Gasco0b9d2892023-11-20 16:23:51 +0000115 parsed_flag.set_is_exported(flag_declaration.is_exported());
Mårten Kongstad403658f2023-06-14 09:51:56 +0200116 let mut tracepoint = ProtoTracepoint::new();
117 tracepoint.set_source(input.source.clone());
118 tracepoint.set_state(DEFAULT_FLAG_STATE);
Zhi Dou71f1b352023-08-21 22:49:46 +0000119 tracepoint.set_permission(flag_permission);
Mårten Kongstad403658f2023-06-14 09:51:56 +0200120 parsed_flag.trace.push(tracepoint);
121
Micha Schwab1a1a08a2023-11-28 16:14:30 -0500122 let mut metadata = ProtoFlagMetadata::new();
123 let purpose = flag_declaration.metadata.purpose();
124 metadata.set_purpose(purpose);
125 parsed_flag.metadata = Some(metadata).into();
126
Mårten Kongstad403658f2023-06-14 09:51:56 +0200127 // verify ParsedFlag looks reasonable
128 crate::protos::parsed_flag::verify_fields(&parsed_flag)?;
129
130 // verify ParsedFlag can be added
131 ensure!(
132 parsed_flags.parsed_flag.iter().all(|other| other.name() != parsed_flag.name()),
133 "failed to declare flag {} from {}: flag already declared",
134 parsed_flag.name(),
135 input.source
136 );
137
138 // add ParsedFlag to ParsedFlags
139 parsed_flags.parsed_flag.push(parsed_flag);
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200140 }
141 }
142
Mårten Kongstadfa23d292023-05-11 14:47:02 +0200143 for mut input in values {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200144 let mut contents = String::new();
Mårten Kongstadcd414d4c2023-07-27 14:25:33 +0200145 input
146 .reader
147 .read_to_string(&mut contents)
148 .with_context(|| format!("failed to read {}", input.source))?;
Mårten Kongstad403658f2023-06-14 09:51:56 +0200149 let flag_values = crate::protos::flag_values::try_from_text_proto(&contents)
Mårten Kongstadcd414d4c2023-07-27 14:25:33 +0200150 .with_context(|| input.error_context())?;
Mårten Kongstad403658f2023-06-14 09:51:56 +0200151 for flag_value in flag_values.flag_value.into_iter() {
152 crate::protos::flag_value::verify_fields(&flag_value)
Mårten Kongstadcd414d4c2023-07-27 14:25:33 +0200153 .with_context(|| input.error_context())?;
Mårten Kongstad403658f2023-06-14 09:51:56 +0200154
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000155 let Some(parsed_flag) = parsed_flags
156 .parsed_flag
157 .iter_mut()
158 .find(|pf| pf.package() == flag_value.package() && pf.name() == flag_value.name())
159 else {
Mårten Kongstad403658f2023-06-14 09:51:56 +0200160 // (silently) skip unknown flags
161 continue;
162 };
163
Zhi Dou71f1b352023-08-21 22:49:46 +0000164 ensure!(
165 !parsed_flag.is_fixed_read_only()
166 || flag_value.permission() == ProtoFlagPermission::READ_ONLY,
167 "failed to set permission of flag {}, since this flag is fixed read only flag",
168 flag_value.name()
169 );
170
Mårten Kongstad403658f2023-06-14 09:51:56 +0200171 parsed_flag.set_state(flag_value.state());
172 parsed_flag.set_permission(flag_value.permission());
173 let mut tracepoint = ProtoTracepoint::new();
174 tracepoint.set_source(input.source.clone());
175 tracepoint.set_state(flag_value.state());
176 tracepoint.set_permission(flag_value.permission());
177 parsed_flag.trace.push(tracepoint);
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200178 }
179 }
180
Zhi Dou92cf0ec2023-07-19 19:29:22 +0000181 // Create a sorted parsed_flags
182 crate::protos::parsed_flags::sort_parsed_flags(&mut parsed_flags);
Mårten Kongstad403658f2023-06-14 09:51:56 +0200183 crate::protos::parsed_flags::verify_fields(&parsed_flags)?;
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200184 let mut output = Vec::new();
Mårten Kongstad403658f2023-06-14 09:51:56 +0200185 parsed_flags.write_to_vec(&mut output)?;
186 Ok(output)
187}
188
Zhi Dou8ba6aa72023-06-26 21:03:40 +0000189#[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)]
190pub enum CodegenMode {
191 Production,
192 Test,
Ted Bauer4a6af782023-11-29 15:44:24 +0000193 Exported,
Zhi Dou8ba6aa72023-06-26 21:03:40 +0000194}
195
196pub fn create_java_lib(mut input: Input, codegen_mode: CodegenMode) -> Result<Vec<OutputFile>> {
Mårten Kongstad403658f2023-06-14 09:51:56 +0200197 let parsed_flags = input.try_parse_flags()?;
198 let Some(package) = find_unique_package(&parsed_flags) else {
199 bail!("no parsed flags, or the parsed flags use different packages");
200 };
Zhi Dou8ba6aa72023-06-26 21:03:40 +0000201 generate_java_code(package, parsed_flags.parsed_flag.iter(), codegen_mode)
Mårten Kongstad403658f2023-06-14 09:51:56 +0200202}
203
Dennis Shen8d544f72023-06-29 00:45:42 +0000204pub fn create_cpp_lib(mut input: Input, codegen_mode: CodegenMode) -> Result<Vec<OutputFile>> {
Mårten Kongstad403658f2023-06-14 09:51:56 +0200205 let parsed_flags = input.try_parse_flags()?;
206 let Some(package) = find_unique_package(&parsed_flags) else {
207 bail!("no parsed flags, or the parsed flags use different packages");
208 };
Dennis Shen8d544f72023-06-29 00:45:42 +0000209 generate_cpp_code(package, parsed_flags.parsed_flag.iter(), codegen_mode)
Mårten Kongstad403658f2023-06-14 09:51:56 +0200210}
211
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000212pub fn create_rust_lib(mut input: Input, codegen_mode: CodegenMode) -> Result<OutputFile> {
Mårten Kongstad403658f2023-06-14 09:51:56 +0200213 let parsed_flags = input.try_parse_flags()?;
214 let Some(package) = find_unique_package(&parsed_flags) else {
215 bail!("no parsed flags, or the parsed flags use different packages");
216 };
Dennis Shen3cfbcf52023-07-17 14:57:23 +0000217 generate_rust_code(package, parsed_flags.parsed_flag.iter(), codegen_mode)
Mårten Kongstad403658f2023-06-14 09:51:56 +0200218}
219
220pub fn create_device_config_defaults(mut input: Input) -> Result<Vec<u8>> {
221 let parsed_flags = input.try_parse_flags()?;
222 let mut output = Vec::new();
223 for parsed_flag in parsed_flags
224 .parsed_flag
225 .into_iter()
226 .filter(|pf| pf.permission() == ProtoFlagPermission::READ_WRITE)
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200227 {
228 let line = format!(
Mårten Kongstadf3f20ef2023-12-07 10:05:09 +0100229 "{}:{}={}\n",
Mårten Kongstad403658f2023-06-14 09:51:56 +0200230 parsed_flag.namespace(),
Mårten Kongstadf3f20ef2023-12-07 10:05:09 +0100231 parsed_flag.fully_qualified_name(),
Mårten Kongstad403658f2023-06-14 09:51:56 +0200232 match parsed_flag.state() {
233 ProtoFlagState::ENABLED => "enabled",
234 ProtoFlagState::DISABLED => "disabled",
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200235 }
236 );
237 output.extend_from_slice(line.as_bytes());
238 }
239 Ok(output)
240}
241
Mårten Kongstad403658f2023-06-14 09:51:56 +0200242pub fn create_device_config_sysprops(mut input: Input) -> Result<Vec<u8>> {
243 let parsed_flags = input.try_parse_flags()?;
Mårten Kongstadc31a6ff2023-06-02 11:54:36 +0200244 let mut output = Vec::new();
Mårten Kongstad403658f2023-06-14 09:51:56 +0200245 for parsed_flag in parsed_flags
246 .parsed_flag
247 .into_iter()
248 .filter(|pf| pf.permission() == ProtoFlagPermission::READ_WRITE)
Mårten Kongstadc31a6ff2023-06-02 11:54:36 +0200249 {
250 let line = format!(
Mårten Kongstadf3f20ef2023-12-07 10:05:09 +0100251 "persist.device_config.{}={}\n",
252 parsed_flag.fully_qualified_name(),
Mårten Kongstad403658f2023-06-14 09:51:56 +0200253 match parsed_flag.state() {
254 ProtoFlagState::ENABLED => "true",
255 ProtoFlagState::DISABLED => "false",
Mårten Kongstadc31a6ff2023-06-02 11:54:36 +0200256 }
257 );
258 output.extend_from_slice(line.as_bytes());
259 }
260 Ok(output)
261}
262
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200263#[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)]
Mårten Kongstadba94e6a2023-05-16 11:00:16 +0200264pub enum DumpFormat {
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200265 Text,
Mårten Kongstadea498142023-07-20 11:07:35 +0200266 Verbose,
Mårten Kongstada1029092023-05-08 11:51:59 +0200267 Protobuf,
Mårten Kongstad3228b292023-06-26 10:17:42 +0200268 Textproto,
Jihoon Kanga95f2b22023-12-06 00:46:01 +0000269 Bool,
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200270}
271
Micha Schwab1a1a08a2023-11-28 16:14:30 -0500272pub fn dump_parsed_flags(
273 mut input: Vec<Input>,
274 format: DumpFormat,
275 dedup: bool,
276) -> Result<Vec<u8>> {
Mårten Kongstad403658f2023-06-14 09:51:56 +0200277 let individually_parsed_flags: Result<Vec<ProtoParsedFlags>> =
278 input.iter_mut().map(|i| i.try_parse_flags()).collect();
279 let parsed_flags: ProtoParsedFlags =
Colin Cross6befb342023-11-28 15:55:07 -0800280 crate::protos::parsed_flags::merge(individually_parsed_flags?, dedup)?;
Mårten Kongstad403658f2023-06-14 09:51:56 +0200281
Mårten Kongstadaf677032023-05-17 16:18:25 +0200282 let mut output = Vec::new();
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200283 match format {
284 DumpFormat::Text => {
Mårten Kongstad403658f2023-06-14 09:51:56 +0200285 for parsed_flag in parsed_flags.parsed_flag.into_iter() {
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200286 let line = format!(
Mårten Kongstadf3f20ef2023-12-07 10:05:09 +0100287 "{} [{}]: {:?} + {:?}\n",
288 parsed_flag.fully_qualified_name(),
Oriol Prieto Gasco7afc7e72023-11-22 13:26:02 +0000289 parsed_flag.container(),
Mårten Kongstad3fa2f072023-07-20 09:35:05 +0200290 parsed_flag.permission(),
291 parsed_flag.state()
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200292 );
293 output.extend_from_slice(line.as_bytes());
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200294 }
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200295 }
Mårten Kongstadea498142023-07-20 11:07:35 +0200296 DumpFormat::Verbose => {
297 for parsed_flag in parsed_flags.parsed_flag.into_iter() {
298 let sources: Vec<_> =
299 parsed_flag.trace.iter().map(|tracepoint| tracepoint.source()).collect();
300 let line = format!(
Mårten Kongstadf3f20ef2023-12-07 10:05:09 +0100301 "{} [{}]: {:?} + {:?} ({})\n",
302 parsed_flag.fully_qualified_name(),
Oriol Prieto Gasco7afc7e72023-11-22 13:26:02 +0000303 parsed_flag.container(),
Mårten Kongstadea498142023-07-20 11:07:35 +0200304 parsed_flag.permission(),
305 parsed_flag.state(),
306 sources.join(", ")
307 );
308 output.extend_from_slice(line.as_bytes());
309 }
310 }
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200311 DumpFormat::Protobuf => {
Mårten Kongstad403658f2023-06-14 09:51:56 +0200312 parsed_flags.write_to_vec(&mut output)?;
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200313 }
Mårten Kongstad3228b292023-06-26 10:17:42 +0200314 DumpFormat::Textproto => {
315 let s = protobuf::text_format::print_to_string_pretty(&parsed_flags);
316 output.extend_from_slice(s.as_bytes());
317 }
Jihoon Kanga95f2b22023-12-06 00:46:01 +0000318 DumpFormat::Bool => {
319 for parsed_flag in parsed_flags.parsed_flag.into_iter() {
320 let line = format!(
Mårten Kongstadf3f20ef2023-12-07 10:05:09 +0100321 "{}={:?}\n",
322 parsed_flag.fully_qualified_name(),
Jihoon Kanga95f2b22023-12-06 00:46:01 +0000323 parsed_flag.state() == ProtoFlagState::ENABLED
324 );
325 output.extend_from_slice(line.as_bytes());
326 }
327 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200328 }
Mårten Kongstadaf677032023-05-17 16:18:25 +0200329 Ok(output)
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200330}
331
Mårten Kongstad403658f2023-06-14 09:51:56 +0200332fn find_unique_package(parsed_flags: &ProtoParsedFlags) -> Option<&str> {
333 let Some(package) = parsed_flags.parsed_flag.first().map(|pf| pf.package()) else {
334 return None;
335 };
336 if parsed_flags.parsed_flag.iter().any(|pf| pf.package() != package) {
337 return None;
338 }
339 Some(package)
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200340}
341
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200342#[cfg(test)]
343mod tests {
344 use super::*;
Micha Schwab1a1a08a2023-11-28 16:14:30 -0500345 use crate::protos::ProtoFlagPurpose;
Mårten Kongstada1029092023-05-08 11:51:59 +0200346
347 #[test]
Mårten Kongstad403658f2023-06-14 09:51:56 +0200348 fn test_parse_flags() {
349 let parsed_flags = crate::test::parse_test_flags(); // calls parse_flags
350 crate::protos::parsed_flags::verify_fields(&parsed_flags).unwrap();
351
352 let enabled_ro =
353 parsed_flags.parsed_flag.iter().find(|pf| pf.name() == "enabled_ro").unwrap();
354 assert!(crate::protos::parsed_flag::verify_fields(enabled_ro).is_ok());
355 assert_eq!("com.android.aconfig.test", enabled_ro.package());
356 assert_eq!("enabled_ro", enabled_ro.name());
357 assert_eq!("This flag is ENABLED + READ_ONLY", enabled_ro.description());
358 assert_eq!(ProtoFlagState::ENABLED, enabled_ro.state());
359 assert_eq!(ProtoFlagPermission::READ_ONLY, enabled_ro.permission());
Micha Schwab1a1a08a2023-11-28 16:14:30 -0500360 assert_eq!(ProtoFlagPurpose::PURPOSE_BUGFIX, enabled_ro.metadata.purpose());
Mårten Kongstad403658f2023-06-14 09:51:56 +0200361 assert_eq!(3, enabled_ro.trace.len());
Zhi Dou71f1b352023-08-21 22:49:46 +0000362 assert!(!enabled_ro.is_fixed_read_only());
Mårten Kongstad403658f2023-06-14 09:51:56 +0200363 assert_eq!("tests/test.aconfig", enabled_ro.trace[0].source());
364 assert_eq!(ProtoFlagState::DISABLED, enabled_ro.trace[0].state());
365 assert_eq!(ProtoFlagPermission::READ_WRITE, enabled_ro.trace[0].permission());
366 assert_eq!("tests/first.values", enabled_ro.trace[1].source());
367 assert_eq!(ProtoFlagState::DISABLED, enabled_ro.trace[1].state());
368 assert_eq!(ProtoFlagPermission::READ_WRITE, enabled_ro.trace[1].permission());
369 assert_eq!("tests/second.values", enabled_ro.trace[2].source());
370 assert_eq!(ProtoFlagState::ENABLED, enabled_ro.trace[2].state());
371 assert_eq!(ProtoFlagPermission::READ_ONLY, enabled_ro.trace[2].permission());
372
Oriol Prieto Gascobbeda852023-12-11 12:10:36 +0000373 assert_eq!(8, parsed_flags.parsed_flag.len());
Mårten Kongstad403658f2023-06-14 09:51:56 +0200374 for pf in parsed_flags.parsed_flag.iter() {
Zhi Dou71f1b352023-08-21 22:49:46 +0000375 if pf.name() == "enabled_fixed_ro" {
376 continue;
377 }
Mårten Kongstad403658f2023-06-14 09:51:56 +0200378 let first = pf.trace.first().unwrap();
379 assert_eq!(DEFAULT_FLAG_STATE, first.state());
380 assert_eq!(DEFAULT_FLAG_PERMISSION, first.permission());
381
382 let last = pf.trace.last().unwrap();
383 assert_eq!(pf.state(), last.state());
384 assert_eq!(pf.permission(), last.permission());
385 }
Zhi Dou71f1b352023-08-21 22:49:46 +0000386
387 let enabled_fixed_ro =
388 parsed_flags.parsed_flag.iter().find(|pf| pf.name() == "enabled_fixed_ro").unwrap();
389 assert!(enabled_fixed_ro.is_fixed_read_only());
390 assert_eq!(ProtoFlagState::ENABLED, enabled_fixed_ro.state());
391 assert_eq!(ProtoFlagPermission::READ_ONLY, enabled_fixed_ro.permission());
392 assert_eq!(2, enabled_fixed_ro.trace.len());
393 assert_eq!(ProtoFlagPermission::READ_ONLY, enabled_fixed_ro.trace[0].permission());
394 assert_eq!(ProtoFlagPermission::READ_ONLY, enabled_fixed_ro.trace[1].permission());
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200395 }
Mårten Kongstada1029092023-05-08 11:51:59 +0200396
397 #[test]
Zhi Dou24a0b6a2023-08-10 21:39:59 +0000398 fn test_parse_flags_setting_default() {
399 let first_flag = r#"
400 package: "com.first"
401 flag {
402 name: "first"
403 namespace: "first_ns"
404 description: "This is the description of the first flag."
405 bug: "123"
406 }
407 "#;
408 let declaration =
409 vec![Input { source: "momery".to_string(), reader: Box::new(first_flag.as_bytes()) }];
410 let value: Vec<Input> = vec![];
411
412 let flags_bytes = crate::commands::parse_flags(
413 "com.first",
Oriol Prieto Gasco7afc7e72023-11-22 13:26:02 +0000414 None,
Zhi Dou24a0b6a2023-08-10 21:39:59 +0000415 declaration,
416 value,
417 ProtoFlagPermission::READ_ONLY,
418 )
419 .unwrap();
420 let parsed_flags =
421 crate::protos::parsed_flags::try_from_binary_proto(&flags_bytes).unwrap();
422 assert_eq!(1, parsed_flags.parsed_flag.len());
423 let parsed_flag = parsed_flags.parsed_flag.first().unwrap();
424 assert_eq!(ProtoFlagState::DISABLED, parsed_flag.state());
425 assert_eq!(ProtoFlagPermission::READ_ONLY, parsed_flag.permission());
426 }
427
428 #[test]
Oriol Prieto Gasco7afc7e72023-11-22 13:26:02 +0000429 fn test_parse_flags_package_mismatch_between_declaration_and_command_line() {
430 let first_flag = r#"
431 package: "com.declaration.package"
432 container: "first.container"
433 flag {
434 name: "first"
435 namespace: "first_ns"
436 description: "This is the description of the first flag."
437 bug: "123"
438 }
439 "#;
440 let declaration =
441 vec![Input { source: "memory".to_string(), reader: Box::new(first_flag.as_bytes()) }];
442
443 let value: Vec<Input> = vec![];
444
445 let error = crate::commands::parse_flags(
446 "com.argument.package",
447 Some("first.container"),
448 declaration,
449 value,
450 ProtoFlagPermission::READ_WRITE,
451 )
452 .unwrap_err();
453 assert_eq!(
454 format!("{:?}", error),
455 "failed to parse memory: expected package com.argument.package, got com.declaration.package"
456 );
457 }
458
459 #[test]
460 fn test_parse_flags_container_mismatch_between_declaration_and_command_line() {
461 let first_flag = r#"
462 package: "com.first"
463 container: "declaration.container"
464 flag {
465 name: "first"
466 namespace: "first_ns"
467 description: "This is the description of the first flag."
468 bug: "123"
469 }
470 "#;
471 let declaration =
472 vec![Input { source: "memory".to_string(), reader: Box::new(first_flag.as_bytes()) }];
473
474 let value: Vec<Input> = vec![];
475
476 let error = crate::commands::parse_flags(
477 "com.first",
478 Some("argument.container"),
479 declaration,
480 value,
481 ProtoFlagPermission::READ_WRITE,
482 )
483 .unwrap_err();
484 assert_eq!(
485 format!("{:?}", error),
486 "failed to parse memory: expected container argument.container, got declaration.container"
487 );
488 }
489
490 #[test]
Zhi Dou71f1b352023-08-21 22:49:46 +0000491 fn test_parse_flags_override_fixed_read_only() {
492 let first_flag = r#"
493 package: "com.first"
Oriol Prieto Gasco7afc7e72023-11-22 13:26:02 +0000494 container: "com.first.container"
Zhi Dou71f1b352023-08-21 22:49:46 +0000495 flag {
496 name: "first"
497 namespace: "first_ns"
498 description: "This is the description of the first flag."
499 bug: "123"
500 is_fixed_read_only: true
501 }
502 "#;
503 let declaration =
504 vec![Input { source: "memory".to_string(), reader: Box::new(first_flag.as_bytes()) }];
505
506 let first_flag_value = r#"
507 flag_value {
508 package: "com.first"
509 name: "first"
510 state: DISABLED
511 permission: READ_WRITE
512 }
513 "#;
514 let value = vec![Input {
515 source: "memory".to_string(),
516 reader: Box::new(first_flag_value.as_bytes()),
517 }];
518 let error = crate::commands::parse_flags(
519 "com.first",
Oriol Prieto Gasco7afc7e72023-11-22 13:26:02 +0000520 Some("com.first.container"),
Zhi Dou71f1b352023-08-21 22:49:46 +0000521 declaration,
522 value,
523 ProtoFlagPermission::READ_WRITE,
524 )
525 .unwrap_err();
526 assert_eq!(
527 format!("{:?}", error),
528 "failed to set permission of flag first, since this flag is fixed read only flag"
529 );
530 }
531
532 #[test]
Micha Schwab1a1a08a2023-11-28 16:14:30 -0500533 fn test_parse_flags_metadata() {
534 let metadata_flag = r#"
535 package: "com.first"
536 flag {
537 name: "first"
538 namespace: "first_ns"
539 description: "This is the description of this feature flag."
540 bug: "123"
541 metadata {
542 purpose: PURPOSE_FEATURE
543 }
544 }
545 "#;
546 let declaration = vec![Input {
547 source: "memory".to_string(),
548 reader: Box::new(metadata_flag.as_bytes()),
549 }];
550 let value: Vec<Input> = vec![];
551
552 let flags_bytes = crate::commands::parse_flags(
553 "com.first",
554 None,
555 declaration,
556 value,
557 ProtoFlagPermission::READ_ONLY,
558 )
559 .unwrap();
560 let parsed_flags =
561 crate::protos::parsed_flags::try_from_binary_proto(&flags_bytes).unwrap();
562 assert_eq!(1, parsed_flags.parsed_flag.len());
563 let parsed_flag = parsed_flags.parsed_flag.first().unwrap();
564 assert_eq!(ProtoFlagPurpose::PURPOSE_FEATURE, parsed_flag.metadata.purpose());
565 }
566
567 #[test]
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200568 fn test_create_device_config_defaults() {
Mårten Kongstad403658f2023-06-14 09:51:56 +0200569 let input = parse_test_flags_as_input();
570 let bytes = create_device_config_defaults(input).unwrap();
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200571 let text = std::str::from_utf8(&bytes).unwrap();
Ted Bauer4a6af782023-11-29 15:44:24 +0000572 assert_eq!("aconfig_test:com.android.aconfig.test.disabled_rw=disabled\naconfig_test:com.android.aconfig.test.disabled_rw_exported=disabled\nother_namespace:com.android.aconfig.test.disabled_rw_in_other_namespace=disabled\naconfig_test:com.android.aconfig.test.enabled_rw=enabled\n", text);
Mårten Kongstadf02734e2023-06-02 11:34:24 +0200573 }
574
575 #[test]
Mårten Kongstadc31a6ff2023-06-02 11:54:36 +0200576 fn test_create_device_config_sysprops() {
Mårten Kongstad403658f2023-06-14 09:51:56 +0200577 let input = parse_test_flags_as_input();
578 let bytes = create_device_config_sysprops(input).unwrap();
Mårten Kongstadc31a6ff2023-06-02 11:54:36 +0200579 let text = std::str::from_utf8(&bytes).unwrap();
Ted Bauer4a6af782023-11-29 15:44:24 +0000580 assert_eq!("persist.device_config.com.android.aconfig.test.disabled_rw=false\npersist.device_config.com.android.aconfig.test.disabled_rw_exported=false\npersist.device_config.com.android.aconfig.test.disabled_rw_in_other_namespace=false\npersist.device_config.com.android.aconfig.test.enabled_rw=true\n", text);
Mårten Kongstadc31a6ff2023-06-02 11:54:36 +0200581 }
582
583 #[test]
Mårten Kongstada1029092023-05-08 11:51:59 +0200584 fn test_dump_text_format() {
Mårten Kongstad403658f2023-06-14 09:51:56 +0200585 let input = parse_test_flags_as_input();
Colin Cross6befb342023-11-28 15:55:07 -0800586 let bytes = dump_parsed_flags(vec![input], DumpFormat::Text, false).unwrap();
Mårten Kongstada1029092023-05-08 11:51:59 +0200587 let text = std::str::from_utf8(&bytes).unwrap();
Oriol Prieto Gasco7afc7e72023-11-22 13:26:02 +0000588 assert!(
589 text.contains("com.android.aconfig.test.disabled_ro [system]: READ_ONLY + DISABLED")
590 );
Mårten Kongstada1029092023-05-08 11:51:59 +0200591 }
592
Mårten Kongstad1b8636b2023-06-22 10:12:24 +0200593 #[test]
594 fn test_dump_protobuf_format() {
Mårten Kongstad3228b292023-06-26 10:17:42 +0200595 let expected = protobuf::text_format::parse_from_str::<ProtoParsedFlags>(
596 crate::test::TEST_FLAGS_TEXTPROTO,
597 )
598 .unwrap()
599 .write_to_bytes()
600 .unwrap();
Mårten Kongstad1b8636b2023-06-22 10:12:24 +0200601
602 let input = parse_test_flags_as_input();
Colin Cross6befb342023-11-28 15:55:07 -0800603 let actual = dump_parsed_flags(vec![input], DumpFormat::Protobuf, false).unwrap();
Mårten Kongstad1b8636b2023-06-22 10:12:24 +0200604
605 assert_eq!(expected, actual);
606 }
607
Mårten Kongstad3228b292023-06-26 10:17:42 +0200608 #[test]
609 fn test_dump_textproto_format() {
610 let input = parse_test_flags_as_input();
Colin Cross6befb342023-11-28 15:55:07 -0800611 let bytes = dump_parsed_flags(vec![input], DumpFormat::Textproto, false).unwrap();
612 let text = std::str::from_utf8(&bytes).unwrap();
613 assert_eq!(crate::test::TEST_FLAGS_TEXTPROTO.trim(), text.trim());
614 }
615
616 #[test]
617 fn test_dump_textproto_format_dedup() {
618 let input = parse_test_flags_as_input();
619 let input2 = parse_test_flags_as_input();
620 let bytes = dump_parsed_flags(vec![input, input2], DumpFormat::Textproto, true).unwrap();
Mårten Kongstad3228b292023-06-26 10:17:42 +0200621 let text = std::str::from_utf8(&bytes).unwrap();
622 assert_eq!(crate::test::TEST_FLAGS_TEXTPROTO.trim(), text.trim());
623 }
624
Mårten Kongstad403658f2023-06-14 09:51:56 +0200625 fn parse_test_flags_as_input() -> Input {
626 let parsed_flags = crate::test::parse_test_flags();
627 let binary_proto = parsed_flags.write_to_bytes().unwrap();
628 let cursor = std::io::Cursor::new(binary_proto);
629 let reader = Box::new(cursor);
630 Input { source: "test.data".to_string(), reader }
Mårten Kongstadaf677032023-05-17 16:18:25 +0200631 }
Mårten Kongstad4d2b4b02023-04-27 16:05:58 +0200632}