add test cases and rework spaces

Signed-off-by: Michael Pollind <mpollind@gmail.com>
This commit is contained in:
Michael Pollind 2025-05-05 19:17:21 -07:00 committed by Guillaume Gomez
parent 8862325e9b
commit ef489b60f6
6 changed files with 190 additions and 22 deletions

View File

@ -608,7 +608,7 @@ impl<'a> Generator<'a, '_> {
call: &'a WithSpan<'a, Call<'_>>,
) -> Result<usize, CompileError> {
let Call {
ws,
ws1,
scope,
name,
ref args,
@ -650,7 +650,7 @@ impl<'a> Generator<'a, '_> {
self.seen_macros.push((def, ctx.file_info_of(call.span())));
}
self.seen_callers.push(call);
self.flush_ws(ws); // Cannot handle_ws() here: whitespace from macro definition comes first
self.flush_ws(ws1); // Cannot handle_ws() here: whitespace from macro definition comes first
let size_hint = self.push_locals(|this| {
macro_call_ensure_arg_count(call, def, ctx)?;
@ -771,7 +771,7 @@ impl<'a> Generator<'a, '_> {
buf.write('}');
Ok(size_hint)
})?;
self.prepare_ws(ws);
self.prepare_ws(ws1);
self.seen_macros.pop();
self.seen_callers.pop();
Ok(size_hint)
@ -1119,9 +1119,10 @@ impl<'a> Generator<'a, '_> {
if ***path == Expr::Var("super") {
return self.write_block(ctx, buf, None, ws, s.span());
} else if ***path == Expr::Var("caller") {
let def = self.seen_callers.last().ok_or_else(|| {
let def = self.seen_callers.pop().ok_or_else(|| {
ctx.generate_error(format_args!("block is not defined for caller"), s.span())
})?;
self.handle_ws(ws);
let size_hint = self.push_locals(|this| {
this.write_buf_writable(ctx, buf)?;
buf.write('{');
@ -1180,14 +1181,14 @@ impl<'a> Generator<'a, '_> {
}
}
}
let mut size_hint = this.handle(ctx, &def.nodes, buf, AstLevel::Nested)?;
this.flush_ws(def.ws2);
size_hint += this.write_buf_writable(ctx, buf)?;
buf.write('}');
Ok(size_hint)
})?;
self.prepare_ws(ws);
self.seen_callers.push(def);
return Ok(size_hint);
}
}

View File

@ -877,12 +877,11 @@ impl<'a> Import<'a> {
#[derive(Debug, PartialEq)]
pub struct Call<'a> {
pub ws: Ws,
pub ws1: Ws,
pub caller_args: Vec<&'a str>,
pub scope: Option<&'a str>,
pub name: &'a str,
pub args: Vec<WithSpan<'a, Expr<'a>>>,
pub ws1: Ws,
pub nodes: Vec<Node<'a>>,
pub ws2: Ws,
}
@ -947,12 +946,11 @@ impl<'a> Call<'a> {
Ok(WithSpan::new(
Self {
ws: Ws(pws, nws),
ws1: Ws(pws, nws),
caller_args: call_args.unwrap_or_default(),
scope,
name,
args,
ws1: Ws(pws, pws2),
nodes,
ws2: Ws(pws2, nws2),
},

View File

@ -125,17 +125,18 @@ nested
assert_eq!(x.render().unwrap(), "nested");
}
#[test]
fn test_caller_struct() {
struct TestInput<'a> {
a: &'a str,
b: &'a str
a: &'a str,
b: &'a str,
}
#[derive(Template)]
#[template(
source = r#"
{%- macro test(a) -%}
{{caller(a)}}
{{- caller(a) -}}
{%- endmacro -%}
{%- call(value) test(a) -%}
a: {{value.a}}
@ -145,13 +146,10 @@ b: {{value.b}}
ext = "txt"
)]
struct Tmpl<'a> {
a: TestInput<'a>
a: TestInput<'a>,
}
let x = Tmpl {
a: TestInput {
a: "one",
b: "two"
}
a: TestInput { a: "one", b: "two" },
};
assert_eq!(x.render().unwrap(), "a: one\nb: two");
}
@ -162,18 +160,18 @@ fn test_caller_args() {
#[template(
source = r#"
{%- macro test() -%}
{{- caller("test") -}}
{{- caller(1) -}}
{{~ caller("test") ~}}
{{~ caller(1) ~}}
{%- endmacro -%}
{%- call(value) test() -%}
nested {{value}}
nested {{value}}
{%- endcall -%}
"#,
ext = "html"
)]
struct CallerEmpty {}
let x = CallerEmpty {};
assert_eq!(x.render().unwrap(), "nested testnested 1");
assert_eq!(x.render().unwrap(), "nested test\nnested 1");
}
// Ensures that fields are not moved when calling a jinja macro.

View File

@ -238,6 +238,48 @@ fn test_default_value3() {
);
}
// This test a caller expression with expressions in the arguments.
#[test]
fn test_caller_expr() {
#[derive(Template)]
#[template(
source = "{%- macro thrice(a, b, c) -%}
{{caller(a+10,b - 10,a+b+c)}}
{% endmacro -%}
{%- call(a,b,c) thrice(10,11,13) -%}{{a}} {{b}} {{c + 1}}{%- endcall -%}
",
ext = "html"
)]
struct MacroCallerExpr;
assert_eq!(MacroCallerExpr.render().unwrap(), "20 1 35\n");
}
#[test]
fn test_caller_in_caller() {
#[derive(Template)]
#[template(
source = r#"
{%- macro test2() -%}
{{~ caller("bb") ~}}
{%- endmacro -%}
{%- macro test() -%}
{{~ caller("a") ~}}
{%- endmacro -%}
{%- call(a) test() -%}
{%- call(b) test2() -%}
one: {{ b }}
{%- endcall -%}
two: {{- a -}}
{%- endcall -%}
"#,
ext = "txt"
)]
struct CallerInCaller;
assert_eq!(CallerInCaller.render().unwrap(), "one: bbtwo:a");
}
// This test ensures that we can use declared variables as default value for
// macro arguments.
#[test]

View File

@ -0,0 +1,70 @@
use askama::Template;
#[derive(Template)]
#[template(
source = r#"
{% macro test() %}
{{- caller("a", "b") -}}
{%- endmacro -%}
{%- call(a,b,c) test() -%}
{{- a -}}
{%- endcall -%}
"#,
ext = "txt"
)]
struct InvalidNumberArguments {
}
#[derive(Template)]
#[template(
source = r#"
{% macro test() %}
{{- caller("a") -}}
{%- endmacro -%}
{%- call(a test() -%}
{{- a -}}
{%- endcall -%}
"#,
ext = "txt"
)]
struct NoClosingParen {
}
#[derive(Template)]
#[template(
source = r#"
{% macro test() %}
{{- caller("a") -}}
{%- endmacro -%}
{%- call(a) test() -%}
{{- caller(a) -}}
{%- endcall -%}
"#,
ext = "txt"
)]
struct CallerInCaller {
}
#[derive(Template)]
#[template(
source = r#"
{% macro test2() %}
{{ caller("bb") }}
{% endmacro %}
{% macro test() %}
{{ caller("a") }}
{%- endmacro -%}
{%- call(a) test() -%}
{% call(b) test2() %}
{{ caller("b") }}
{% endcall %}
{{- a -}}
{%- endcall -%}
"#,
ext = "txt"
)]
struct CallerInCaller1 {
}
fn main() {}

View File

@ -0,0 +1,59 @@
error: missing `c` argument
--> InvalidNumberArguments.txt:3:18
"(\"a\", \"b\") -}}\n {%- endmacro -%}\n {%- call(a,b,c) test() -%}\n {{- a"...
--> tests/ui/caller_arguments.rs:5:14
|
5 | source = r#"
| ______________^
6 | | {% macro test() %}
7 | | {{- caller("a", "b") -}}
8 | | {%- endmacro -%}
... |
11 | | {%- endcall -%}
12 | | "#,
| |______^
error: expected `)` to close call argument list
--> <source attribute>:5:15
"test() -%}\n {{- a -}}\n {%- endcall -%}\n "
--> tests/ui/caller_arguments.rs:20:14
|
20 | source = r#"
| ______________^
21 | | {% macro test() %}
22 | | {{- caller("a") -}}
23 | | {%- endmacro -%}
... |
26 | | {%- endcall -%}
27 | | "#,
| |______^
error: block is not defined for caller
--> CallerInCaller.txt:6:18
"(a) -}}\n {%- endcall -%}\n "
--> tests/ui/caller_arguments.rs:35:14
|
35 | source = r#"
| ______________^
36 | | {% macro test() %}
37 | | {{- caller("a") -}}
38 | | {%- endmacro -%}
... |
41 | | {%- endcall -%}
42 | | "#,
| |______^
error: block is not defined for caller
--> CallerInCaller1.txt:10:21
"(\"b\") }}\n {% endcall %}\n {{- a -}}\n {%- endcall -%}\n "
--> tests/ui/caller_arguments.rs:50:14
|
50 | source = r#"
| ______________^
51 | | {% macro test2() %}
52 | | {{ caller("bb") }}
53 | | {% endmacro %}
... |
62 | | {%- endcall -%}
63 | | "#,
| |______^