use crate::{Document, TemplateSpec}; use std::collections::HashMap; use std::fs::File; use std::io::prelude::{Read, Write}; use std::path::Path; use base64::encode; use tera::{Context, Tera, Value}; use anyhow::Result; /// Return the requested template specification. pub fn template_spec(templates: &Path, doc: &Document) -> Result { let template = match doc.meta().template_name() { Some(x) => &x, None => "python", }; let mut filename = templates.to_path_buf(); filename.push(Path::new(template)); filename.push(Path::new("template.yaml")); Ok(TemplateSpec::from_file(&filename)?) } /// Generate a test program from a document, using a template spec. pub fn generate_test_program( doc: &mut Document, spec: &TemplateSpec, filename: &Path, ) -> Result<()> { let context = context(doc)?; let tera = tera(&spec)?; let code = tera.render("template", &context).expect("render"); write(filename, &code)?; Ok(()) } fn context(doc: &mut Document) -> Result { let mut context = Context::new(); context.insert("scenarios", &doc.matched_scenarios()?); context.insert("files", doc.files()); let (funcs_filename, funcs) = match doc.meta().functions_filename() { Some(filename) => (filename, cat(filename)?), None => (Path::new(""), "".to_string()), }; context.insert("functions", &funcs); context.insert("functions_filename", funcs_filename); Ok(context) } fn tera(tmplspec: &TemplateSpec) -> Result { // Tera insists on a glob, but we want to load a specific template // only, so we use a glob that doesn't match anything. let mut tera = Tera::new(&"*notexist").expect("new"); tera.register_filter("base64", base64); tera.add_template_file(tmplspec.template_filename(), Some("template"))?; Ok(tera) } fn cat>(filename: P) -> Result { let mut f = File::open(filename)?; let mut buf = String::new(); f.read_to_string(&mut buf)?; Ok(buf) } fn write(filename: &Path, content: &str) -> Result<()> { let mut f: File = File::create(filename)?; f.write_all(&content.as_bytes())?; Ok(()) } fn base64(v: &Value, _: &HashMap) -> tera::Result { match v { Value::String(s) => Ok(Value::String(encode(s))), _ => Err(tera::Error::msg( "can only base64 encode strings".to_string(), )), } }