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