blob: d3b5b378b2307255bf1e258db54b3bebb761ff1f [file] [log] [blame]
Mårten Kongstadfe753f52023-04-26 09:13:03 +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
17// When building with the Android tool-chain
18//
19// - an external crate `aconfig_protos` will be generated
20// - the feature "cargo" will be disabled
21//
22// When building with cargo
23//
24// - a local sub-module will be generated in OUT_DIR and included in this file
25// - the feature "cargo" will be enabled
26//
27// This module hides these differences from the rest of aconfig.
28
Mårten Kongstadbb520722023-04-26 13:16:41 +020029// ---- When building with the Android tool-chain ----
Mårten Kongstadfe753f52023-04-26 09:13:03 +020030#[cfg(not(feature = "cargo"))]
Mårten Kongstadf9422522023-06-14 08:38:46 +020031mod auto_generated {
32 pub use aconfig_protos::aconfig::Flag_declaration as ProtoFlagDeclaration;
33 pub use aconfig_protos::aconfig::Flag_declarations as ProtoFlagDeclarations;
34 pub use aconfig_protos::aconfig::Flag_permission as ProtoFlagPermission;
35 pub use aconfig_protos::aconfig::Flag_state as ProtoFlagState;
36 pub use aconfig_protos::aconfig::Flag_value as ProtoFlagValue;
37 pub use aconfig_protos::aconfig::Flag_values as ProtoFlagValues;
38 pub use aconfig_protos::aconfig::Parsed_flag as ProtoParsedFlag;
39 pub use aconfig_protos::aconfig::Parsed_flags as ProtoParsedFlags;
40 pub use aconfig_protos::aconfig::Tracepoint as ProtoTracepoint;
41}
Mårten Kongstada1029092023-05-08 11:51:59 +020042
Mårten Kongstadbb520722023-04-26 13:16:41 +020043// ---- When building with cargo ----
Mårten Kongstadfe753f52023-04-26 09:13:03 +020044#[cfg(feature = "cargo")]
Mårten Kongstadf9422522023-06-14 08:38:46 +020045mod auto_generated {
46 // include! statements should be avoided (because they import file contents verbatim), but
47 // because this is only used during local development, and only if using cargo instead of the
48 // Android tool-chain, we allow it
49 include!(concat!(env!("OUT_DIR"), "/aconfig_proto/mod.rs"));
50 pub use aconfig::Flag_declaration as ProtoFlagDeclaration;
51 pub use aconfig::Flag_declarations as ProtoFlagDeclarations;
52 pub use aconfig::Flag_permission as ProtoFlagPermission;
53 pub use aconfig::Flag_state as ProtoFlagState;
54 pub use aconfig::Flag_value as ProtoFlagValue;
55 pub use aconfig::Flag_values as ProtoFlagValues;
56 pub use aconfig::Parsed_flag as ProtoParsedFlag;
57 pub use aconfig::Parsed_flags as ProtoParsedFlags;
58 pub use aconfig::Tracepoint as ProtoTracepoint;
59}
Mårten Kongstada1029092023-05-08 11:51:59 +020060
Mårten Kongstadbb520722023-04-26 13:16:41 +020061// ---- Common for both the Android tool-chain and cargo ----
Mårten Kongstadf9422522023-06-14 08:38:46 +020062pub use auto_generated::*;
63
Mårten Kongstadbb520722023-04-26 13:16:41 +020064use anyhow::Result;
Mårten Kongstad1b8636b2023-06-22 10:12:24 +020065use paste::paste;
Mårten Kongstadbb520722023-04-26 13:16:41 +020066
Mårten Kongstad403658f2023-06-14 09:51:56 +020067fn try_from_text_proto<T>(s: &str) -> Result<T>
Mårten Kongstadbb520722023-04-26 13:16:41 +020068where
69 T: protobuf::MessageFull,
70{
Mårten Kongstadbb520722023-04-26 13:16:41 +020071 protobuf::text_format::parse_from_str(s).map_err(|e| e.into())
72}
Mårten Kongstad403658f2023-06-14 09:51:56 +020073
Mårten Kongstad1b8636b2023-06-22 10:12:24 +020074macro_rules! ensure_required_fields {
75 ($type:expr, $struct:expr, $($field:expr),+) => {
76 $(
77 paste! {
78 ensure!($struct.[<has_ $field>](), "bad {}: missing {}", $type, $field);
79 }
80 )+
81 };
82}
83
Mårten Kongstad403658f2023-06-14 09:51:56 +020084pub mod flag_declaration {
85 use super::*;
86 use crate::codegen;
87 use anyhow::ensure;
88
89 pub fn verify_fields(pdf: &ProtoFlagDeclaration) -> Result<()> {
Mårten Kongstad1b8636b2023-06-22 10:12:24 +020090 ensure_required_fields!("flag declaration", pdf, "name", "namespace", "description");
Mårten Kongstada2e5ab82023-06-19 16:28:54 +020091
Mårten Kongstad403658f2023-06-14 09:51:56 +020092 ensure!(codegen::is_valid_name_ident(pdf.name()), "bad flag declaration: bad name");
93 ensure!(codegen::is_valid_name_ident(pdf.namespace()), "bad flag declaration: bad name");
94 ensure!(!pdf.description().is_empty(), "bad flag declaration: empty description");
Mårten Kongstad6353c6c2023-07-26 13:18:50 +020095 ensure!(pdf.bug.len() == 1, "bad flag declaration: exactly one bug required");
Mårten Kongstad1b8636b2023-06-22 10:12:24 +020096
Mårten Kongstad403658f2023-06-14 09:51:56 +020097 Ok(())
98 }
99}
100
101pub mod flag_declarations {
102 use super::*;
103 use crate::codegen;
104 use anyhow::ensure;
105
106 pub fn try_from_text_proto(s: &str) -> Result<ProtoFlagDeclarations> {
107 let pdf: ProtoFlagDeclarations = super::try_from_text_proto(s)?;
108 verify_fields(&pdf)?;
109 Ok(pdf)
110 }
111
112 pub fn verify_fields(pdf: &ProtoFlagDeclarations) -> Result<()> {
Mårten Kongstad1b8636b2023-06-22 10:12:24 +0200113 ensure_required_fields!("flag declarations", pdf, "package");
Mårten Kongstada2e5ab82023-06-19 16:28:54 +0200114
Mårten Kongstad403658f2023-06-14 09:51:56 +0200115 ensure!(
116 codegen::is_valid_package_ident(pdf.package()),
117 "bad flag declarations: bad package"
118 );
119 for flag_declaration in pdf.flag.iter() {
120 super::flag_declaration::verify_fields(flag_declaration)?;
121 }
Mårten Kongstada2e5ab82023-06-19 16:28:54 +0200122
Mårten Kongstad403658f2023-06-14 09:51:56 +0200123 Ok(())
124 }
125}
126
127pub mod flag_value {
128 use super::*;
129 use crate::codegen;
130 use anyhow::ensure;
131
132 pub fn verify_fields(fv: &ProtoFlagValue) -> Result<()> {
Mårten Kongstad1b8636b2023-06-22 10:12:24 +0200133 ensure_required_fields!("flag value", fv, "package", "name", "state", "permission");
Mårten Kongstada2e5ab82023-06-19 16:28:54 +0200134
Mårten Kongstad403658f2023-06-14 09:51:56 +0200135 ensure!(codegen::is_valid_package_ident(fv.package()), "bad flag value: bad package");
136 ensure!(codegen::is_valid_name_ident(fv.name()), "bad flag value: bad name");
Mårten Kongstada2e5ab82023-06-19 16:28:54 +0200137
Mårten Kongstad403658f2023-06-14 09:51:56 +0200138 Ok(())
139 }
140}
141
142pub mod flag_values {
143 use super::*;
144
145 pub fn try_from_text_proto(s: &str) -> Result<ProtoFlagValues> {
146 let pfv: ProtoFlagValues = super::try_from_text_proto(s)?;
147 verify_fields(&pfv)?;
148 Ok(pfv)
149 }
150
151 pub fn verify_fields(pfv: &ProtoFlagValues) -> Result<()> {
152 for flag_value in pfv.flag_value.iter() {
153 super::flag_value::verify_fields(flag_value)?;
154 }
155 Ok(())
156 }
157}
158
Zhi Dou24a0b6a2023-08-10 21:39:59 +0000159pub mod flag_permission {
160 use super::*;
161 use anyhow::bail;
162
163 pub fn parse_from_str(permission: &str) -> Result<ProtoFlagPermission> {
164 match permission.to_ascii_lowercase().as_str() {
165 "read_write" => Ok(ProtoFlagPermission::READ_WRITE),
166 "read_only" => Ok(ProtoFlagPermission::READ_ONLY),
167 _ => bail!("Permission needs to be read_only or read_write."),
168 }
169 }
170
171 pub fn to_string(permission: &ProtoFlagPermission) -> &str {
172 match permission {
173 ProtoFlagPermission::READ_WRITE => "read_write",
174 ProtoFlagPermission::READ_ONLY => "read_only",
175 }
176 }
177}
178
Mårten Kongstad403658f2023-06-14 09:51:56 +0200179pub mod tracepoint {
180 use super::*;
181 use anyhow::ensure;
182
183 pub fn verify_fields(tp: &ProtoTracepoint) -> Result<()> {
Mårten Kongstad1b8636b2023-06-22 10:12:24 +0200184 ensure_required_fields!("tracepoint", tp, "source", "state", "permission");
Mårten Kongstada2e5ab82023-06-19 16:28:54 +0200185
Mårten Kongstad403658f2023-06-14 09:51:56 +0200186 ensure!(!tp.source().is_empty(), "bad tracepoint: empty source");
Mårten Kongstada2e5ab82023-06-19 16:28:54 +0200187
Mårten Kongstad403658f2023-06-14 09:51:56 +0200188 Ok(())
189 }
190}
191
192pub mod parsed_flag {
193 use super::*;
194 use crate::codegen;
195 use anyhow::ensure;
196
197 pub fn verify_fields(pf: &ProtoParsedFlag) -> Result<()> {
Mårten Kongstad1b8636b2023-06-22 10:12:24 +0200198 ensure_required_fields!(
199 "parsed flag",
200 pf,
201 "package",
202 "name",
203 "namespace",
204 "description",
205 "state",
206 "permission"
207 );
Mårten Kongstada2e5ab82023-06-19 16:28:54 +0200208
Mårten Kongstad403658f2023-06-14 09:51:56 +0200209 ensure!(codegen::is_valid_package_ident(pf.package()), "bad parsed flag: bad package");
210 ensure!(codegen::is_valid_name_ident(pf.name()), "bad parsed flag: bad name");
211 ensure!(codegen::is_valid_name_ident(pf.namespace()), "bad parsed flag: bad namespace");
212 ensure!(!pf.description().is_empty(), "bad parsed flag: empty description");
213 ensure!(!pf.trace.is_empty(), "bad parsed flag: empty trace");
214 for tp in pf.trace.iter() {
215 super::tracepoint::verify_fields(tp)?;
216 }
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200217 ensure!(pf.bug.len() == 1, "bad flag declaration: exactly one bug required");
Mårten Kongstad21717e72023-09-04 13:28:36 +0200218 if pf.is_fixed_read_only() {
219 ensure!(
220 pf.permission() == ProtoFlagPermission::READ_ONLY,
221 "bad parsed flag: flag is is_fixed_read_only but permission is not READ_ONLY"
222 );
223 for tp in pf.trace.iter() {
224 ensure!(tp.permission() == ProtoFlagPermission::READ_ONLY,
225 "bad parsed flag: flag is is_fixed_read_only but a tracepoint's permission is not READ_ONLY"
226 );
227 }
228 }
Mårten Kongstad1b8636b2023-06-22 10:12:24 +0200229
Mårten Kongstad403658f2023-06-14 09:51:56 +0200230 Ok(())
231 }
Mårten Kongstad206a3822023-07-07 08:52:52 +0200232
233 pub fn path_to_declaration(pf: &ProtoParsedFlag) -> &str {
234 debug_assert!(!pf.trace.is_empty());
235 pf.trace[0].source()
236 }
Mårten Kongstad403658f2023-06-14 09:51:56 +0200237}
238
239pub mod parsed_flags {
240 use super::*;
241 use anyhow::bail;
242 use std::cmp::Ordering;
243
244 pub fn try_from_binary_proto(bytes: &[u8]) -> Result<ProtoParsedFlags> {
245 let message: ProtoParsedFlags = protobuf::Message::parse_from_bytes(bytes)?;
246 verify_fields(&message)?;
247 Ok(message)
248 }
249
250 pub fn verify_fields(pf: &ProtoParsedFlags) -> Result<()> {
Mårten Kongstad206a3822023-07-07 08:52:52 +0200251 use crate::protos::parsed_flag::path_to_declaration;
252
Mårten Kongstad403658f2023-06-14 09:51:56 +0200253 let mut previous: Option<&ProtoParsedFlag> = None;
254 for parsed_flag in pf.parsed_flag.iter() {
255 if let Some(prev) = previous {
256 let a = create_sorting_key(prev);
257 let b = create_sorting_key(parsed_flag);
258 match a.cmp(&b) {
259 Ordering::Less => {}
Mårten Kongstad206a3822023-07-07 08:52:52 +0200260 Ordering::Equal => bail!(
261 "bad parsed flags: duplicate flag {} (defined in {} and {})",
262 a,
263 path_to_declaration(prev),
264 path_to_declaration(parsed_flag)
265 ),
Mårten Kongstad403658f2023-06-14 09:51:56 +0200266 Ordering::Greater => {
267 bail!("bad parsed flags: not sorted: {} comes before {}", a, b)
268 }
269 }
270 }
271 super::parsed_flag::verify_fields(parsed_flag)?;
272 previous = Some(parsed_flag);
273 }
274 Ok(())
275 }
276
277 pub fn merge(parsed_flags: Vec<ProtoParsedFlags>) -> Result<ProtoParsedFlags> {
278 let mut merged = ProtoParsedFlags::new();
279 for mut pfs in parsed_flags.into_iter() {
280 merged.parsed_flag.append(&mut pfs.parsed_flag);
281 }
282 merged.parsed_flag.sort_by_cached_key(create_sorting_key);
283 verify_fields(&merged)?;
284 Ok(merged)
285 }
286
Zhi Dou92cf0ec2023-07-19 19:29:22 +0000287 pub fn sort_parsed_flags(pf: &mut ProtoParsedFlags) {
288 pf.parsed_flag.sort_by_key(create_sorting_key);
289 }
290
Mårten Kongstad403658f2023-06-14 09:51:56 +0200291 fn create_sorting_key(pf: &ProtoParsedFlag) -> String {
292 format!("{}.{}", pf.package(), pf.name())
293 }
294}
295
296#[cfg(test)]
297mod tests {
298 use super::*;
299
300 #[test]
301 fn test_flag_declarations_try_from_text_proto() {
302 // valid input
303 let flag_declarations = flag_declarations::try_from_text_proto(
304 r#"
305package: "com.foo.bar"
306flag {
307 name: "first"
308 namespace: "first_ns"
309 description: "This is the description of the first flag."
Mårten Kongstad1b8636b2023-06-22 10:12:24 +0200310 bug: "123"
Mårten Kongstad403658f2023-06-14 09:51:56 +0200311}
312flag {
313 name: "second"
314 namespace: "second_ns"
315 description: "This is the description of the second flag."
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200316 bug: "abc"
Zhi Dou71f1b352023-08-21 22:49:46 +0000317 is_fixed_read_only: true
Mårten Kongstad403658f2023-06-14 09:51:56 +0200318}
319"#,
320 )
321 .unwrap();
322 assert_eq!(flag_declarations.package(), "com.foo.bar");
323 let first = flag_declarations.flag.iter().find(|pf| pf.name() == "first").unwrap();
324 assert_eq!(first.name(), "first");
325 assert_eq!(first.namespace(), "first_ns");
326 assert_eq!(first.description(), "This is the description of the first flag.");
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200327 assert_eq!(first.bug, vec!["123"]);
Zhi Dou71f1b352023-08-21 22:49:46 +0000328 assert!(!first.is_fixed_read_only());
Mårten Kongstad403658f2023-06-14 09:51:56 +0200329 let second = flag_declarations.flag.iter().find(|pf| pf.name() == "second").unwrap();
330 assert_eq!(second.name(), "second");
331 assert_eq!(second.namespace(), "second_ns");
332 assert_eq!(second.description(), "This is the description of the second flag.");
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200333 assert_eq!(second.bug, vec!["abc"]);
Zhi Dou71f1b352023-08-21 22:49:46 +0000334 assert!(second.is_fixed_read_only());
Mårten Kongstad403658f2023-06-14 09:51:56 +0200335
336 // bad input: missing package in flag declarations
337 let error = flag_declarations::try_from_text_proto(
338 r#"
339flag {
340 name: "first"
341 namespace: "first_ns"
342 description: "This is the description of the first flag."
343}
344flag {
345 name: "second"
346 namespace: "second_ns"
347 description: "This is the description of the second flag."
348}
349"#,
350 )
351 .unwrap_err();
Mårten Kongstada2e5ab82023-06-19 16:28:54 +0200352 assert_eq!(format!("{:?}", error), "bad flag declarations: missing package");
Mårten Kongstad403658f2023-06-14 09:51:56 +0200353
354 // bad input: missing namespace in flag declaration
355 let error = flag_declarations::try_from_text_proto(
356 r#"
357package: "com.foo.bar"
358flag {
359 name: "first"
360 description: "This is the description of the first flag."
361}
362flag {
363 name: "second"
364 namespace: "second_ns"
365 description: "This is the description of the second flag."
366}
367"#,
368 )
369 .unwrap_err();
Mårten Kongstada2e5ab82023-06-19 16:28:54 +0200370 assert_eq!(format!("{:?}", error), "bad flag declaration: missing namespace");
Mårten Kongstad403658f2023-06-14 09:51:56 +0200371
372 // bad input: bad package name in flag declarations
373 let error = flag_declarations::try_from_text_proto(
374 r#"
375package: "_com.FOO__BAR"
376flag {
377 name: "first"
378 namespace: "first_ns"
379 description: "This is the description of the first flag."
380}
381flag {
382 name: "second"
383 namespace: "second_ns"
384 description: "This is the description of the second flag."
385}
386"#,
387 )
388 .unwrap_err();
389 assert!(format!("{:?}", error).contains("bad flag declarations: bad package"));
390
391 // bad input: bad name in flag declaration
392 let error = flag_declarations::try_from_text_proto(
393 r#"
394package: "com.foo.bar"
395flag {
396 name: "FIRST"
397 namespace: "first_ns"
398 description: "This is the description of the first flag."
399}
400flag {
401 name: "second"
402 namespace: "second_ns"
403 description: "This is the description of the second flag."
404}
405"#,
406 )
407 .unwrap_err();
408 assert!(format!("{:?}", error).contains("bad flag declaration: bad name"));
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200409
410 // bad input: no bug entries in flag declaration
411 let error = flag_declarations::try_from_text_proto(
412 r#"
413package: "com.foo.bar"
414flag {
415 name: "first"
416 namespace: "first_ns"
417 description: "This is the description of the first flag."
418}
419"#,
420 )
421 .unwrap_err();
422 assert!(format!("{:?}", error).contains("bad flag declaration: exactly one bug required"));
423
424 // bad input: multiple bug entries in flag declaration
425 let error = flag_declarations::try_from_text_proto(
426 r#"
427package: "com.foo.bar"
428flag {
429 name: "first"
430 namespace: "first_ns"
431 description: "This is the description of the first flag."
432 bug: "123"
433 bug: "abc"
434}
435"#,
436 )
437 .unwrap_err();
438 assert!(format!("{:?}", error).contains("bad flag declaration: exactly one bug required"));
Mårten Kongstad403658f2023-06-14 09:51:56 +0200439 }
440
441 #[test]
442 fn test_flag_values_try_from_text_proto() {
443 // valid input
444 let flag_values = flag_values::try_from_text_proto(
445 r#"
446flag_value {
447 package: "com.first"
448 name: "first"
449 state: DISABLED
450 permission: READ_ONLY
451}
452flag_value {
453 package: "com.second"
454 name: "second"
455 state: ENABLED
456 permission: READ_WRITE
457}
458"#,
459 )
460 .unwrap();
461 let first = flag_values.flag_value.iter().find(|fv| fv.name() == "first").unwrap();
462 assert_eq!(first.package(), "com.first");
463 assert_eq!(first.name(), "first");
464 assert_eq!(first.state(), ProtoFlagState::DISABLED);
465 assert_eq!(first.permission(), ProtoFlagPermission::READ_ONLY);
466 let second = flag_values.flag_value.iter().find(|fv| fv.name() == "second").unwrap();
467 assert_eq!(second.package(), "com.second");
468 assert_eq!(second.name(), "second");
469 assert_eq!(second.state(), ProtoFlagState::ENABLED);
470 assert_eq!(second.permission(), ProtoFlagPermission::READ_WRITE);
471
472 // bad input: bad package in flag value
473 let error = flag_values::try_from_text_proto(
474 r#"
475flag_value {
476 package: "COM.FIRST"
477 name: "first"
478 state: DISABLED
479 permission: READ_ONLY
480}
481"#,
482 )
483 .unwrap_err();
484 assert!(format!("{:?}", error).contains("bad flag value: bad package"));
485
486 // bad input: bad name in flag value
487 let error = flag_values::try_from_text_proto(
488 r#"
489flag_value {
490 package: "com.first"
491 name: "FIRST"
492 state: DISABLED
493 permission: READ_ONLY
494}
495"#,
496 )
497 .unwrap_err();
498 assert!(format!("{:?}", error).contains("bad flag value: bad name"));
499
500 // bad input: missing state in flag value
501 let error = flag_values::try_from_text_proto(
502 r#"
503flag_value {
504 package: "com.first"
505 name: "first"
506 permission: READ_ONLY
507}
508"#,
509 )
510 .unwrap_err();
Mårten Kongstada2e5ab82023-06-19 16:28:54 +0200511 assert_eq!(format!("{:?}", error), "bad flag value: missing state");
Mårten Kongstad403658f2023-06-14 09:51:56 +0200512
513 // bad input: missing permission in flag value
514 let error = flag_values::try_from_text_proto(
515 r#"
516flag_value {
517 package: "com.first"
518 name: "first"
519 state: DISABLED
520}
521"#,
522 )
523 .unwrap_err();
Mårten Kongstada2e5ab82023-06-19 16:28:54 +0200524 assert_eq!(format!("{:?}", error), "bad flag value: missing permission");
Mårten Kongstad403658f2023-06-14 09:51:56 +0200525 }
526
527 fn try_from_binary_proto_from_text_proto(text_proto: &str) -> Result<ProtoParsedFlags> {
528 use protobuf::Message;
529
530 let parsed_flags: ProtoParsedFlags = try_from_text_proto(text_proto)?;
531 let mut binary_proto = Vec::new();
532 parsed_flags.write_to_vec(&mut binary_proto)?;
533 parsed_flags::try_from_binary_proto(&binary_proto)
534 }
535
536 #[test]
537 fn test_parsed_flags_try_from_text_proto() {
538 // valid input
539 let text_proto = r#"
540parsed_flag {
541 package: "com.first"
542 name: "first"
543 namespace: "first_ns"
544 description: "This is the description of the first flag."
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200545 bug: "SOME_BUG"
Mårten Kongstad403658f2023-06-14 09:51:56 +0200546 state: DISABLED
547 permission: READ_ONLY
548 trace {
549 source: "flags.declarations"
550 state: DISABLED
551 permission: READ_ONLY
552 }
553}
554parsed_flag {
555 package: "com.second"
556 name: "second"
557 namespace: "second_ns"
558 description: "This is the description of the second flag."
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200559 bug: "SOME_BUG"
Mårten Kongstad403658f2023-06-14 09:51:56 +0200560 state: ENABLED
Mårten Kongstad21717e72023-09-04 13:28:36 +0200561 permission: READ_ONLY
Mårten Kongstad403658f2023-06-14 09:51:56 +0200562 trace {
563 source: "flags.declarations"
564 state: DISABLED
565 permission: READ_ONLY
566 }
567 trace {
568 source: "flags.values"
569 state: ENABLED
Mårten Kongstad21717e72023-09-04 13:28:36 +0200570 permission: READ_ONLY
Mårten Kongstad403658f2023-06-14 09:51:56 +0200571 }
Zhi Dou71f1b352023-08-21 22:49:46 +0000572 is_fixed_read_only: true
Mårten Kongstad403658f2023-06-14 09:51:56 +0200573}
574"#;
575 let parsed_flags = try_from_binary_proto_from_text_proto(text_proto).unwrap();
576 assert_eq!(parsed_flags.parsed_flag.len(), 2);
577 let second = parsed_flags.parsed_flag.iter().find(|fv| fv.name() == "second").unwrap();
578 assert_eq!(second.package(), "com.second");
579 assert_eq!(second.name(), "second");
580 assert_eq!(second.namespace(), "second_ns");
581 assert_eq!(second.description(), "This is the description of the second flag.");
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200582 assert_eq!(second.bug, vec!["SOME_BUG"]);
Mårten Kongstad403658f2023-06-14 09:51:56 +0200583 assert_eq!(second.state(), ProtoFlagState::ENABLED);
Mårten Kongstad21717e72023-09-04 13:28:36 +0200584 assert_eq!(second.permission(), ProtoFlagPermission::READ_ONLY);
Mårten Kongstad403658f2023-06-14 09:51:56 +0200585 assert_eq!(2, second.trace.len());
586 assert_eq!(second.trace[0].source(), "flags.declarations");
587 assert_eq!(second.trace[0].state(), ProtoFlagState::DISABLED);
588 assert_eq!(second.trace[0].permission(), ProtoFlagPermission::READ_ONLY);
589 assert_eq!(second.trace[1].source(), "flags.values");
590 assert_eq!(second.trace[1].state(), ProtoFlagState::ENABLED);
Mårten Kongstad21717e72023-09-04 13:28:36 +0200591 assert_eq!(second.trace[1].permission(), ProtoFlagPermission::READ_ONLY);
Zhi Dou71f1b352023-08-21 22:49:46 +0000592 assert!(second.is_fixed_read_only());
Mårten Kongstad403658f2023-06-14 09:51:56 +0200593
594 // valid input: empty
595 let parsed_flags = try_from_binary_proto_from_text_proto("").unwrap();
596 assert!(parsed_flags.parsed_flag.is_empty());
597
598 // bad input: empty trace
599 let text_proto = r#"
600parsed_flag {
601 package: "com.first"
602 name: "first"
603 namespace: "first_ns"
604 description: "This is the description of the first flag."
605 state: DISABLED
606 permission: READ_ONLY
607}
608"#;
609 let error = try_from_binary_proto_from_text_proto(text_proto).unwrap_err();
610 assert_eq!(format!("{:?}", error), "bad parsed flag: empty trace");
611
Mårten Kongstada2e5ab82023-06-19 16:28:54 +0200612 // bad input: missing namespace in parsed_flag
Mårten Kongstad403658f2023-06-14 09:51:56 +0200613 let text_proto = r#"
614parsed_flag {
615 package: "com.first"
616 name: "first"
617 description: "This is the description of the first flag."
618 state: DISABLED
619 permission: READ_ONLY
620 trace {
621 source: "flags.declarations"
622 state: DISABLED
623 permission: READ_ONLY
624 }
625}
626"#;
627 let error = try_from_binary_proto_from_text_proto(text_proto).unwrap_err();
Mårten Kongstada2e5ab82023-06-19 16:28:54 +0200628 assert_eq!(format!("{:?}", error), "bad parsed flag: missing namespace");
Mårten Kongstad403658f2023-06-14 09:51:56 +0200629
630 // bad input: parsed_flag not sorted by package
631 let text_proto = r#"
632parsed_flag {
Mårten Kongstad19776d12023-06-29 10:38:02 +0200633 package: "bbb.bbb"
Mårten Kongstad403658f2023-06-14 09:51:56 +0200634 name: "first"
635 namespace: "first_ns"
636 description: "This is the description of the first flag."
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200637 bug: ""
Mårten Kongstad403658f2023-06-14 09:51:56 +0200638 state: DISABLED
639 permission: READ_ONLY
640 trace {
641 source: "flags.declarations"
642 state: DISABLED
643 permission: READ_ONLY
644 }
645}
646parsed_flag {
Mårten Kongstad19776d12023-06-29 10:38:02 +0200647 package: "aaa.aaa"
Mårten Kongstad403658f2023-06-14 09:51:56 +0200648 name: "second"
649 namespace: "second_ns"
650 description: "This is the description of the second flag."
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200651 bug: ""
Mårten Kongstad403658f2023-06-14 09:51:56 +0200652 state: ENABLED
653 permission: READ_WRITE
654 trace {
655 source: "flags.declarations"
656 state: DISABLED
657 permission: READ_ONLY
658 }
659}
660"#;
661 let error = try_from_binary_proto_from_text_proto(text_proto).unwrap_err();
662 assert_eq!(
663 format!("{:?}", error),
Mårten Kongstad19776d12023-06-29 10:38:02 +0200664 "bad parsed flags: not sorted: bbb.bbb.first comes before aaa.aaa.second"
Mårten Kongstad403658f2023-06-14 09:51:56 +0200665 );
666
667 // bad input: parsed_flag not sorted by name
668 let text_proto = r#"
669parsed_flag {
670 package: "com.foo"
671 name: "bbb"
672 namespace: "first_ns"
673 description: "This is the description of the first flag."
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200674 bug: ""
Mårten Kongstad403658f2023-06-14 09:51:56 +0200675 state: DISABLED
676 permission: READ_ONLY
677 trace {
678 source: "flags.declarations"
679 state: DISABLED
680 permission: READ_ONLY
681 }
682}
683parsed_flag {
684 package: "com.foo"
685 name: "aaa"
686 namespace: "second_ns"
687 description: "This is the description of the second flag."
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200688 bug: ""
Mårten Kongstad403658f2023-06-14 09:51:56 +0200689 state: ENABLED
690 permission: READ_WRITE
691 trace {
692 source: "flags.declarations"
693 state: DISABLED
694 permission: READ_ONLY
695 }
696}
697"#;
698 let error = try_from_binary_proto_from_text_proto(text_proto).unwrap_err();
699 assert_eq!(
700 format!("{:?}", error),
701 "bad parsed flags: not sorted: com.foo.bbb comes before com.foo.aaa"
702 );
703
704 // bad input: duplicate flags
705 let text_proto = r#"
706parsed_flag {
707 package: "com.foo"
708 name: "bar"
709 namespace: "first_ns"
710 description: "This is the description of the first flag."
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200711 bug: ""
Mårten Kongstad403658f2023-06-14 09:51:56 +0200712 state: DISABLED
713 permission: READ_ONLY
714 trace {
715 source: "flags.declarations"
716 state: DISABLED
717 permission: READ_ONLY
718 }
719}
720parsed_flag {
721 package: "com.foo"
722 name: "bar"
723 namespace: "second_ns"
724 description: "This is the description of the second flag."
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200725 bug: ""
Mårten Kongstad403658f2023-06-14 09:51:56 +0200726 state: ENABLED
727 permission: READ_WRITE
728 trace {
729 source: "flags.declarations"
730 state: DISABLED
731 permission: READ_ONLY
732 }
733}
734"#;
735 let error = try_from_binary_proto_from_text_proto(text_proto).unwrap_err();
Mårten Kongstad206a3822023-07-07 08:52:52 +0200736 assert_eq!(format!("{:?}", error), "bad parsed flags: duplicate flag com.foo.bar (defined in flags.declarations and flags.declarations)");
737 }
738
739 #[test]
740 fn test_parsed_flag_path_to_declaration() {
741 let text_proto = r#"
742parsed_flag {
743 package: "com.foo"
744 name: "bar"
745 namespace: "first_ns"
746 description: "This is the description of the first flag."
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200747 bug: "b/12345678"
Mårten Kongstad206a3822023-07-07 08:52:52 +0200748 state: DISABLED
749 permission: READ_ONLY
750 trace {
751 source: "flags.declarations"
752 state: DISABLED
753 permission: READ_ONLY
754 }
755 trace {
756 source: "flags.values"
757 state: ENABLED
758 permission: READ_ONLY
759 }
760}
761"#;
762 let parsed_flags = try_from_binary_proto_from_text_proto(text_proto).unwrap();
763 let parsed_flag = &parsed_flags.parsed_flag[0];
764 assert_eq!(
765 crate::protos::parsed_flag::path_to_declaration(parsed_flag),
766 "flags.declarations"
767 );
Mårten Kongstad403658f2023-06-14 09:51:56 +0200768 }
769
770 #[test]
771 fn test_parsed_flags_merge() {
772 let text_proto = r#"
773parsed_flag {
774 package: "com.first"
775 name: "first"
776 namespace: "first_ns"
777 description: "This is the description of the first flag."
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200778 bug: "a"
Mårten Kongstad403658f2023-06-14 09:51:56 +0200779 state: DISABLED
780 permission: READ_ONLY
781 trace {
782 source: "flags.declarations"
783 state: DISABLED
784 permission: READ_ONLY
785 }
786}
787parsed_flag {
788 package: "com.second"
789 name: "second"
790 namespace: "second_ns"
791 description: "This is the description of the second flag."
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200792 bug: "b"
Mårten Kongstad403658f2023-06-14 09:51:56 +0200793 state: ENABLED
794 permission: READ_WRITE
795 trace {
796 source: "flags.declarations"
797 state: DISABLED
798 permission: READ_ONLY
799 }
800}
801"#;
802 let expected = try_from_binary_proto_from_text_proto(text_proto).unwrap();
803
804 let text_proto = r#"
805parsed_flag {
806 package: "com.first"
807 name: "first"
808 namespace: "first_ns"
809 description: "This is the description of the first flag."
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200810 bug: "a"
Mårten Kongstad403658f2023-06-14 09:51:56 +0200811 state: DISABLED
812 permission: READ_ONLY
813 trace {
814 source: "flags.declarations"
815 state: DISABLED
816 permission: READ_ONLY
817 }
818}
819"#;
820 let first = try_from_binary_proto_from_text_proto(text_proto).unwrap();
821
822 let text_proto = r#"
823parsed_flag {
824 package: "com.second"
825 name: "second"
826 namespace: "second_ns"
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200827 bug: "b"
Mårten Kongstad403658f2023-06-14 09:51:56 +0200828 description: "This is the description of the second flag."
829 state: ENABLED
830 permission: READ_WRITE
831 trace {
832 source: "flags.declarations"
833 state: DISABLED
834 permission: READ_ONLY
835 }
836}
837"#;
838 let second = try_from_binary_proto_from_text_proto(text_proto).unwrap();
839
840 // bad cases
841 let error = parsed_flags::merge(vec![first.clone(), first.clone()]).unwrap_err();
Mårten Kongstad206a3822023-07-07 08:52:52 +0200842 assert_eq!(format!("{:?}", error), "bad parsed flags: duplicate flag com.first.first (defined in flags.declarations and flags.declarations)");
Mårten Kongstad403658f2023-06-14 09:51:56 +0200843
844 // valid cases
845 assert!(parsed_flags::merge(vec![]).unwrap().parsed_flag.is_empty());
846 assert_eq!(first, parsed_flags::merge(vec![first.clone()]).unwrap());
847 assert_eq!(expected, parsed_flags::merge(vec![first.clone(), second.clone()]).unwrap());
848 assert_eq!(expected, parsed_flags::merge(vec![second, first]).unwrap());
849 }
850}