diff options
-rw-r--r-- | askama_shared/Cargo.toml | 4 | ||||
-rw-r--r-- | askama_shared/src/generator.rs | 60 | ||||
-rw-r--r-- | askama_shared/src/heritage.rs | 2 | ||||
-rw-r--r-- | askama_shared/src/parser.rs | 247 | ||||
-rw-r--r-- | book/src/filters.md | 4 | ||||
-rw-r--r-- | testing/templates/if-coerce.html | 51 | ||||
-rw-r--r-- | testing/templates/macro-short-circuit.html | 9 | ||||
-rw-r--r-- | testing/tests/coerce.rs | 14 | ||||
-rw-r--r-- | testing/tests/gen_ws_tests.py | 186 | ||||
-rw-r--r-- | testing/tests/macro.rs | 10 | ||||
-rw-r--r-- | testing/tests/matches.rs | 22 | ||||
-rw-r--r-- | testing/tests/operators.rs | 10 | ||||
-rw-r--r-- | testing/tests/simple.rs | 9 | ||||
-rw-r--r-- | testing/tests/whitespace.rs | 2 | ||||
-rw-r--r-- | testing/tests/ws.rs | 214 |
15 files changed, 760 insertions, 84 deletions
diff --git a/askama_shared/Cargo.toml b/askama_shared/Cargo.toml index f5ac4b6..fdc5a4c 100644 --- a/askama_shared/Cargo.toml +++ b/askama_shared/Cargo.toml @@ -19,9 +19,7 @@ yaml = ["serde", "serde_yaml"] [dependencies] askama_escape = { version = "0.10", path = "../askama_escape" } humansize = { version = "1.1.0", optional = true } -# default for features for nom don't work result in linker errors: -# https://github.com/rust-lang/rust/issues/62146 -nom = { version = "6", features = ["std"] } +nom = { version = "6", features = ["std"], default-features = false } num-traits = { version = "0.2.6", optional = true } proc-macro2 = "1" quote = "1" diff --git a/askama_shared/src/generator.rs b/askama_shared/src/generator.rs index 3b73170..146f9db 100644 --- a/askama_shared/src/generator.rs +++ b/askama_shared/src/generator.rs @@ -444,8 +444,8 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> { Node::Cond(ref conds, ws) => { self.write_cond(ctx, buf, conds, ws)?; } - Node::Match(ws1, ref expr, inter, ref arms, ws2) => { - self.write_match(ctx, buf, ws1, expr, inter, arms, ws2)?; + Node::Match(ws1, ref expr, ref arms, ws2) => { + self.write_match(ctx, buf, ws1, expr, arms, ws2)?; } Node::Loop(ws1, ref var, ref iter, ref body, ws2) => { self.write_loop(ctx, buf, ws1, var, iter, body, ws2)?; @@ -505,8 +505,9 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> { let mut has_else = false; for (i, &(cws, ref cond, ref nodes)) in conds.iter().enumerate() { self.handle_ws(cws); - if arm_sizes.is_empty() { - flushed += self.write_buf_writable(buf)?; + flushed += self.write_buf_writable(buf)?; + if i > 0 { + self.locals.pop(); } let mut arm_size = 0; @@ -518,8 +519,15 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> { buf.dedent()?; buf.write("} else if "); } + // The following syntax `*(&(...) as &bool)` is used to + // trigger Rust's automatic dereferencing, to coerce + // e.g. `&&&&&bool` to `bool`. First `&(...) as &bool` + // coerces e.g. `&&&bool` to `&bool`. Then `*(&bool)` + // finally dereferences it to `bool`. + buf.write("*(&("); let expr_code = self.visit_expr_root(expr)?; buf.write(&expr_code); + buf.write(") as &bool)"); } None => { buf.dedent()?; @@ -532,14 +540,14 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> { self.locals.push(); arm_size += self.handle(ctx, nodes, buf, AstLevel::Nested)?; - arm_size += self.write_buf_writable(buf)?; arm_sizes.push(arm_size); - - self.locals.pop(); } self.handle_ws(ws); + flushed += self.write_buf_writable(buf)?; buf.writeln("}")?; + self.locals.pop(); + if !has_else { arm_sizes.push(0); } @@ -553,23 +561,28 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> { buf: &mut Buffer, ws1: WS, expr: &Expr, - inter: Option<&'a str>, arms: &'a [When], ws2: WS, ) -> Result<usize, CompileError> { self.flush_ws(ws1); let flushed = self.write_buf_writable(buf)?; let mut arm_sizes = Vec::new(); - if let Some(inter) = inter { - if !inter.is_empty() { - self.next_ws = Some(inter); - } - } let expr_code = self.visit_expr_root(expr)?; buf.writeln(&format!("match &{} {{", expr_code))?; - for arm in arms { + + let mut arm_size = 0; + for (i, arm) in arms.iter().enumerate() { let &(ws, ref variant, ref params, ref body) = arm; + self.handle_ws(ws); + + if i > 0 { + arm_sizes.push(arm_size + self.write_buf_writable(buf)?); + + buf.writeln("}")?; + self.locals.pop(); + } + self.locals.push(); match *variant { Some(ref param) => { @@ -616,15 +629,17 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> { } } buf.writeln(" => {")?; - self.handle_ws(ws); - let arm_size = self.handle(ctx, body, buf, AstLevel::Nested)?; - arm_sizes.push(arm_size + self.write_buf_writable(buf)?); - buf.writeln("}")?; - self.locals.pop(); + + arm_size = self.handle(ctx, body, buf, AstLevel::Nested)?; } - buf.writeln("}")?; self.handle_ws(ws2); + arm_sizes.push(arm_size + self.write_buf_writable(buf)?); + buf.writeln("}")?; + self.locals.pop(); + + buf.writeln("}")?; + Ok(flushed + median(&mut arm_sizes)) } @@ -717,10 +732,11 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> { } names.write(arg); - values.write("&"); + values.write("&("); values.write(&self.visit_expr_root(args.get(i).ok_or_else(|| { CompileError::String(format!("macro '{}' takes more than {} arguments", name, i)) })?)?); + values.write(")"); self.locals.insert(arg); } @@ -944,7 +960,7 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> { let expression = match wrapped { Wrapped => expr_buf.buf, Unwrapped => format!( - "::askama::MarkupDisplay::new_unsafe(&{}, {})", + "::askama::MarkupDisplay::new_unsafe(&({}), {})", expr_buf.buf, self.input.escaper ), }; diff --git a/askama_shared/src/heritage.rs b/askama_shared/src/heritage.rs index bc9e701..87f23e0 100644 --- a/askama_shared/src/heritage.rs +++ b/askama_shared/src/heritage.rs @@ -89,7 +89,7 @@ impl<'a> Context<'a> { Node::Loop(_, _, _, nodes, _) => { nested.push(nodes); } - Node::Match(_, _, _, arms, _) => { + Node::Match(_, _, arms, _) => { for (_, _, _, arm) in arms { nested.push(arm); } diff --git a/askama_shared/src/parser.rs b/askama_shared/src/parser.rs index 9344c07..a40e967 100644 --- a/askama_shared/src/parser.rs +++ b/askama_shared/src/parser.rs @@ -1,7 +1,7 @@ use nom::branch::alt; use nom::bytes::complete::{escaped, is_not, tag, take_until}; use nom::character::complete::{anychar, char, digit1}; -use nom::combinator::{complete, map, opt}; +use nom::combinator::{complete, map, opt, value}; use nom::error::ParseError; use nom::multi::{many0, many1, separated_list0, separated_list1}; use nom::sequence::{delimited, pair, tuple}; @@ -19,7 +19,7 @@ pub enum Node<'a> { LetDecl(WS, Target<'a>), Let(WS, Target<'a>, Expr<'a>), Cond(Vec<(WS, Option<Expr<'a>>, Vec<Node<'a>>)>, WS), - Match(WS, Expr<'a>, Option<&'a str>, Vec<When<'a>>, WS), + Match(WS, Expr<'a>, Vec<When<'a>>, WS), Loop(WS, Target<'a>, Expr<'a>, Vec<Node<'a>>, WS), Extends(Expr<'a>), BlockDef(WS, &'a str, Vec<Node<'a>>, WS), @@ -312,10 +312,12 @@ fn expr_var_call(i: &[u8]) -> IResult<&[u8], Expr> { } fn path(i: &[u8]) -> IResult<&[u8], Vec<&str>> { + let root = opt(value("", ws(tag("::")))); let tail = separated_list1(ws(tag("::")), identifier); - let (i, (start, _, rest)) = tuple((identifier, ws(tag("::")), tail))(i)?; - - let mut path = vec![start]; + let (i, (root, start, _, rest)) = tuple((root, identifier, ws(tag("::")), tail))(i)?; + let mut path = Vec::new(); + path.extend(root); + path.push(start); path.extend(rest); Ok((i, path)) } @@ -573,36 +575,32 @@ fn expr_rust_macro(i: &[u8]) -> IResult<&[u8], Expr> { macro_rules! expr_prec_layer { ( $name:ident, $inner:ident, $op:expr ) => { fn $name(i: &[u8]) -> IResult<&[u8], Expr> { - let (i, (left, op_and_right)) = tuple(( + let (i, left) = $inner(i)?; + let (i, right) = many0(pair( + ws(tag($op)), $inner, - opt(pair( - ws(tag($op)), - expr_any, - )) ))(i)?; - Ok((i, match op_and_right { - Some((op, right)) => Expr::BinOp( - str::from_utf8(op).unwrap(), Box::new(left), Box::new(right) - ), - None => left, - })) + Ok(( + i, + right.into_iter().fold(left, |left, (op, right)| { + Expr::BinOp(str::from_utf8(op).unwrap(), Box::new(left), Box::new(right)) + }), + )) } }; ( $name:ident, $inner:ident, $( $op:expr ),+ ) => { fn $name(i: &[u8]) -> IResult<&[u8], Expr> { - let (i, (left, op_and_right)) = tuple(( + let (i, left) = $inner(i)?; + let (i, right) = many0(pair( + ws(alt(($( tag($op) ),*,))), $inner, - opt(pair( - ws(alt(($( tag($op) ),*,))), - expr_any - )) ))(i)?; - Ok((i, match op_and_right { - Some((op, right)) => Expr::BinOp( - str::from_utf8(op).unwrap(), Box::new(left), Box::new(right) - ), - None => left, - })) + Ok(( + i, + right.into_iter().fold(left, |left, (op, right)| { + Expr::BinOp(str::from_utf8(op).unwrap(), Box::new(left), Box::new(right)) + }), + )) } } } @@ -773,8 +771,8 @@ fn block_match<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Node<'a> arms.push(arm); } - let inter = match inter { - Some(Node::Lit(lws, val, rws)) => { + match inter { + Some(Node::Lit(_, val, rws)) => { assert!( val.is_empty(), "only whitespace allowed between match and first when, found {}", @@ -785,18 +783,16 @@ fn block_match<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Node<'a> "only whitespace allowed between match and first when, found {}", rws ); - Some(lws) } - None => None, + None => {} _ => panic!("only literals allowed between match and first when"), - }; + } Ok(( i, Node::Match( WS(pws1.is_some(), nws1.is_some()), expr, - inter, arms, WS(pws2.is_some(), nws2.is_some()), ), @@ -1078,12 +1074,13 @@ pub fn parse<'a>(src: &'a str, syntax: &'a Syntax<'a>) -> Result<Vec<Node<'a>>, #[cfg(test)] mod tests { + use super::{Expr, Node, WS}; use crate::Syntax; fn check_ws_split(s: &str, res: &(&str, &str, &str)) { let node = super::split_ws_parts(s.as_bytes()); match node { - super::Node::Lit(lws, s, rws) => { + Node::Lit(lws, s, rws) => { assert_eq!(lws, res.0); assert_eq!(s, res.1); assert_eq!(rws, res.2); @@ -1118,12 +1115,9 @@ mod tests { fn test_parse_var_call() { assert_eq!( super::parse("{{ function(\"123\", 3) }}", &Syntax::default()).unwrap(), - vec![super::Node::Expr( - super::WS(false, false), - super::Expr::VarCall( - "function", - vec![super::Expr::StrLit("123"), super::Expr::NumLit("3")] - ), + vec![Node::Expr( + WS(false, false), + Expr::VarCall("function", vec![Expr::StrLit("123"), Expr::NumLit("3")]), )], ); } @@ -1132,17 +1126,36 @@ mod tests { fn test_parse_path_call() { assert_eq!( super::parse("{{ self::function(\"123\", 3) }}", &Syntax::default()).unwrap(), - vec![super::Node::Expr( - super::WS(false, false), - super::Expr::PathCall( + vec![Node::Expr( + WS(false, false), + Expr::PathCall( vec!["self", "function"], - vec![super::Expr::StrLit("123"), super::Expr::NumLit("3")], + vec![Expr::StrLit("123"), Expr::NumLit("3")], ), )], ); } #[test] + fn test_parse_root_path() { + let syntax = Syntax::default(); + assert_eq!( + super::parse("{{ std::string::String::new() }}", &syntax).unwrap(), + vec![Node::Expr( + WS(false, false), + Expr::PathCall(vec!["std", "string", "String", "new"], vec![]), + )], + ); + assert_eq!( + super::parse("{{ ::std::string::String::new() }}", &syntax).unwrap(), + vec![Node::Expr( + WS(false, false), + Expr::PathCall(vec!["", "std", "string", "String", "new"], vec![]), + )], + ); + } + + #[test] fn change_delimiters_parse_filter() { let syntax = Syntax { expr_start: "{~", @@ -1152,6 +1165,152 @@ mod tests { super::parse("{~ strvar|e ~}", &syntax).unwrap(); } + + #[test] + fn test_precedence() { + use Expr::*; + let syntax = Syntax::default(); + assert_eq!( + super::parse("{{ a + b == c }}", &syntax).unwrap(), + vec![Node::Expr( + WS(false, false), + BinOp( + "==", + BinOp("+", Var("a").into(), Var("b").into()).into(), + Var("c").into(), + ) + )], + ); + assert_eq!( + super::parse("{{ a + b * c - d / e }}", &syntax).unwrap(), + vec![Node::Expr( + WS(false, false), + BinOp( + "-", + BinOp( + "+", + Var("a").into(), + BinOp("*", Var("b").into(), Var("c").into()).into(), + ) + .into(), + BinOp("/", Var("d").into(), Var("e").into()).into(), + ) + )], + ); + assert_eq!( + super::parse("{{ a * (b + c) / -d }}", &syntax).unwrap(), + vec![Node::Expr( + WS(false, false), + BinOp( + "/", + BinOp( + "*", + Var("a").into(), + Group(BinOp("+", Var("b").into(), Var("c").into()).into()).into() + ) + .into(), + Unary("-", Var("d").into()).into() + ) + )], + ); + assert_eq!( + super::parse("{{ a || b && c || d && e }}", &syntax).unwrap(), + vec![Node::Expr( + WS(false, false), + BinOp( + "||", + BinOp( + "||", + Var("a").into(), + BinOp("&&", Var("b").into(), Var("c").into()).into(), + ) + .into(), + BinOp("&&", Var("d").into(), Var("e").into()).into(), + ) + )], + ); + } + + #[test] + fn test_associativity() { + use Expr::*; + let syntax = Syntax::default(); + assert_eq!( + super::parse("{{ a + b + c }}", &syntax).unwrap(), + vec![Node::Expr( + WS(false, false), + BinOp( + "+", + BinOp("+", Var("a").into(), Var("b").into()).into(), + Var("c").into() + ) + )], + ); + assert_eq!( + super::parse("{{ a * b * c }}", &syntax).unwrap(), + vec![Node::Expr( + WS(false, false), + BinOp( + "*", + BinOp("*", Var("a").into(), Var("b").into()).into(), + Var("c").into() + ) + )], + ); + assert_eq!( + super::parse("{{ a && b && c }}", &syntax).unwrap(), + vec![Node::Expr( + WS(false, false), + BinOp( + "&&", + BinOp("&&", Var("a").into(), Var("b").into()).into(), + Var("c").into() + ) + )], + ); + assert_eq!( + super::parse("{{ a + b - c + d }}", &syntax).unwrap(), + vec![Node::Expr( + WS(false, false), + BinOp( + "+", + BinOp( + "-", + BinOp("+", Var("a").into(), Var("b").into()).into(), + Var("c").into() + ) + .into(), + Var("d").into() + ) + )], + ); + assert_eq!( + super::parse("{{ a == b != c > d > e == f }}", &syntax).unwrap(), + vec![Node::Expr( + WS(false, false), + BinOp( + "==", + BinOp( + ">", + BinOp( + ">", + BinOp( + "!=", + BinOp("==", Var("a").into(), Var("b").into()).into(), + Var("c").into() + ) + .into(), + Var("d").into() + ) + .into(), + Var("e").into() + ) + .into(), + Var("f").into() + ) + )], + ); + } } type ParserError<'a, T> = Result<(&'a [u8], T), nom::Err<nom::error::Error<&'a [u8]>>>; diff --git a/book/src/filters.md b/book/src/filters.md index 25fbbe1..47fafdb 100644 --- a/book/src/filters.md +++ b/book/src/filters.md @@ -258,7 +258,7 @@ fn main() { ## The `json` filter -Enabling the `serde-json` filter will enable the use of the `json` filter. +Enabling the `serde-json` feature will enable the use of the `json` filter. This will output formatted JSON for any value that implements the required `Serialize` trait. @@ -271,7 +271,7 @@ This will output formatted JSON for any value that implements the required ## The `yaml` filter -Enabling the `serde-yaml` filter will enable the use of the `yaml` filter. +Enabling the `serde-yaml` feature will enable the use of the `yaml` filter. This will output formatted JSON for any value that implements the required `Serialize` trait. diff --git a/testing/templates/if-coerce.html b/testing/templates/if-coerce.html new file mode 100644 index 0000000..e32c2fe --- /dev/null +++ b/testing/templates/if-coerce.html @@ -0,0 +1,51 @@ +{% macro foo(b) -%} + {% if b %}t{% else %}f{% endif -%} +{% endmacro -%} + +{% macro bar(b) -%} + {%- call foo(b) -%} +{% endmacro -%} + +{% macro baz(b) -%} + {%- call bar(b) -%} +{% endmacro -%} + +{% macro qux(b) -%} + {%- call baz(b) -%} +{% endmacro -%} + +{%- call foo(false) -%} +{%- call bar(true) -%} +{%- call baz(false) -%} +{%- call qux(true) -%} + +{%- call qux(true && false) -%} +{%- call qux(false || true) -%} + +{%- call qux(self.t) -%} +{%- call qux(self.f) -%} +{%- call qux(self.f || self.t) -%} + +{%- if false -%} +if +{%- else if false || true -%} +elseif +{%- else -%} +else +{%- endif -%} + +{%- if true && false -%} +if +{%- else if false -%} +elseif +{%- else -%} +else +{%- endif -%} + +{%- if false || true -%} +if +{%- else if (true && false) -%} +elseif +{%- else -%} +else +{%- endif -%} diff --git a/testing/templates/macro-short-circuit.html b/testing/templates/macro-short-circuit.html new file mode 100644 index 0000000..4a19b86 --- /dev/null +++ b/testing/templates/macro-short-circuit.html @@ -0,0 +1,9 @@ +{% macro foo(b) -%} + {{ b }} +{%- endmacro -%} +{% call foo(true) -%} +{% call foo(true && true) -%} +{% call foo(true && true && true) -%} +{% call foo(false) -%} +{% call foo(false || true) -%} +{% call foo(false || false || true) -%} diff --git a/testing/tests/coerce.rs b/testing/tests/coerce.rs new file mode 100644 index 0000000..1a44781 --- /dev/null +++ b/testing/tests/coerce.rs @@ -0,0 +1,14 @@ +use askama::Template; + +#[derive(Template)] +#[template(path = "if-coerce.html")] +struct IfCoerceTemplate { + t: bool, + f: bool, +} + +#[test] +fn test_coerce() { + let t = IfCoerceTemplate { t: true, f: false }; + assert_eq!(t.render().unwrap(), "ftftfttftelseifelseif"); +} diff --git a/testing/tests/gen_ws_tests.py b/testing/tests/gen_ws_tests.py new file mode 100644 index 0000000..c2e24cb --- /dev/null +++ b/testing/tests/gen_ws_tests.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from itertools import product, chain, zip_longest, tee + + +# The amount of branches to generate +BRANCHES = 2 # branches + +IF, ELSE_IF, ELSE, END_IF = 0, 1, 2, 3 + +NL = "\\n" +dash = lambda ws: [" ", "-"][ws] + + +def trim(s, ws): + if ws[0]: + s = s.lstrip() + if ws[1]: + s = s.rstrip() + return s + + +def cond_kind(i, n): + i += 1 + if i == 1: + return IF # if + elif (i == n) and (i > 1): + return ELSE # else + elif i > n: + return END_IF # endif + else: + return ELSE_IF # else if + + +# From: https://docs.python.org/3/library/itertools.html#itertools-recipes +def pairwise(iterable): + a, b = tee(iterable) + next(b, None) + return zip(a, b) + + +def write_cond(conds, active_branch): + n = len(conds) - 1 + + lits = [] + for i in range(1, n + 2 + 1): + ws1 = "\\n" * i + ws2 = "\\r\\n" * i + lits.append((ws1, str(i), ws2)) + + conds = list(conds) + for i, (pws, nws) in enumerate(conds): + kind = cond_kind(i, n) + b = str(i == active_branch).lower() + cond = [f"if {b}", f"else if {b}", "else", "endif"][kind] + cond = f"{{%{dash(pws)} {cond} {dash(nws)}%}}" + conds[i] = cond + + it = map("".join, lits) + it = filter(None, chain.from_iterable(zip_longest(it, conds))) + code = "".join(it) + + expected = f"{lits[0][0]}{lits[0][1]}" + for i, (cond, (before, after)) in enumerate(zip(conds, pairwise(lits))): + kind = cond_kind(i, n) + pws = cond.startswith("{%-") + nws = cond.endswith("-%}") + + cond = i == active_branch + prev_cond = i == (active_branch + 1) + + if prev_cond or (kind == IF): + expected += before[2] * (not pws) + if cond or (kind == END_IF): + expected += after[0] * (not nws) + expected += after[1] + + # FIXME: Askama does not include whitespace before eof + # expected += lits[-1][2] + + return code, expected + + +def write_match(contents, arms, match_ws): + before, expr, after = contents + code = before + + pws, nws = match_ws[0] + code += f"{{%{dash(pws)} match {expr} {dash(nws)}%}}" + + for (arm, expr), (pws, nws) in zip(arms, match_ws[1:-1]): + code += f"{{%{dash(pws)} when {arm} {dash(nws)}%}}{expr}" + + pws, nws = match_ws[-1] + code += f"{{%{dash(pws)} endmatch {dash(nws)}%}}" + code += after + + return code + + +def write_match_result(active_arm, contents, arms, match_ws): + before, expr, after = contents + expected = "" + + expected += trim(before, (False, match_ws[0][0])) + expected += trim(arms[active_arm][1], (match_ws[1:][active_arm][1], match_ws[1:][active_arm+1][0])) + expected += trim(after, (match_ws[-1][1], False)) + return expected + + +def write_cond_tests(f): + f.write(""" +macro_rules! test_template { + ($source:literal, $rendered:expr) => {{ + #[derive(Template)] + #[template(source = $source, ext = "txt")] + struct CondWS; + + assert_eq!(CondWS.render().unwrap(), $rendered); + }}; +} + +#[rustfmt::skip] +#[test] +fn test_cond_ws() { +""") + + for branches in range(1, BRANCHES + 1): + for x in product([False, True], repeat=(branches+1)*2): + # it = iter(x) + # conds = list(zip(it, it)) + conds = list(zip(x[::2], x[1::2])) + + for i in range(branches): + code, expected = write_cond(conds, i) + f.write(f' test_template!("{code}", "{expected}");\n') + + if branches != BRANCHES: + f.write("\n") + f.write("}\n") + + +def write_match_tests(f): + f.write(""" +#[rustfmt::skip] +macro_rules! test_match { + ($source:literal, $some_rendered:expr, $none_rendered:expr) => {{ + #[derive(Template)] + #[template(source = $source, ext = "txt")] + struct MatchWS { + item: Option<&'static str>, + } + + assert_eq!(MatchWS { item: Some("foo") }.render().unwrap(), $some_rendered); + assert_eq!(MatchWS { item: None }.render().unwrap(), $none_rendered); + }}; +} + +#[rustfmt::skip] +#[test] +fn test_match_ws() { +""") + + contents = "before ", "item", " after" + arms = [("Some with (item)", " foo "), ("None", " bar ")] + + for x in product([False, True], repeat=len(arms)*2+1): + x = [False, False, *x, False] + arms_ws = list(zip(x[::2], x[1::2])) + + code = write_match(contents, arms, arms_ws) + some_expected = write_match_result(0, contents, arms, arms_ws) + none_expected = write_match_result(1, contents, arms, arms_ws) + + f.write(f' test_match!("{code}", "{some_expected}", "{none_expected}");\n') + + f.write("}\n") + + +if __name__ == "__main__": + with open("ws.rs", "w") as f: + f.write("// This file is auto generated by gen_ws_tests.py\n\n") + f.write("use askama::Template;\n") + write_cond_tests(f) + write_match_tests(f) diff --git a/testing/tests/macro.rs b/testing/tests/macro.rs index 51fbcdc..459b1e2 100644 --- a/testing/tests/macro.rs +++ b/testing/tests/macro.rs @@ -43,3 +43,13 @@ fn test_deep_import() { let t = DeepImportTemplate; assert_eq!(t.render().unwrap(), "foo"); } + +#[derive(Template)] +#[template(path = "macro-short-circuit.html")] +struct ShortCircuitTemplate {} + +#[test] +fn test_short_circuit() { + let t = ShortCircuitTemplate {}; + assert_eq!(t.render().unwrap(), "truetruetruefalsetruetrue"); +} diff --git a/testing/tests/matches.rs b/testing/tests/matches.rs index 811f3ce..d75a6c4 100644 --- a/testing/tests/matches.rs +++ b/testing/tests/matches.rs @@ -17,19 +17,19 @@ struct MatchOptRefTemplate<'a> { #[test] fn test_match_option() { let s = MatchOptTemplate { item: Some("foo") }; - assert_eq!(s.render().unwrap(), "\n\nFound literal foo\n"); + assert_eq!(s.render().unwrap(), "\nFound literal foo\n"); let s = MatchOptTemplate { item: Some("bar") }; - assert_eq!(s.render().unwrap(), "\n\nFound bar\n"); + assert_eq!(s.render().unwrap(), "\nFound bar\n"); let s = MatchOptTemplate { item: None }; - assert_eq!(s.render().unwrap(), "\n\nNot Found\n"); + assert_eq!(s.render().unwrap(), "\nNot Found\n"); } #[test] fn test_match_ref_deref() { let s = MatchOptRefTemplate { item: &Some("foo") }; - assert_eq!(s.render().unwrap(), "\n\nFound literal foo\n"); + assert_eq!(s.render().unwrap(), "\nFound literal foo\n"); } #[derive(Template)] @@ -41,10 +41,10 @@ struct MatchLitTemplate<'a> { #[test] fn test_match_literal() { let s = MatchLitTemplate { item: "bar" }; - assert_eq!(s.render().unwrap(), "\n\nFound literal bar\n"); + assert_eq!(s.render().unwrap(), "\nFound literal bar\n"); let s = MatchLitTemplate { item: "qux" }; - assert_eq!(s.render().unwrap(), "\n\nElse found qux\n"); + assert_eq!(s.render().unwrap(), "\nElse found qux\n"); } #[derive(Template)] @@ -56,10 +56,10 @@ struct MatchLitCharTemplate { #[test] fn test_match_literal_char() { let s = MatchLitCharTemplate { item: 'b' }; - assert_eq!(s.render().unwrap(), "\n\nFound literal b\n"); + assert_eq!(s.render().unwrap(), "\nFound literal b\n"); let s = MatchLitCharTemplate { item: 'c' }; - assert_eq!(s.render().unwrap(), "\n\nElse found c\n"); + assert_eq!(s.render().unwrap(), "\nElse found c\n"); } #[derive(Template)] @@ -71,10 +71,10 @@ struct MatchLitNumTemplate { #[test] fn test_match_literal_num() { let s = MatchLitNumTemplate { item: 42 }; - assert_eq!(s.render().unwrap(), "\n\nFound answer to everything\n"); + assert_eq!(s.render().unwrap(), "\nFound answer to everything\n"); let s = MatchLitNumTemplate { item: 23 }; - assert_eq!(s.render().unwrap(), "\n\nElse found 23\n"); + assert_eq!(s.render().unwrap(), "\nElse found 23\n"); } #[allow(dead_code)] @@ -99,7 +99,7 @@ fn test_match_custom_enum() { b: 255, }, }; - assert_eq!(s.render().unwrap(), "\n\nColorful: #A000FF\n"); + assert_eq!(s.render().unwrap(), "\nColorful: #A000FF\n"); } #[derive(Template)] diff --git a/testing/tests/operators.rs b/testing/tests/operators.rs index 99a2a4c..05c1dab 100644 --- a/testing/tests/operators.rs +++ b/testing/tests/operators.rs @@ -53,3 +53,13 @@ fn test_ranges() { }; assert_eq!(t.render().unwrap(), "abcd\nbcd\n\na\nab"); } + +#[derive(Template)] +#[template(source = "{{ true && true }}{{ false || true }}", ext = "txt")] +struct ShortCircuitTemplate {} + +#[test] +fn test_short_circuit() { + let t = ShortCircuitTemplate {}; + assert_eq!(t.render().unwrap(), "truetrue"); +} diff --git a/testing/tests/simple.rs b/testing/tests/simple.rs index 7241005..5ef03b1 100644 --- a/testing/tests/simple.rs +++ b/testing/tests/simple.rs @@ -291,6 +291,15 @@ fn test_path_func_call() { } #[derive(Template)] +#[template(source = "{{ ::std::string::ToString::to_string(123) }}", ext = "txt")] +struct RootPathFunctionTemplate; + +#[test] +fn test_root_path_func_call() { + assert_eq!(RootPathFunctionTemplate.render().unwrap(), "123"); +} + +#[derive(Template)] #[template(source = "Hello, {{ Self::world3(self, \"123\", 4) }}!", ext = "txt")] struct FunctionTemplate; diff --git a/testing/tests/whitespace.rs b/testing/tests/whitespace.rs index 93c601e..ca72b23 100644 --- a/testing/tests/whitespace.rs +++ b/testing/tests/whitespace.rs @@ -37,5 +37,5 @@ fn test_extra_whitespace() { let mut template = AllowWhitespaces::default(); template.nested_1.nested_2.array = &["a0", "a1", "a2", "a3"]; template.nested_1.nested_2.hash.insert("key", "value"); - assert_eq!(template.render().unwrap(), "\n0\n0\n0\n0\n\n\n\n0\n0\n0\n0\n0\n\na0\na1\nvalue\n\n\n\n\n\n[\n \"a0\",\n \"a1\",\n \"a2\",\n \"a3\"\n]\n[\n \"a0\",\n \"a1\",\n \"a2\",\n \"a3\"\n][\n \"a0\",\n \"a1\",\n \"a2\",\n \"a3\"\n]\n[\n \"a1\"\n][\n \"a1\"\n]\n[\n \"a1\",\n \"a2\"\n][\n \"a1\",\n \"a2\"\n]\n[\n \"a1\"\n][\n \"a1\"\n]1-1-1\n3333 3\n2222 2\n0000 0\n3333 3\n\ntruefalse\nfalsefalsefalse\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); + assert_eq!(template.render().unwrap(), "\n0\n0\n0\n0\n\n\n\n0\n0\n0\n0\n0\n\na0\na1\nvalue\n\n\n\n\n\n[\n \"a0\",\n \"a1\",\n \"a2\",\n \"a3\"\n]\n[\n \"a0\",\n \"a1\",\n \"a2\",\n \"a3\"\n][\n \"a0\",\n \"a1\",\n \"a2\",\n \"a3\"\n]\n[\n \"a1\"\n][\n \"a1\"\n]\n[\n \"a1\",\n \"a2\"\n][\n \"a1\",\n \"a2\"\n]\n[\n \"a1\"\n][\n \"a1\"\n]1-1-1\n3333 3\n2222 2\n0000 0\n3333 3\n\ntruefalse\nfalsefalsefalse\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); } diff --git a/testing/tests/ws.rs b/testing/tests/ws.rs new file mode 100644 index 0000000..3f62da5 --- /dev/null +++ b/testing/tests/ws.rs @@ -0,0 +1,214 @@ +// This file is auto generated by gen_ws_tests.py + +use askama::Template; + +macro_rules! test_template { + ($source:literal, $rendered:expr) => {{ + #[derive(Template)] + #[template(source = $source, ext = "txt")] + struct CondWS; + + assert_eq!(CondWS.render().unwrap(), $rendered); + }}; +} + +#[rustfmt::skip] +#[test] +fn test_cond_ws() { + test_template!("\n1\r\n{% if true %}\n\n2\r\n\r\n{% endif %}\n\n\n3\r\n\r\n\r\n", "\n1\r\n\n\n2\r\n\r\n\n\n\n3"); + test_template!("\n1\r\n{% if true %}\n\n2\r\n\r\n{% endif -%}\n\n\n3\r\n\r\n\r\n", "\n1\r\n\n\n2\r\n\r\n3"); + test_template!("\n1\r\n{% if true %}\n\n2\r\n\r\n{%- endif %}\n\n\n3\r\n\r\n\r\n", "\n1\r\n\n\n2\n\n\n3"); + test_template!("\n1\r\n{% if true %}\n\n2\r\n\r\n{%- endif -%}\n\n\n3\r\n\r\n\r\n", "\n1\r\n\n\n23"); + test_template!("\n1\r\n{% if true -%}\n\n2\r\n\r\n{% endif %}\n\n\n3\r\n\r\n\r\n", "\n1\r\n2\r\n\r\n\n\n\n3"); + test_template!("\n1\r\n{% if true -%}\n\n2\r\n\r\n{% endif -%}\n\n\n3\r\n\r\n\r\n", "\n1\r\n2\r\n\r\n3"); + test_template!("\n1\r\n{% if true -%}\n\n2\r\n\r\n{%- endif %}\n\n\n3\r\n\r\n\r\n", "\n1\r\n2\n\n\n3"); + test_template!("\n1\r\n{% if true -%}\n\n2\r\n\r\n{%- endif -%}\n\n\n3\r\n\r\n\r\n", "\n1\r\n23"); + test_template!("\n1\r\n{%- if true %}\n\n2\r\n\r\n{% endif %}\n\n\n3\r\n\r\n\r\n", "\n1\n\n2\r\n\r\n\n\n\n3"); + test_template!("\n1\r\n{%- if true %}\n\n2\r\n\r\n{% endif -%}\n\n\n3\r\n\r\n\r\n", "\n1\n\n2\r\n\r\n3"); + test_template!("\n1\r\n{%- if true %}\n\n2\r\n\r\n{%- endif %}\n\n\n3\r\n\r\n\r\n", "\n1\n\n2\n\n\n3"); + test_template!("\n1\r\n{%- if true %}\n\n2\r\n\r\n{%- endif -%}\n\n\n3\r\n\r\n\r\n", "\n1\n\n23"); + test_template!("\n1\r\n{%- if true -%}\n\n2\r\n\r\n{% endif %}\n\n\n3\r\n\r\n\r\n", "\n12\r\n\r\n\n\n\n3"); + test_template!("\n1\r\n{%- if true -%}\n\n2\r\n\r\n{% endif -%}\n\n\n3\r\n\r\n\r\n", "\n12\r\n\r\n3"); + test_template!("\n1\r\n{%- if true -%}\n\n2\r\n\r\n{%- endif %}\n\n\n3\r\n\r\n\r\n", "\n12\n\n\n3"); + test_template!("\n1\r\n{%- if true -%}\n\n2\r\n\r\n{%- endif -%}\n\n\n3\r\n\r\n\r\n", "\n123"); + + test_template!("\n1\r\n{% if true %}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n2\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{% if false %}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n\n3\r\n\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{% if true %}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n2\r\n\r\n4"); + test_template!("\n1\r\n{% if false %}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n\n3\r\n\r\n\r\n4"); + test_template!("\n1\r\n{% if true %}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n2\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{% if false %}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n\n3\n\n\n\n4"); + test_template!("\n1\r\n{% if true %}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n2\r\n\r\n4"); + test_template!("\n1\r\n{% if false %}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n\n34"); + test_template!("\n1\r\n{% if true %}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n2\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{% if false %}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n3\r\n\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{% if true %}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n2\r\n\r\n4"); + test_template!("\n1\r\n{% if false %}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n3\r\n\r\n\r\n4"); + test_template!("\n1\r\n{% if true %}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n2\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{% if false %}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n3\n\n\n\n4"); + test_template!("\n1\r\n{% if true %}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n2\r\n\r\n4"); + test_template!("\n1\r\n{% if false %}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n34"); + test_template!("\n1\r\n{% if true %}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n2\n\n\n\n4"); + test_template!("\n1\r\n{% if false %}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n\n3\r\n\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{% if true %}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n24"); + test_template!("\n1\r\n{% if false %}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n\n3\r\n\r\n\r\n4"); + test_template!("\n1\r\n{% if true %}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n2\n\n\n\n4"); + test_template!("\n1\r\n{% if false %}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n\n3\n\n\n\n4"); + test_template!("\n1\r\n{% if true %}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n24"); + test_template!("\n1\r\n{% if false %}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n\n34"); + test_template!("\n1\r\n{% if true %}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n2\n\n\n\n4"); + test_template!("\n1\r\n{% if false %}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n3\r\n\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{% if true %}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n24"); + test_template!("\n1\r\n{% if false %}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n3\r\n\r\n\r\n4"); + test_template!("\n1\r\n{% if true %}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n2\n\n\n\n4"); + test_template!("\n1\r\n{% if false %}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n3\n\n\n\n4"); + test_template!("\n1\r\n{% if true %}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n24"); + test_template!("\n1\r\n{% if false %}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n34"); + test_template!("\n1\r\n{% if true -%}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n2\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{% if false -%}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n\n3\r\n\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{% if true -%}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n2\r\n\r\n4"); + test_template!("\n1\r\n{% if false -%}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n\n3\r\n\r\n\r\n4"); + test_template!("\n1\r\n{% if true -%}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n2\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{% if false -%}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n\n3\n\n\n\n4"); + test_template!("\n1\r\n{% if true -%}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n2\r\n\r\n4"); + test_template!("\n1\r\n{% if false -%}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n\n34"); + test_template!("\n1\r\n{% if true -%}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n2\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{% if false -%}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n3\r\n\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{% if true -%}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n2\r\n\r\n4"); + test_template!("\n1\r\n{% if false -%}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n3\r\n\r\n\r\n4"); + test_template!("\n1\r\n{% if true -%}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n2\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{% if false -%}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n3\n\n\n\n4"); + test_template!("\n1\r\n{% if true -%}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n2\r\n\r\n4"); + test_template!("\n1\r\n{% if false -%}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n34"); + test_template!("\n1\r\n{% if true -%}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n2\n\n\n\n4"); + test_template!("\n1\r\n{% if false -%}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n\n3\r\n\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{% if true -%}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n24"); + test_template!("\n1\r\n{% if false -%}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n\n3\r\n\r\n\r\n4"); + test_template!("\n1\r\n{% if true -%}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n2\n\n\n\n4"); + test_template!("\n1\r\n{% if false -%}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n\n3\n\n\n\n4"); + test_template!("\n1\r\n{% if true -%}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n24"); + test_template!("\n1\r\n{% if false -%}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n\n\n\n34"); + test_template!("\n1\r\n{% if true -%}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n2\n\n\n\n4"); + test_template!("\n1\r\n{% if false -%}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n3\r\n\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{% if true -%}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n24"); + test_template!("\n1\r\n{% if false -%}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n3\r\n\r\n\r\n4"); + test_template!("\n1\r\n{% if true -%}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n2\n\n\n\n4"); + test_template!("\n1\r\n{% if false -%}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n3\n\n\n\n4"); + test_template!("\n1\r\n{% if true -%}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n24"); + test_template!("\n1\r\n{% if false -%}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\r\n34"); + test_template!("\n1\r\n{%- if true %}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n2\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{%- if false %}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n\n3\r\n\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{%- if true %}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n2\r\n\r\n4"); + test_template!("\n1\r\n{%- if false %}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n\n3\r\n\r\n\r\n4"); + test_template!("\n1\r\n{%- if true %}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n2\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{%- if false %}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n\n3\n\n\n\n4"); + test_template!("\n1\r\n{%- if true %}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n2\r\n\r\n4"); + test_template!("\n1\r\n{%- if false %}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n\n34"); + test_template!("\n1\r\n{%- if true %}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n2\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{%- if false %}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n13\r\n\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{%- if true %}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n2\r\n\r\n4"); + test_template!("\n1\r\n{%- if false %}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n13\r\n\r\n\r\n4"); + test_template!("\n1\r\n{%- if true %}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n2\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{%- if false %}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n13\n\n\n\n4"); + test_template!("\n1\r\n{%- if true %}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n2\r\n\r\n4"); + test_template!("\n1\r\n{%- if false %}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n134"); + test_template!("\n1\r\n{%- if true %}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n2\n\n\n\n4"); + test_template!("\n1\r\n{%- if false %}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n\n3\r\n\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{%- if true %}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n24"); + test_template!("\n1\r\n{%- if false %}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n\n3\r\n\r\n\r\n4"); + test_template!("\n1\r\n{%- if true %}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n2\n\n\n\n4"); + test_template!("\n1\r\n{%- if false %}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n\n3\n\n\n\n4"); + test_template!("\n1\r\n{%- if true %}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n24"); + test_template!("\n1\r\n{%- if false %}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n\n34"); + test_template!("\n1\r\n{%- if true %}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n2\n\n\n\n4"); + test_template!("\n1\r\n{%- if false %}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n13\r\n\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{%- if true %}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n24"); + test_template!("\n1\r\n{%- if false %}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n13\r\n\r\n\r\n4"); + test_template!("\n1\r\n{%- if true %}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n2\n\n\n\n4"); + test_template!("\n1\r\n{%- if false %}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n13\n\n\n\n4"); + test_template!("\n1\r\n{%- if true %}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n24"); + test_template!("\n1\r\n{%- if false %}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n134"); + test_template!("\n1\r\n{%- if true -%}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n12\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{%- if false -%}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n\n3\r\n\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{%- if true -%}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n12\r\n\r\n4"); + test_template!("\n1\r\n{%- if false -%}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n\n3\r\n\r\n\r\n4"); + test_template!("\n1\r\n{%- if true -%}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n12\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{%- if false -%}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n\n3\n\n\n\n4"); + test_template!("\n1\r\n{%- if true -%}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n12\r\n\r\n4"); + test_template!("\n1\r\n{%- if false -%}\n\n2\r\n\r\n{% else %}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n\n34"); + test_template!("\n1\r\n{%- if true -%}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n12\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{%- if false -%}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n13\r\n\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{%- if true -%}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n12\r\n\r\n4"); + test_template!("\n1\r\n{%- if false -%}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n13\r\n\r\n\r\n4"); + test_template!("\n1\r\n{%- if true -%}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n12\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{%- if false -%}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n13\n\n\n\n4"); + test_template!("\n1\r\n{%- if true -%}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n12\r\n\r\n4"); + test_template!("\n1\r\n{%- if false -%}\n\n2\r\n\r\n{% else -%}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n134"); + test_template!("\n1\r\n{%- if true -%}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n12\n\n\n\n4"); + test_template!("\n1\r\n{%- if false -%}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n\n3\r\n\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{%- if true -%}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n124"); + test_template!("\n1\r\n{%- if false -%}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n\n3\r\n\r\n\r\n4"); + test_template!("\n1\r\n{%- if true -%}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n12\n\n\n\n4"); + test_template!("\n1\r\n{%- if false -%}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n\n3\n\n\n\n4"); + test_template!("\n1\r\n{%- if true -%}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n124"); + test_template!("\n1\r\n{%- if false -%}\n\n2\r\n\r\n{%- else %}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n1\n\n\n34"); + test_template!("\n1\r\n{%- if true -%}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n12\n\n\n\n4"); + test_template!("\n1\r\n{%- if false -%}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{% endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n13\r\n\r\n\r\n\n\n\n\n4"); + test_template!("\n1\r\n{%- if true -%}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n124"); + test_template!("\n1\r\n{%- if false -%}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{% endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n13\r\n\r\n\r\n4"); + test_template!("\n1\r\n{%- if true -%}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n12\n\n\n\n4"); + test_template!("\n1\r\n{%- if false -%}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{%- endif %}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n13\n\n\n\n4"); + test_template!("\n1\r\n{%- if true -%}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n124"); + test_template!("\n1\r\n{%- if false -%}\n\n2\r\n\r\n{%- else -%}\n\n\n3\r\n\r\n\r\n{%- endif -%}\n\n\n\n4\r\n\r\n\r\n\r\n", "\n134"); +} + +#[rustfmt::skip] +macro_rules! test_match { + ($source:literal, $some_rendered:expr, $none_rendered:expr) => {{ + #[derive(Template)] + #[template(source = $source, ext = "txt")] + struct MatchWS { + item: Option<&'static str>, + } + + assert_eq!(MatchWS { item: Some("foo") }.render().unwrap(), $some_rendered); + assert_eq!(MatchWS { item: None }.render().unwrap(), $none_rendered); + }}; +} + +#[rustfmt::skip] +#[test] +fn test_match_ws() { + test_match!("before {% match item %}{% when Some with (item) %} foo {% when None %} bar {% endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{% when Some with (item) %} foo {% when None %} bar {%- endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{% when Some with (item) %} foo {% when None -%} bar {% endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{% when Some with (item) %} foo {% when None -%} bar {%- endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{% when Some with (item) %} foo {%- when None %} bar {% endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{% when Some with (item) %} foo {%- when None %} bar {%- endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{% when Some with (item) %} foo {%- when None -%} bar {% endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{% when Some with (item) %} foo {%- when None -%} bar {%- endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{% when Some with (item) -%} foo {% when None %} bar {% endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{% when Some with (item) -%} foo {% when None %} bar {%- endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{% when Some with (item) -%} foo {% when None -%} bar {% endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{% when Some with (item) -%} foo {% when None -%} bar {%- endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{% when Some with (item) -%} foo {%- when None %} bar {% endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{% when Some with (item) -%} foo {%- when None %} bar {%- endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{% when Some with (item) -%} foo {%- when None -%} bar {% endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{% when Some with (item) -%} foo {%- when None -%} bar {%- endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{%- when Some with (item) %} foo {% when None %} bar {% endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{%- when Some with (item) %} foo {% when None %} bar {%- endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{%- when Some with (item) %} foo {% when None -%} bar {% endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{%- when Some with (item) %} foo {% when None -%} bar {%- endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{%- when Some with (item) %} foo {%- when None %} bar {% endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{%- when Some with (item) %} foo {%- when None %} bar {%- endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{%- when Some with (item) %} foo {%- when None -%} bar {% endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{%- when Some with (item) %} foo {%- when None -%} bar {%- endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{%- when Some with (item) -%} foo {% when None %} bar {% endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{%- when Some with (item) -%} foo {% when None %} bar {%- endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{%- when Some with (item) -%} foo {% when None -%} bar {% endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{%- when Some with (item) -%} foo {% when None -%} bar {%- endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{%- when Some with (item) -%} foo {%- when None %} bar {% endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{%- when Some with (item) -%} foo {%- when None %} bar {%- endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{%- when Some with (item) -%} foo {%- when None -%} bar {% endmatch %} after", "before foo after", "before bar after"); + test_match!("before {% match item %}{%- when Some with (item) -%} foo {%- when None -%} bar {%- endmatch %} after", "before foo after", "before bar after"); +} |