Skip to main content

yaml_schema/
engine.rs

1use std::collections::HashMap;
2use std::rc::Rc;
3
4use saphyr::LoadableYamlNode;
5
6use crate::Error;
7use crate::Result;
8use crate::RootSchema;
9use crate::Validator as _;
10use crate::YamlSchema;
11use crate::validation::Context;
12
13#[derive(Debug)]
14pub struct Engine<'a> {
15    pub root_schema: &'a RootSchema,
16    pub context: Context<'a>,
17}
18
19impl<'a> Engine<'a> {
20    pub fn new(root_schema: &'a RootSchema, context: Context<'a>) -> Self {
21        Engine {
22            root_schema,
23            context,
24        }
25    }
26
27    pub fn evaluate<'b: 'a>(
28        root_schema: &'b RootSchema,
29        value: &str,
30        fail_fast: bool,
31    ) -> Result<Context<'b>> {
32        Self::evaluate_with_schemas(root_schema, value, fail_fast, HashMap::new())
33    }
34
35    /// Evaluate with pre-loaded schemas (e.g. from multiple -f flags).
36    /// Schemas are keyed by document URI (file:// or https://).
37    pub fn evaluate_with_schemas<'b: 'a>(
38        root_schema: &'b RootSchema,
39        value: &str,
40        fail_fast: bool,
41        preloaded_schemas: HashMap<String, Rc<RootSchema>>,
42    ) -> Result<Context<'b>> {
43        let context =
44            Context::with_root_schema_and_schemas(root_schema, fail_fast, preloaded_schemas);
45        let engine = Engine::new(root_schema, context);
46        let docs = saphyr::MarkedYaml::load_from_str(value).map_err(Error::YamlParsingError)?;
47        match docs.first() {
48            Some(yaml) => match engine.root_schema.validate(&engine.context, yaml) {
49                Ok(()) | Err(Error::FailFast) => {}
50                Err(e) => return Err(e),
51            },
52            None => match &engine.root_schema.schema {
53                YamlSchema::Empty | YamlSchema::BooleanLiteral(true) => (),
54                _ => engine
55                    .context
56                    .add_doc_error("Empty YAML document is not allowed"),
57            },
58        }
59        Ok(engine.context)
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66    use crate::YamlSchema;
67
68    #[test]
69    fn test_engine_empty_schema() {
70        let root_schema = RootSchema::new(YamlSchema::Empty);
71        let context = Engine::evaluate(&root_schema, "", false).unwrap();
72        assert!(!context.has_errors());
73    }
74
75    #[test]
76    fn test_engine_boolean_literal_true() {
77        let root_schema = RootSchema::new(YamlSchema::BooleanLiteral(true));
78        let context = Engine::evaluate(&root_schema, "", false).unwrap();
79        assert!(!context.has_errors());
80    }
81
82    #[test]
83    fn test_engine_boolean_literal_false() {
84        let root_schema = RootSchema::new(YamlSchema::BooleanLiteral(false));
85        let context = Engine::evaluate(&root_schema, "", false).unwrap();
86        assert!(context.has_errors());
87    }
88}