summaryrefslogtreecommitdiff
path: root/src/codegen.rs
blob: 70d196693ae3863dad8fcd00c4fc863c6bda53e7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
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<TemplateSpec> {
    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<Context> {
    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> {
    // 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<P: AsRef<Path>>(filename: P) -> Result<String> {
    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<String, Value>) -> tera::Result<Value> {
    match v {
        Value::String(s) => Ok(Value::String(encode(s))),
        _ => Err(tera::Error::msg(
            "can only base64 encode strings".to_string(),
        )),
    }
}