cml/
lib.rs

1// Copyright 2023 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//! A library of common utilities used by `cmc` and related tools.
6//! To manually regenerate reference documentation from doc comments in
7//! this file, see the instructions at:
8//!
9//!   tools/lib/reference_doc/macro/derive-reference-doc-tests/src/test_data/README.md
10
11pub mod error;
12pub mod features;
13pub mod one_or_many;
14pub mod types;
15pub(crate) mod validate;
16
17#[allow(unused)] // A test-only macro is defined outside of a test builds.
18pub mod translate;
19
20use crate::error::Error;
21use cml_macro::{OneOrMany, Reference};
22use json5format::{FormatOptions, PathOption};
23use maplit::{hashmap, hashset};
24use serde::{Deserialize, Serialize, de, ser};
25use serde_json::{Map, Value};
26use std::fmt;
27use std::hash::Hash;
28use std::num::NonZeroU32;
29use std::str::FromStr;
30use std::sync::Arc;
31
32pub use crate::types::capability::{Capability, CapabilityFromRef, ContextCapability};
33pub use crate::types::capability_id::CapabilityId;
34pub use crate::types::child::Child;
35pub use crate::types::collection::Collection;
36use crate::types::common::{ContextCapabilityClause, ContextSpanned, Origin};
37pub use crate::types::document::{
38    Document, DocumentContext, ParsedDocument, convert_parsed_to_document,
39};
40pub use crate::types::environment::{Environment, ResolverRegistration};
41pub use crate::types::expose::{ContextExpose, Expose};
42pub use crate::types::offer::{
43    Offer, OfferFromRef, OfferToAllCapability, OfferToRef, offer_to_all_from_offer,
44};
45pub use crate::types::program::Program;
46pub use crate::types::r#use::{Use, UseFromRef};
47
48pub use cm_types::{
49    AllowedOffers, Availability, BorrowedName, BoundedName, DeliveryType, DependencyType,
50    Durability, HandleType, Name, NamespacePath, OnTerminate, ParseError, Path, RelativePath,
51    StartupMode, StorageId, Url,
52};
53use error::Location;
54
55pub use crate::one_or_many::OneOrMany;
56pub use crate::translate::{CompileOptions, compile};
57pub use crate::validate::{CapabilityRequirements, MustUseRequirement};
58
59/// Parses a string `buffer` into a [Document]. `file` is used for error reporting.
60pub fn parse_one_document(buffer: &String, file: &std::path::Path) -> Result<Document, Error> {
61    serde_json5::from_str(&buffer).map_err(|e| {
62        let serde_json5::Error::Message { location, msg } = e;
63        let location = location.map(|l| Location { line: l.line, column: l.column });
64        Error::parse(msg, location, Some(file))
65    })
66}
67
68pub fn load_cml_with_context(
69    buffer: &String,
70    file: &std::path::Path,
71) -> Result<DocumentContext, Error> {
72    let file_arc = Arc::new(file.to_path_buf());
73    let parsed_doc: ParsedDocument = json_spanned_value::from_str(&buffer).map_err(|e| {
74        let location = Location { line: e.line(), column: e.column() };
75        Error::parse(e, Some(location), Some(file))
76    })?;
77    let doc = convert_parsed_to_document(parsed_doc, file_arc, buffer);
78    Ok(doc)
79}
80
81/// Parses a string `buffer` into a vector of [Document]. `file` is used for error reporting.
82/// Supports JSON encoded as an array of Document JSON objects.
83pub fn parse_many_documents(
84    buffer: &String,
85    file: &std::path::Path,
86) -> Result<Vec<Document>, Error> {
87    let res: Result<Vec<Document>, _> = serde_json5::from_str(&buffer);
88    match res {
89        Err(_) => {
90            let d = parse_one_document(buffer, file)?;
91            Ok(vec![d])
92        }
93        Ok(docs) => Ok(docs),
94    }
95}
96
97pub fn byte_index_to_location(source: &String, index: usize) -> Location {
98    let mut line = 1usize;
99    let mut column = 1usize;
100
101    for (i, ch) in source.char_indices() {
102        if i == index {
103            break;
104        }
105
106        if ch == '\n' {
107            line += 1;
108            column = 1;
109        } else {
110            column += 1;
111        }
112    }
113
114    return Location { line, column };
115}
116
117/// Generates deserializer for `OneOrMany<Name>`.
118#[derive(OneOrMany, Debug, Clone)]
119#[one_or_many(
120    expected = "a name or nonempty array of names, with unique elements",
121    inner_type = "Name",
122    min_length = 1,
123    unique_items = true
124)]
125pub struct OneOrManyNames;
126
127/// Generates deserializer for `OneOrMany<Path>`.
128#[derive(OneOrMany, Debug, Clone)]
129#[one_or_many(
130    expected = "a path or nonempty array of paths, with unique elements",
131    inner_type = "Path",
132    min_length = 1,
133    unique_items = true
134)]
135pub struct OneOrManyPaths;
136
137/// Generates deserializer for `OneOrMany<EventScope>`.
138#[derive(OneOrMany, Debug, Clone)]
139#[one_or_many(
140    expected = "one or an array of \"#<collection-name>\", or \"#<child-name>\"",
141    inner_type = "EventScope",
142    min_length = 1,
143    unique_items = true
144)]
145pub struct OneOrManyEventScope;
146
147/// A reference in an `offer to` or `exose to`.
148#[derive(Debug, Deserialize, PartialEq, Eq, Hash, Clone, Serialize)]
149#[serde(rename_all = "snake_case")]
150pub enum SourceAvailability {
151    Required,
152    Unknown,
153}
154
155impl Default for SourceAvailability {
156    fn default() -> Self {
157        Self::Required
158    }
159}
160
161impl<T> Canonicalize for Vec<T>
162where
163    T: Canonicalize + CapabilityClause + PathClause,
164{
165    fn canonicalize(&mut self) {
166        // Collapse like-entries into one. Like entries are those that are equal in all fields
167        // but their capability names. Accomplish this by collecting all the names into a vector
168        // keyed by an instance of T with its names removed.
169        let mut to_merge: Vec<(T, Vec<Name>)> = vec![];
170        let mut to_keep: Vec<T> = vec![];
171        self.iter().for_each(|c| {
172            // Any entry with a `path` set cannot be merged with another.
173            if !c.are_many_names_allowed() || c.path().is_some() {
174                to_keep.push(c.clone());
175                return;
176            }
177            let mut names: Vec<Name> = c.names().into_iter().map(Into::into).collect();
178            let mut copy: T = c.clone();
179            copy.set_names(vec![Name::from_str("a").unwrap()]); // The name here is arbitrary.
180            let r = to_merge.iter().position(|(t, _)| t == &copy);
181            match r {
182                Some(i) => to_merge[i].1.append(&mut names),
183                None => to_merge.push((copy, names)),
184            };
185        });
186        let mut merged = to_merge
187            .into_iter()
188            .map(|(mut t, names)| {
189                t.set_names(names);
190                t
191            })
192            .collect::<Vec<_>>();
193        to_keep.append(&mut merged);
194        *self = to_keep;
195
196        self.iter_mut().for_each(|c| c.canonicalize());
197        self.sort_by(|a, b| {
198            // Sort by capability type, then by the name of the first entry for
199            // that type.
200            let a_type = a.capability_type().unwrap();
201            let b_type = b.capability_type().unwrap();
202            a_type.cmp(b_type).then_with(|| {
203                let a_names = a.names();
204                let b_names = b.names();
205                let a_first_name = a_names.first().unwrap();
206                let b_first_name = b_names.first().unwrap();
207                a_first_name.cmp(b_first_name)
208            })
209        });
210    }
211}
212
213/// A relative reference to another object. This is a generic type that can encode any supported
214/// reference subtype. For named references, it holds a reference to the name instead of the name
215/// itself.
216///
217/// Objects of this type are usually derived from conversions of context-specific reference
218/// types that `#[derive(Reference)]`. This type makes it easy to write helper functions that operate on
219/// generic references.
220#[derive(Debug, PartialEq, Eq, Hash, Clone)]
221pub enum AnyRef<'a> {
222    /// A named reference. Parsed as `#name`.
223    Named(&'a BorrowedName),
224    /// A reference to the parent. Parsed as `parent`.
225    Parent,
226    /// A reference to the framework (component manager). Parsed as `framework`.
227    Framework,
228    /// A reference to the debug. Parsed as `debug`.
229    Debug,
230    /// A reference to this component. Parsed as `self`.
231    Self_,
232    /// An intentionally omitted reference.
233    Void,
234    /// A reference to a dictionary. Parsed as a dictionary path.
235    Dictionary(&'a DictionaryRef),
236    /// A reference to a dictionary defined by this component. Parsed as
237    /// `self/<dictionary>`.
238    OwnDictionary(&'a BorrowedName),
239}
240
241/// Format an `AnyRef` as a string.
242impl fmt::Display for AnyRef<'_> {
243    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244        match self {
245            Self::Named(name) => write!(f, "#{}", name),
246            Self::Parent => write!(f, "parent"),
247            Self::Framework => write!(f, "framework"),
248            Self::Debug => write!(f, "debug"),
249            Self::Self_ => write!(f, "self"),
250            Self::Void => write!(f, "void"),
251            Self::Dictionary(d) => write!(f, "{}", d),
252            Self::OwnDictionary(name) => write!(f, "self/{}", name),
253        }
254    }
255}
256
257/// A reference to a (possibly nested) dictionary.
258#[derive(Debug, PartialEq, Eq, Hash, Clone)]
259pub struct DictionaryRef {
260    /// Path to the dictionary relative to `root_dictionary`.
261    pub path: RelativePath,
262    pub root: RootDictionaryRef,
263}
264
265impl<'a> From<&'a DictionaryRef> for AnyRef<'a> {
266    fn from(r: &'a DictionaryRef) -> Self {
267        Self::Dictionary(r)
268    }
269}
270
271impl FromStr for DictionaryRef {
272    type Err = ParseError;
273
274    fn from_str(path: &str) -> Result<Self, ParseError> {
275        match path.find('/') {
276            Some(n) => {
277                let root = path[..n].parse().map_err(|_| ParseError::InvalidValue)?;
278                let path = RelativePath::new(&path[n + 1..])?;
279                Ok(Self { root, path })
280            }
281            None => Err(ParseError::InvalidValue),
282        }
283    }
284}
285
286impl fmt::Display for DictionaryRef {
287    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
288        write!(f, "{}/{}", self.root, self.path)
289    }
290}
291
292impl ser::Serialize for DictionaryRef {
293    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
294    where
295        S: serde::ser::Serializer,
296    {
297        format!("{}", self).serialize(serializer)
298    }
299}
300
301const DICTIONARY_REF_EXPECT_STR: &str = "a path to a dictionary no more \
302    than 4095 characters in length";
303
304impl<'de> de::Deserialize<'de> for DictionaryRef {
305    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
306    where
307        D: de::Deserializer<'de>,
308    {
309        struct Visitor;
310
311        impl<'de> de::Visitor<'de> for Visitor {
312            type Value = DictionaryRef;
313
314            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
315                f.write_str(DICTIONARY_REF_EXPECT_STR)
316            }
317
318            fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
319            where
320                E: de::Error,
321            {
322                s.parse().map_err(|err| match err {
323                    ParseError::InvalidValue => {
324                        E::invalid_value(de::Unexpected::Str(s), &DICTIONARY_REF_EXPECT_STR)
325                    }
326                    ParseError::TooLong | ParseError::Empty => {
327                        E::invalid_length(s.len(), &DICTIONARY_REF_EXPECT_STR)
328                    }
329                    e => {
330                        panic!("unexpected parse error: {:?}", e);
331                    }
332                })
333            }
334        }
335
336        deserializer.deserialize_string(Visitor)
337    }
338}
339
340/// A reference to a root dictionary.
341#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference)]
342#[reference(expected = "\"parent\", \"self\", \"#<child-name>\"")]
343pub enum RootDictionaryRef {
344    /// A reference to a child.
345    Named(Name),
346    /// A reference to the parent.
347    Parent,
348    /// A reference to this component.
349    Self_,
350}
351
352/// The scope of an event.
353#[derive(Debug, PartialEq, Eq, Hash, Clone, Reference, Ord, PartialOrd)]
354#[reference(expected = "\"#<collection-name>\", \"#<child-name>\", or none")]
355pub enum EventScope {
356    /// A reference to a child or a collection.
357    Named(Name),
358}
359
360#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
361#[serde(rename_all = "snake_case")]
362pub enum ConfigType {
363    Bool,
364    Uint8,
365    Uint16,
366    Uint32,
367    Uint64,
368    Int8,
369    Int16,
370    Int32,
371    Int64,
372    String,
373    Vector,
374}
375
376impl From<&cm_rust::ConfigValueType> for ConfigType {
377    fn from(value: &cm_rust::ConfigValueType) -> Self {
378        match value {
379            cm_rust::ConfigValueType::Bool => ConfigType::Bool,
380            cm_rust::ConfigValueType::Uint8 => ConfigType::Uint8,
381            cm_rust::ConfigValueType::Int8 => ConfigType::Int8,
382            cm_rust::ConfigValueType::Uint16 => ConfigType::Uint16,
383            cm_rust::ConfigValueType::Int16 => ConfigType::Int16,
384            cm_rust::ConfigValueType::Uint32 => ConfigType::Uint32,
385            cm_rust::ConfigValueType::Int32 => ConfigType::Int32,
386            cm_rust::ConfigValueType::Uint64 => ConfigType::Uint64,
387            cm_rust::ConfigValueType::Int64 => ConfigType::Int64,
388            cm_rust::ConfigValueType::String { .. } => ConfigType::String,
389            cm_rust::ConfigValueType::Vector { .. } => ConfigType::Vector,
390        }
391    }
392}
393
394#[derive(Clone, Deserialize, Debug, PartialEq, Serialize)]
395#[serde(tag = "type", deny_unknown_fields, rename_all = "lowercase")]
396pub enum ConfigNestedValueType {
397    Bool {},
398    Uint8 {},
399    Uint16 {},
400    Uint32 {},
401    Uint64 {},
402    Int8 {},
403    Int16 {},
404    Int32 {},
405    Int64 {},
406    String { max_size: NonZeroU32 },
407}
408
409impl ConfigNestedValueType {
410    /// Update the hasher by digesting the ConfigVectorElementType enum value
411    pub fn update_digest(&self, hasher: &mut impl sha2::Digest) {
412        let val = match self {
413            ConfigNestedValueType::Bool {} => 0u8,
414            ConfigNestedValueType::Uint8 {} => 1u8,
415            ConfigNestedValueType::Uint16 {} => 2u8,
416            ConfigNestedValueType::Uint32 {} => 3u8,
417            ConfigNestedValueType::Uint64 {} => 4u8,
418            ConfigNestedValueType::Int8 {} => 5u8,
419            ConfigNestedValueType::Int16 {} => 6u8,
420            ConfigNestedValueType::Int32 {} => 7u8,
421            ConfigNestedValueType::Int64 {} => 8u8,
422            ConfigNestedValueType::String { max_size } => {
423                hasher.update(max_size.get().to_le_bytes());
424                9u8
425            }
426        };
427        hasher.update([val])
428    }
429}
430
431impl From<ConfigNestedValueType> for cm_rust::ConfigNestedValueType {
432    fn from(value: ConfigNestedValueType) -> Self {
433        match value {
434            ConfigNestedValueType::Bool {} => cm_rust::ConfigNestedValueType::Bool,
435            ConfigNestedValueType::Uint8 {} => cm_rust::ConfigNestedValueType::Uint8,
436            ConfigNestedValueType::Uint16 {} => cm_rust::ConfigNestedValueType::Uint16,
437            ConfigNestedValueType::Uint32 {} => cm_rust::ConfigNestedValueType::Uint32,
438            ConfigNestedValueType::Uint64 {} => cm_rust::ConfigNestedValueType::Uint64,
439            ConfigNestedValueType::Int8 {} => cm_rust::ConfigNestedValueType::Int8,
440            ConfigNestedValueType::Int16 {} => cm_rust::ConfigNestedValueType::Int16,
441            ConfigNestedValueType::Int32 {} => cm_rust::ConfigNestedValueType::Int32,
442            ConfigNestedValueType::Int64 {} => cm_rust::ConfigNestedValueType::Int64,
443            ConfigNestedValueType::String { max_size } => {
444                cm_rust::ConfigNestedValueType::String { max_size: max_size.into() }
445            }
446        }
447    }
448}
449
450impl TryFrom<&cm_rust::ConfigNestedValueType> for ConfigNestedValueType {
451    type Error = ();
452    fn try_from(nested: &cm_rust::ConfigNestedValueType) -> Result<Self, ()> {
453        Ok(match nested {
454            cm_rust::ConfigNestedValueType::Bool => ConfigNestedValueType::Bool {},
455            cm_rust::ConfigNestedValueType::Uint8 => ConfigNestedValueType::Uint8 {},
456            cm_rust::ConfigNestedValueType::Int8 => ConfigNestedValueType::Int8 {},
457            cm_rust::ConfigNestedValueType::Uint16 => ConfigNestedValueType::Uint16 {},
458            cm_rust::ConfigNestedValueType::Int16 => ConfigNestedValueType::Int16 {},
459            cm_rust::ConfigNestedValueType::Uint32 => ConfigNestedValueType::Uint32 {},
460            cm_rust::ConfigNestedValueType::Int32 => ConfigNestedValueType::Int32 {},
461            cm_rust::ConfigNestedValueType::Uint64 => ConfigNestedValueType::Uint64 {},
462            cm_rust::ConfigNestedValueType::Int64 => ConfigNestedValueType::Int64 {},
463            cm_rust::ConfigNestedValueType::String { max_size } => {
464                ConfigNestedValueType::String { max_size: NonZeroU32::new(*max_size).ok_or(())? }
465            }
466        })
467    }
468}
469
470#[derive(Clone, Hash, Debug, PartialEq, PartialOrd, Eq, Ord, Serialize)]
471pub struct ConfigKey(String);
472
473impl ConfigKey {
474    pub fn as_str(&self) -> &str {
475        self.0.as_str()
476    }
477}
478
479impl std::fmt::Display for ConfigKey {
480    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
481        write!(f, "{}", self.0)
482    }
483}
484
485impl FromStr for ConfigKey {
486    type Err = ParseError;
487
488    fn from_str(s: &str) -> Result<Self, ParseError> {
489        let length = s.len();
490        if length == 0 {
491            return Err(ParseError::Empty);
492        }
493        if length > 64 {
494            return Err(ParseError::TooLong);
495        }
496
497        // identifiers must start with a letter
498        let first_is_letter = s.chars().next().expect("non-empty string").is_ascii_lowercase();
499        // can contain letters, numbers, and underscores
500        let contains_invalid_chars =
501            s.chars().any(|c| !(c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_'));
502        // cannot end with an underscore
503        let last_is_underscore = s.chars().next_back().expect("non-empty string") == '_';
504
505        if !first_is_letter || contains_invalid_chars || last_is_underscore {
506            return Err(ParseError::InvalidValue);
507        }
508
509        Ok(Self(s.to_string()))
510    }
511}
512
513impl<'de> de::Deserialize<'de> for ConfigKey {
514    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
515    where
516        D: de::Deserializer<'de>,
517    {
518        struct Visitor;
519
520        impl<'de> de::Visitor<'de> for Visitor {
521            type Value = ConfigKey;
522
523            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
524                f.write_str(
525                    "a non-empty string no more than 64 characters in length, which must \
526                    start with a letter, can contain letters, numbers, and underscores, \
527                    but cannot end with an underscore",
528                )
529            }
530
531            fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
532            where
533                E: de::Error,
534            {
535                s.parse().map_err(|err| match err {
536                    ParseError::InvalidValue => E::invalid_value(
537                        de::Unexpected::Str(s),
538                        &"a name which must start with a letter, can contain letters, \
539                        numbers, and underscores, but cannot end with an underscore",
540                    ),
541                    ParseError::TooLong | ParseError::Empty => E::invalid_length(
542                        s.len(),
543                        &"a non-empty name no more than 64 characters in length",
544                    ),
545                    e => {
546                        panic!("unexpected parse error: {:?}", e);
547                    }
548                })
549            }
550        }
551        deserializer.deserialize_string(Visitor)
552    }
553}
554
555#[derive(Clone, Deserialize, Debug, PartialEq, Serialize)]
556#[serde(deny_unknown_fields, rename_all = "lowercase")]
557pub enum ConfigRuntimeSource {
558    Parent,
559}
560
561#[derive(Clone, Deserialize, Debug, PartialEq, Serialize)]
562#[serde(tag = "type", deny_unknown_fields, rename_all = "lowercase")]
563pub enum ConfigValueType {
564    Bool {
565        mutability: Option<Vec<ConfigRuntimeSource>>,
566    },
567    Uint8 {
568        mutability: Option<Vec<ConfigRuntimeSource>>,
569    },
570    Uint16 {
571        mutability: Option<Vec<ConfigRuntimeSource>>,
572    },
573    Uint32 {
574        mutability: Option<Vec<ConfigRuntimeSource>>,
575    },
576    Uint64 {
577        mutability: Option<Vec<ConfigRuntimeSource>>,
578    },
579    Int8 {
580        mutability: Option<Vec<ConfigRuntimeSource>>,
581    },
582    Int16 {
583        mutability: Option<Vec<ConfigRuntimeSource>>,
584    },
585    Int32 {
586        mutability: Option<Vec<ConfigRuntimeSource>>,
587    },
588    Int64 {
589        mutability: Option<Vec<ConfigRuntimeSource>>,
590    },
591    String {
592        max_size: NonZeroU32,
593        mutability: Option<Vec<ConfigRuntimeSource>>,
594    },
595    Vector {
596        max_count: NonZeroU32,
597        element: ConfigNestedValueType,
598        mutability: Option<Vec<ConfigRuntimeSource>>,
599    },
600}
601
602impl ConfigValueType {
603    /// Update the hasher by digesting the ConfigValueType enum value
604    pub fn update_digest(&self, hasher: &mut impl sha2::Digest) {
605        let val = match self {
606            ConfigValueType::Bool { .. } => 0u8,
607            ConfigValueType::Uint8 { .. } => 1u8,
608            ConfigValueType::Uint16 { .. } => 2u8,
609            ConfigValueType::Uint32 { .. } => 3u8,
610            ConfigValueType::Uint64 { .. } => 4u8,
611            ConfigValueType::Int8 { .. } => 5u8,
612            ConfigValueType::Int16 { .. } => 6u8,
613            ConfigValueType::Int32 { .. } => 7u8,
614            ConfigValueType::Int64 { .. } => 8u8,
615            ConfigValueType::String { max_size, .. } => {
616                hasher.update(max_size.get().to_le_bytes());
617                9u8
618            }
619            ConfigValueType::Vector { max_count, element, .. } => {
620                hasher.update(max_count.get().to_le_bytes());
621                element.update_digest(hasher);
622                10u8
623            }
624        };
625        hasher.update([val])
626    }
627}
628
629impl From<ConfigValueType> for cm_rust::ConfigValueType {
630    fn from(value: ConfigValueType) -> Self {
631        match value {
632            ConfigValueType::Bool { .. } => cm_rust::ConfigValueType::Bool,
633            ConfigValueType::Uint8 { .. } => cm_rust::ConfigValueType::Uint8,
634            ConfigValueType::Uint16 { .. } => cm_rust::ConfigValueType::Uint16,
635            ConfigValueType::Uint32 { .. } => cm_rust::ConfigValueType::Uint32,
636            ConfigValueType::Uint64 { .. } => cm_rust::ConfigValueType::Uint64,
637            ConfigValueType::Int8 { .. } => cm_rust::ConfigValueType::Int8,
638            ConfigValueType::Int16 { .. } => cm_rust::ConfigValueType::Int16,
639            ConfigValueType::Int32 { .. } => cm_rust::ConfigValueType::Int32,
640            ConfigValueType::Int64 { .. } => cm_rust::ConfigValueType::Int64,
641            ConfigValueType::String { max_size, .. } => {
642                cm_rust::ConfigValueType::String { max_size: max_size.into() }
643            }
644            ConfigValueType::Vector { max_count, element, .. } => {
645                cm_rust::ConfigValueType::Vector {
646                    max_count: max_count.into(),
647                    nested_type: element.into(),
648                }
649            }
650        }
651    }
652}
653
654pub trait FromClause {
655    fn from_(&self) -> OneOrMany<AnyRef<'_>>;
656}
657
658pub trait FromClauseContext {
659    fn from_(&self) -> ContextSpanned<OneOrMany<AnyRef<'_>>>;
660}
661
662pub trait CapabilityClause: Clone + PartialEq + std::fmt::Debug {
663    fn service(&self) -> Option<OneOrMany<&BorrowedName>>;
664    fn protocol(&self) -> Option<OneOrMany<&BorrowedName>>;
665    fn directory(&self) -> Option<OneOrMany<&BorrowedName>>;
666    fn storage(&self) -> Option<OneOrMany<&BorrowedName>>;
667    fn runner(&self) -> Option<OneOrMany<&BorrowedName>>;
668    fn resolver(&self) -> Option<OneOrMany<&BorrowedName>>;
669    fn event_stream(&self) -> Option<OneOrMany<&BorrowedName>>;
670    fn dictionary(&self) -> Option<OneOrMany<&BorrowedName>>;
671    fn config(&self) -> Option<OneOrMany<&BorrowedName>>;
672    fn set_service(&mut self, o: Option<OneOrMany<Name>>);
673    fn set_protocol(&mut self, o: Option<OneOrMany<Name>>);
674    fn set_directory(&mut self, o: Option<OneOrMany<Name>>);
675    fn set_storage(&mut self, o: Option<OneOrMany<Name>>);
676    fn set_runner(&mut self, o: Option<OneOrMany<Name>>);
677    fn set_resolver(&mut self, o: Option<OneOrMany<Name>>);
678    fn set_event_stream(&mut self, o: Option<OneOrMany<Name>>);
679    fn set_dictionary(&mut self, o: Option<OneOrMany<Name>>);
680    fn set_config(&mut self, o: Option<OneOrMany<Name>>);
681
682    fn availability(&self) -> Option<Availability>;
683    fn set_availability(&mut self, a: Option<Availability>);
684
685    /// Returns the name of the capability for display purposes.
686    /// If `service()` returns `Some`, the capability name must be "service", etc.
687    ///
688    /// Returns an error if the capability name is not set, or if there is more than one.
689    fn capability_type(&self) -> Result<&'static str, Error> {
690        let mut types = Vec::new();
691        if self.service().is_some() {
692            types.push("service");
693        }
694        if self.protocol().is_some() {
695            types.push("protocol");
696        }
697        if self.directory().is_some() {
698            types.push("directory");
699        }
700        if self.storage().is_some() {
701            types.push("storage");
702        }
703        if self.event_stream().is_some() {
704            types.push("event_stream");
705        }
706        if self.runner().is_some() {
707            types.push("runner");
708        }
709        if self.config().is_some() {
710            types.push("config");
711        }
712        if self.resolver().is_some() {
713            types.push("resolver");
714        }
715        if self.dictionary().is_some() {
716            types.push("dictionary");
717        }
718        match types.len() {
719            0 => {
720                let supported_keywords = self
721                    .supported()
722                    .into_iter()
723                    .map(|k| format!("\"{}\"", k))
724                    .collect::<Vec<_>>()
725                    .join(", ");
726                Err(Error::validate(format!(
727                    "`{}` declaration is missing a capability keyword, one of: {}",
728                    self.decl_type(),
729                    supported_keywords,
730                )))
731            }
732            1 => Ok(types[0]),
733            _ => Err(Error::validate(format!(
734                "{} declaration has multiple capability types defined: {:?}",
735                self.decl_type(),
736                types
737            ))),
738        }
739    }
740
741    /// Returns true if this capability type allows the ::Many variant of OneOrMany.
742    fn are_many_names_allowed(&self) -> bool;
743
744    fn decl_type(&self) -> &'static str;
745    fn supported(&self) -> &[&'static str];
746
747    /// Returns the names of the capabilities in this clause.
748    /// If `protocol()` returns `Some(OneOrMany::Many(vec!["a", "b"]))`, this returns!["a", "b"].
749    fn names(&self) -> Vec<&BorrowedName> {
750        let res = vec![
751            self.service(),
752            self.protocol(),
753            self.directory(),
754            self.storage(),
755            self.runner(),
756            self.config(),
757            self.resolver(),
758            self.event_stream(),
759            self.dictionary(),
760        ];
761        res.into_iter()
762            .map(|o| o.map(|o| o.into_iter().collect::<Vec<&BorrowedName>>()).unwrap_or(vec![]))
763            .flatten()
764            .collect()
765    }
766
767    fn set_names(&mut self, names: Vec<Name>) {
768        let names = match names.len() {
769            0 => None,
770            1 => Some(OneOrMany::One(names.first().unwrap().clone())),
771            _ => Some(OneOrMany::Many(names)),
772        };
773
774        let cap_type = self.capability_type().unwrap();
775        if cap_type == "protocol" {
776            self.set_protocol(names);
777        } else if cap_type == "service" {
778            self.set_service(names);
779        } else if cap_type == "directory" {
780            self.set_directory(names);
781        } else if cap_type == "storage" {
782            self.set_storage(names);
783        } else if cap_type == "runner" {
784            self.set_runner(names);
785        } else if cap_type == "resolver" {
786            self.set_resolver(names);
787        } else if cap_type == "event_stream" {
788            self.set_event_stream(names);
789        } else if cap_type == "dictionary" {
790            self.set_dictionary(names);
791        } else if cap_type == "config" {
792            self.set_config(names);
793        } else {
794            panic!("Unknown capability type {}", cap_type);
795        }
796    }
797}
798
799trait Canonicalize {
800    fn canonicalize(&mut self);
801}
802
803pub trait AsClause {
804    fn r#as(&self) -> Option<&BorrowedName>;
805}
806
807pub trait AsClauseContext {
808    fn r#as(&self) -> Option<ContextSpanned<&BorrowedName>>;
809}
810
811pub trait PathClause {
812    fn path(&self) -> Option<&Path>;
813}
814
815pub trait FilterClause {
816    fn filter(&self) -> Option<&Map<String, Value>>;
817}
818
819pub fn alias_or_name<'a>(
820    alias: Option<&'a BorrowedName>,
821    name: &'a BorrowedName,
822) -> &'a BorrowedName {
823    alias.unwrap_or(name)
824}
825
826pub fn alias_or_name_context<'a>(
827    alias: Option<ContextSpanned<&'a BorrowedName>>,
828    name: &'a BorrowedName,
829    origin: Origin,
830) -> ContextSpanned<&'a BorrowedName> {
831    alias.unwrap_or(ContextSpanned { value: name, origin })
832}
833
834pub fn alias_or_path<'a>(alias: Option<&'a Path>, path: &'a Path) -> &'a Path {
835    alias.unwrap_or(path)
836}
837
838pub fn format_cml(buffer: &str, file: Option<&std::path::Path>) -> Result<Vec<u8>, Error> {
839    let general_order = PathOption::PropertyNameOrder(vec![
840        "name",
841        "url",
842        "startup",
843        "environment",
844        "config",
845        "dictionary",
846        "durability",
847        "service",
848        "protocol",
849        "directory",
850        "storage",
851        "runner",
852        "resolver",
853        "event",
854        "event_stream",
855        "from",
856        "as",
857        "to",
858        "rights",
859        "path",
860        "subdir",
861        "filter",
862        "dependency",
863        "extends",
864        "runners",
865        "resolvers",
866        "debug",
867    ]);
868    let options = FormatOptions {
869        collapse_containers_of_one: true,
870        sort_array_items: true, // but use options_by_path to turn this off for program args
871        options_by_path: hashmap! {
872            "/*" => hashset! {
873                PathOption::PropertyNameOrder(vec![
874                    "include",
875                    "program",
876                    "children",
877                    "collections",
878                    "capabilities",
879                    "use",
880                    "offer",
881                    "expose",
882                    "environments",
883                    "facets",
884                ])
885            },
886            "/*/program" => hashset! {
887                PathOption::CollapseContainersOfOne(false),
888                PathOption::PropertyNameOrder(vec![
889                    "runner",
890                    "binary",
891                    "args",
892                ]),
893            },
894            "/*/program/*" => hashset! {
895                PathOption::SortArrayItems(false),
896            },
897            "/*/*/*" => hashset! {
898                general_order.clone()
899            },
900            "/*/*/*/*/*" => hashset! {
901                general_order
902            },
903        },
904        ..Default::default()
905    };
906
907    json5format::format(buffer, file.map(|f| f.to_string_lossy().to_string()), Some(options))
908        .map_err(|e| Error::json5(e, file))
909}
910
911#[cfg(test)]
912mod tests {
913    use super::*;
914    use crate::types::document::Document;
915    use crate::types::environment::RunnerRegistration;
916    use crate::types::right::Right;
917    use assert_matches::assert_matches;
918    use difference::Changeset;
919    use fidl_fuchsia_io as fio;
920    use serde_json::{json, to_string_pretty, to_value};
921    use std::path;
922    use std::path::Path;
923    use test_case::test_case;
924
925    macro_rules! assert_json_eq {
926        ($a:expr, $e:expr) => {{
927            if $a != $e {
928                let expected = to_string_pretty(&$e).unwrap();
929                let actual = to_string_pretty(&$a).unwrap();
930                assert_eq!(
931                    $a,
932                    $e,
933                    "JSON actual != expected. Diffs:\n\n{}",
934                    Changeset::new(&actual, &expected, "\n")
935                );
936            }
937        }};
938    }
939
940    // Exercise reference parsing tests on `OfferFromRef` because it contains every reference
941    // subtype.
942
943    #[test]
944    fn test_parse_named_reference() {
945        assert_matches!("#some-child".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "some-child");
946        assert_matches!("#A".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "A");
947        assert_matches!("#7".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "7");
948        assert_matches!("#_".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "_");
949
950        assert_matches!("#-".parse::<OfferFromRef>(), Err(_));
951        assert_matches!("#.".parse::<OfferFromRef>(), Err(_));
952        assert_matches!("#".parse::<OfferFromRef>(), Err(_));
953        assert_matches!("some-child".parse::<OfferFromRef>(), Err(_));
954    }
955
956    #[test]
957    fn test_parse_reference_test() {
958        assert_matches!("parent".parse::<OfferFromRef>(), Ok(OfferFromRef::Parent));
959        assert_matches!("framework".parse::<OfferFromRef>(), Ok(OfferFromRef::Framework));
960        assert_matches!("self".parse::<OfferFromRef>(), Ok(OfferFromRef::Self_));
961        assert_matches!("#child".parse::<OfferFromRef>(), Ok(OfferFromRef::Named(name)) if name == "child");
962
963        assert_matches!("invalid".parse::<OfferFromRef>(), Err(_));
964        assert_matches!("#invalid-child^".parse::<OfferFromRef>(), Err(_));
965    }
966
967    fn json_value_from_str(json: &str, filename: &Path) -> Result<Value, Error> {
968        serde_json::from_str(json).map_err(|e| {
969            Error::parse(
970                format!("Couldn't read input as JSON: {}", e),
971                Some(Location { line: e.line(), column: e.column() }),
972                Some(filename),
973            )
974        })
975    }
976
977    fn parse_as_ref(input: &str) -> Result<OfferFromRef, Error> {
978        serde_json::from_value::<OfferFromRef>(json_value_from_str(input, &Path::new("test.cml"))?)
979            .map_err(|e| Error::parse(format!("{}", e), None, None))
980    }
981
982    #[test]
983    fn test_deserialize_ref() -> Result<(), Error> {
984        assert_matches!(parse_as_ref("\"self\""), Ok(OfferFromRef::Self_));
985        assert_matches!(parse_as_ref("\"parent\""), Ok(OfferFromRef::Parent));
986        assert_matches!(parse_as_ref("\"#child\""), Ok(OfferFromRef::Named(name)) if name == "child");
987
988        assert_matches!(parse_as_ref(r#""invalid""#), Err(_));
989
990        Ok(())
991    }
992
993    macro_rules! test_parse_rights {
994        (
995            $(
996                ($input:expr, $expected:expr),
997            )+
998        ) => {
999            #[test]
1000            fn parse_rights() {
1001                $(
1002                    parse_rights_test($input, $expected);
1003                )+
1004            }
1005        }
1006    }
1007
1008    fn parse_rights_test(input: &str, expected: Right) {
1009        let r: Right = serde_json5::from_str(&format!("\"{}\"", input)).expect("invalid json");
1010        assert_eq!(r, expected);
1011    }
1012
1013    test_parse_rights! {
1014        ("connect", Right::Connect),
1015        ("enumerate", Right::Enumerate),
1016        ("execute", Right::Execute),
1017        ("get_attributes", Right::GetAttributes),
1018        ("modify_directory", Right::ModifyDirectory),
1019        ("read_bytes", Right::ReadBytes),
1020        ("traverse", Right::Traverse),
1021        ("update_attributes", Right::UpdateAttributes),
1022        ("write_bytes", Right::WriteBytes),
1023        ("r*", Right::ReadAlias),
1024        ("w*", Right::WriteAlias),
1025        ("x*", Right::ExecuteAlias),
1026        ("rw*", Right::ReadWriteAlias),
1027        ("rx*", Right::ReadExecuteAlias),
1028    }
1029
1030    macro_rules! test_expand_rights {
1031        (
1032            $(
1033                ($input:expr, $expected:expr),
1034            )+
1035        ) => {
1036            #[test]
1037            fn expand_rights() {
1038                $(
1039                    expand_rights_test($input, $expected);
1040                )+
1041            }
1042        }
1043    }
1044
1045    fn expand_rights_test(input: Right, expected: Vec<fio::Operations>) {
1046        assert_eq!(input.expand(), expected);
1047    }
1048
1049    test_expand_rights! {
1050        (Right::Connect, vec![fio::Operations::CONNECT]),
1051        (Right::Enumerate, vec![fio::Operations::ENUMERATE]),
1052        (Right::Execute, vec![fio::Operations::EXECUTE]),
1053        (Right::GetAttributes, vec![fio::Operations::GET_ATTRIBUTES]),
1054        (Right::ModifyDirectory, vec![fio::Operations::MODIFY_DIRECTORY]),
1055        (Right::ReadBytes, vec![fio::Operations::READ_BYTES]),
1056        (Right::Traverse, vec![fio::Operations::TRAVERSE]),
1057        (Right::UpdateAttributes, vec![fio::Operations::UPDATE_ATTRIBUTES]),
1058        (Right::WriteBytes, vec![fio::Operations::WRITE_BYTES]),
1059        (Right::ReadAlias, vec![
1060            fio::Operations::CONNECT,
1061            fio::Operations::ENUMERATE,
1062            fio::Operations::TRAVERSE,
1063            fio::Operations::READ_BYTES,
1064            fio::Operations::GET_ATTRIBUTES,
1065        ]),
1066        (Right::WriteAlias, vec![
1067            fio::Operations::CONNECT,
1068            fio::Operations::ENUMERATE,
1069            fio::Operations::TRAVERSE,
1070            fio::Operations::WRITE_BYTES,
1071            fio::Operations::MODIFY_DIRECTORY,
1072            fio::Operations::UPDATE_ATTRIBUTES,
1073        ]),
1074        (Right::ExecuteAlias, vec![
1075            fio::Operations::CONNECT,
1076            fio::Operations::ENUMERATE,
1077            fio::Operations::TRAVERSE,
1078            fio::Operations::EXECUTE,
1079        ]),
1080        (Right::ReadWriteAlias, vec![
1081            fio::Operations::CONNECT,
1082            fio::Operations::ENUMERATE,
1083            fio::Operations::TRAVERSE,
1084            fio::Operations::READ_BYTES,
1085            fio::Operations::WRITE_BYTES,
1086            fio::Operations::MODIFY_DIRECTORY,
1087            fio::Operations::GET_ATTRIBUTES,
1088            fio::Operations::UPDATE_ATTRIBUTES,
1089        ]),
1090        (Right::ReadExecuteAlias, vec![
1091            fio::Operations::CONNECT,
1092            fio::Operations::ENUMERATE,
1093            fio::Operations::TRAVERSE,
1094            fio::Operations::READ_BYTES,
1095            fio::Operations::GET_ATTRIBUTES,
1096            fio::Operations::EXECUTE,
1097        ]),
1098    }
1099
1100    #[test]
1101    fn test_deny_unknown_fields() {
1102        assert_matches!(serde_json5::from_str::<Document>("{ unknown: \"\" }"), Err(_));
1103        assert_matches!(serde_json5::from_str::<Environment>("{ unknown: \"\" }"), Err(_));
1104        assert_matches!(serde_json5::from_str::<RunnerRegistration>("{ unknown: \"\" }"), Err(_));
1105        assert_matches!(serde_json5::from_str::<ResolverRegistration>("{ unknown: \"\" }"), Err(_));
1106        assert_matches!(serde_json5::from_str::<Use>("{ unknown: \"\" }"), Err(_));
1107        assert_matches!(serde_json5::from_str::<Expose>("{ unknown: \"\" }"), Err(_));
1108        assert_matches!(serde_json5::from_str::<Offer>("{ unknown: \"\" }"), Err(_));
1109        assert_matches!(serde_json5::from_str::<Capability>("{ unknown: \"\" }"), Err(_));
1110        assert_matches!(serde_json5::from_str::<Child>("{ unknown: \"\" }"), Err(_));
1111        assert_matches!(serde_json5::from_str::<Collection>("{ unknown: \"\" }"), Err(_));
1112    }
1113
1114    // TODO: Use Default::default() instead
1115
1116    fn empty_offer() -> Offer {
1117        Offer {
1118            service: None,
1119            protocol: None,
1120            directory: None,
1121            storage: None,
1122            runner: None,
1123            resolver: None,
1124            dictionary: None,
1125            config: None,
1126            from: OneOrMany::One(OfferFromRef::Self_),
1127            to: OneOrMany::Many(vec![]),
1128            r#as: None,
1129            rights: None,
1130            subdir: None,
1131            dependency: None,
1132            event_stream: None,
1133            scope: None,
1134            availability: None,
1135            source_availability: None,
1136            target_availability: None,
1137        }
1138    }
1139
1140    fn empty_use() -> Use {
1141        Use {
1142            service: None,
1143            protocol: None,
1144            scope: None,
1145            directory: None,
1146            storage: None,
1147            config: None,
1148            dictionary: None,
1149            key: None,
1150            from: None,
1151            path: None,
1152            numbered_handle: None,
1153            rights: None,
1154            subdir: None,
1155            event_stream: None,
1156            runner: None,
1157            filter: None,
1158            dependency: None,
1159            availability: None,
1160            config_element_type: None,
1161            config_max_count: None,
1162            config_max_size: None,
1163            config_type: None,
1164            config_default: None,
1165        }
1166    }
1167
1168    #[test]
1169    fn test_capability_id() -> Result<(), Error> {
1170        // service
1171        let a: Name = "a".parse().unwrap();
1172        let b: Name = "b".parse().unwrap();
1173        assert_eq!(
1174            CapabilityId::from_offer_expose(&Offer {
1175                service: Some(OneOrMany::One(a.clone())),
1176                ..empty_offer()
1177            },)?,
1178            vec![CapabilityId::Service(&a)]
1179        );
1180        assert_eq!(
1181            CapabilityId::from_offer_expose(&Offer {
1182                service: Some(OneOrMany::Many(vec![a.clone(), b.clone()],)),
1183                ..empty_offer()
1184            },)?,
1185            vec![CapabilityId::Service(&a), CapabilityId::Service(&b)]
1186        );
1187        assert_eq!(
1188            CapabilityId::from_use(&Use {
1189                service: Some(OneOrMany::One(a.clone())),
1190                ..empty_use()
1191            },)?,
1192            vec![CapabilityId::UsedService("/svc/a".parse().unwrap())]
1193        );
1194        assert_eq!(
1195            CapabilityId::from_use(&Use {
1196                service: Some(OneOrMany::Many(vec![a.clone(), b.clone(),],)),
1197                ..empty_use()
1198            },)?,
1199            vec![
1200                CapabilityId::UsedService("/svc/a".parse().unwrap()),
1201                CapabilityId::UsedService("/svc/b".parse().unwrap())
1202            ]
1203        );
1204        assert_eq!(
1205            CapabilityId::from_use(&Use {
1206                event_stream: Some(OneOrMany::One(Name::new("test".to_string()).unwrap())),
1207                path: Some(cm_types::Path::new("/svc/myevent".to_string()).unwrap()),
1208                ..empty_use()
1209            },)?,
1210            vec![CapabilityId::UsedEventStream("/svc/myevent".parse().unwrap()),]
1211        );
1212        assert_eq!(
1213            CapabilityId::from_use(&Use {
1214                event_stream: Some(OneOrMany::One(Name::new("test".to_string()).unwrap())),
1215                ..empty_use()
1216            },)?,
1217            vec![CapabilityId::UsedEventStream(
1218                "/svc/fuchsia.component.EventStream".parse().unwrap()
1219            ),]
1220        );
1221        assert_eq!(
1222            CapabilityId::from_use(&Use {
1223                service: Some(OneOrMany::One(a.clone())),
1224                path: Some("/b".parse().unwrap()),
1225                ..empty_use()
1226            },)?,
1227            vec![CapabilityId::UsedService("/b".parse().unwrap())]
1228        );
1229
1230        // protocol
1231        assert_eq!(
1232            CapabilityId::from_offer_expose(&Offer {
1233                protocol: Some(OneOrMany::One(a.clone())),
1234                ..empty_offer()
1235            },)?,
1236            vec![CapabilityId::Protocol(&a)]
1237        );
1238        assert_eq!(
1239            CapabilityId::from_offer_expose(&Offer {
1240                protocol: Some(OneOrMany::Many(vec![a.clone(), b.clone()],)),
1241                ..empty_offer()
1242            },)?,
1243            vec![CapabilityId::Protocol(&a), CapabilityId::Protocol(&b)]
1244        );
1245        assert_eq!(
1246            CapabilityId::from_use(&Use {
1247                protocol: Some(OneOrMany::One(a.clone())),
1248                ..empty_use()
1249            },)?,
1250            vec![CapabilityId::UsedProtocol("/svc/a".parse().unwrap())]
1251        );
1252        assert_eq!(
1253            CapabilityId::from_use(&Use {
1254                protocol: Some(OneOrMany::Many(vec![a.clone(), b.clone(),],)),
1255                ..empty_use()
1256            },)?,
1257            vec![
1258                CapabilityId::UsedProtocol("/svc/a".parse().unwrap()),
1259                CapabilityId::UsedProtocol("/svc/b".parse().unwrap())
1260            ]
1261        );
1262        assert_eq!(
1263            CapabilityId::from_use(&Use {
1264                protocol: Some(OneOrMany::One(a.clone())),
1265                path: Some("/b".parse().unwrap()),
1266                ..empty_use()
1267            },)?,
1268            vec![CapabilityId::UsedProtocol("/b".parse().unwrap())]
1269        );
1270
1271        // directory
1272        assert_eq!(
1273            CapabilityId::from_offer_expose(&Offer {
1274                directory: Some(OneOrMany::One(a.clone())),
1275                ..empty_offer()
1276            },)?,
1277            vec![CapabilityId::Directory(&a)]
1278        );
1279        assert_eq!(
1280            CapabilityId::from_offer_expose(&Offer {
1281                directory: Some(OneOrMany::Many(vec![a.clone(), b.clone()])),
1282                ..empty_offer()
1283            },)?,
1284            vec![CapabilityId::Directory(&a), CapabilityId::Directory(&b),]
1285        );
1286        assert_eq!(
1287            CapabilityId::from_use(&Use {
1288                directory: Some(a.clone()),
1289                path: Some("/b".parse().unwrap()),
1290                ..empty_use()
1291            },)?,
1292            vec![CapabilityId::UsedDirectory("/b".parse().unwrap())]
1293        );
1294
1295        // storage
1296        assert_eq!(
1297            CapabilityId::from_offer_expose(&Offer {
1298                storage: Some(OneOrMany::One(a.clone())),
1299                ..empty_offer()
1300            },)?,
1301            vec![CapabilityId::Storage(&a)]
1302        );
1303        assert_eq!(
1304            CapabilityId::from_offer_expose(&Offer {
1305                storage: Some(OneOrMany::Many(vec![a.clone(), b.clone()])),
1306                ..empty_offer()
1307            },)?,
1308            vec![CapabilityId::Storage(&a), CapabilityId::Storage(&b),]
1309        );
1310        assert_eq!(
1311            CapabilityId::from_use(&Use {
1312                storage: Some(a.clone()),
1313                path: Some("/b".parse().unwrap()),
1314                ..empty_use()
1315            },)?,
1316            vec![CapabilityId::UsedStorage("/b".parse().unwrap())]
1317        );
1318
1319        // runner
1320        assert_eq!(
1321            CapabilityId::from_use(&Use { runner: Some("elf".parse().unwrap()), ..empty_use() })?,
1322            vec![CapabilityId::UsedRunner(BorrowedName::new("elf").unwrap())]
1323        );
1324
1325        // dictionary
1326        assert_eq!(
1327            CapabilityId::from_offer_expose(&Offer {
1328                dictionary: Some(OneOrMany::One(a.clone())),
1329                ..empty_offer()
1330            },)?,
1331            vec![CapabilityId::Dictionary(&a)]
1332        );
1333        assert_eq!(
1334            CapabilityId::from_offer_expose(&Offer {
1335                dictionary: Some(OneOrMany::Many(vec![a.clone(), b.clone()],)),
1336                ..empty_offer()
1337            },)?,
1338            vec![CapabilityId::Dictionary(&a), CapabilityId::Dictionary(&b)]
1339        );
1340        assert_eq!(
1341            CapabilityId::from_use(&Use {
1342                dictionary: Some(OneOrMany::One(a.clone())),
1343                ..empty_use()
1344            },)?,
1345            vec![CapabilityId::UsedDictionary("/svc/a".parse().unwrap())]
1346        );
1347        assert_eq!(
1348            CapabilityId::from_use(&Use {
1349                dictionary: Some(OneOrMany::Many(vec![a.clone(), b.clone(),],)),
1350                ..empty_use()
1351            },)?,
1352            vec![
1353                CapabilityId::UsedDictionary("/svc/a".parse().unwrap()),
1354                CapabilityId::UsedDictionary("/svc/b".parse().unwrap())
1355            ]
1356        );
1357        assert_eq!(
1358            CapabilityId::from_use(&Use {
1359                dictionary: Some(OneOrMany::One(a.clone())),
1360                path: Some("/b".parse().unwrap()),
1361                ..empty_use()
1362            },)?,
1363            vec![CapabilityId::UsedDictionary("/b".parse().unwrap())]
1364        );
1365
1366        // "as" aliasing.
1367        assert_eq!(
1368            CapabilityId::from_offer_expose(&Offer {
1369                service: Some(OneOrMany::One(a.clone())),
1370                r#as: Some(b.clone()),
1371                ..empty_offer()
1372            },)?,
1373            vec![CapabilityId::Service(&b)]
1374        );
1375
1376        // Error case.
1377        assert_matches!(CapabilityId::from_offer_expose(&empty_offer()), Err(_));
1378
1379        Ok(())
1380    }
1381
1382    fn document(contents: serde_json::Value) -> Document {
1383        serde_json5::from_str::<Document>(&contents.to_string()).unwrap()
1384    }
1385
1386    #[test]
1387    fn test_includes() {
1388        assert_eq!(document(json!({})).includes(), Vec::<String>::new());
1389        assert_eq!(document(json!({ "include": []})).includes(), Vec::<String>::new());
1390        assert_eq!(
1391            document(json!({ "include": [ "foo.cml", "bar.cml" ]})).includes(),
1392            vec!["foo.cml", "bar.cml"]
1393        );
1394    }
1395
1396    #[test]
1397    fn test_merge_same_section() {
1398        let mut some = document(json!({ "use": [{ "protocol": "foo" }] }));
1399        let mut other = document(json!({ "use": [{ "protocol": "bar" }] }));
1400        some.merge_from(&mut other, &Path::new("some/path")).unwrap();
1401        let uses = some.r#use.as_ref().unwrap();
1402        assert_eq!(uses.len(), 2);
1403        assert_eq!(
1404            uses[0].protocol.as_ref().unwrap(),
1405            &OneOrMany::One("foo".parse::<Name>().unwrap())
1406        );
1407        assert_eq!(
1408            uses[1].protocol.as_ref().unwrap(),
1409            &OneOrMany::One("bar".parse::<Name>().unwrap())
1410        );
1411    }
1412
1413    #[test]
1414    fn test_merge_upgraded_availability() {
1415        let mut some =
1416            document(json!({ "use": [{ "protocol": "foo", "availability": "optional" }] }));
1417        let mut other1 = document(json!({ "use": [{ "protocol": "foo" }] }));
1418        let mut other2 =
1419            document(json!({ "use": [{ "protocol": "foo", "availability": "transitional" }] }));
1420        let mut other3 =
1421            document(json!({ "use": [{ "protocol": "foo", "availability": "same_as_target" }] }));
1422        some.merge_from(&mut other1, &Path::new("some/path")).unwrap();
1423        some.merge_from(&mut other2, &Path::new("some/path")).unwrap();
1424        some.merge_from(&mut other3, &Path::new("some/path")).unwrap();
1425        let uses = some.r#use.as_ref().unwrap();
1426        assert_eq!(uses.len(), 2);
1427        assert_eq!(
1428            uses[0].protocol.as_ref().unwrap(),
1429            &OneOrMany::One("foo".parse::<Name>().unwrap())
1430        );
1431        assert!(uses[0].availability.is_none());
1432        assert_eq!(
1433            uses[1].protocol.as_ref().unwrap(),
1434            &OneOrMany::One("foo".parse::<Name>().unwrap())
1435        );
1436        assert_eq!(uses[1].availability.as_ref().unwrap(), &Availability::SameAsTarget,);
1437    }
1438
1439    #[test]
1440    fn test_merge_different_sections() {
1441        let mut some = document(json!({ "use": [{ "protocol": "foo" }] }));
1442        let mut other = document(json!({ "expose": [{ "protocol": "bar", "from": "self" }] }));
1443        some.merge_from(&mut other, &Path::new("some/path")).unwrap();
1444        let uses = some.r#use.as_ref().unwrap();
1445        let exposes = some.expose.as_ref().unwrap();
1446        assert_eq!(uses.len(), 1);
1447        assert_eq!(exposes.len(), 1);
1448        assert_eq!(
1449            uses[0].protocol.as_ref().unwrap(),
1450            &OneOrMany::One("foo".parse::<Name>().unwrap())
1451        );
1452        assert_eq!(
1453            exposes[0].protocol.as_ref().unwrap(),
1454            &OneOrMany::One("bar".parse::<Name>().unwrap())
1455        );
1456    }
1457
1458    #[test]
1459    fn test_merge_environments() {
1460        let mut some = document(json!({ "environments": [
1461            {
1462                "name": "one",
1463                "extends": "realm",
1464            },
1465            {
1466                "name": "two",
1467                "extends": "none",
1468                "runners": [
1469                    {
1470                        "runner": "r1",
1471                        "from": "#c1",
1472                    },
1473                    {
1474                        "runner": "r2",
1475                        "from": "#c2",
1476                    },
1477                ],
1478                "resolvers": [
1479                    {
1480                        "resolver": "res1",
1481                        "from": "#c1",
1482                        "scheme": "foo",
1483                    },
1484                ],
1485                "debug": [
1486                    {
1487                        "protocol": "baz",
1488                        "from": "#c2"
1489                    }
1490                ]
1491            },
1492        ]}));
1493        let mut other = document(json!({ "environments": [
1494            {
1495                "name": "two",
1496                "__stop_timeout_ms": 100,
1497                "runners": [
1498                    {
1499                        "runner": "r3",
1500                        "from": "#c3",
1501                    },
1502                ],
1503                "resolvers": [
1504                    {
1505                        "resolver": "res2",
1506                        "from": "#c1",
1507                        "scheme": "bar",
1508                    },
1509                ],
1510                "debug": [
1511                    {
1512                        "protocol": "faz",
1513                        "from": "#c2"
1514                    }
1515                ]
1516            },
1517            {
1518                "name": "three",
1519                "__stop_timeout_ms": 1000,
1520            },
1521        ]}));
1522        some.merge_from(&mut other, &Path::new("some/path")).unwrap();
1523        assert_eq!(
1524            to_value(some).unwrap(),
1525            json!({"environments": [
1526                {
1527                    "name": "one",
1528                    "extends": "realm",
1529                },
1530                {
1531                    "name": "three",
1532                    "__stop_timeout_ms": 1000,
1533                },
1534                {
1535                    "name": "two",
1536                    "extends": "none",
1537                    "__stop_timeout_ms": 100,
1538                    "runners": [
1539                        {
1540                            "runner": "r1",
1541                            "from": "#c1",
1542                        },
1543                        {
1544                            "runner": "r2",
1545                            "from": "#c2",
1546                        },
1547                        {
1548                            "runner": "r3",
1549                            "from": "#c3",
1550                        },
1551                    ],
1552                    "resolvers": [
1553                        {
1554                            "resolver": "res1",
1555                            "from": "#c1",
1556                            "scheme": "foo",
1557                        },
1558                        {
1559                            "resolver": "res2",
1560                            "from": "#c1",
1561                            "scheme": "bar",
1562                        },
1563                    ],
1564                    "debug": [
1565                        {
1566                            "protocol": "baz",
1567                            "from": "#c2"
1568                        },
1569                        {
1570                            "protocol": "faz",
1571                            "from": "#c2"
1572                        }
1573                    ]
1574                },
1575            ]})
1576        );
1577    }
1578
1579    #[test]
1580    fn test_merge_environments_errors() {
1581        {
1582            let mut some = document(json!({"environments": [{"name": "one", "extends": "realm"}]}));
1583            let mut other = document(json!({"environments": [{"name": "one", "extends": "none"}]}));
1584            assert!(some.merge_from(&mut other, &Path::new("some/path")).is_err());
1585        }
1586        {
1587            let mut some =
1588                document(json!({"environments": [{"name": "one", "__stop_timeout_ms": 10}]}));
1589            let mut other =
1590                document(json!({"environments": [{"name": "one", "__stop_timeout_ms": 20}]}));
1591            assert!(some.merge_from(&mut other, &Path::new("some/path")).is_err());
1592        }
1593
1594        // It's ok if the values match.
1595        {
1596            let mut some = document(json!({"environments": [{"name": "one", "extends": "realm"}]}));
1597            let mut other =
1598                document(json!({"environments": [{"name": "one", "extends": "realm"}]}));
1599            some.merge_from(&mut other, &Path::new("some/path")).unwrap();
1600            assert_eq!(
1601                to_value(some).unwrap(),
1602                json!({"environments": [{"name": "one", "extends": "realm"}]})
1603            );
1604        }
1605        {
1606            let mut some =
1607                document(json!({"environments": [{"name": "one", "__stop_timeout_ms": 10}]}));
1608            let mut other =
1609                document(json!({"environments": [{"name": "one", "__stop_timeout_ms": 10}]}));
1610            some.merge_from(&mut other, &Path::new("some/path")).unwrap();
1611            assert_eq!(
1612                to_value(some).unwrap(),
1613                json!({"environments": [{"name": "one", "__stop_timeout_ms": 10}]})
1614            );
1615        }
1616    }
1617
1618    #[test]
1619    fn test_merge_from_other_config() {
1620        let mut some = document(json!({}));
1621        let mut other = document(json!({ "config": { "bar": { "type": "bool" } } }));
1622
1623        some.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
1624        let expected = document(json!({ "config": { "bar": { "type": "bool" } } }));
1625        assert_eq!(some.config, expected.config);
1626    }
1627
1628    #[test]
1629    fn test_merge_from_some_config() {
1630        let mut some = document(json!({ "config": { "bar": { "type": "bool" } } }));
1631        let mut other = document(json!({}));
1632
1633        some.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
1634        let expected = document(json!({ "config": { "bar": { "type": "bool" } } }));
1635        assert_eq!(some.config, expected.config);
1636    }
1637
1638    #[test]
1639    fn test_merge_from_config() {
1640        let mut some = document(json!({ "config": { "foo": { "type": "bool" } } }));
1641        let mut other = document(json!({ "config": { "bar": { "type": "bool" } } }));
1642        some.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
1643
1644        assert_eq!(
1645            some,
1646            document(json!({
1647                "config": {
1648                    "foo": { "type": "bool" },
1649                    "bar": { "type": "bool" },
1650                }
1651            })),
1652        );
1653    }
1654
1655    #[test]
1656    fn test_merge_from_config_dedupe_identical_fields() {
1657        let mut some = document(json!({ "config": { "foo": { "type": "bool" } } }));
1658        let mut other = document(json!({ "config": { "foo": { "type": "bool" } } }));
1659        some.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
1660
1661        assert_eq!(some, document(json!({ "config": { "foo": { "type": "bool" } } })));
1662    }
1663
1664    #[test]
1665    fn test_merge_from_config_conflicting_keys() {
1666        let mut some = document(json!({ "config": { "foo": { "type": "bool" } } }));
1667        let mut other = document(json!({ "config": { "foo": { "type": "uint8" } } }));
1668
1669        assert_matches::assert_matches!(
1670            some.merge_from(&mut other, &path::Path::new("some/path")),
1671            Err(Error::Validate { err, .. })
1672                if err == "Found conflicting entry for config key `foo` in `some/path`."
1673        );
1674    }
1675
1676    #[test]
1677    fn test_canonicalize() {
1678        let mut some = document(json!({
1679            "children": [
1680                // Will be sorted by name
1681                { "name": "b_child", "url": "http://foo/b" },
1682                { "name": "a_child", "url": "http://foo/a" },
1683            ],
1684            "environments": [
1685                // Will be sorted by name
1686                { "name": "b_env" },
1687                { "name": "a_env" },
1688            ],
1689            "collections": [
1690                // Will be sorted by name
1691                { "name": "b_coll", "durability": "transient" },
1692                { "name": "a_coll", "durability": "transient" },
1693            ],
1694            // Will have entries sorted by capability type, then
1695            // by capability name (using the first entry in Many cases).
1696            "capabilities": [
1697                // Will be merged with "bar"
1698                { "protocol": ["foo"] },
1699                { "protocol": "bar" },
1700                // Will not be merged, but will be sorted before "bar"
1701                { "protocol": "arg", "path": "/arg" },
1702                // Will have list of names sorted
1703                { "service": ["b", "a"] },
1704                // Will have list of names sorted
1705                { "event_stream": ["b", "a"] },
1706                { "runner": "myrunner" },
1707                // The following two will *not* be merged, because they have a `path`.
1708                { "runner": "mypathrunner1", "path": "/foo" },
1709                { "runner": "mypathrunner2", "path": "/foo" },
1710            ],
1711            // Same rules as for "capabilities".
1712            "offer": [
1713                // Will be sorted after "bar"
1714                { "protocol": "baz", "from": "#a_child", "to": "#c_child"  },
1715                // The following two entries will be merged
1716                { "protocol": ["foo"], "from": "#a_child", "to": "#b_child"  },
1717                { "protocol": "bar", "from": "#a_child", "to": "#b_child"  },
1718                // Will have list of names sorted
1719                { "service": ["b", "a"], "from": "#a_child", "to": "#b_child"  },
1720                // Will have list of names sorted
1721                {
1722                    "event_stream": ["b", "a"],
1723                    "from": "#a_child",
1724                    "to": "#b_child",
1725                    "scope": ["#b", "#c", "#a"]  // Also gets sorted
1726                },
1727                { "runner": [ "myrunner", "a" ], "from": "#a_child", "to": "#b_child"  },
1728                { "runner": [ "b" ], "from": "#a_child", "to": "#b_child"  },
1729                { "directory": [ "b" ], "from": "#a_child", "to": "#b_child"  },
1730            ],
1731            "expose": [
1732                { "protocol": ["foo"], "from": "#a_child" },
1733                { "protocol": "bar", "from": "#a_child" },  // Will appear before protocol: foo
1734                // Will have list of names sorted
1735                { "service": ["b", "a"], "from": "#a_child" },
1736                // Will have list of names sorted
1737                {
1738                    "event_stream": ["b", "a"],
1739                    "from": "#a_child",
1740                    "scope": ["#b", "#c", "#a"]  // Also gets sorted
1741                },
1742                { "runner": [ "myrunner", "a" ], "from": "#a_child" },
1743                { "runner": [ "b" ], "from": "#a_child" },
1744                { "directory": [ "b" ], "from": "#a_child" },
1745            ],
1746            "use": [
1747                // Will be sorted after "baz"
1748                { "protocol": ["zazzle"], "path": "/zazbaz" },
1749                // These will be merged
1750                { "protocol": ["foo"] },
1751                { "protocol": "bar" },
1752                // Will have list of names sorted
1753                { "service": ["b", "a"] },
1754                // Will have list of names sorted
1755                { "event_stream": ["b", "a"], "scope": ["#b", "#a"] },
1756            ],
1757        }));
1758        some.canonicalize();
1759
1760        assert_json_eq!(
1761            some,
1762            document(json!({
1763                "children": [
1764                    { "name": "a_child", "url": "http://foo/a" },
1765                    { "name": "b_child", "url": "http://foo/b" },
1766                ],
1767                "collections": [
1768                    { "name": "a_coll", "durability": "transient" },
1769                    { "name": "b_coll", "durability": "transient" },
1770                ],
1771                "environments": [
1772                    { "name": "a_env" },
1773                    { "name": "b_env" },
1774                ],
1775                "capabilities": [
1776                    { "event_stream": ["a", "b"] },
1777                    { "protocol": "arg", "path": "/arg" },
1778                    { "protocol": ["bar", "foo"] },
1779                    { "runner": "mypathrunner1", "path": "/foo" },
1780                    { "runner": "mypathrunner2", "path": "/foo" },
1781                    { "runner": "myrunner" },
1782                    { "service": ["a", "b"] },
1783                ],
1784                "use": [
1785                    { "event_stream": ["a", "b"], "scope": ["#a", "#b"] },
1786                    { "protocol": ["bar", "foo"] },
1787                    { "protocol": "zazzle", "path": "/zazbaz" },
1788                    { "service": ["a", "b"] },
1789                ],
1790                "offer": [
1791                    { "directory": "b", "from": "#a_child", "to": "#b_child" },
1792                    {
1793                        "event_stream": ["a", "b"],
1794                        "from": "#a_child",
1795                        "to": "#b_child",
1796                        "scope": ["#a", "#b", "#c"],
1797                    },
1798                    { "protocol": ["bar", "foo"], "from": "#a_child", "to": "#b_child" },
1799                    { "protocol": "baz", "from": "#a_child", "to": "#c_child"  },
1800                    { "runner": [ "a", "b", "myrunner" ], "from": "#a_child", "to": "#b_child" },
1801                    { "service": ["a", "b"], "from": "#a_child", "to": "#b_child" },
1802                ],
1803                "expose": [
1804                    { "directory": "b", "from": "#a_child" },
1805                    {
1806                        "event_stream": ["a", "b"],
1807                        "from": "#a_child",
1808                        "scope": ["#a", "#b", "#c"],
1809                    },
1810                    { "protocol": ["bar", "foo"], "from": "#a_child" },
1811                    { "runner": [ "a", "b", "myrunner" ], "from": "#a_child" },
1812                    { "service": ["a", "b"], "from": "#a_child" },
1813                ],
1814            }))
1815        )
1816    }
1817
1818    #[test]
1819    fn deny_unknown_config_type_fields() {
1820        let input = json!({ "config": { "foo": { "type": "bool", "unknown": "should error" } } });
1821        serde_json5::from_str::<Document>(&input.to_string())
1822            .expect_err("must reject unknown config field attributes");
1823    }
1824
1825    #[test]
1826    fn deny_unknown_config_nested_type_fields() {
1827        let input = json!({
1828            "config": {
1829                "foo": {
1830                    "type": "vector",
1831                    "max_count": 10,
1832                    "element": {
1833                        "type": "bool",
1834                        "unknown": "should error"
1835                    },
1836
1837                }
1838            }
1839        });
1840        serde_json5::from_str::<Document>(&input.to_string())
1841            .expect_err("must reject unknown config field attributes");
1842    }
1843
1844    #[test]
1845    fn test_merge_from_program() {
1846        let mut some = document(json!({ "program": { "binary": "bin/hello_world" } }));
1847        let mut other = document(json!({ "program": { "runner": "elf" } }));
1848        some.merge_from(&mut other, &Path::new("some/path")).unwrap();
1849        let expected =
1850            document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
1851        assert_eq!(some.program, expected.program);
1852    }
1853
1854    #[test]
1855    fn test_merge_from_program_without_runner() {
1856        let mut some =
1857            document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
1858        // https://fxbug.dev/42160240: merging with a document that doesn't have a runner doesn't override the
1859        // runner that we already have assigned.
1860        let mut other = document(json!({ "program": {} }));
1861        some.merge_from(&mut other, &Path::new("some/path")).unwrap();
1862        let expected =
1863            document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
1864        assert_eq!(some.program, expected.program);
1865    }
1866
1867    #[test]
1868    fn test_merge_from_program_overlapping_environ() {
1869        // It's ok to merge `program.environ` by concatenating the arrays together.
1870        let mut some = document(json!({ "program": { "environ": ["1"] } }));
1871        let mut other = document(json!({ "program": { "environ": ["2"] } }));
1872        some.merge_from(&mut other, &Path::new("some/path")).unwrap();
1873        let expected = document(json!({ "program": { "environ": ["1", "2"] } }));
1874        assert_eq!(some.program, expected.program);
1875    }
1876
1877    #[test]
1878    fn test_merge_from_program_overlapping_runner() {
1879        // It's ok to merge `program.runner = "elf"` with `program.runner = "elf"`.
1880        let mut some =
1881            document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
1882        let mut other = document(json!({ "program": { "runner": "elf" } }));
1883        some.merge_from(&mut other, &Path::new("some/path")).unwrap();
1884        let expected =
1885            document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
1886        assert_eq!(some.program, expected.program);
1887    }
1888
1889    #[test_case(
1890        document(json!({ "program": { "runner": "elf" } })),
1891        document(json!({ "program": { "runner": "fle" } })),
1892        "runner"
1893        ; "when_runner_conflicts"
1894    )]
1895    #[test_case(
1896        document(json!({ "program": { "binary": "bin/hello_world" } })),
1897        document(json!({ "program": { "binary": "bin/hola_mundo" } })),
1898        "binary"
1899        ; "when_binary_conflicts"
1900    )]
1901    #[test_case(
1902        document(json!({ "program": { "args": ["a".to_owned()] } })),
1903        document(json!({ "program": { "args": ["b".to_owned()] } })),
1904        "args"
1905        ; "when_args_conflicts"
1906    )]
1907    fn test_merge_from_program_error(mut some: Document, mut other: Document, field: &str) {
1908        assert_matches::assert_matches!(
1909            some.merge_from(&mut other, &path::Path::new("some/path")),
1910            Err(Error::Validate {  err, .. })
1911                if err == format!("manifest include had a conflicting `program.{}`: some/path", field)
1912        );
1913    }
1914
1915    #[test_case(
1916        document(json!({ "facets": { "my.key": "my.value" } })),
1917        document(json!({ "facets": { "other.key": "other.value" } })),
1918        document(json!({ "facets": { "my.key": "my.value",  "other.key": "other.value" } }))
1919        ; "two separate keys"
1920    )]
1921    #[test_case(
1922        document(json!({ "facets": { "my.key": "my.value" } })),
1923        document(json!({ "facets": {} })),
1924        document(json!({ "facets": { "my.key": "my.value" } }))
1925        ; "empty other facet"
1926    )]
1927    #[test_case(
1928        document(json!({ "facets": {} })),
1929        document(json!({ "facets": { "other.key": "other.value" } })),
1930        document(json!({ "facets": { "other.key": "other.value" } }))
1931        ; "empty my facet"
1932    )]
1933    #[test_case(
1934        document(json!({ "facets": { "key": { "type": "some_type" } } })),
1935        document(json!({ "facets": { "key": { "runner": "some_runner"} } })),
1936        document(json!({ "facets": { "key": { "type": "some_type", "runner": "some_runner" } } }))
1937        ; "nested facet key"
1938    )]
1939    #[test_case(
1940        document(json!({ "facets": { "key": { "type": "some_type", "nested_key": { "type": "new type" }}}})),
1941        document(json!({ "facets": { "key": { "nested_key": { "runner": "some_runner" }} } })),
1942        document(json!({ "facets": { "key": { "type": "some_type", "nested_key": { "runner": "some_runner", "type": "new type" }}}}))
1943        ; "double nested facet key"
1944    )]
1945    #[test_case(
1946        document(json!({ "facets": { "key": { "array_key": ["value_1", "value_2"] } } })),
1947        document(json!({ "facets": { "key": { "array_key": ["value_3", "value_4"] } } })),
1948        document(json!({ "facets": { "key": { "array_key": ["value_1", "value_2", "value_3", "value_4"] } } }))
1949        ; "merge array values"
1950    )]
1951    fn test_merge_from_facets(mut my: Document, mut other: Document, expected: Document) {
1952        my.merge_from(&mut other, &Path::new("some/path")).unwrap();
1953        assert_eq!(my.facets, expected.facets);
1954    }
1955
1956    #[test_case(
1957        document(json!({ "facets": { "key": "my.value" }})),
1958        document(json!({ "facets": { "key": "other.value" }})),
1959        "facets.key"
1960        ; "conflict first level keys"
1961    )]
1962    #[test_case(
1963        document(json!({ "facets": { "key":  {"type": "cts" }}})),
1964        document(json!({ "facets": { "key":  {"type": "system" }}})),
1965        "facets.key.type"
1966        ; "conflict second level keys"
1967    )]
1968    #[test_case(
1969        document(json!({ "facets": { "key":  {"type": {"key": "value" }}}})),
1970        document(json!({ "facets": { "key":  {"type": "system" }}})),
1971        "facets.key.type"
1972        ; "incompatible self nested type"
1973    )]
1974    #[test_case(
1975        document(json!({ "facets": { "key":  {"type": "system" }}})),
1976        document(json!({ "facets": { "key":  {"type":  {"key": "value" }}}})),
1977        "facets.key.type"
1978        ; "incompatible other nested type"
1979    )]
1980    #[test_case(
1981        document(json!({ "facets": { "key":  {"type": {"key": "my.value" }}}})),
1982        document(json!({ "facets": { "key":  {"type":  {"key": "some.value" }}}})),
1983        "facets.key.type.key"
1984        ; "conflict third level keys"
1985    )]
1986    #[test_case(
1987        document(json!({ "facets": { "key":  {"type": [ "value_1" ]}}})),
1988        document(json!({ "facets": { "key":  {"type":  "value_2" }}})),
1989        "facets.key.type"
1990        ; "incompatible keys"
1991    )]
1992    fn test_merge_from_facet_error(mut my: Document, mut other: Document, field: &str) {
1993        assert_matches::assert_matches!(
1994            my.merge_from(&mut other, &path::Path::new("some/path")),
1995            Err(Error::Validate {  err, .. })
1996                if err == format!("manifest include had a conflicting `{}`: some/path", field)
1997        );
1998    }
1999
2000    #[test_case("protocol")]
2001    #[test_case("service")]
2002    #[test_case("event_stream")]
2003    fn test_merge_from_duplicate_use_array(typename: &str) {
2004        let mut my = document(json!({ "use": [{ typename: "a" }]}));
2005        let mut other = document(json!({ "use": [
2006            { typename: ["a", "b"], "availability": "optional"}
2007        ]}));
2008        let result = document(json!({ "use": [
2009            { typename: "a" },
2010            { typename: "b", "availability": "optional" },
2011        ]}));
2012
2013        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
2014        assert_eq!(my, result);
2015    }
2016
2017    #[test_case("directory")]
2018    #[test_case("storage")]
2019    fn test_merge_from_duplicate_use_noarray(typename: &str) {
2020        let mut my = document(json!({ "use": [{ typename: "a", "path": "/a"}]}));
2021        let mut other = document(json!({ "use": [
2022            { typename: "a", "path": "/a", "availability": "optional" },
2023            { typename: "b", "path": "/b", "availability": "optional" },
2024        ]}));
2025        let result = document(json!({ "use": [
2026            { typename: "a", "path": "/a" },
2027            { typename: "b", "path": "/b", "availability": "optional" },
2028        ]}));
2029        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
2030        assert_eq!(my, result);
2031    }
2032
2033    #[test_case("protocol")]
2034    #[test_case("service")]
2035    #[test_case("event_stream")]
2036    fn test_merge_from_duplicate_capabilities_array(typename: &str) {
2037        let mut my = document(json!({ "capabilities": [{ typename: "a" }]}));
2038        let mut other = document(json!({ "capabilities": [ { typename: ["a", "b"] } ]}));
2039        let result = document(json!({ "capabilities": [ { typename: "a" }, { typename: "b" } ]}));
2040
2041        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
2042        assert_eq!(my, result);
2043    }
2044
2045    #[test_case("directory")]
2046    #[test_case("storage")]
2047    #[test_case("runner")]
2048    #[test_case("resolver")]
2049    fn test_merge_from_duplicate_capabilities_noarray(typename: &str) {
2050        let mut my = document(json!({ "capabilities": [{ typename: "a", "path": "/a"}]}));
2051        let mut other = document(json!({ "capabilities": [
2052            { typename: "a", "path": "/a" },
2053            { typename: "b", "path": "/b" },
2054        ]}));
2055        let result = document(json!({ "capabilities": [
2056            { typename: "a", "path": "/a" },
2057            { typename: "b", "path": "/b" },
2058        ]}));
2059        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
2060        assert_eq!(my, result);
2061    }
2062
2063    #[test]
2064    fn test_merge_with_empty_names() {
2065        // This document is an error because there is no capability name.
2066        let mut my = document(json!({ "capabilities": [{ "path": "/a"}]}));
2067
2068        let mut other = document(json!({ "capabilities": [
2069            { "directory": "a", "path": "/a" },
2070            { "directory": "b", "path": "/b" },
2071        ]}));
2072        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap_err();
2073    }
2074
2075    #[test_case("protocol")]
2076    #[test_case("service")]
2077    #[test_case("event_stream")]
2078    #[test_case("directory")]
2079    #[test_case("storage")]
2080    #[test_case("runner")]
2081    #[test_case("resolver")]
2082    fn test_merge_from_duplicate_offers(typename: &str) {
2083        let mut my = document(json!({ "offer": [{ typename: "a", "from": "self", "to": "#c" }]}));
2084        let mut other = document(json!({ "offer": [
2085            { typename: ["a", "b"], "from": "self", "to": "#c", "availability": "optional" }
2086        ]}));
2087        let result = document(json!({ "offer": [
2088            { typename: "a", "from": "self", "to": "#c" },
2089            { typename: "b", "from": "self", "to": "#c", "availability": "optional" },
2090        ]}));
2091
2092        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
2093        assert_eq!(my, result);
2094    }
2095
2096    #[test_case("protocol")]
2097    #[test_case("service")]
2098    #[test_case("event_stream")]
2099    #[test_case("directory")]
2100    #[test_case("runner")]
2101    #[test_case("resolver")]
2102    fn test_merge_from_duplicate_exposes(typename: &str) {
2103        let mut my = document(json!({ "expose": [{ typename: "a", "from": "self" }]}));
2104        let mut other = document(json!({ "expose": [
2105            { typename: ["a", "b"], "from": "self" }
2106        ]}));
2107        let result = document(json!({ "expose": [
2108            { typename: "a", "from": "self" },
2109            { typename: "b", "from": "self" },
2110        ]}));
2111
2112        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
2113        assert_eq!(my, result);
2114    }
2115
2116    #[test_case(
2117        document(json!({ "use": [
2118            { "protocol": "a", "availability": "required" },
2119            { "protocol": "b", "availability": "optional" },
2120            { "protocol": "c", "availability": "transitional" },
2121            { "protocol": "d", "availability": "same_as_target" },
2122        ]})),
2123        document(json!({ "use": [
2124            { "protocol": ["a"], "availability": "required" },
2125            { "protocol": ["b"], "availability": "optional" },
2126            { "protocol": ["c"], "availability": "transitional" },
2127            { "protocol": ["d"], "availability": "same_as_target" },
2128        ]})),
2129        document(json!({ "use": [
2130            { "protocol": "a", "availability": "required" },
2131            { "protocol": "b", "availability": "optional" },
2132            { "protocol": "c", "availability": "transitional" },
2133            { "protocol": "d", "availability": "same_as_target" },
2134        ]}))
2135        ; "merge both same"
2136    )]
2137    #[test_case(
2138        document(json!({ "use": [
2139            { "protocol": "a", "availability": "optional" },
2140            { "protocol": "b", "availability": "transitional" },
2141            { "protocol": "c", "availability": "transitional" },
2142        ]})),
2143        document(json!({ "use": [
2144            { "protocol": ["a", "x"], "availability": "required" },
2145            { "protocol": ["b", "y"], "availability": "optional" },
2146            { "protocol": ["c", "z"], "availability": "required" },
2147        ]})),
2148        document(json!({ "use": [
2149            { "protocol": ["a", "x"], "availability": "required" },
2150            { "protocol": ["b", "y"], "availability": "optional" },
2151            { "protocol": ["c", "z"], "availability": "required" },
2152        ]}))
2153        ; "merge with upgrade"
2154    )]
2155    #[test_case(
2156        document(json!({ "use": [
2157            { "protocol": "a", "availability": "required" },
2158            { "protocol": "b", "availability": "optional" },
2159            { "protocol": "c", "availability": "required" },
2160        ]})),
2161        document(json!({ "use": [
2162            { "protocol": ["a", "x"], "availability": "optional" },
2163            { "protocol": ["b", "y"], "availability": "transitional" },
2164            { "protocol": ["c", "z"], "availability": "transitional" },
2165        ]})),
2166        document(json!({ "use": [
2167            { "protocol": "a", "availability": "required" },
2168            { "protocol": "b", "availability": "optional" },
2169            { "protocol": "c", "availability": "required" },
2170            { "protocol": "x", "availability": "optional" },
2171            { "protocol": "y", "availability": "transitional" },
2172            { "protocol": "z", "availability": "transitional" },
2173        ]}))
2174        ; "merge with downgrade"
2175    )]
2176    #[test_case(
2177        document(json!({ "use": [
2178            { "protocol": "a", "availability": "optional" },
2179            { "protocol": "b", "availability": "transitional" },
2180            { "protocol": "c", "availability": "transitional" },
2181        ]})),
2182        document(json!({ "use": [
2183            { "protocol": ["a", "x"], "availability": "same_as_target" },
2184            { "protocol": ["b", "y"], "availability": "same_as_target" },
2185            { "protocol": ["c", "z"], "availability": "same_as_target" },
2186        ]})),
2187        document(json!({ "use": [
2188            { "protocol": "a", "availability": "optional" },
2189            { "protocol": "b", "availability": "transitional" },
2190            { "protocol": "c", "availability": "transitional" },
2191            { "protocol": ["a", "x"], "availability": "same_as_target" },
2192            { "protocol": ["b", "y"], "availability": "same_as_target" },
2193            { "protocol": ["c", "z"], "availability": "same_as_target" },
2194        ]}))
2195        ; "merge with no replacement"
2196    )]
2197    #[test_case(
2198        document(json!({ "use": [
2199            { "protocol": ["a", "b", "c"], "availability": "optional" },
2200            { "protocol": "d", "availability": "same_as_target" },
2201            { "protocol": ["e", "f"] },
2202        ]})),
2203        document(json!({ "use": [
2204            { "protocol": ["c", "e", "g"] },
2205            { "protocol": ["d", "h"] },
2206            { "protocol": ["f", "i"], "availability": "transitional" },
2207        ]})),
2208        document(json!({ "use": [
2209            { "protocol": ["a", "b"], "availability": "optional" },
2210            { "protocol": "d", "availability": "same_as_target" },
2211            { "protocol": ["e", "f"] },
2212            { "protocol": ["c", "g"] },
2213            { "protocol": ["d", "h"] },
2214            { "protocol": "i", "availability": "transitional" },
2215        ]}))
2216        ; "merge multiple"
2217    )]
2218
2219    fn test_merge_from_duplicate_capability_availability(
2220        mut my: Document,
2221        mut other: Document,
2222        result: Document,
2223    ) {
2224        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
2225        assert_eq!(my, result);
2226    }
2227
2228    #[test_case(
2229        document(json!({ "use": [{ "protocol": ["a", "b"] }]})),
2230        document(json!({ "use": [{ "protocol": ["c", "d"] }]})),
2231        document(json!({ "use": [
2232            { "protocol": ["a", "b"] }, { "protocol": ["c", "d"] }
2233        ]}))
2234        ; "merge capabilities with disjoint sets"
2235    )]
2236    #[test_case(
2237        document(json!({ "use": [
2238            { "protocol": ["a"] },
2239            { "protocol": "b" },
2240        ]})),
2241        document(json!({ "use": [{ "protocol": ["a", "b"] }]})),
2242        document(json!({ "use": [
2243            { "protocol": ["a"] }, { "protocol": "b" },
2244        ]}))
2245        ; "merge capabilities with equal set"
2246    )]
2247    #[test_case(
2248        document(json!({ "use": [
2249            { "protocol": ["a", "b"] },
2250            { "protocol": "c" },
2251        ]})),
2252        document(json!({ "use": [{ "protocol": ["a", "b"] }]})),
2253        document(json!({ "use": [
2254            { "protocol": ["a", "b"] }, { "protocol": "c" },
2255        ]}))
2256        ; "merge capabilities with subset"
2257    )]
2258    #[test_case(
2259        document(json!({ "use": [
2260            { "protocol": ["a", "b"] },
2261        ]})),
2262        document(json!({ "use": [{ "protocol": ["a", "b", "c"] }]})),
2263        document(json!({ "use": [
2264            { "protocol": ["a", "b"] },
2265            { "protocol": "c" },
2266        ]}))
2267        ; "merge capabilities with superset"
2268    )]
2269    #[test_case(
2270        document(json!({ "use": [
2271            { "protocol": ["a", "b"] },
2272        ]})),
2273        document(json!({ "use": [{ "protocol": ["b", "c", "d"] }]})),
2274        document(json!({ "use": [
2275            { "protocol": ["a", "b"] }, { "protocol": ["c", "d"] }
2276        ]}))
2277        ; "merge capabilities with intersection"
2278    )]
2279    #[test_case(
2280        document(json!({ "use": [{ "protocol": ["a", "b"] }]})),
2281        document(json!({ "use": [
2282            { "protocol": ["c", "b", "d"] },
2283            { "protocol": ["e", "d"] },
2284        ]})),
2285        document(json!({ "use": [
2286            {"protocol": ["a", "b"] },
2287            {"protocol": ["c", "d"] },
2288            {"protocol": "e" }]}))
2289        ; "merge capabilities from multiple arrays"
2290    )]
2291    #[test_case(
2292        document(json!({ "use": [{ "protocol": "foo.bar.Baz", "from": "self"}]})),
2293        document(json!({ "use": [{ "service": "foo.bar.Baz", "from": "self"}]})),
2294        document(json!({ "use": [
2295            {"protocol": "foo.bar.Baz", "from": "self"},
2296            {"service": "foo.bar.Baz", "from": "self"}]}))
2297        ; "merge capabilities, types don't match"
2298    )]
2299    #[test_case(
2300        document(json!({ "use": [{ "protocol": "foo.bar.Baz", "from": "self"}]})),
2301        document(json!({ "use": [{ "protocol": "foo.bar.Baz" }]})),
2302        document(json!({ "use": [
2303            {"protocol": "foo.bar.Baz", "from": "self"},
2304            {"protocol": "foo.bar.Baz"}]}))
2305        ; "merge capabilities, fields don't match"
2306    )]
2307
2308    fn test_merge_from_duplicate_capability(
2309        mut my: Document,
2310        mut other: Document,
2311        result: Document,
2312    ) {
2313        my.merge_from(&mut other, &path::Path::new("some/path")).unwrap();
2314        assert_eq!(my, result);
2315    }
2316
2317    #[test_case(&Right::Connect; "connect right")]
2318    #[test_case(&Right::Enumerate; "enumerate right")]
2319    #[test_case(&Right::Execute; "execute right")]
2320    #[test_case(&Right::GetAttributes; "getattr right")]
2321    #[test_case(&Right::ModifyDirectory; "modifydir right")]
2322    #[test_case(&Right::ReadBytes; "readbytes right")]
2323    #[test_case(&Right::Traverse; "traverse right")]
2324    #[test_case(&Right::UpdateAttributes; "updateattrs right")]
2325    #[test_case(&Right::WriteBytes; "writebytes right")]
2326    #[test_case(&Right::ReadAlias; "r right")]
2327    #[test_case(&Right::WriteAlias; "w right")]
2328    #[test_case(&Right::ExecuteAlias; "x right")]
2329    #[test_case(&Right::ReadWriteAlias; "rw right")]
2330    #[test_case(&Right::ReadExecuteAlias; "rx right")]
2331    #[test_case(&OfferFromRef::Self_; "offer from self")]
2332    #[test_case(&OfferFromRef::Parent; "offer from parent")]
2333    #[test_case(&OfferFromRef::Named(Name::new("child".to_string()).unwrap()); "offer from named")]
2334    #[test_case(
2335        &document(json!({}));
2336        "empty document"
2337    )]
2338    #[test_case(
2339        &document(json!({ "use": [{ "protocol": "foo.bar.Baz", "from": "self"}]}));
2340        "use one from self"
2341    )]
2342    #[test_case(
2343        &document(json!({ "use": [{ "protocol": ["foo.bar.Baz", "some.other.Protocol"], "from": "self"}]}));
2344        "use multiple from self"
2345    )]
2346    #[test_case(
2347        &document(json!({
2348            "offer": [{ "protocol": "foo.bar.Baz", "from": "self", "to": "#elements"}],
2349            "collections" :[{"name": "elements", "durability": "transient" }]
2350        }));
2351        "offer from self to collection"
2352    )]
2353    #[test_case(
2354        &document(json!({
2355            "offer": [
2356                { "service": "foo.bar.Baz", "from": "self", "to": "#elements" },
2357                { "service": "some.other.Service", "from": "self", "to": "#elements"},
2358            ],
2359            "collections":[ {"name": "elements", "durability": "transient"} ]}));
2360        "service offers"
2361    )]
2362    #[test_case(
2363        &document(json!({ "expose": [{ "protocol": ["foo.bar.Baz", "some.other.Protocol"], "from": "self"}]}));
2364        "expose protocols from self"
2365    )]
2366    #[test_case(
2367        &document(json!({ "expose": [{ "service": ["foo.bar.Baz", "some.other.Service"], "from": "self"}]}));
2368        "expose service from self"
2369    )]
2370    #[test_case(
2371        &document(json!({ "capabilities": [{ "protocol": "foo.bar.Baz", "from": "self"}]}));
2372        "capabilities from self"
2373    )]
2374    #[test_case(
2375        &document(json!({ "facets": { "my.key": "my.value" } }));
2376        "facets"
2377    )]
2378    #[test_case(
2379        &document(json!({ "program": { "binary": "bin/hello_world", "runner": "elf" } }));
2380        "elf runner program"
2381    )]
2382    fn serialize_roundtrips<T>(val: &T)
2383    where
2384        T: serde::de::DeserializeOwned + Serialize + PartialEq + std::fmt::Debug,
2385    {
2386        let raw = serde_json::to_string(val).expect("serializing `val` should work");
2387        let parsed: T =
2388            serde_json::from_str(&raw).expect("must be able to parse back serialized value");
2389        assert_eq!(val, &parsed, "parsed value must equal original value");
2390    }
2391}