1#![warn(missing_docs)]
6
7use cm_rust::{
10 ConfigChecksum, ConfigDecl, ConfigField as ConfigFieldDecl, ConfigMutability,
11 ConfigNestedValueType, ConfigOverride, ConfigSingleValue, ConfigValue, ConfigValueType,
12 ConfigValuesData, ConfigVectorValue, NativeIntoFidl,
13};
14use dynfidl::{BasicField, Field, Structure, VectorField};
15use fidl_fuchsia_component_decl as fdecl;
16use flyweights::FlyStr;
17use thiserror::Error;
18
19#[derive(Clone, Debug, PartialEq)]
21pub struct ConfigFields {
22 pub fields: Vec<ConfigField>,
24 pub checksum: ConfigChecksum,
26}
27
28impl ConfigFields {
29 pub fn resolve(
32 decl: &ConfigDecl,
33 base_values: ConfigValuesData,
34 parent_overrides: Option<&[ConfigOverride]>,
35 ) -> Result<Self, ResolutionError> {
36 if decl.checksum != base_values.checksum {
38 return Err(ResolutionError::ChecksumFailure {
39 expected: decl.checksum.clone(),
40 received: base_values.checksum,
41 });
42 }
43
44 if decl.fields.len() != base_values.values.len() {
46 return Err(ResolutionError::WrongNumberOfValues {
47 expected: decl.fields.len(),
48 received: base_values.values.len(),
49 });
50 }
51
52 if let Some(overrides) = parent_overrides {
54 for key in overrides.iter().map(|o| &o.key) {
55 if !decl.fields.iter().any(|f| &f.key == key) {
56 return Err(ResolutionError::FieldDoesNotExist { key: key.clone() });
57 }
58 }
59 }
60
61 let mut resolved_fields = vec![];
62 for (decl_field, spec_field) in
63 decl.fields.iter().zip(IntoIterator::into_iter(base_values.values))
64 {
65 let mut from_parent = None;
67 if let Some(parent_overrides) = parent_overrides {
68 for o in parent_overrides {
69 if o.key == decl_field.key {
71 if !decl_field.mutability.contains(ConfigMutability::PARENT) {
72 return Err(ResolutionError::FieldIsNotMutable {
73 key: decl_field.key.clone(),
74 });
75 }
76 from_parent = Some(o.value.clone());
77 }
78 }
79 }
80
81 let value = if let Some(v) = from_parent { v } else { spec_field.value };
83 let resolved_field = ConfigField::resolve(value, &decl_field).map_err(|source| {
84 ResolutionError::InvalidValue { key: decl_field.key.clone(), source }
85 })?;
86 resolved_fields.push(resolved_field);
87 }
88
89 Ok(Self { fields: resolved_fields, checksum: decl.checksum.clone() })
90 }
91
92 pub fn encode_as_fidl_struct(self) -> Vec<u8> {
98 let Self { fields, checksum: ConfigChecksum::Sha256(checksum) } = self;
99 let mut structure = Structure::default();
100 for ConfigField { value, .. } in fields {
101 structure = match value {
102 ConfigValue::Single(ConfigSingleValue::Bool(b)) => {
103 structure.field(Field::Basic(BasicField::Bool(b)))
104 }
105 ConfigValue::Single(ConfigSingleValue::Uint8(n)) => {
106 structure.field(Field::Basic(BasicField::UInt8(n)))
107 }
108 ConfigValue::Single(ConfigSingleValue::Uint16(n)) => {
109 structure.field(Field::Basic(BasicField::UInt16(n)))
110 }
111 ConfigValue::Single(ConfigSingleValue::Uint32(n)) => {
112 structure.field(Field::Basic(BasicField::UInt32(n)))
113 }
114 ConfigValue::Single(ConfigSingleValue::Uint64(n)) => {
115 structure.field(Field::Basic(BasicField::UInt64(n)))
116 }
117 ConfigValue::Single(ConfigSingleValue::Int8(n)) => {
118 structure.field(Field::Basic(BasicField::Int8(n)))
119 }
120 ConfigValue::Single(ConfigSingleValue::Int16(n)) => {
121 structure.field(Field::Basic(BasicField::Int16(n)))
122 }
123 ConfigValue::Single(ConfigSingleValue::Int32(n)) => {
124 structure.field(Field::Basic(BasicField::Int32(n)))
125 }
126 ConfigValue::Single(ConfigSingleValue::Int64(n)) => {
127 structure.field(Field::Basic(BasicField::Int64(n)))
128 }
129 ConfigValue::Single(ConfigSingleValue::String(s)) => {
130 structure.field(Field::Vector(VectorField::UInt8Vector(s.as_bytes().to_vec())))
132 }
133 ConfigValue::Vector(ConfigVectorValue::BoolVector(b)) => {
134 structure.field(Field::Vector(VectorField::BoolVector(b.into())))
135 }
136 ConfigValue::Vector(ConfigVectorValue::Uint8Vector(n)) => {
137 structure.field(Field::Vector(VectorField::UInt8Vector(n.into())))
138 }
139 ConfigValue::Vector(ConfigVectorValue::Uint16Vector(n)) => {
140 structure.field(Field::Vector(VectorField::UInt16Vector(n.into())))
141 }
142 ConfigValue::Vector(ConfigVectorValue::Uint32Vector(n)) => {
143 structure.field(Field::Vector(VectorField::UInt32Vector(n.into())))
144 }
145 ConfigValue::Vector(ConfigVectorValue::Uint64Vector(n)) => {
146 structure.field(Field::Vector(VectorField::UInt64Vector(n.into())))
147 }
148 ConfigValue::Vector(ConfigVectorValue::Int8Vector(n)) => {
149 structure.field(Field::Vector(VectorField::Int8Vector(n.into())))
150 }
151 ConfigValue::Vector(ConfigVectorValue::Int16Vector(n)) => {
152 structure.field(Field::Vector(VectorField::Int16Vector(n.into())))
153 }
154 ConfigValue::Vector(ConfigVectorValue::Int32Vector(n)) => {
155 structure.field(Field::Vector(VectorField::Int32Vector(n.into())))
156 }
157 ConfigValue::Vector(ConfigVectorValue::Int64Vector(n)) => {
158 structure.field(Field::Vector(VectorField::Int64Vector(n.into())))
159 }
160 ConfigValue::Vector(ConfigVectorValue::StringVector(s)) => {
161 structure.field(Field::Vector(
162 VectorField::UInt8VectorVector(
164 IntoIterator::into_iter(s).map(|s| s.as_bytes().to_vec()).collect(),
165 ),
166 ))
167 }
168 };
169 }
170
171 let mut buf = Vec::new();
172 buf.extend((checksum.len() as u16).to_le_bytes());
173 buf.extend(checksum);
174 buf.extend(structure.encode_persistent());
175 buf
176 }
177}
178
179impl Into<fdecl::ResolvedConfig> for ConfigFields {
180 fn into(self) -> fdecl::ResolvedConfig {
181 let checksum = self.checksum.native_into_fidl();
182 let fields = self.fields.into_iter().map(|f| f.into()).collect();
183 fdecl::ResolvedConfig { checksum, fields }
184 }
185}
186
187#[derive(Clone, Debug, PartialEq)]
189pub struct ConfigField {
190 pub key: FlyStr,
192
193 pub value: ConfigValue,
195
196 pub mutability: ConfigMutability,
198}
199
200impl ConfigField {
201 pub fn resolve(value: ConfigValue, decl_field: &ConfigFieldDecl) -> Result<Self, ValueError> {
204 let key = decl_field.key.clone();
205
206 match (&value, &decl_field.type_) {
207 (ConfigValue::Single(ConfigSingleValue::Bool(_)), ConfigValueType::Bool)
208 | (ConfigValue::Single(ConfigSingleValue::Uint8(_)), ConfigValueType::Uint8)
209 | (ConfigValue::Single(ConfigSingleValue::Uint16(_)), ConfigValueType::Uint16)
210 | (ConfigValue::Single(ConfigSingleValue::Uint32(_)), ConfigValueType::Uint32)
211 | (ConfigValue::Single(ConfigSingleValue::Uint64(_)), ConfigValueType::Uint64)
212 | (ConfigValue::Single(ConfigSingleValue::Int8(_)), ConfigValueType::Int8)
213 | (ConfigValue::Single(ConfigSingleValue::Int16(_)), ConfigValueType::Int16)
214 | (ConfigValue::Single(ConfigSingleValue::Int32(_)), ConfigValueType::Int32)
215 | (ConfigValue::Single(ConfigSingleValue::Int64(_)), ConfigValueType::Int64) => (),
216 (
217 ConfigValue::Single(ConfigSingleValue::String(text)),
218 ConfigValueType::String { max_size },
219 ) => {
220 let max_size = *max_size as usize;
221 if text.len() > max_size {
222 return Err(ValueError::StringTooLong { max: max_size, actual: text.len() });
223 }
224 }
225 (ConfigValue::Vector(list), ConfigValueType::Vector { nested_type, max_count }) => {
226 let max_count = *max_count as usize;
227 let actual_count = match (list, nested_type) {
228 (ConfigVectorValue::BoolVector(l), ConfigNestedValueType::Bool) => l.len(),
229 (ConfigVectorValue::Uint8Vector(l), ConfigNestedValueType::Uint8) => l.len(),
230 (ConfigVectorValue::Uint16Vector(l), ConfigNestedValueType::Uint16) => l.len(),
231 (ConfigVectorValue::Uint32Vector(l), ConfigNestedValueType::Uint32) => l.len(),
232 (ConfigVectorValue::Uint64Vector(l), ConfigNestedValueType::Uint64) => l.len(),
233 (ConfigVectorValue::Int8Vector(l), ConfigNestedValueType::Int8) => l.len(),
234 (ConfigVectorValue::Int16Vector(l), ConfigNestedValueType::Int16) => l.len(),
235 (ConfigVectorValue::Int32Vector(l), ConfigNestedValueType::Int32) => l.len(),
236 (ConfigVectorValue::Int64Vector(l), ConfigNestedValueType::Int64) => l.len(),
237 (
238 ConfigVectorValue::StringVector(l),
239 ConfigNestedValueType::String { max_size },
240 ) => {
241 let max_size = *max_size as usize;
242 for (i, s) in l.iter().enumerate() {
243 if s.len() > max_size {
244 return Err(ValueError::VectorElementInvalid {
245 offset: i,
246 source: Box::new(ValueError::StringTooLong {
247 max: max_size,
248 actual: s.len(),
249 }),
250 });
251 }
252 }
253 l.len()
254 }
255 (other_list, other_ty) => {
256 return Err(ValueError::TypeMismatch {
257 expected: format!("{:?}", other_ty),
258 received: format!("{:?}", other_list),
259 });
260 }
261 };
262
263 if actual_count > max_count {
264 return Err(ValueError::VectorTooLong { max: max_count, actual: actual_count });
265 }
266 }
267 (other_val, other_ty) => {
268 return Err(ValueError::TypeMismatch {
269 expected: format!("{:?}", other_ty),
270 received: format!("{:?}", other_val),
271 });
272 }
273 }
274
275 Ok(ConfigField { key, value, mutability: decl_field.mutability })
276 }
277}
278
279impl Into<fdecl::ResolvedConfigField> for ConfigField {
280 fn into(self) -> fdecl::ResolvedConfigField {
281 fdecl::ResolvedConfigField {
282 key: self.key.to_string(),
283 value: self.value.native_into_fidl(),
284 }
285 }
286}
287
288#[derive(Clone, Debug, Error, PartialEq)]
289#[allow(missing_docs)]
290pub enum ResolutionError {
291 #[error(
292 "Checksums in declaration and value file do not match. Expected {expected:04x?}, received {received:04x?}"
293 )]
294 ChecksumFailure { expected: ConfigChecksum, received: ConfigChecksum },
295
296 #[error(
297 "Value file has a different number of values ({received}) than declaration has fields ({expected})."
298 )]
299 WrongNumberOfValues { expected: usize, received: usize },
300
301 #[error("Provided a value for `{key}` which is not in the component's configuration schema.")]
302 FieldDoesNotExist { key: FlyStr },
303
304 #[error("Provided an override which is not mutable in the component's configuration schema.")]
305 FieldIsNotMutable { key: FlyStr },
306
307 #[error("Received invalid value for `{key}`:\n\t{source}")]
308 InvalidValue {
309 key: FlyStr,
310 #[source]
311 source: ValueError,
312 },
313}
314
315#[derive(Clone, Debug, Error, PartialEq)]
316#[allow(missing_docs)]
317pub enum ValueError {
318 #[error("Value of type `{received}` does not match declaration of type {expected}.")]
319 TypeMismatch { expected: String, received: String },
320
321 #[error("Received string of length {actual} for a field with a max of {max}.")]
322 StringTooLong { max: usize, actual: usize },
323
324 #[error("Received vector of length {actual} for a field with a max of {max}.")]
325 VectorTooLong { max: usize, actual: usize },
326
327 #[error("Vector element at {offset} index is invalid.")]
328 VectorElementInvalid {
329 offset: usize,
330 #[source]
331 source: Box<Self>,
332 },
333}
334
335#[cfg(test)]
336mod tests {
337 use super::*;
338 use fidl_fuchsia_component_config_ext::{config_decl, values_data};
339 use fidl_test_config_encoder::BasicSuccessSchema;
340
341 use ConfigSingleValue::*;
342 use ConfigValue::*;
343 use ConfigVectorValue::*;
344
345 #[test]
346 fn basic_success() {
347 let decl = config_decl! {
348 ck@ ConfigChecksum::Sha256([0; 32]),
349 my_flag: { bool },
350 my_uint8: { uint8 },
351 my_uint16: { uint16 },
352 my_uint32: { uint32 },
353 my_uint64: { uint64 },
354 my_int8: { int8 },
355 my_int16: { int16 },
356 my_int32: { int32 },
357 my_int64: { int64 },
358 my_string: { string, max_size: 100 },
359 my_vector_of_flag: { vector, element: bool, max_count: 100 },
360 my_vector_of_uint8: { vector, element: uint8, max_count: 100 },
361 my_vector_of_uint16: { vector, element: uint16, max_count: 100 },
362 my_vector_of_uint32: { vector, element: uint32, max_count: 100 },
363 my_vector_of_uint64: { vector, element: uint64, max_count: 100 },
364 my_vector_of_int8: { vector, element: int8, max_count: 100 },
365 my_vector_of_int16: { vector, element: int16, max_count: 100 },
366 my_vector_of_int32: { vector, element: int32, max_count: 100 },
367 my_vector_of_int64: { vector, element: int64, max_count: 100 },
368 my_vector_of_string: {
369 vector,
370 element: { string, max_size: 100 },
371 max_count: 100
372 },
373 };
374
375 let specs = values_data![
376 ck@ decl.checksum.clone(),
377 Single(Bool(false)),
378 Single(Uint8(255u8)),
379 Single(Uint16(65535u16)),
380 Single(Uint32(4000000000u32)),
381 Single(Uint64(8000000000u64)),
382 Single(Int8(-127i8)),
383 Single(Int16(-32766i16)),
384 Single(Int32(-2000000000i32)),
385 Single(Int64(-4000000000i64)),
386 Single(String("hello, world!".into())),
387 Vector(BoolVector(Box::from([true, false]))),
388 Vector(Uint8Vector(Box::from([1, 2, 3]))),
389 Vector(Uint16Vector(Box::from([2, 3, 4]))),
390 Vector(Uint32Vector(Box::from([3, 4, 5]))),
391 Vector(Uint64Vector(Box::from([4, 5, 6]))),
392 Vector(Int8Vector(Box::from([-1, -2, 3]))),
393 Vector(Int16Vector(Box::from([-2, -3, 4]))),
394 Vector(Int32Vector(Box::from([-3, -4, 5]))),
395 Vector(Int64Vector(Box::from([-4, -5, 6]))),
396 Vector(StringVector(Box::from(["valid".into(), "valid".into()]))),
397 ];
398
399 let resolved = ConfigFields::resolve(&decl, specs, None).unwrap();
400 assert_eq!(
401 resolved,
402 ConfigFields {
403 fields: vec![
404 ConfigField {
405 key: "my_flag".into(),
406 value: Single(Bool(false)),
407 mutability: Default::default(),
408 },
409 ConfigField {
410 key: "my_uint8".into(),
411 value: Single(Uint8(255)),
412 mutability: Default::default(),
413 },
414 ConfigField {
415 key: "my_uint16".into(),
416 value: Single(Uint16(65535)),
417 mutability: Default::default(),
418 },
419 ConfigField {
420 key: "my_uint32".into(),
421 value: Single(Uint32(4000000000)),
422 mutability: Default::default(),
423 },
424 ConfigField {
425 key: "my_uint64".into(),
426 value: Single(Uint64(8000000000)),
427 mutability: Default::default(),
428 },
429 ConfigField {
430 key: "my_int8".into(),
431 value: Single(Int8(-127)),
432 mutability: Default::default(),
433 },
434 ConfigField {
435 key: "my_int16".into(),
436 value: Single(Int16(-32766)),
437 mutability: Default::default(),
438 },
439 ConfigField {
440 key: "my_int32".into(),
441 value: Single(Int32(-2000000000)),
442 mutability: Default::default(),
443 },
444 ConfigField {
445 key: "my_int64".into(),
446 value: Single(Int64(-4000000000)),
447 mutability: Default::default(),
448 },
449 ConfigField {
450 key: "my_string".into(),
451 value: Single(String("hello, world!".into())),
452 mutability: Default::default(),
453 },
454 ConfigField {
455 key: "my_vector_of_flag".into(),
456 value: Vector(BoolVector(Box::from([true, false]))),
457 mutability: Default::default(),
458 },
459 ConfigField {
460 key: "my_vector_of_uint8".into(),
461 value: Vector(Uint8Vector(Box::from([1, 2, 3]))),
462 mutability: Default::default(),
463 },
464 ConfigField {
465 key: "my_vector_of_uint16".into(),
466 value: Vector(Uint16Vector(Box::from([2, 3, 4]))),
467 mutability: Default::default(),
468 },
469 ConfigField {
470 key: "my_vector_of_uint32".into(),
471 value: Vector(Uint32Vector(Box::from([3, 4, 5]))),
472 mutability: Default::default(),
473 },
474 ConfigField {
475 key: "my_vector_of_uint64".into(),
476 value: Vector(Uint64Vector(Box::from([4, 5, 6]))),
477 mutability: Default::default(),
478 },
479 ConfigField {
480 key: "my_vector_of_int8".into(),
481 value: Vector(Int8Vector(Box::from([-1, -2, 3]))),
482 mutability: Default::default(),
483 },
484 ConfigField {
485 key: "my_vector_of_int16".into(),
486 value: Vector(Int16Vector(Box::from([-2, -3, 4]))),
487 mutability: Default::default(),
488 },
489 ConfigField {
490 key: "my_vector_of_int32".into(),
491 value: Vector(Int32Vector(Box::from([-3, -4, 5]))),
492 mutability: Default::default(),
493 },
494 ConfigField {
495 key: "my_vector_of_int64".into(),
496 value: Vector(Int64Vector(Box::from([-4, -5, 6]))),
497 mutability: Default::default(),
498 },
499 ConfigField {
500 key: "my_vector_of_string".into(),
501 value: Vector(StringVector(Box::from(["valid".into(), "valid".into()]))),
502 mutability: Default::default(),
503 },
504 ],
505 checksum: decl.checksum.clone(),
506 }
507 );
508
509 let encoded = resolved.encode_as_fidl_struct();
510
511 let checksum_len = u16::from_le_bytes(encoded[..2].try_into().unwrap());
512 let struct_start = 2 + checksum_len as usize;
513 assert_eq!(&encoded[2..struct_start], [0; 32]);
514
515 let decoded: BasicSuccessSchema = fidl::unpersist(&encoded[struct_start..]).unwrap();
516 assert_eq!(
517 decoded,
518 BasicSuccessSchema {
519 my_flag: false,
520 my_uint8: 255,
521 my_uint16: 65535,
522 my_uint32: 4000000000,
523 my_uint64: 8000000000,
524 my_int8: -127,
525 my_int16: -32766,
526 my_int32: -2000000000,
527 my_int64: -4000000000,
528 my_string: "hello, world!".into(),
529 my_vector_of_flag: vec![true, false],
530 my_vector_of_uint8: vec![1, 2, 3],
531 my_vector_of_uint16: vec![2, 3, 4],
532 my_vector_of_uint32: vec![3, 4, 5],
533 my_vector_of_uint64: vec![4, 5, 6],
534 my_vector_of_int8: vec![-1, -2, 3],
535 my_vector_of_int16: vec![-2, -3, 4],
536 my_vector_of_int32: vec![-3, -4, 5],
537 my_vector_of_int64: vec![-4, -5, 6],
538 my_vector_of_string: vec!["valid".into(), "valid".into()],
539 }
540 );
541 }
542
543 #[test]
544 fn checksums_must_match() {
545 let expected = ConfigChecksum::Sha256([0; 32]);
546 let received = ConfigChecksum::Sha256([0xFF; 32]);
547 let decl = config_decl! {
548 ck@ expected.clone(),
549 foo: { bool },
550 };
551 let specs = values_data! [
552 ck@ received.clone(),
553 ConfigValue::Single(ConfigSingleValue::Bool(true)),
554 ];
555 assert_eq!(
556 ConfigFields::resolve(&decl, specs, None).unwrap_err(),
557 ResolutionError::ChecksumFailure { expected, received }
558 );
559 }
560
561 #[test]
562 fn too_many_values_fails() {
563 let decl = config_decl! {
564 ck@ ConfigChecksum::Sha256([0; 32]),
565 foo: { bool },
566 };
567 let specs = values_data! [
568 ck@ decl.checksum.clone(),
569 ConfigValue::Single(ConfigSingleValue::Bool(true)),
570 ConfigValue::Single(ConfigSingleValue::Bool(false)),
571 ];
572 assert_eq!(
573 ConfigFields::resolve(&decl, specs, None).unwrap_err(),
574 ResolutionError::WrongNumberOfValues { expected: 1, received: 2 }
575 );
576 }
577
578 #[test]
579 fn not_enough_values_fails() {
580 let decl = config_decl! {
581 ck@ ConfigChecksum::Sha256([0; 32]),
582 foo: { bool },
583 };
584 let specs = values_data! {
585 ck@ decl.checksum.clone(),
586 };
587 assert_eq!(
588 ConfigFields::resolve(&decl, specs, None).unwrap_err(),
589 ResolutionError::WrongNumberOfValues { expected: 1, received: 0 }
590 );
591 }
592
593 #[test]
594 fn string_length_is_validated() {
595 let decl = config_decl! {
596 ck@ ConfigChecksum::Sha256([0; 32]),
597 foo: { string, max_size: 10 },
598 };
599 let specs = values_data! [
600 ck@ decl.checksum.clone(),
601 ConfigValue::Single(ConfigSingleValue::String("hello, world!".into())),
602 ];
603 assert_eq!(
604 ConfigFields::resolve(&decl, specs, None).unwrap_err(),
605 ResolutionError::InvalidValue {
606 key: "foo".into(),
607 source: ValueError::StringTooLong { max: 10, actual: 13 },
608 }
609 );
610 }
611
612 #[test]
613 fn vector_length_is_validated() {
614 let decl = config_decl! {
615 ck@ ConfigChecksum::Sha256([0; 32]),
616 foo: { vector, element: uint8, max_count: 2 },
617 };
618 let specs = values_data! [
619 ck@ decl.checksum.clone(),
620 ConfigValue::Vector(ConfigVectorValue::Uint8Vector(Box::from([1, 2, 3]))),
621 ];
622 assert_eq!(
623 ConfigFields::resolve(&decl, specs, None).unwrap_err(),
624 ResolutionError::InvalidValue {
625 key: "foo".into(),
626 source: ValueError::VectorTooLong { max: 2, actual: 3 },
627 }
628 );
629 }
630
631 #[test]
632 fn vector_elements_validated() {
633 let decl = config_decl! {
634 ck@ ConfigChecksum::Sha256([0; 32]),
635 foo: { vector, element: { string, max_size: 5 }, max_count: 2 },
636 };
637 let specs = values_data! [
638 ck@ decl.checksum.clone(),
639 ConfigValue::Vector(ConfigVectorValue::StringVector(Box::from([
640 "valid".into(),
641 "invalid".into(),
642 ]))),
643 ];
644 assert_eq!(
645 ConfigFields::resolve(&decl, specs, None).unwrap_err(),
646 ResolutionError::InvalidValue {
647 key: "foo".into(),
648 source: ValueError::VectorElementInvalid {
649 offset: 1,
650 source: Box::new(ValueError::StringTooLong { max: 5, actual: 7 })
651 },
652 }
653 );
654 }
655
656 #[test]
657 fn parent_overrides_take_precedence() {
658 let overridden_key = FlyStr::new("my_flag");
659 let defaulted_key = FlyStr::new("my_other_flag");
660 let decl = cm_rust::ConfigDecl {
661 fields: Box::from([
662 cm_rust::ConfigField {
663 key: overridden_key.clone(),
664 type_: cm_rust::ConfigValueType::Bool,
665 mutability: ConfigMutability::PARENT,
666 },
667 cm_rust::ConfigField {
668 key: defaulted_key.clone().into(),
669 type_: cm_rust::ConfigValueType::Bool,
670 mutability: ConfigMutability::empty(),
671 },
672 ]),
673 checksum: ConfigChecksum::Sha256([0; 32]),
674 value_source: cm_rust::ConfigValueSource::PackagePath("fake.cvf".into()),
675 };
676
677 let packaged = values_data![
678 ck@ decl.checksum.clone(),
679 Single(Bool(false)),
680 Single(Bool(false)),
681 ];
682
683 let expected_value = Single(Bool(true));
684 let overrides = vec![ConfigOverride {
685 key: overridden_key.clone().into(),
686 value: expected_value.clone(),
687 }];
688
689 assert_eq!(
690 ConfigFields::resolve(&decl, packaged, Some(&overrides)).unwrap(),
691 ConfigFields {
692 fields: vec![
693 ConfigField {
694 key: overridden_key.clone().into(),
695 value: expected_value,
696 mutability: ConfigMutability::PARENT,
697 },
698 ConfigField {
699 key: defaulted_key.into(),
700 value: Single(Bool(false)),
701 mutability: ConfigMutability::empty(),
702 },
703 ],
704 checksum: decl.checksum.clone(),
705 }
706 );
707 }
708
709 #[test]
710 fn overrides_must_match_declared_fields() {
711 let decl = cm_rust::ConfigDecl {
712 fields: Box::from([cm_rust::ConfigField {
713 key: FlyStr::new("my_flag"),
714 type_: cm_rust::ConfigValueType::Bool,
715 mutability: ConfigMutability::PARENT,
716 }]),
717 checksum: ConfigChecksum::Sha256([0; 32]),
718 value_source: cm_rust::ConfigValueSource::PackagePath("fake.cvf".into()),
719 };
720
721 let packaged = values_data![
722 ck@ decl.checksum.clone(),
723 Single(Bool(false)),
724 ];
725
726 let overridden_key = FlyStr::new("not_my_flag");
727 let expected_value = Single(Bool(true));
728 let overrides = vec![ConfigOverride {
729 key: overridden_key.clone().into(),
730 value: expected_value.clone(),
731 }];
732
733 assert_eq!(
734 ConfigFields::resolve(&decl, packaged, Some(&overrides)).unwrap_err(),
735 ResolutionError::FieldDoesNotExist { key: overridden_key.clone() },
736 );
737 }
738
739 #[test]
740 fn overrides_must_be_for_mutable_by_parent_fields() {
741 let overridden_key = FlyStr::new("my_flag");
742 let defaulted_key = FlyStr::new("my_other_flag");
743 let decl = cm_rust::ConfigDecl {
744 fields: Box::from([
745 cm_rust::ConfigField {
746 key: overridden_key.clone().into(),
747 type_: cm_rust::ConfigValueType::Bool,
748 mutability: ConfigMutability::empty(),
749 },
750 cm_rust::ConfigField {
752 key: defaulted_key.clone().into(),
753 type_: cm_rust::ConfigValueType::Bool,
754 mutability: ConfigMutability::PARENT,
755 },
756 ]),
757 checksum: ConfigChecksum::Sha256([0; 32]),
758 value_source: cm_rust::ConfigValueSource::PackagePath("fake.cvf".into()),
759 };
760
761 let packaged = values_data![
762 ck@ decl.checksum.clone(),
763 Single(Bool(false)),
764 Single(Bool(false)),
765 ];
766
767 let overrides =
768 vec![ConfigOverride { key: overridden_key.clone(), value: Single(Bool(true)) }];
769
770 assert_eq!(
771 ConfigFields::resolve(&decl, packaged, Some(&overrides)).unwrap_err(),
772 ResolutionError::FieldIsNotMutable { key: overridden_key.clone() },
773 );
774 }
775
776 #[test]
777 fn overrides_must_match_declared_type_exactly() {
778 let overridden_key = FlyStr::new("my_flag");
779 let decl = cm_rust::ConfigDecl {
780 fields: Box::from([cm_rust::ConfigField {
781 key: overridden_key.clone().into(),
782 type_: cm_rust::ConfigValueType::Bool,
783 mutability: ConfigMutability::PARENT,
784 }]),
785 checksum: ConfigChecksum::Sha256([0; 32]),
786 value_source: cm_rust::ConfigValueSource::PackagePath("fake.cvf".into()),
787 };
788
789 let packaged = values_data![
790 ck@ decl.checksum.clone(),
791 Single(Bool(false)),
792 ];
793
794 let overrides =
795 vec![ConfigOverride { key: overridden_key.clone().into(), value: Single(Uint8(1)) }];
796
797 assert_eq!(
798 ConfigFields::resolve(&decl, packaged, Some(&overrides)).unwrap_err(),
799 ResolutionError::InvalidValue {
800 key: overridden_key.into(),
801 source: ValueError::TypeMismatch {
802 expected: "Bool".to_string(),
803 received: "Single(Uint8(1))".to_string()
804 },
805 },
806 );
807 }
808
809 macro_rules! type_mismatch_test {
810 ($test_name:ident: { $($ty_toks:tt)* }, $valid_spec:pat) => {
811 #[test]
812 fn $test_name() {
813 let decl = ConfigFieldDecl {
814 key: "test_key".into(),
815 type_: fidl_fuchsia_component_config_ext::config_ty!($($ty_toks)*),
816 mutability: Default::default(),
817 };
818 for value in [
819 Single(Bool(true)),
821 Single(Uint8(1)),
822 Single(Uint16(1)),
823 Single(Uint32(1)),
824 Single(Uint64(1)),
825 Single(Int8(1)),
826 Single(Int16(1)),
827 Single(Int32(1)),
828 Single(Int64(1)),
829 Single(String("".into())),
830 Vector(BoolVector(Box::from([]))),
831 Vector(Uint8Vector(Box::from([]))),
832 Vector(Uint16Vector(Box::from([]))),
833 Vector(Uint32Vector(Box::from([]))),
834 Vector(Uint64Vector(Box::from([]))),
835 Vector(Int8Vector(Box::from([]))),
836 Vector(Int16Vector(Box::from([]))),
837 Vector(Int32Vector(Box::from([]))),
838 Vector(Int64Vector(Box::from([]))),
839 Vector(StringVector(Box::from([]))),
840 ] {
841 let should_succeed = matches!(value, $valid_spec);
842 match ConfigField::resolve(value, &decl) {
843 Ok(..) if should_succeed => (),
844 Err(ValueError::TypeMismatch { .. }) if !should_succeed => (),
845 other => panic!(
846 "test case {:?} received unexpected resolved value {:#?}",
847 decl, other
848 ),
849 }
850 }
851 }
852 };
853 }
854
855 type_mismatch_test!(bool_type_mismatches: { bool }, Single(Bool(..)));
856 type_mismatch_test!(uint8_type_mismatches: { uint8 }, Single(Uint8(..)));
857 type_mismatch_test!(uint16_type_mismatches: { uint16 }, Single(Uint16(..)));
858 type_mismatch_test!(uint32_type_mismatches: { uint32 }, Single(Uint32(..)));
859 type_mismatch_test!(uint64_type_mismatches: { uint64 }, Single(Uint64(..)));
860 type_mismatch_test!(int8_type_mismatches: { int8 }, Single(Int8(..)));
861 type_mismatch_test!(int16_type_mismatches: { int16 }, Single(Int16(..)));
862 type_mismatch_test!(int32_type_mismatches: { int32 }, Single(Int32(..)));
863 type_mismatch_test!(int64_type_mismatches: { int64 }, Single(Int64(..)));
864 type_mismatch_test!(string_type_mismatches: { string, max_size: 10 }, Single(String(..)));
865
866 type_mismatch_test!(
867 bool_vector_type_mismatches: { vector, element: bool, max_count: 1 }, Vector(BoolVector(..))
868 );
869 type_mismatch_test!(
870 uint8_vector_type_mismatches:
871 { vector, element: uint8, max_count: 1 },
872 Vector(Uint8Vector(..))
873 );
874 type_mismatch_test!(
875 uint16_vector_type_mismatches:
876 { vector, element: uint16, max_count: 1 },
877 Vector(Uint16Vector(..))
878 );
879 type_mismatch_test!(
880 uint32_vector_type_mismatches:
881 { vector, element: uint32, max_count: 1 },
882 Vector(Uint32Vector(..))
883 );
884 type_mismatch_test!(
885 uint64_vector_type_mismatches:
886 { vector, element: uint64, max_count: 1 },
887 Vector(Uint64Vector(..))
888 );
889 type_mismatch_test!(
890 int8_vector_type_mismatches:
891 { vector, element: int8, max_count: 1 },
892 Vector(Int8Vector(..))
893 );
894 type_mismatch_test!(
895 int16_vector_type_mismatches:
896 { vector, element: int16, max_count: 1 },
897 Vector(Int16Vector(..))
898 );
899 type_mismatch_test!(
900 int32_vector_type_mismatches:
901 { vector, element: int32, max_count: 1 },
902 Vector(Int32Vector(..))
903 );
904 type_mismatch_test!(
905 int64_vector_type_mismatches:
906 { vector, element: int64, max_count: 1 },
907 Vector(Int64Vector(..))
908 );
909 type_mismatch_test!(
910 string_vector_type_mismatches:
911 { vector, element: { string, max_size: 10 }, max_count: 1 },
912 Vector(StringVector(..))
913 );
914}