blob: 2ab6e05b31928658303ff964e7c19e45fbe1f36b [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
159pub mod tracepoint {
160 use super::*;
161 use anyhow::ensure;
162
163 pub fn verify_fields(tp: &ProtoTracepoint) -> Result<()> {
Mårten Kongstad1b8636b2023-06-22 10:12:24 +0200164 ensure_required_fields!("tracepoint", tp, "source", "state", "permission");
Mårten Kongstada2e5ab82023-06-19 16:28:54 +0200165
Mårten Kongstad403658f2023-06-14 09:51:56 +0200166 ensure!(!tp.source().is_empty(), "bad tracepoint: empty source");
Mårten Kongstada2e5ab82023-06-19 16:28:54 +0200167
Mårten Kongstad403658f2023-06-14 09:51:56 +0200168 Ok(())
169 }
170}
171
172pub mod parsed_flag {
173 use super::*;
174 use crate::codegen;
175 use anyhow::ensure;
176
177 pub fn verify_fields(pf: &ProtoParsedFlag) -> Result<()> {
Mårten Kongstad1b8636b2023-06-22 10:12:24 +0200178 ensure_required_fields!(
179 "parsed flag",
180 pf,
181 "package",
182 "name",
183 "namespace",
184 "description",
185 "state",
186 "permission"
187 );
Mårten Kongstada2e5ab82023-06-19 16:28:54 +0200188
Mårten Kongstad403658f2023-06-14 09:51:56 +0200189 ensure!(codegen::is_valid_package_ident(pf.package()), "bad parsed flag: bad package");
190 ensure!(codegen::is_valid_name_ident(pf.name()), "bad parsed flag: bad name");
191 ensure!(codegen::is_valid_name_ident(pf.namespace()), "bad parsed flag: bad namespace");
192 ensure!(!pf.description().is_empty(), "bad parsed flag: empty description");
193 ensure!(!pf.trace.is_empty(), "bad parsed flag: empty trace");
194 for tp in pf.trace.iter() {
195 super::tracepoint::verify_fields(tp)?;
196 }
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200197 ensure!(pf.bug.len() == 1, "bad flag declaration: exactly one bug required");
Mårten Kongstad1b8636b2023-06-22 10:12:24 +0200198
Mårten Kongstad403658f2023-06-14 09:51:56 +0200199 Ok(())
200 }
Mårten Kongstad206a3822023-07-07 08:52:52 +0200201
202 pub fn path_to_declaration(pf: &ProtoParsedFlag) -> &str {
203 debug_assert!(!pf.trace.is_empty());
204 pf.trace[0].source()
205 }
Mårten Kongstad403658f2023-06-14 09:51:56 +0200206}
207
208pub mod parsed_flags {
209 use super::*;
210 use anyhow::bail;
211 use std::cmp::Ordering;
212
213 pub fn try_from_binary_proto(bytes: &[u8]) -> Result<ProtoParsedFlags> {
214 let message: ProtoParsedFlags = protobuf::Message::parse_from_bytes(bytes)?;
215 verify_fields(&message)?;
216 Ok(message)
217 }
218
219 pub fn verify_fields(pf: &ProtoParsedFlags) -> Result<()> {
Mårten Kongstad206a3822023-07-07 08:52:52 +0200220 use crate::protos::parsed_flag::path_to_declaration;
221
Mårten Kongstad403658f2023-06-14 09:51:56 +0200222 let mut previous: Option<&ProtoParsedFlag> = None;
223 for parsed_flag in pf.parsed_flag.iter() {
224 if let Some(prev) = previous {
225 let a = create_sorting_key(prev);
226 let b = create_sorting_key(parsed_flag);
227 match a.cmp(&b) {
228 Ordering::Less => {}
Mårten Kongstad206a3822023-07-07 08:52:52 +0200229 Ordering::Equal => bail!(
230 "bad parsed flags: duplicate flag {} (defined in {} and {})",
231 a,
232 path_to_declaration(prev),
233 path_to_declaration(parsed_flag)
234 ),
Mårten Kongstad403658f2023-06-14 09:51:56 +0200235 Ordering::Greater => {
236 bail!("bad parsed flags: not sorted: {} comes before {}", a, b)
237 }
238 }
239 }
240 super::parsed_flag::verify_fields(parsed_flag)?;
241 previous = Some(parsed_flag);
242 }
243 Ok(())
244 }
245
246 pub fn merge(parsed_flags: Vec<ProtoParsedFlags>) -> Result<ProtoParsedFlags> {
247 let mut merged = ProtoParsedFlags::new();
248 for mut pfs in parsed_flags.into_iter() {
249 merged.parsed_flag.append(&mut pfs.parsed_flag);
250 }
251 merged.parsed_flag.sort_by_cached_key(create_sorting_key);
252 verify_fields(&merged)?;
253 Ok(merged)
254 }
255
Zhi Dou92cf0ec2023-07-19 19:29:22 +0000256 pub fn sort_parsed_flags(pf: &mut ProtoParsedFlags) {
257 pf.parsed_flag.sort_by_key(create_sorting_key);
258 }
259
Mårten Kongstad403658f2023-06-14 09:51:56 +0200260 fn create_sorting_key(pf: &ProtoParsedFlag) -> String {
261 format!("{}.{}", pf.package(), pf.name())
262 }
263}
264
265#[cfg(test)]
266mod tests {
267 use super::*;
268
269 #[test]
270 fn test_flag_declarations_try_from_text_proto() {
271 // valid input
272 let flag_declarations = flag_declarations::try_from_text_proto(
273 r#"
274package: "com.foo.bar"
275flag {
276 name: "first"
277 namespace: "first_ns"
278 description: "This is the description of the first flag."
Mårten Kongstad1b8636b2023-06-22 10:12:24 +0200279 bug: "123"
Mårten Kongstad403658f2023-06-14 09:51:56 +0200280}
281flag {
282 name: "second"
283 namespace: "second_ns"
284 description: "This is the description of the second flag."
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200285 bug: "abc"
Mårten Kongstad403658f2023-06-14 09:51:56 +0200286}
287"#,
288 )
289 .unwrap();
290 assert_eq!(flag_declarations.package(), "com.foo.bar");
291 let first = flag_declarations.flag.iter().find(|pf| pf.name() == "first").unwrap();
292 assert_eq!(first.name(), "first");
293 assert_eq!(first.namespace(), "first_ns");
294 assert_eq!(first.description(), "This is the description of the first flag.");
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200295 assert_eq!(first.bug, vec!["123"]);
Mårten Kongstad403658f2023-06-14 09:51:56 +0200296 let second = flag_declarations.flag.iter().find(|pf| pf.name() == "second").unwrap();
297 assert_eq!(second.name(), "second");
298 assert_eq!(second.namespace(), "second_ns");
299 assert_eq!(second.description(), "This is the description of the second flag.");
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200300 assert_eq!(second.bug, vec!["abc"]);
Mårten Kongstad403658f2023-06-14 09:51:56 +0200301
302 // bad input: missing package in flag declarations
303 let error = flag_declarations::try_from_text_proto(
304 r#"
305flag {
306 name: "first"
307 namespace: "first_ns"
308 description: "This is the description of the first flag."
309}
310flag {
311 name: "second"
312 namespace: "second_ns"
313 description: "This is the description of the second flag."
314}
315"#,
316 )
317 .unwrap_err();
Mårten Kongstada2e5ab82023-06-19 16:28:54 +0200318 assert_eq!(format!("{:?}", error), "bad flag declarations: missing package");
Mårten Kongstad403658f2023-06-14 09:51:56 +0200319
320 // bad input: missing namespace in flag declaration
321 let error = flag_declarations::try_from_text_proto(
322 r#"
323package: "com.foo.bar"
324flag {
325 name: "first"
326 description: "This is the description of the first flag."
327}
328flag {
329 name: "second"
330 namespace: "second_ns"
331 description: "This is the description of the second flag."
332}
333"#,
334 )
335 .unwrap_err();
Mårten Kongstada2e5ab82023-06-19 16:28:54 +0200336 assert_eq!(format!("{:?}", error), "bad flag declaration: missing namespace");
Mårten Kongstad403658f2023-06-14 09:51:56 +0200337
338 // bad input: bad package name in flag declarations
339 let error = flag_declarations::try_from_text_proto(
340 r#"
341package: "_com.FOO__BAR"
342flag {
343 name: "first"
344 namespace: "first_ns"
345 description: "This is the description of the first flag."
346}
347flag {
348 name: "second"
349 namespace: "second_ns"
350 description: "This is the description of the second flag."
351}
352"#,
353 )
354 .unwrap_err();
355 assert!(format!("{:?}", error).contains("bad flag declarations: bad package"));
356
357 // bad input: bad name in flag declaration
358 let error = flag_declarations::try_from_text_proto(
359 r#"
360package: "com.foo.bar"
361flag {
362 name: "FIRST"
363 namespace: "first_ns"
364 description: "This is the description of the first flag."
365}
366flag {
367 name: "second"
368 namespace: "second_ns"
369 description: "This is the description of the second flag."
370}
371"#,
372 )
373 .unwrap_err();
374 assert!(format!("{:?}", error).contains("bad flag declaration: bad name"));
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200375
376 // bad input: no bug entries in flag declaration
377 let error = flag_declarations::try_from_text_proto(
378 r#"
379package: "com.foo.bar"
380flag {
381 name: "first"
382 namespace: "first_ns"
383 description: "This is the description of the first flag."
384}
385"#,
386 )
387 .unwrap_err();
388 assert!(format!("{:?}", error).contains("bad flag declaration: exactly one bug required"));
389
390 // bad input: multiple bug entries in flag declaration
391 let error = flag_declarations::try_from_text_proto(
392 r#"
393package: "com.foo.bar"
394flag {
395 name: "first"
396 namespace: "first_ns"
397 description: "This is the description of the first flag."
398 bug: "123"
399 bug: "abc"
400}
401"#,
402 )
403 .unwrap_err();
404 assert!(format!("{:?}", error).contains("bad flag declaration: exactly one bug required"));
Mårten Kongstad403658f2023-06-14 09:51:56 +0200405 }
406
407 #[test]
408 fn test_flag_values_try_from_text_proto() {
409 // valid input
410 let flag_values = flag_values::try_from_text_proto(
411 r#"
412flag_value {
413 package: "com.first"
414 name: "first"
415 state: DISABLED
416 permission: READ_ONLY
417}
418flag_value {
419 package: "com.second"
420 name: "second"
421 state: ENABLED
422 permission: READ_WRITE
423}
424"#,
425 )
426 .unwrap();
427 let first = flag_values.flag_value.iter().find(|fv| fv.name() == "first").unwrap();
428 assert_eq!(first.package(), "com.first");
429 assert_eq!(first.name(), "first");
430 assert_eq!(first.state(), ProtoFlagState::DISABLED);
431 assert_eq!(first.permission(), ProtoFlagPermission::READ_ONLY);
432 let second = flag_values.flag_value.iter().find(|fv| fv.name() == "second").unwrap();
433 assert_eq!(second.package(), "com.second");
434 assert_eq!(second.name(), "second");
435 assert_eq!(second.state(), ProtoFlagState::ENABLED);
436 assert_eq!(second.permission(), ProtoFlagPermission::READ_WRITE);
437
438 // bad input: bad package in flag value
439 let error = flag_values::try_from_text_proto(
440 r#"
441flag_value {
442 package: "COM.FIRST"
443 name: "first"
444 state: DISABLED
445 permission: READ_ONLY
446}
447"#,
448 )
449 .unwrap_err();
450 assert!(format!("{:?}", error).contains("bad flag value: bad package"));
451
452 // bad input: bad name in flag value
453 let error = flag_values::try_from_text_proto(
454 r#"
455flag_value {
456 package: "com.first"
457 name: "FIRST"
458 state: DISABLED
459 permission: READ_ONLY
460}
461"#,
462 )
463 .unwrap_err();
464 assert!(format!("{:?}", error).contains("bad flag value: bad name"));
465
466 // bad input: missing state in flag value
467 let error = flag_values::try_from_text_proto(
468 r#"
469flag_value {
470 package: "com.first"
471 name: "first"
472 permission: READ_ONLY
473}
474"#,
475 )
476 .unwrap_err();
Mårten Kongstada2e5ab82023-06-19 16:28:54 +0200477 assert_eq!(format!("{:?}", error), "bad flag value: missing state");
Mårten Kongstad403658f2023-06-14 09:51:56 +0200478
479 // bad input: missing permission in flag value
480 let error = flag_values::try_from_text_proto(
481 r#"
482flag_value {
483 package: "com.first"
484 name: "first"
485 state: DISABLED
486}
487"#,
488 )
489 .unwrap_err();
Mårten Kongstada2e5ab82023-06-19 16:28:54 +0200490 assert_eq!(format!("{:?}", error), "bad flag value: missing permission");
Mårten Kongstad403658f2023-06-14 09:51:56 +0200491 }
492
493 fn try_from_binary_proto_from_text_proto(text_proto: &str) -> Result<ProtoParsedFlags> {
494 use protobuf::Message;
495
496 let parsed_flags: ProtoParsedFlags = try_from_text_proto(text_proto)?;
497 let mut binary_proto = Vec::new();
498 parsed_flags.write_to_vec(&mut binary_proto)?;
499 parsed_flags::try_from_binary_proto(&binary_proto)
500 }
501
502 #[test]
503 fn test_parsed_flags_try_from_text_proto() {
504 // valid input
505 let text_proto = r#"
506parsed_flag {
507 package: "com.first"
508 name: "first"
509 namespace: "first_ns"
510 description: "This is the description of the first flag."
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200511 bug: "SOME_BUG"
Mårten Kongstad403658f2023-06-14 09:51:56 +0200512 state: DISABLED
513 permission: READ_ONLY
514 trace {
515 source: "flags.declarations"
516 state: DISABLED
517 permission: READ_ONLY
518 }
519}
520parsed_flag {
521 package: "com.second"
522 name: "second"
523 namespace: "second_ns"
524 description: "This is the description of the second flag."
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200525 bug: "SOME_BUG"
Mårten Kongstad403658f2023-06-14 09:51:56 +0200526 state: ENABLED
527 permission: READ_WRITE
528 trace {
529 source: "flags.declarations"
530 state: DISABLED
531 permission: READ_ONLY
532 }
533 trace {
534 source: "flags.values"
535 state: ENABLED
536 permission: READ_WRITE
537 }
538}
539"#;
540 let parsed_flags = try_from_binary_proto_from_text_proto(text_proto).unwrap();
541 assert_eq!(parsed_flags.parsed_flag.len(), 2);
542 let second = parsed_flags.parsed_flag.iter().find(|fv| fv.name() == "second").unwrap();
543 assert_eq!(second.package(), "com.second");
544 assert_eq!(second.name(), "second");
545 assert_eq!(second.namespace(), "second_ns");
546 assert_eq!(second.description(), "This is the description of the second flag.");
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200547 assert_eq!(second.bug, vec!["SOME_BUG"]);
Mårten Kongstad403658f2023-06-14 09:51:56 +0200548 assert_eq!(second.state(), ProtoFlagState::ENABLED);
549 assert_eq!(second.permission(), ProtoFlagPermission::READ_WRITE);
550 assert_eq!(2, second.trace.len());
551 assert_eq!(second.trace[0].source(), "flags.declarations");
552 assert_eq!(second.trace[0].state(), ProtoFlagState::DISABLED);
553 assert_eq!(second.trace[0].permission(), ProtoFlagPermission::READ_ONLY);
554 assert_eq!(second.trace[1].source(), "flags.values");
555 assert_eq!(second.trace[1].state(), ProtoFlagState::ENABLED);
556 assert_eq!(second.trace[1].permission(), ProtoFlagPermission::READ_WRITE);
557
558 // valid input: empty
559 let parsed_flags = try_from_binary_proto_from_text_proto("").unwrap();
560 assert!(parsed_flags.parsed_flag.is_empty());
561
562 // bad input: empty trace
563 let text_proto = r#"
564parsed_flag {
565 package: "com.first"
566 name: "first"
567 namespace: "first_ns"
568 description: "This is the description of the first flag."
569 state: DISABLED
570 permission: READ_ONLY
571}
572"#;
573 let error = try_from_binary_proto_from_text_proto(text_proto).unwrap_err();
574 assert_eq!(format!("{:?}", error), "bad parsed flag: empty trace");
575
Mårten Kongstada2e5ab82023-06-19 16:28:54 +0200576 // bad input: missing namespace in parsed_flag
Mårten Kongstad403658f2023-06-14 09:51:56 +0200577 let text_proto = r#"
578parsed_flag {
579 package: "com.first"
580 name: "first"
581 description: "This is the description of the first flag."
582 state: DISABLED
583 permission: READ_ONLY
584 trace {
585 source: "flags.declarations"
586 state: DISABLED
587 permission: READ_ONLY
588 }
589}
590"#;
591 let error = try_from_binary_proto_from_text_proto(text_proto).unwrap_err();
Mårten Kongstada2e5ab82023-06-19 16:28:54 +0200592 assert_eq!(format!("{:?}", error), "bad parsed flag: missing namespace");
Mårten Kongstad403658f2023-06-14 09:51:56 +0200593
594 // bad input: parsed_flag not sorted by package
595 let text_proto = r#"
596parsed_flag {
Mårten Kongstad19776d12023-06-29 10:38:02 +0200597 package: "bbb.bbb"
Mårten Kongstad403658f2023-06-14 09:51:56 +0200598 name: "first"
599 namespace: "first_ns"
600 description: "This is the description of the first flag."
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200601 bug: ""
Mårten Kongstad403658f2023-06-14 09:51:56 +0200602 state: DISABLED
603 permission: READ_ONLY
604 trace {
605 source: "flags.declarations"
606 state: DISABLED
607 permission: READ_ONLY
608 }
609}
610parsed_flag {
Mårten Kongstad19776d12023-06-29 10:38:02 +0200611 package: "aaa.aaa"
Mårten Kongstad403658f2023-06-14 09:51:56 +0200612 name: "second"
613 namespace: "second_ns"
614 description: "This is the description of the second flag."
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200615 bug: ""
Mårten Kongstad403658f2023-06-14 09:51:56 +0200616 state: ENABLED
617 permission: READ_WRITE
618 trace {
619 source: "flags.declarations"
620 state: DISABLED
621 permission: READ_ONLY
622 }
623}
624"#;
625 let error = try_from_binary_proto_from_text_proto(text_proto).unwrap_err();
626 assert_eq!(
627 format!("{:?}", error),
Mårten Kongstad19776d12023-06-29 10:38:02 +0200628 "bad parsed flags: not sorted: bbb.bbb.first comes before aaa.aaa.second"
Mårten Kongstad403658f2023-06-14 09:51:56 +0200629 );
630
631 // bad input: parsed_flag not sorted by name
632 let text_proto = r#"
633parsed_flag {
634 package: "com.foo"
635 name: "bbb"
636 namespace: "first_ns"
637 description: "This is the description of the first flag."
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200638 bug: ""
Mårten Kongstad403658f2023-06-14 09:51:56 +0200639 state: DISABLED
640 permission: READ_ONLY
641 trace {
642 source: "flags.declarations"
643 state: DISABLED
644 permission: READ_ONLY
645 }
646}
647parsed_flag {
648 package: "com.foo"
649 name: "aaa"
650 namespace: "second_ns"
651 description: "This is the description of the second flag."
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200652 bug: ""
Mårten Kongstad403658f2023-06-14 09:51:56 +0200653 state: ENABLED
654 permission: READ_WRITE
655 trace {
656 source: "flags.declarations"
657 state: DISABLED
658 permission: READ_ONLY
659 }
660}
661"#;
662 let error = try_from_binary_proto_from_text_proto(text_proto).unwrap_err();
663 assert_eq!(
664 format!("{:?}", error),
665 "bad parsed flags: not sorted: com.foo.bbb comes before com.foo.aaa"
666 );
667
668 // bad input: duplicate flags
669 let text_proto = r#"
670parsed_flag {
671 package: "com.foo"
672 name: "bar"
673 namespace: "first_ns"
674 description: "This is the description of the first flag."
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200675 bug: ""
Mårten Kongstad403658f2023-06-14 09:51:56 +0200676 state: DISABLED
677 permission: READ_ONLY
678 trace {
679 source: "flags.declarations"
680 state: DISABLED
681 permission: READ_ONLY
682 }
683}
684parsed_flag {
685 package: "com.foo"
686 name: "bar"
687 namespace: "second_ns"
688 description: "This is the description of the second flag."
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200689 bug: ""
Mårten Kongstad403658f2023-06-14 09:51:56 +0200690 state: ENABLED
691 permission: READ_WRITE
692 trace {
693 source: "flags.declarations"
694 state: DISABLED
695 permission: READ_ONLY
696 }
697}
698"#;
699 let error = try_from_binary_proto_from_text_proto(text_proto).unwrap_err();
Mårten Kongstad206a3822023-07-07 08:52:52 +0200700 assert_eq!(format!("{:?}", error), "bad parsed flags: duplicate flag com.foo.bar (defined in flags.declarations and flags.declarations)");
701 }
702
703 #[test]
704 fn test_parsed_flag_path_to_declaration() {
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: "b/12345678"
Mårten Kongstad206a3822023-07-07 08:52:52 +0200712 state: DISABLED
713 permission: READ_ONLY
714 trace {
715 source: "flags.declarations"
716 state: DISABLED
717 permission: READ_ONLY
718 }
719 trace {
720 source: "flags.values"
721 state: ENABLED
722 permission: READ_ONLY
723 }
724}
725"#;
726 let parsed_flags = try_from_binary_proto_from_text_proto(text_proto).unwrap();
727 let parsed_flag = &parsed_flags.parsed_flag[0];
728 assert_eq!(
729 crate::protos::parsed_flag::path_to_declaration(parsed_flag),
730 "flags.declarations"
731 );
Mårten Kongstad403658f2023-06-14 09:51:56 +0200732 }
733
734 #[test]
735 fn test_parsed_flags_merge() {
736 let text_proto = r#"
737parsed_flag {
738 package: "com.first"
739 name: "first"
740 namespace: "first_ns"
741 description: "This is the description of the first flag."
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200742 bug: "a"
Mårten Kongstad403658f2023-06-14 09:51:56 +0200743 state: DISABLED
744 permission: READ_ONLY
745 trace {
746 source: "flags.declarations"
747 state: DISABLED
748 permission: READ_ONLY
749 }
750}
751parsed_flag {
752 package: "com.second"
753 name: "second"
754 namespace: "second_ns"
755 description: "This is the description of the second flag."
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200756 bug: "b"
Mårten Kongstad403658f2023-06-14 09:51:56 +0200757 state: ENABLED
758 permission: READ_WRITE
759 trace {
760 source: "flags.declarations"
761 state: DISABLED
762 permission: READ_ONLY
763 }
764}
765"#;
766 let expected = try_from_binary_proto_from_text_proto(text_proto).unwrap();
767
768 let text_proto = r#"
769parsed_flag {
770 package: "com.first"
771 name: "first"
772 namespace: "first_ns"
773 description: "This is the description of the first flag."
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200774 bug: "a"
Mårten Kongstad403658f2023-06-14 09:51:56 +0200775 state: DISABLED
776 permission: READ_ONLY
777 trace {
778 source: "flags.declarations"
779 state: DISABLED
780 permission: READ_ONLY
781 }
782}
783"#;
784 let first = try_from_binary_proto_from_text_proto(text_proto).unwrap();
785
786 let text_proto = r#"
787parsed_flag {
788 package: "com.second"
789 name: "second"
790 namespace: "second_ns"
Mårten Kongstad6353c6c2023-07-26 13:18:50 +0200791 bug: "b"
Mårten Kongstad403658f2023-06-14 09:51:56 +0200792 description: "This is the description of the second flag."
793 state: ENABLED
794 permission: READ_WRITE
795 trace {
796 source: "flags.declarations"
797 state: DISABLED
798 permission: READ_ONLY
799 }
800}
801"#;
802 let second = try_from_binary_proto_from_text_proto(text_proto).unwrap();
803
804 // bad cases
805 let error = parsed_flags::merge(vec![first.clone(), first.clone()]).unwrap_err();
Mårten Kongstad206a3822023-07-07 08:52:52 +0200806 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 +0200807
808 // valid cases
809 assert!(parsed_flags::merge(vec![]).unwrap().parsed_flag.is_empty());
810 assert_eq!(first, parsed_flags::merge(vec![first.clone()]).unwrap());
811 assert_eq!(expected, parsed_flags::merge(vec![first.clone(), second.clone()]).unwrap());
812 assert_eq!(expected, parsed_flags::merge(vec![second, first]).unwrap());
813 }
814}