go_template/
exec.rs

1use std::collections::VecDeque;
2use std::io::Write;
3
4use crate::error::ExecError;
5use crate::node::*;
6use crate::template::Template;
7use crate::utils::is_true;
8
9use gtmpl_value::{Func, Value};
10
11const MAX_TEMPLATE_DEPTH: usize = 100_000;
12#[derive(Debug)]
13struct Variable {
14    name: String,
15    value: Value,
16}
17
18struct State<'a, 'b, T: Write> {
19    template: &'a Template,
20    writer: &'b mut T,
21    node: Option<&'a Nodes>,
22    vars: VecDeque<VecDeque<Variable>>,
23    depth: usize,
24}
25
26/// A Context for the template. Passed to the template exectution.
27pub struct Context {
28    dot: Value,
29}
30
31impl Context {
32    pub fn empty() -> Context {
33        Context { dot: Value::Nil }
34    }
35
36    pub fn from<T>(value: T) -> Context
37    where
38        T: Into<Value>,
39    {
40        let serialized: Value = value.into();
41        Context { dot: serialized }
42    }
43}
44
45impl<'b> Template {
46    pub fn execute<T: Write>(&self, writer: &'b mut T, data: &Context) -> Result<(), ExecError> {
47        let mut vars: VecDeque<VecDeque<Variable>> = VecDeque::new();
48        let mut dot = VecDeque::new();
49        dot.push_back(Variable {
50            name: "$".to_owned(),
51            value: data.dot.clone(),
52        });
53        vars.push_back(dot);
54
55        let mut state = State {
56            template: self,
57            writer,
58            node: None,
59            vars,
60            depth: 0,
61        };
62
63        let root = self
64            .tree_set
65            .get(&self.name)
66            .and_then(|tree| tree.root.as_ref())
67            .ok_or_else(|| ExecError::IncompleteTemplate(self.name.clone()))?;
68        state.walk(data, root)?;
69
70        Ok(())
71    }
72
73    pub fn render(&self, data: &Context) -> Result<String, ExecError> {
74        let mut w: Vec<u8> = vec![];
75        self.execute(&mut w, data)?;
76        String::from_utf8(w).map_err(ExecError::Utf8ConversionFailed)
77    }
78}
79
80impl<'a, 'b, T: Write> State<'a, 'b, T> {
81    fn set_kth_last_var_value(&mut self, k: usize, value: Value) -> Result<(), ExecError> {
82        if let Some(last_vars) = self.vars.back_mut() {
83            let i = last_vars.len() - k;
84            if let Some(kth_last_var) = last_vars.get_mut(i) {
85                kth_last_var.value = value;
86                return Ok(());
87            }
88            return Err(ExecError::VarContextToSmall(k));
89        }
90        Err(ExecError::EmptyStack)
91    }
92
93    fn var_value(&self, key: &str) -> Result<Value, ExecError> {
94        for context in self.vars.iter().rev() {
95            for var in context.iter().rev() {
96                if var.name == key {
97                    return Ok(var.value.clone());
98                }
99            }
100        }
101        Err(ExecError::VariableNotFound(key.to_string()))
102    }
103
104    fn walk_list(&mut self, ctx: &Context, node: &'a ListNode) -> Result<(), ExecError> {
105        for n in &node.nodes {
106            self.walk(ctx, n)?;
107        }
108        Ok(())
109    }
110
111    // Top level walk function. Steps through the major parts for the template strcuture and
112    // writes to the output.
113    fn walk(&mut self, ctx: &Context, node: &'a Nodes) -> Result<(), ExecError> {
114        self.node = Some(node);
115        match *node {
116            Nodes::Action(ref n) => {
117                let val = self.eval_pipeline(ctx, &n.pipe)?;
118                if n.pipe.decl.is_empty() {
119                    self.print_value(&val)?;
120                }
121                Ok(())
122            }
123            Nodes::If(_) | Nodes::With(_) => self.walk_if_or_with(node, ctx),
124            Nodes::Range(ref n) => self.walk_range(ctx, n),
125            Nodes::List(ref n) => self.walk_list(ctx, n),
126            Nodes::Text(ref n) => write!(self.writer, "{}", n).map_err(ExecError::IOError),
127            Nodes::Template(ref n) => self.walk_template(ctx, n),
128            _ => Err(ExecError::UnknownNode(node.clone())),
129        }
130    }
131
132    fn walk_template(&mut self, ctx: &Context, template: &TemplateNode) -> Result<(), ExecError> {
133        let name = match template.name {
134            PipeOrString::String(ref name) => name.to_owned(),
135            PipeOrString::Pipe(ref pipe) => {
136                if let Value::String(s) = self.eval_pipeline(ctx, pipe)? {
137                    s
138                } else {
139                    return Err(ExecError::PipelineMustYieldString);
140                }
141            }
142        };
143        if self.depth >= MAX_TEMPLATE_DEPTH {
144            return Err(ExecError::MaxTemplateDepth);
145        }
146        let tree = self.template.tree_set.get(&name);
147        if let Some(tree) = tree {
148            if let Some(ref root) = tree.root {
149                let mut vars = VecDeque::new();
150                let mut dot = VecDeque::new();
151                let value = if let Some(ref pipe) = template.pipe {
152                    self.eval_pipeline(ctx, pipe)?
153                } else {
154                    Value::NoValue
155                };
156                dot.push_back(Variable {
157                    name: "$".to_owned(),
158                    value: value.clone(),
159                });
160                vars.push_back(dot);
161                let mut new_state = State {
162                    template: self.template,
163                    writer: self.writer,
164                    node: None,
165                    vars,
166                    depth: self.depth + 1,
167                };
168                return new_state.walk(&Context::from(value), root);
169            }
170        }
171        Err(ExecError::TemplateNotDefined(name))
172    }
173
174    fn eval_pipeline(&mut self, ctx: &Context, pipe: &PipeNode) -> Result<Value, ExecError> {
175        let mut val: Option<Value> = None;
176        for cmd in &pipe.cmds {
177            val = Some(self.eval_command(ctx, cmd, &val)?);
178            // TODO
179        }
180        let val = val.ok_or_else(|| ExecError::ErrorEvaluatingPipe(pipe.clone()))?;
181        for var in &pipe.decl {
182            if pipe.is_assign == true {
183                let mut idx2 = -1;
184                let mut idx1 = -1;
185                for (k, v) in self.vars.iter().enumerate() {
186                    for (k2, v2) in v.iter().enumerate() {
187                        if v2.name == var.ident[0] {
188                            idx2 = k2 as i32;
189                            idx1 = k as i32;
190                        }
191                    }
192                }
193                // println!("val assign is   {:?}", self.vars);
194                self.vars[idx1 as usize].remove(idx2 as usize);
195                self.vars[idx1 as usize].insert(
196                    idx2 as usize,
197                    Variable {
198                        name: var.ident[0].clone(),
199                        value: val.clone(),
200                    },
201                );
202                // println!(
203                //     "val assign is{} {:?}, {:?}",
204                //     var.ident[0],
205                //     val.clone(),
206                //     self.vars
207                // );
208            } else {
209                // println!("val no assign is{} {:?}", var.ident[0].clone(), val.clone());
210
211                self.vars
212                    .back_mut()
213                    .map(|v| {
214                        v.push_back(Variable {
215                            name: var.ident[0].clone(),
216                            value: val.clone(),
217                        })
218                    })
219                    .ok_or(ExecError::EmptyStack)?;
220            }
221        }
222        Ok(val)
223    }
224
225    fn eval_command(
226        &mut self,
227        ctx: &Context,
228        cmd: &CommandNode,
229        val: &Option<Value>,
230    ) -> Result<Value, ExecError> {
231        let first_word = &cmd
232            .args
233            .first()
234            .ok_or_else(|| ExecError::NoArgsForCommandNode(cmd.clone()))?;
235
236        match *(*first_word) {
237            Nodes::Field(ref n) => return self.eval_field_node(ctx, n, &cmd.args, val),
238            Nodes::Variable(ref n) => return self.eval_variable_node(n, &cmd.args, val),
239            Nodes::Pipe(ref n) => return self.eval_pipeline(ctx, n),
240            Nodes::Chain(ref n) => return self.eval_chain_node(ctx, n, &cmd.args, val),
241            Nodes::Identifier(ref n) => return self.eval_function(ctx, n, &cmd.args, val),
242            _ => {}
243        }
244        not_a_function(&cmd.args, val)?;
245        match *(*first_word) {
246            Nodes::Bool(ref n) => Ok(n.value.clone()),
247            Nodes::Dot(_) => Ok(ctx.dot.clone()),
248            Nodes::Number(ref n) => Ok(n.value.clone()),
249            Nodes::String(ref n) => Ok(n.value.clone()),
250            _ => Err(ExecError::CannotEvaluateCommand((*first_word).clone())),
251        }
252    }
253
254    fn eval_function(
255        &mut self,
256        ctx: &Context,
257        ident: &IdentifierNode,
258        args: &[Nodes],
259        fin: &Option<Value>,
260    ) -> Result<Value, ExecError> {
261        let name = &ident.ident;
262        let function = self
263            .template
264            .funcs
265            .get(name.as_str())
266            .ok_or_else(|| ExecError::UndefinedFunction(name.to_string()))?;
267        self.eval_call(ctx, *function, args, fin)
268    }
269
270    fn eval_call(
271        &mut self,
272        ctx: &Context,
273        function: Func,
274        args: &[Nodes],
275        fin: &Option<Value>,
276    ) -> Result<Value, ExecError> {
277        let mut arg_vals = vec![];
278        if !args.is_empty() {
279            for arg in &args[1..] {
280                let val = self.eval_arg(ctx, arg)?;
281                arg_vals.push(val);
282            }
283        }
284        if let Some(ref f) = *fin {
285            arg_vals.push(f.clone());
286        }
287        // println!("{:?}", arg_vals);
288
289        function(&arg_vals).map_err(Into::into)
290    }
291
292    fn eval_chain_node(
293        &mut self,
294        ctx: &Context,
295        chain: &ChainNode,
296        args: &[Nodes],
297        fin: &Option<Value>,
298    ) -> Result<Value, ExecError> {
299        if chain.field.is_empty() {
300            return Err(ExecError::NoFieldsInEvalChainNode);
301        }
302        if let Nodes::Nil(_) = *chain.node {
303            return Err(ExecError::NullInChain(chain.clone()));
304        }
305        let pipe = self.eval_arg(ctx, &*chain.node)?;
306        self.eval_field_chain(&pipe, &chain.field, args, fin)
307    }
308
309    fn eval_arg(&mut self, ctx: &Context, node: &Nodes) -> Result<Value, ExecError> {
310        match *node {
311            Nodes::Dot(_) => Ok(ctx.dot.clone()),
312            //Nodes::Nil
313            Nodes::Field(ref n) => self.eval_field_node(ctx, n, &[], &None), // args?
314            Nodes::Variable(ref n) => self.eval_variable_node(n, &[], &None),
315            Nodes::Pipe(ref n) => self.eval_pipeline(ctx, n),
316            // Nodes::Identifier
317            Nodes::Identifier(ref n) => self.eval_function(ctx, n, &[], &None),
318            Nodes::Chain(ref n) => self.eval_chain_node(ctx, n, &[], &None),
319            Nodes::String(ref n) => Ok(n.value.clone()),
320            Nodes::Bool(ref n) => Ok(n.value.clone()),
321            Nodes::Number(ref n) => Ok(n.value.clone()),
322            _ => Err(ExecError::InvalidArgument(node.clone())),
323        }
324    }
325
326    fn eval_field_node(
327        &mut self,
328        ctx: &Context,
329        field: &FieldNode,
330        args: &[Nodes],
331        fin: &Option<Value>,
332    ) -> Result<Value, ExecError> {
333        self.eval_field_chain(&ctx.dot, &field.ident, args, fin)
334    }
335
336    fn eval_field_chain(
337        &mut self,
338        receiver: &Value,
339        ident: &[String],
340        args: &[Nodes],
341        fin: &Option<Value>,
342    ) -> Result<Value, ExecError> {
343        let n = ident.len();
344        if n < 1 {
345            return Err(ExecError::FieldChainWithoutFields);
346        }
347        // TODO clean shit up
348        let mut r: Value = Value::from(0);
349        for (i, id) in ident.iter().enumerate().take(n - 1) {
350            r = self.eval_field(if i == 0 { receiver } else { &r }, id, &[], &None)?;
351        }
352        self.eval_field(if n == 1 { receiver } else { &r }, &ident[n - 1], args, fin)
353    }
354
355    fn eval_field(
356        &mut self,
357        receiver: &Value,
358        field_name: &str,
359        args: &[Nodes],
360        fin: &Option<Value>,
361    ) -> Result<Value, ExecError> {
362        let has_args = args.len() > 1 || fin.is_some();
363        if has_args {
364            return Err(ExecError::NotAFunctionButArguments(field_name.to_string()));
365        }
366        let ret = match *receiver {
367            Value::Object(ref o) => o
368                .get(field_name)
369                .cloned()
370                .ok_or_else(|| ExecError::NoFiledFor(field_name.to_string(), receiver.clone())),
371            Value::Map(ref o) => Ok(o.get(field_name).cloned().unwrap_or(Value::NoValue)),
372            _ => Err(ExecError::OnlyMapsAndObjectsHaveFields),
373        };
374        if let Ok(Value::Function(ref f)) = ret {
375            return (f.f)(&[receiver.clone()]).map_err(Into::into);
376        }
377        ret
378    }
379
380    fn eval_variable_node(
381        &mut self,
382        variable: &VariableNode,
383        args: &[Nodes],
384        fin: &Option<Value>,
385    ) -> Result<Value, ExecError> {
386        let val = self.var_value(&variable.ident[0])?;
387        if variable.ident.len() == 1 {
388            not_a_function(args, fin)?;
389            return Ok(val);
390        }
391        self.eval_field_chain(&val, &variable.ident[1..], args, fin)
392    }
393
394    // Walks an `if` or `with` node. They behave the same, except that `with` sets dot.
395    fn walk_if_or_with(&mut self, node: &'a Nodes, ctx: &Context) -> Result<(), ExecError> {
396        let pipe = match *node {
397            Nodes::If(ref n) | Nodes::With(ref n) => &n.pipe,
398            _ => return Err(ExecError::ExpectedIfOrWith(node.clone())),
399        };
400        let val = self.eval_pipeline(ctx, pipe)?;
401        let truth = is_true(&val);
402        if truth {
403            match *node {
404                Nodes::If(ref n) => self.walk_list(ctx, &n.list)?,
405                Nodes::With(ref n) => {
406                    let ctx = Context { dot: val };
407                    self.walk_list(&ctx, &n.list)?;
408                }
409                _ => {}
410            }
411        } else {
412            match *node {
413                Nodes::If(ref n) | Nodes::With(ref n) => {
414                    if let Some(ref otherwise) = n.else_list {
415                        self.walk_list(ctx, otherwise)?;
416                    }
417                }
418                _ => {}
419            }
420        }
421        Ok(())
422    }
423
424    fn one_iteration(
425        &mut self,
426        key: Value,
427        val: Value,
428        range: &'a RangeNode,
429    ) -> Result<(), ExecError> {
430        if !range.pipe.decl.is_empty() {
431            self.set_kth_last_var_value(1, val.clone())?;
432        }
433        if range.pipe.decl.len() > 1 {
434            self.set_kth_last_var_value(2, key)?;
435        }
436        let vars = VecDeque::new();
437        self.vars.push_back(vars);
438        let ctx = Context { dot: val };
439        self.walk_list(&ctx, &range.list)?;
440        self.vars.pop_back();
441        Ok(())
442    }
443
444    fn walk_range(&mut self, ctx: &Context, range: &'a RangeNode) -> Result<(), ExecError> {
445        let val = self.eval_pipeline(ctx, &range.pipe)?;
446        match val {
447            Value::Object(ref map) | Value::Map(ref map) => {
448                for (k, v) in map.clone() {
449                    self.one_iteration(Value::from(k), v, range)?;
450                }
451            }
452            Value::Array(ref vec) => {
453                for (k, v) in vec.iter().enumerate() {
454                    self.one_iteration(Value::from(k), v.clone(), range)?;
455                }
456            }
457            _ => return Err(ExecError::InvalidRange(val)),
458        }
459        if let Some(ref else_list) = range.else_list {
460            self.walk_list(ctx, else_list)?;
461        }
462        Ok(())
463    }
464
465    fn print_value(&mut self, val: &Value) -> Result<(), ExecError> {
466        write!(self.writer, "{}", val).map_err(ExecError::IOError)?;
467        Ok(())
468    }
469}
470
471fn not_a_function(args: &[Nodes], val: &Option<Value>) -> Result<(), ExecError> {
472    if args.len() > 1 || val.is_some() {
473        return Err(ExecError::ArgumentForNonFunction(args[0].clone()));
474    }
475    Ok(())
476}
477
478#[cfg(test)]
479mod tests_mocked {
480    use super::*;
481    use anyhow::anyhow;
482    use gtmpl_derive::Gtmpl;
483    use gtmpl_value::FuncError;
484    use std::collections::HashMap;
485
486    #[test]
487    fn simple_template() {
488        let data = Context::from(1);
489        let mut w: Vec<u8> = vec![];
490        let mut t = Template::default();
491        assert!(t.parse(r#"{{ if false }} 2000 {{ end }}"#).is_ok());
492        let out = t.execute(&mut w, &data);
493        assert!(out.is_ok());
494        assert_eq!(String::from_utf8(w).unwrap(), "");
495
496        let data = Context::from(1);
497        let mut w: Vec<u8> = vec![];
498        let mut t = Template::default();
499        assert!(t.parse(r#"{{ if true }} 2000 {{ end }}"#).is_ok());
500        let out = t.execute(&mut w, &data);
501        assert!(out.is_ok());
502        assert_eq!(String::from_utf8(w).unwrap(), " 2000 ");
503
504        let data = Context::from(1);
505        let mut w: Vec<u8> = vec![];
506        let mut t = Template::default();
507        assert!(t.parse(r#"{{ if true -}} 2000 {{- end }}"#).is_ok());
508        let out = t.execute(&mut w, &data);
509        assert!(out.is_ok());
510        assert_eq!(String::from_utf8(w).unwrap(), "2000");
511
512        let data = Context::from(1);
513        let mut w: Vec<u8> = vec![];
514        let mut t = Template::default();
515        assert!(t
516            .parse(r#"{{ if false -}} 2000 {{- else -}} 3000 {{- end }}"#)
517            .is_ok());
518        let out = t.execute(&mut w, &data);
519        assert!(out.is_ok());
520        assert_eq!(String::from_utf8(w).unwrap(), "3000");
521    }
522
523    #[test]
524    fn test_dot() {
525        let data = Context::from(1);
526        let mut w: Vec<u8> = vec![];
527        let mut t = Template::default();
528        assert!(t
529            .parse(r#"{{ if . -}} 2000 {{- else -}} 3000 {{- end }}"#)
530            .is_ok());
531        let out = t.execute(&mut w, &data);
532        assert!(out.is_ok());
533        assert_eq!(String::from_utf8(w).unwrap(), "2000");
534
535        let data = Context::from(false);
536        let mut w: Vec<u8> = vec![];
537        let mut t = Template::default();
538        assert!(t
539            .parse(r#"{{ if . -}} 2000 {{- else -}} 3000 {{- end }}"#)
540            .is_ok());
541        let out = t.execute(&mut w, &data);
542        assert!(out.is_ok());
543        assert_eq!(String::from_utf8(w).unwrap(), "3000");
544    }
545
546    #[test]
547    fn test_sub() {
548        let data = Context::from(1u8);
549        let mut w: Vec<u8> = vec![];
550        let mut t = Template::default();
551        assert!(t.parse(r#"{{.}}"#).is_ok());
552        let out = t.execute(&mut w, &data);
553        assert!(out.is_ok());
554        assert_eq!(String::from_utf8(w).unwrap(), "1");
555
556        #[derive(Gtmpl)]
557        struct Foo {
558            foo: u8,
559        }
560        let f = Foo { foo: 1 };
561        let data = Context::from(f);
562        let mut w: Vec<u8> = vec![];
563        let mut t = Template::default();
564        assert!(t.parse(r#"{{.foo}}"#).is_ok());
565        let out = t.execute(&mut w, &data);
566        assert!(out.is_ok());
567        assert_eq!(String::from_utf8(w).unwrap(), "1");
568    }
569
570    #[test]
571    fn test_novalue() {
572        #[derive(Gtmpl)]
573        struct Foo {
574            foo: u8,
575        }
576        let f = Foo { foo: 1 };
577        let data = Context::from(f);
578        let mut w: Vec<u8> = vec![];
579        let mut t = Template::default();
580        assert!(t.parse(r#"{{.foobar}}"#).is_ok());
581        let out = t.execute(&mut w, &data);
582        assert!(out.is_err());
583
584        let map: HashMap<String, u64> = [("foo".to_owned(), 23u64)].iter().cloned().collect();
585        let data = Context::from(map);
586        let mut w: Vec<u8> = vec![];
587        let mut t = Template::default();
588        assert!(t.parse(r#"{{.foo2}}"#).is_ok());
589        let out = t.execute(&mut w, &data);
590        assert!(out.is_ok());
591        assert_eq!(String::from_utf8(w).unwrap(), Value::NoValue.to_string());
592    }
593
594    #[test]
595    fn test_dollar_dot() {
596        #[derive(Gtmpl, Clone)]
597        struct Foo {
598            foo: u8,
599        }
600        let data = Context::from(Foo { foo: 1u8 });
601        let mut w: Vec<u8> = vec![];
602        let mut t = Template::default();
603        assert!(t.parse(r#"{{$.foo}}"#).is_ok());
604        let out = t.execute(&mut w, &data);
605        assert!(out.is_ok());
606        assert_eq!(String::from_utf8(w).unwrap(), "1");
607    }
608
609    #[test]
610    fn test_function_via_dot() {
611        #[derive(Gtmpl)]
612        struct Foo {
613            foo: Func,
614        }
615        fn foo(_: &[Value]) -> Result<Value, FuncError> {
616            Ok(Value::from("foobar"))
617        }
618        let data = Context::from(Foo { foo });
619        let mut w: Vec<u8> = vec![];
620        let mut t = Template::default();
621        assert!(t.parse(r#"{{.foo}}"#).is_ok());
622        let out = t.execute(&mut w, &data);
623        assert!(out.is_ok());
624        assert_eq!(String::from_utf8(w).unwrap(), "foobar");
625
626        fn plus_one(args: &[Value]) -> Result<Value, FuncError> {
627            if let Value::Object(ref o) = &args[0] {
628                if let Some(Value::Number(ref n)) = o.get("num") {
629                    if let Some(i) = n.as_i64() {
630                        return Ok((i + 1).into());
631                    }
632                }
633            }
634            Err(anyhow!("integer required, got: {:?}", args).into())
635        }
636
637        #[derive(Gtmpl)]
638        struct AddMe {
639            num: u8,
640            plus_one: Func,
641        }
642        let data = Context::from(AddMe { num: 42, plus_one });
643        let mut w: Vec<u8> = vec![];
644        let mut t = Template::default();
645        assert!(t.parse(r#"{{.plus_one}}"#).is_ok());
646        let out = t.execute(&mut w, &data);
647        assert!(out.is_ok());
648        assert_eq!(String::from_utf8(w).unwrap(), "43");
649    }
650
651    #[test]
652    fn test_function_ret_map() {
653        fn map(_: &[Value]) -> Result<Value, FuncError> {
654            let mut h = HashMap::new();
655            h.insert("field".to_owned(), 1);
656            Ok(h.into())
657        }
658
659        let data = Context::empty();
660        let mut w: Vec<u8> = vec![];
661        let mut t = Template::default();
662        t.add_func("map", map);
663        assert!(t.parse(r#"{{map.field}}"#).is_ok());
664        let out = t.execute(&mut w, &data);
665        assert!(out.is_ok());
666        assert_eq!(String::from_utf8(w).unwrap(), "1");
667    }
668
669    #[test]
670    fn test_dot_value() {
671        #[derive(Gtmpl, Clone)]
672        struct Foo {
673            foo: u8,
674        }
675        #[derive(Gtmpl)]
676        struct Bar {
677            bar: Foo,
678        }
679        let f = Foo { foo: 1 };
680        let data = Context::from(f);
681        let mut w: Vec<u8> = vec![];
682        let mut t = Template::default();
683        assert!(t
684            .parse(r#"{{ if .foo -}} 2000 {{- else -}} 3000 {{- end }}"#)
685            .is_ok());
686        let out = t.execute(&mut w, &data);
687        assert!(out.is_ok());
688        assert_eq!(String::from_utf8(w).unwrap(), "2000");
689
690        let f = Foo { foo: 0 };
691        let data = Context::from(f);
692        let mut w: Vec<u8> = vec![];
693        let mut t = Template::default();
694        assert!(t
695            .parse(r#"{{ if .foo -}} 2000 {{- else -}} 3000 {{- end }}"#)
696            .is_ok());
697        let out = t.execute(&mut w, &data);
698        assert!(out.is_ok());
699        assert_eq!(String::from_utf8(w).unwrap(), "3000");
700
701        let bar = Bar {
702            bar: Foo { foo: 1 },
703        };
704        let data = Context::from(bar);
705        let mut w: Vec<u8> = vec![];
706        let mut t = Template::default();
707        assert!(t
708            .parse(r#"{{ if .bar.foo -}} 2000 {{- else -}} 3000 {{- end }}"#)
709            .is_ok());
710        let out = t.execute(&mut w, &data);
711        assert!(out.is_ok());
712        assert_eq!(String::from_utf8(w).unwrap(), "2000");
713
714        let bar = Bar {
715            bar: Foo { foo: 0 },
716        };
717        let data = Context::from(bar);
718        let mut w: Vec<u8> = vec![];
719        let mut t = Template::default();
720        assert!(t
721            .parse(r#"{{ if .bar.foo -}} 2000 {{- else -}} 3000 {{- end }}"#)
722            .is_ok());
723        let out = t.execute(&mut w, &data);
724        assert!(out.is_ok());
725        assert_eq!(String::from_utf8(w).unwrap(), "3000");
726    }
727
728    #[test]
729    fn test_with() {
730        #[derive(Gtmpl)]
731        struct Foo {
732            foo: u16,
733        }
734        let f = Foo { foo: 1000 };
735        let data = Context::from(f);
736        let mut w: Vec<u8> = vec![];
737        let mut t = Template::default();
738        assert!(t
739            .parse(r#"{{ with .foo -}} {{.}} {{- else -}} 3000 {{- end }}"#)
740            .is_ok());
741        let out = t.execute(&mut w, &data);
742        assert!(out.is_ok());
743        assert_eq!(String::from_utf8(w).unwrap(), "1000");
744    }
745
746    fn to_sorted_string(buf: Vec<u8>) -> String {
747        let mut chars: Vec<char> = String::from_utf8(buf).unwrap().chars().collect();
748        chars.sort_unstable();
749        chars.iter().cloned().collect::<String>()
750    }
751
752    #[test]
753    fn test_range() {
754        let mut map = HashMap::new();
755        map.insert("a".to_owned(), 1);
756        map.insert("b".to_owned(), 2);
757        let data = Context::from(map);
758        let mut w: Vec<u8> = vec![];
759        let mut t = Template::default();
760        assert!(t.parse(r#"{{ range . -}} {{.}} {{- end }}"#).is_ok());
761        let out = t.execute(&mut w, &data);
762        assert!(out.is_ok());
763        assert_eq!(to_sorted_string(w), "12");
764
765        let vec = vec!["foo", "bar", "2000"];
766        let data = Context::from(vec);
767        let mut w: Vec<u8> = vec![];
768        let mut t = Template::default();
769        assert!(t.parse(r#"{{ range . -}} {{.}} {{- end }}"#).is_ok());
770        let out = t.execute(&mut w, &data);
771        assert!(out.is_ok());
772        assert_eq!(String::from_utf8(w).unwrap(), "foobar2000");
773    }
774
775    #[test]
776    fn test_proper_range() {
777        let vec = vec!["a".to_string(), "b".to_string()];
778        let data = Context::from(vec);
779        let mut w: Vec<u8> = vec![];
780        let mut t = Template::default();
781        assert!(t
782            .parse(r#"{{ range $k, $v := . -}} {{ $k }}{{ $v }} {{- end }}"#)
783            .is_ok());
784        let out = t.execute(&mut w, &data);
785        assert!(out.is_ok());
786        assert_eq!(String::from_utf8(w).unwrap(), "0a1b");
787
788        let mut map = HashMap::new();
789        map.insert("a".to_owned(), 1);
790        map.insert("b".to_owned(), 2);
791        let data = Context::from(map);
792        let mut w: Vec<u8> = vec![];
793        let mut t = Template::default();
794        assert!(t
795            .parse(r#"{{ range $k, $v := . -}} {{ $v }} {{- end }}"#)
796            .is_ok());
797        let out = t.execute(&mut w, &data);
798        assert!(out.is_ok());
799        assert_eq!(to_sorted_string(w), "12");
800
801        let mut map = HashMap::new();
802        map.insert("a".to_owned(), "b");
803        map.insert("c".to_owned(), "d");
804        let data = Context::from(map);
805        let mut w: Vec<u8> = vec![];
806        let mut t = Template::default();
807        assert!(t
808            .parse(r#"{{ range $k, $v := . -}} {{ $k }}{{ $v }} {{- end }}"#)
809            .is_ok());
810        let out = t.execute(&mut w, &data);
811        assert!(out.is_ok());
812        assert_eq!(to_sorted_string(w), "abcd");
813
814        let mut map = HashMap::new();
815        map.insert("a".to_owned(), 1);
816        map.insert("b".to_owned(), 2);
817        let data = Context::from(map);
818        let mut w: Vec<u8> = vec![];
819        let mut t = Template::default();
820        assert!(t
821            .parse(r#"{{ range $k, $v := . -}} {{ $k }}{{ $v }} {{- end }}"#)
822            .is_ok());
823        let out = t.execute(&mut w, &data);
824        assert!(out.is_ok());
825        assert_eq!(to_sorted_string(w), "12ab");
826
827        let mut map = HashMap::new();
828        map.insert("a".to_owned(), 1);
829        map.insert("b".to_owned(), 2);
830        #[derive(Gtmpl)]
831        struct Foo {
832            foo: HashMap<String, i32>,
833        }
834        let f = Foo { foo: map };
835        let data = Context::from(f);
836        let mut w: Vec<u8> = vec![];
837        let mut t = Template::default();
838        assert!(t
839            .parse(r#"{{ range $k, $v := .foo -}} {{ $v }} {{- end }}"#)
840            .is_ok());
841        let out = t.execute(&mut w, &data);
842        assert!(out.is_ok());
843        assert_eq!(to_sorted_string(w), "12");
844
845        let mut map = HashMap::new();
846        #[derive(Gtmpl, Clone)]
847        struct Bar {
848            bar: i32,
849        }
850        map.insert("a".to_owned(), Bar { bar: 1 });
851        map.insert("b".to_owned(), Bar { bar: 2 });
852        let data = Context::from(map);
853        let mut w: Vec<u8> = vec![];
854        let mut t = Template::default();
855        assert!(t
856            .parse(r#"{{ range $k, $v := . -}} {{ $v.bar }} {{- end }}"#)
857            .is_ok());
858        let out = t.execute(&mut w, &data);
859        assert!(out.is_ok());
860        assert_eq!(to_sorted_string(w), "12");
861    }
862
863    #[test]
864    fn test_len() {
865        let mut w: Vec<u8> = vec![];
866        let mut t = Template::default();
867        assert!(t.parse(r#"my len is {{ len . }}"#).is_ok());
868        let data = Context::from(vec![1, 2, 3]);
869        let out = t.execute(&mut w, &data);
870        assert!(out.is_ok());
871        assert_eq!(String::from_utf8(w).unwrap(), "my len is 3");
872
873        let mut w: Vec<u8> = vec![];
874        let mut t = Template::default();
875        assert!(t.parse(r#"{{ len . }}"#).is_ok());
876        let data = Context::from("hello".to_owned());
877        let out = t.execute(&mut w, &data);
878        assert!(out.is_ok());
879        assert_eq!(String::from_utf8(w).unwrap(), "5");
880    }
881
882    #[test]
883    fn test_pipeline_function() {
884        let mut w: Vec<u8> = vec![];
885        let mut t = Template::default();
886        assert!(t.parse(r#"{{ if ( 1 | eq . ) -}} 2000 {{- end }}"#).is_ok());
887        let data = Context::from(1);
888        let out = t.execute(&mut w, &data);
889        assert!(out.is_ok());
890        assert_eq!(String::from_utf8(w).unwrap(), "2000");
891    }
892
893    #[test]
894    fn test_function() {
895        let mut w: Vec<u8> = vec![];
896        let mut t = Template::default();
897        assert!(t.parse(r#"{{ if eq . . -}} 2000 {{- end }}"#).is_ok());
898        let data = Context::from(1);
899        let out = t.execute(&mut w, &data);
900        assert!(out.is_ok());
901        assert_eq!(String::from_utf8(w).unwrap(), "2000");
902    }
903
904    #[test]
905    fn test_eq() {
906        let mut w: Vec<u8> = vec![];
907        let mut t = Template::default();
908        assert!(t.parse(r#"{{ if eq "a" "a" -}} 2000 {{- end }}"#).is_ok());
909        let data = Context::from(1);
910        let out = t.execute(&mut w, &data);
911        assert!(out.is_ok());
912        assert_eq!(String::from_utf8(w).unwrap(), "2000");
913
914        let mut w: Vec<u8> = vec![];
915        let mut t = Template::default();
916        assert!(t.parse(r#"{{ if eq "a" "b" -}} 2000 {{- end }}"#).is_ok());
917        let data = Context::from(1);
918        let out = t.execute(&mut w, &data);
919        assert!(out.is_ok());
920        assert_eq!(String::from_utf8(w).unwrap(), "");
921
922        let mut w: Vec<u8> = vec![];
923        let mut t = Template::default();
924        assert!(t.parse(r#"{{ if eq true true -}} 2000 {{- end }}"#).is_ok());
925        let data = Context::from(1);
926        let out = t.execute(&mut w, &data);
927        assert!(out.is_ok());
928        assert_eq!(String::from_utf8(w).unwrap(), "2000");
929
930        let mut w: Vec<u8> = vec![];
931        let mut t = Template::default();
932        assert!(t
933            .parse(r#"{{ if eq true false -}} 2000 {{- end }}"#)
934            .is_ok());
935        let data = Context::from(1);
936        let out = t.execute(&mut w, &data);
937        assert!(out.is_ok());
938        assert_eq!(String::from_utf8(w).unwrap(), "");
939
940        let mut w: Vec<u8> = vec![];
941        let mut t = Template::default();
942        assert!(t
943            .parse(r#"{{ if eq 23.42 23.42 -}} 2000 {{- end }}"#)
944            .is_ok());
945        let data = Context::from(1);
946        let out = t.execute(&mut w, &data);
947        assert!(out.is_ok());
948        assert_eq!(String::from_utf8(w).unwrap(), "2000");
949
950        let mut w: Vec<u8> = vec![];
951        let mut t = Template::default();
952        assert!(t.parse(r#"{{ if eq 1 . -}} 2000 {{- end }}"#).is_ok());
953        let data = Context::from(1);
954        let out = t.execute(&mut w, &data);
955        assert!(out.is_ok());
956        assert_eq!(String::from_utf8(w).unwrap(), "2000");
957    }
958
959    #[test]
960    fn test_block() {
961        let mut w: Vec<u8> = vec![];
962        let mut t = Template::default();
963        assert!(t
964            .parse(r#"{{ block "foobar" true -}} {{ $ }} {{- end }}"#)
965            .is_ok());
966        let data = Context::from(2000);
967        let out = t.execute(&mut w, &data);
968        assert!(out.is_ok());
969        assert_eq!(String::from_utf8(w).unwrap(), "true");
970    }
971
972    #[test]
973    fn test_assign_string() {
974        let mut w: Vec<u8> = vec![];
975        let mut t = Template::default();
976        assert!(t
977            .parse(r#"{{ with $foo := "bar" }}{{ $foo }}{{ end }}"#)
978            .is_ok());
979        let data = Context::from(1);
980        let out = t.execute(&mut w, &data);
981        assert!(out.is_ok());
982        assert_eq!(String::from_utf8(w).unwrap(), "bar");
983    }
984}