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