config_encoder/
lib.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#![warn(missing_docs)]
6
7//! Library for resolving and encoding the runtime configuration values of a component.
8
9use 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/// The resolved configuration for a component.
19#[derive(Clone, Debug, PartialEq)]
20pub struct ConfigFields {
21    /// A list of all resolved fields, in the order of the compiled manifest.
22    pub fields: Vec<ConfigField>,
23    /// A checksum from the compiled manifest.
24    pub checksum: ConfigChecksum,
25}
26
27impl ConfigFields {
28    /// Resolve a component's configuration values according to its declared schema. Should not fail if
29    /// `decl` and `specs` are well-formed.
30    pub fn resolve(
31        decl: &ConfigDecl,
32        base_values: ConfigValuesData,
33        parent_overrides: Option<&Vec<ConfigOverride>>,
34    ) -> Result<Self, ResolutionError> {
35        // base values must have been packaged for the exact same layout as the decl contains
36        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        // ensure we have the correct number of base values for resolving by offset
44        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        // reject overrides which don't match any fields in the schema
52        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            // see if the parent component provided a value
63            let mut from_parent = None;
64            if let Some(parent_overrides) = parent_overrides {
65                for o in parent_overrides {
66                    // parent overrides are resolved according to string key, not index
67                    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            // prefer parent-provided values over packaged values
79            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    /// Encode the resolved fields as a FIDL struct with every field non-nullable.
90    ///
91    /// The first two bytes of the encoded buffer are a little-endian unsigned integer which denotes
92    /// the `checksum_length`. Bytes `2..2+checksum_length` are used to store the declaration
93    /// checksum. All remaining bytes are used to store the FIDL header and struct.
94    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                    // TODO(https://fxbug.dev/42169377) improve string representation too
128                    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                        // TODO(https://fxbug.dev/42169377) improve string representation too
160                        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/// A single resolved configuration field.
185#[derive(Clone, Debug, PartialEq)]
186pub struct ConfigField {
187    /// The configuration field's key.
188    pub key: String,
189
190    /// The configuration field's value.
191    pub value: ConfigValue,
192
193    /// Ways this component's packaged values could have been overridden.
194    pub mutability: ConfigMutability,
195}
196
197impl ConfigField {
198    /// Reconciles a config field schema from the manifest with a value from the value file.
199    /// If the types and constraints don't match, an error is returned.
200    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                // this field having parent mutability should not allow the other field to mutate
737                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                    // one value of each type
806                    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}