]> git.proxmox.com Git - rustc.git/blob - vendor/tera/src/parser/tests/parser.rs
New upstream version 1.55.0+dfsg1
[rustc.git] / vendor / tera / src / parser / tests / parser.rs
1 use std::collections::HashMap;
2
3 use crate::parser::ast::*;
4 use crate::parser::parse;
5
6 #[test]
7 fn parse_empty_template() {
8 let ast = parse("").unwrap();
9 assert_eq!(ast.len(), 0);
10 }
11
12 #[test]
13 fn parse_text() {
14 let ast = parse("hello world").unwrap();
15 assert_eq!(ast[0], Node::Text("hello world".to_string()));
16 }
17
18 #[test]
19 fn parse_text_with_whitespace() {
20 let ast = parse(" hello world ").unwrap();
21 assert_eq!(ast[0], Node::Text(" hello world ".to_string()));
22 }
23
24 #[test]
25 fn parse_include_tag() {
26 let ast = parse("{% include \"index.html\" -%}").unwrap();
27 assert_eq!(
28 ast[0],
29 Node::Include(WS { left: false, right: true }, vec!["index.html".to_string()], false,),
30 );
31 let ast =
32 parse("{% include [\"custom/index.html\", \"index.html\"] ignore missing %}").unwrap();
33 assert_eq!(
34 ast[0],
35 Node::Include(
36 WS { left: false, right: false },
37 vec!["custom/index.html".to_string(), "index.html".to_string()],
38 true,
39 ),
40 );
41 }
42
43 #[test]
44 fn parse_extends() {
45 let ast = parse("{% extends \"index.html\" -%}").unwrap();
46 assert_eq!(ast[0], Node::Extends(WS { left: false, right: true }, "index.html".to_string(),),);
47 }
48
49 #[test]
50 fn parse_comments_before_extends() {
51 let ast = parse("{# A comment #}{% extends \"index.html\" -%}").unwrap();
52 assert_eq!(ast[0], Node::Extends(WS { left: false, right: true }, "index.html".to_string(),),);
53 }
54
55 #[test]
56 fn parse_import_macro() {
57 let ast = parse("\n{% import \"macros.html\" as macros -%}").unwrap();
58 assert_eq!(
59 ast[0],
60 Node::ImportMacro(
61 WS { left: false, right: true },
62 "macros.html".to_string(),
63 "macros".to_string(),
64 ),
65 );
66 }
67
68 #[test]
69 fn parse_variable_with_whitespace_trimming() {
70 let ast = parse("{{- id }}").unwrap();
71 assert_eq!(
72 ast[0],
73 Node::VariableBlock(
74 WS { left: true, right: false },
75 Expr::new(ExprVal::Ident("id".to_string()))
76 ),
77 );
78 }
79
80 #[test]
81 fn parse_variable_tag_ident() {
82 let ast = parse("{{ id }}").unwrap();
83 assert_eq!(
84 ast[0],
85 Node::VariableBlock(WS::default(), Expr::new(ExprVal::Ident("id".to_string()))),
86 );
87 }
88
89 #[test]
90 fn parse_variable_tag_ident_with_simple_filters() {
91 let ast = parse("{{ arr | first | join(n=2) }}").unwrap();
92 let mut join_args = HashMap::new();
93 join_args.insert("n".to_string(), Expr::new(ExprVal::Int(2)));
94
95 assert_eq!(
96 ast[0],
97 Node::VariableBlock(
98 WS::default(),
99 Expr::with_filters(
100 ExprVal::Ident("arr".to_string()),
101 vec![
102 FunctionCall { name: "first".to_string(), args: HashMap::new() },
103 FunctionCall { name: "join".to_string(), args: join_args },
104 ],
105 )
106 )
107 );
108 }
109
110 #[test]
111 fn parse_variable_tag_lit() {
112 let ast = parse("{{ 2 }}{{ 3.14 }}{{ \"hey\" }}{{ true }}").unwrap();
113 assert_eq!(ast[0], Node::VariableBlock(WS::default(), Expr::new(ExprVal::Int(2))));
114 assert_eq!(ast[1], Node::VariableBlock(WS::default(), Expr::new(ExprVal::Float(3.14))));
115 assert_eq!(
116 ast[2],
117 Node::VariableBlock(WS::default(), Expr::new(ExprVal::String("hey".to_string()))),
118 );
119 assert_eq!(ast[3], Node::VariableBlock(WS::default(), Expr::new(ExprVal::Bool(true))));
120 }
121
122 #[test]
123 fn parse_variable_tag_array_lit() {
124 let ast = parse("{{ [1, 2, 3] }}").unwrap();
125 let mut join_args = HashMap::new();
126 join_args.insert("n".to_string(), Expr::new(ExprVal::Int(2)));
127
128 assert_eq!(
129 ast[0],
130 Node::VariableBlock(
131 WS::default(),
132 Expr::new(ExprVal::Array(vec![
133 Expr::new(ExprVal::Int(1)),
134 Expr::new(ExprVal::Int(2)),
135 Expr::new(ExprVal::Int(3))
136 ]),)
137 )
138 );
139 }
140
141 #[test]
142 fn parse_variable_tag_array_lit_with_filter() {
143 let ast = parse("{{ [1, 2, 3] | length }}").unwrap();
144 let mut join_args = HashMap::new();
145 join_args.insert("n".to_string(), Expr::new(ExprVal::Int(2)));
146
147 assert_eq!(
148 ast[0],
149 Node::VariableBlock(
150 WS::default(),
151 Expr::with_filters(
152 ExprVal::Array(vec![
153 Expr::new(ExprVal::Int(1)),
154 Expr::new(ExprVal::Int(2)),
155 Expr::new(ExprVal::Int(3))
156 ]),
157 vec![FunctionCall { name: "length".to_string(), args: HashMap::new() },],
158 )
159 )
160 );
161 }
162
163 #[test]
164 fn parse_variable_tag_lit_math_expression() {
165 let ast = parse("{{ count + 1 * 2.5 }}").unwrap();
166
167 assert_eq!(
168 ast[0],
169 Node::VariableBlock(
170 WS::default(),
171 Expr::new(ExprVal::Math(MathExpr {
172 lhs: Box::new(Expr::new(ExprVal::Ident("count".to_string()))),
173 operator: MathOperator::Add,
174 rhs: Box::new(Expr::new(ExprVal::Math(MathExpr {
175 lhs: Box::new(Expr::new(ExprVal::Int(1))),
176 operator: MathOperator::Mul,
177 rhs: Box::new(Expr::new(ExprVal::Float(2.5))),
178 },))),
179 },))
180 ),
181 );
182 }
183
184 #[test]
185 fn parse_variable_tag_lit_math_expression_with_parentheses() {
186 let ast = parse("{{ (count + 1) * 2.5 }}").unwrap();
187 assert_eq!(
188 ast[0],
189 Node::VariableBlock(
190 WS::default(),
191 Expr::new(ExprVal::Math(MathExpr {
192 lhs: Box::new(Expr::new(ExprVal::Math(MathExpr {
193 lhs: Box::new(Expr::new(ExprVal::Ident("count".to_string()))),
194 operator: MathOperator::Add,
195 rhs: Box::new(Expr::new(ExprVal::Int(1))),
196 },))),
197 operator: MathOperator::Mul,
198 rhs: Box::new(Expr::new(ExprVal::Float(2.5))),
199 },))
200 )
201 );
202 }
203
204 #[test]
205 fn parse_variable_tag_lit_math_expression_with_parentheses_and_filter() {
206 let ast = parse("{{ (count + 1) * 2.5 | round }}").unwrap();
207 assert_eq!(
208 ast[0],
209 Node::VariableBlock(
210 WS::default(),
211 Expr::with_filters(
212 ExprVal::Math(MathExpr {
213 lhs: Box::new(Expr::new(ExprVal::Math(MathExpr {
214 lhs: Box::new(Expr::new(ExprVal::Ident("count".to_string()))),
215 operator: MathOperator::Add,
216 rhs: Box::new(Expr::new(ExprVal::Int(1))),
217 },))),
218 operator: MathOperator::Mul,
219 rhs: Box::new(Expr::new(ExprVal::Float(2.5))),
220 },),
221 vec![FunctionCall { name: "round".to_string(), args: HashMap::new() },],
222 )
223 )
224 );
225 }
226
227 #[test]
228 fn parse_variable_math_on_filter() {
229 let ast = parse("{{ a | length - 1 }}").unwrap();
230 assert_eq!(
231 ast[0],
232 Node::VariableBlock(
233 WS::default(),
234 Expr::new(ExprVal::Math(MathExpr {
235 lhs: Box::new(Expr::with_filters(
236 ExprVal::Ident("a".to_string()),
237 vec![FunctionCall { name: "length".to_string(), args: HashMap::new() },],
238 )),
239 operator: MathOperator::Sub,
240 rhs: Box::new(Expr::new(ExprVal::Int(1))),
241 },))
242 )
243 );
244 }
245
246 #[test]
247 fn parse_variable_tag_simple_logic_expression() {
248 let ast = parse("{{ 1 > 2 }}").unwrap();
249 assert_eq!(
250 ast[0],
251 Node::VariableBlock(
252 WS::default(),
253 Expr::new(ExprVal::Logic(LogicExpr {
254 lhs: Box::new(Expr::new(ExprVal::Int(1))),
255 operator: LogicOperator::Gt,
256 rhs: Box::new(Expr::new(ExprVal::Int(2))),
257 },))
258 )
259 );
260 }
261
262 #[test]
263 fn parse_variable_tag_math_and_logic_expression() {
264 let ast = parse("{{ count + 1 * 2.5 and admin }}").unwrap();
265 assert_eq!(
266 ast[0],
267 Node::VariableBlock(
268 WS::default(),
269 Expr::new(ExprVal::Logic(LogicExpr {
270 lhs: Box::new(Expr::new(ExprVal::Math(MathExpr {
271 lhs: Box::new(Expr::new(ExprVal::Ident("count".to_string()))),
272 operator: MathOperator::Add,
273 rhs: Box::new(Expr::new(ExprVal::Math(MathExpr {
274 lhs: Box::new(Expr::new(ExprVal::Int(1))),
275 operator: MathOperator::Mul,
276 rhs: Box::new(Expr::new(ExprVal::Float(2.5))),
277 },))),
278 },))),
279 operator: LogicOperator::And,
280 rhs: Box::new(Expr::new(ExprVal::Ident("admin".to_string()))),
281 },))
282 )
283 );
284 }
285
286 #[test]
287 fn parse_variable_tag_math_with_filters_and_logic_expression() {
288 let ast = parse("{{ count + 1 * 2.5 | round and admin }}").unwrap();
289 assert_eq!(
290 ast[0],
291 Node::VariableBlock(
292 WS::default(),
293 Expr::new(ExprVal::Logic(LogicExpr {
294 lhs: Box::new(Expr::with_filters(
295 ExprVal::Math(MathExpr {
296 lhs: Box::new(Expr::new(ExprVal::Ident("count".to_string()))),
297 operator: MathOperator::Add,
298 rhs: Box::new(Expr::new(ExprVal::Math(MathExpr {
299 lhs: Box::new(Expr::new(ExprVal::Int(1))),
300 operator: MathOperator::Mul,
301 rhs: Box::new(Expr::new(ExprVal::Float(2.5))),
302 },))),
303 },),
304 vec![FunctionCall { name: "round".to_string(), args: HashMap::new() },],
305 )),
306 operator: LogicOperator::And,
307 rhs: Box::new(Expr::new(ExprVal::Ident("admin".to_string()))),
308 },))
309 )
310 );
311 }
312
313 #[test]
314 fn parse_variable_tag_simple_negated_expr() {
315 let ast = parse("{{ not id }}").unwrap();
316 assert_eq!(
317 ast[0],
318 Node::VariableBlock(WS::default(), Expr::new_negated(ExprVal::Ident("id".to_string())))
319 );
320 }
321
322 #[test]
323 fn parse_test() {
324 let ast = parse("{{ a is divisibleby(2) }}").unwrap();
325 assert_eq!(
326 ast[0],
327 Node::VariableBlock(
328 WS::default(),
329 Expr::new(ExprVal::Test(Test {
330 ident: "a".to_string(),
331 negated: false,
332 name: "divisibleby".to_string(),
333 args: vec![Expr::new(ExprVal::Int(2))]
334 }))
335 )
336 );
337 }
338
339 #[test]
340 fn parse_variable_tag_negated_expr() {
341 let ast = parse("{{ not id and not true and not 1 + 1 }}").unwrap();
342 assert_eq!(
343 ast[0],
344 Node::VariableBlock(
345 WS::default(),
346 Expr::new(ExprVal::Logic(LogicExpr {
347 lhs: Box::new(Expr::new(ExprVal::Logic(LogicExpr {
348 lhs: Box::new(Expr::new_negated(ExprVal::Ident("id".to_string()))),
349 operator: LogicOperator::And,
350 rhs: Box::new(Expr::new_negated(ExprVal::Bool(true))),
351 },))),
352 operator: LogicOperator::And,
353 rhs: Box::new(Expr::new_negated(ExprVal::Math(MathExpr {
354 lhs: Box::new(Expr::new(ExprVal::Int(1))),
355 operator: MathOperator::Add,
356 rhs: Box::new(Expr::new(ExprVal::Int(1))),
357 },))),
358 },))
359 )
360 );
361 }
362
363 #[test]
364 fn parse_variable_tag_simple_test() {
365 let ast = parse("{{ id is defined }}").unwrap();
366 assert_eq!(
367 ast[0],
368 Node::VariableBlock(
369 WS::default(),
370 Expr::new(ExprVal::Test(Test {
371 ident: "id".to_string(),
372 negated: false,
373 name: "defined".to_string(),
374 args: vec![],
375 },))
376 )
377 );
378 }
379
380 #[test]
381 fn parse_variable_tag_simple_negated_test() {
382 let ast = parse("{{ id is not defined }}").unwrap();
383 assert_eq!(
384 ast[0],
385 Node::VariableBlock(
386 WS::default(),
387 Expr::new(ExprVal::Test(Test {
388 ident: "id".to_string(),
389 negated: true,
390 name: "defined".to_string(),
391 args: vec![],
392 },))
393 )
394 );
395 }
396
397 #[test]
398 fn parse_variable_tag_test_as_expression() {
399 let ast = parse("{{ user is defined and user.admin }}").unwrap();
400 assert_eq!(
401 ast[0],
402 Node::VariableBlock(
403 WS::default(),
404 Expr::new(ExprVal::Logic(LogicExpr {
405 lhs: Box::new(Expr::new(ExprVal::Test(Test {
406 ident: "user".to_string(),
407 negated: false,
408 name: "defined".to_string(),
409 args: vec![],
410 },))),
411 operator: LogicOperator::And,
412 rhs: Box::new(Expr::new(ExprVal::Ident("user.admin".to_string()))),
413 },))
414 )
415 );
416 }
417
418 #[test]
419 fn parse_variable_tag_macro_call() {
420 let ast = parse("{{ macros::get_time(some=1) }}").unwrap();
421 let mut args = HashMap::new();
422 args.insert("some".to_string(), Expr::new(ExprVal::Int(1)));
423
424 assert_eq!(
425 ast[0],
426 Node::VariableBlock(
427 WS::default(),
428 Expr::new(ExprVal::MacroCall(MacroCall {
429 namespace: "macros".to_string(),
430 name: "get_time".to_string(),
431 args,
432 },)),
433 )
434 );
435 }
436
437 #[test]
438 fn parse_allow_block_in_filter_section() {
439 let ast =
440 parse("{% filter upper %}{% block content %}Hello{% endblock %}{% endfilter %}").unwrap();
441
442 assert_eq!(
443 ast[0],
444 Node::FilterSection(
445 WS::default(),
446 FilterSection {
447 filter: FunctionCall { name: "upper".to_owned(), args: HashMap::default() },
448 body: vec![Node::Block(
449 WS::default(),
450 Block {
451 name: "content".to_owned(),
452 body: vec![Node::Text("Hello".to_owned())]
453 },
454 WS::default(),
455 )],
456 },
457 WS::default(),
458 )
459 );
460 }
461
462 // smoke test for array in kwargs
463 #[test]
464 fn parse_variable_tag_macro_call_with_array() {
465 let ast = parse("{{ macros::get_time(some=[1, 2]) }}").unwrap();
466 let mut args = HashMap::new();
467 args.insert(
468 "some".to_string(),
469 Expr::new(ExprVal::Array(vec![Expr::new(ExprVal::Int(1)), Expr::new(ExprVal::Int(2))])),
470 );
471
472 assert_eq!(
473 ast[0],
474 Node::VariableBlock(
475 WS::default(),
476 Expr::new(ExprVal::MacroCall(MacroCall {
477 namespace: "macros".to_string(),
478 name: "get_time".to_string(),
479 args,
480 },))
481 )
482 );
483 }
484
485 // smoke test for array in kwargs
486 #[test]
487 fn parse_variable_tag_macro_call_with_array_with_filters() {
488 let ast = parse("{{ macros::get_time(some=[1, 2] | reverse) }}").unwrap();
489 let mut args = HashMap::new();
490 args.insert(
491 "some".to_string(),
492 Expr::with_filters(
493 ExprVal::Array(vec![Expr::new(ExprVal::Int(1)), Expr::new(ExprVal::Int(2))]),
494 vec![FunctionCall { name: "reverse".to_string(), args: HashMap::new() }],
495 ),
496 );
497
498 assert_eq!(
499 ast[0],
500 Node::VariableBlock(
501 WS::default(),
502 Expr::new(ExprVal::MacroCall(MacroCall {
503 namespace: "macros".to_string(),
504 name: "get_time".to_string(),
505 args,
506 },))
507 )
508 );
509 }
510
511 #[test]
512 fn parse_variable_tag_macro_call_with_filter() {
513 let ast = parse("{{ macros::get_time(some=1) | round }}").unwrap();
514 let mut args = HashMap::new();
515 args.insert("some".to_string(), Expr::new(ExprVal::Int(1)));
516
517 assert_eq!(
518 ast[0],
519 Node::VariableBlock(
520 WS::default(),
521 Expr::with_filters(
522 ExprVal::MacroCall(MacroCall {
523 namespace: "macros".to_string(),
524 name: "get_time".to_string(),
525 args,
526 },),
527 vec![FunctionCall { name: "round".to_string(), args: HashMap::new() },],
528 )
529 )
530 );
531 }
532
533 #[test]
534 fn parse_variable_tag_global_function() {
535 let ast = parse("{{ get_time(some=1) }}").unwrap();
536 let mut args = HashMap::new();
537 args.insert("some".to_string(), Expr::new(ExprVal::Int(1)));
538
539 assert_eq!(
540 ast[0],
541 Node::VariableBlock(
542 WS::default(),
543 Expr::new(ExprVal::FunctionCall(FunctionCall { name: "get_time".to_string(), args },))
544 )
545 );
546 }
547
548 #[test]
549 fn parse_in_condition() {
550 let ast = parse("{{ b in c }}").unwrap();
551 let mut args = HashMap::new();
552 args.insert("some".to_string(), Expr::new(ExprVal::Int(1)));
553
554 assert_eq!(
555 ast[0],
556 Node::VariableBlock(
557 WS::default(),
558 Expr::new(ExprVal::In(In {
559 lhs: Box::new(Expr::new(ExprVal::Ident("b".to_string()))),
560 rhs: Box::new(Expr::new(ExprVal::Ident("c".to_string()))),
561 negated: false,
562 }))
563 )
564 );
565 }
566
567 #[test]
568 fn parse_negated_in_condition() {
569 let ast = parse("{{ b not in c }}").unwrap();
570 let mut args = HashMap::new();
571 args.insert("some".to_string(), Expr::new(ExprVal::Int(1)));
572
573 assert_eq!(
574 ast[0],
575 Node::VariableBlock(
576 WS::default(),
577 Expr::new(ExprVal::In(In {
578 lhs: Box::new(Expr::new(ExprVal::Ident("b".to_string()))),
579 rhs: Box::new(Expr::new(ExprVal::Ident("c".to_string()))),
580 negated: true,
581 }))
582 )
583 );
584 }
585
586 #[test]
587 fn parse_variable_tag_global_function_with_filter() {
588 let ast = parse("{{ get_time(some=1) | round | upper }}").unwrap();
589 let mut args = HashMap::new();
590 args.insert("some".to_string(), Expr::new(ExprVal::Int(1)));
591
592 assert_eq!(
593 ast[0],
594 Node::VariableBlock(
595 WS::default(),
596 Expr::with_filters(
597 ExprVal::FunctionCall(FunctionCall { name: "get_time".to_string(), args },),
598 vec![
599 FunctionCall { name: "round".to_string(), args: HashMap::new() },
600 FunctionCall { name: "upper".to_string(), args: HashMap::new() },
601 ],
602 )
603 )
604 );
605 }
606
607 #[test]
608 fn parse_comment_tag() {
609 let ast = parse("{# hey #}").unwrap();
610 assert!(ast.is_empty());
611 }
612
613 #[test]
614 fn parse_set_tag_lit() {
615 let ast = parse("{% set hello = \"hi\" %}").unwrap();
616 assert_eq!(
617 ast[0],
618 Node::Set(
619 WS::default(),
620 Set {
621 key: "hello".to_string(),
622 value: Expr::new(ExprVal::String("hi".to_string())),
623 global: false,
624 },
625 )
626 );
627 }
628
629 #[test]
630 fn parse_set_tag_macro_call() {
631 let ast = parse("{% set hello = macros::something() %}").unwrap();
632 assert_eq!(
633 ast[0],
634 Node::Set(
635 WS::default(),
636 Set {
637 key: "hello".to_string(),
638 value: Expr::new(ExprVal::MacroCall(MacroCall {
639 namespace: "macros".to_string(),
640 name: "something".to_string(),
641 args: HashMap::new(),
642 },)),
643 global: false,
644 },
645 )
646 );
647 }
648
649 #[test]
650 fn parse_set_tag_fn_call() {
651 let ast = parse("{% set hello = utcnow() %}").unwrap();
652 assert_eq!(
653 ast[0],
654 Node::Set(
655 WS::default(),
656 Set {
657 key: "hello".to_string(),
658 value: Expr::new(ExprVal::FunctionCall(FunctionCall {
659 name: "utcnow".to_string(),
660 args: HashMap::new(),
661 },)),
662 global: false,
663 },
664 )
665 );
666 }
667
668 #[test]
669 fn parse_set_array() {
670 let ast = parse("{% set hello = [1, true, 'hello'] %}").unwrap();
671 assert_eq!(
672 ast[0],
673 Node::Set(
674 WS::default(),
675 Set {
676 key: "hello".to_string(),
677 value: Expr::new(ExprVal::Array(vec![
678 Expr::new(ExprVal::Int(1)),
679 Expr::new(ExprVal::Bool(true)),
680 Expr::new(ExprVal::String("hello".to_string())),
681 ])),
682 global: false,
683 },
684 )
685 );
686 }
687
688 #[test]
689 fn parse_set_array_with_filter() {
690 let ast = parse("{% set hello = [1, true, 'hello'] | length %}").unwrap();
691 assert_eq!(
692 ast[0],
693 Node::Set(
694 WS::default(),
695 Set {
696 key: "hello".to_string(),
697 value: Expr::with_filters(
698 ExprVal::Array(vec![
699 Expr::new(ExprVal::Int(1)),
700 Expr::new(ExprVal::Bool(true)),
701 Expr::new(ExprVal::String("hello".to_string())),
702 ]),
703 vec![FunctionCall { name: "length".to_string(), args: HashMap::new() },],
704 ),
705 global: false,
706 },
707 )
708 );
709 }
710
711 #[test]
712 fn parse_set_global_tag() {
713 let ast = parse("{% set_global hello = utcnow() %}").unwrap();
714 assert_eq!(
715 ast[0],
716 Node::Set(
717 WS::default(),
718 Set {
719 key: "hello".to_string(),
720 value: Expr::new(ExprVal::FunctionCall(FunctionCall {
721 name: "utcnow".to_string(),
722 args: HashMap::new(),
723 },)),
724 global: true,
725 },
726 )
727 );
728 }
729
730 #[test]
731 fn parse_raw_tag() {
732 let ast = parse("{% raw -%}{{hey}}{%- endraw %}").unwrap();
733 let mut start_ws = WS::default();
734 start_ws.right = true;
735 let mut end_ws = WS::default();
736 end_ws.left = true;
737
738 assert_eq!(ast[0], Node::Raw(start_ws, "{{hey}}".to_string(), end_ws));
739 }
740
741 // https://github.com/Keats/tera/issues/513
742 #[test]
743 fn parse_raw_tag_with_ws() {
744 // println!("{}", parse("{% raw %} yaml_test: {% endraw %}").unwrap_err());
745 let ast = parse("{% raw %} yaml_test: {% endraw %}").unwrap();
746 let start_ws = WS::default();
747 let end_ws = WS::default();
748
749 assert_eq!(ast[0], Node::Raw(start_ws, " yaml_test: ".to_string(), end_ws));
750 }
751
752 #[test]
753 fn parse_filter_section_without_args() {
754 let ast = parse("{% filter upper -%}A{%- endfilter %}").unwrap();
755 let mut start_ws = WS::default();
756 start_ws.right = true;
757 let mut end_ws = WS::default();
758 end_ws.left = true;
759
760 assert_eq!(
761 ast[0],
762 Node::FilterSection(
763 start_ws,
764 FilterSection {
765 filter: FunctionCall { name: "upper".to_string(), args: HashMap::new() },
766 body: vec![Node::Text("A".to_string())],
767 },
768 end_ws,
769 )
770 );
771 }
772
773 #[test]
774 fn parse_filter_section_with_args() {
775 let ast = parse("{% filter upper(attr=1) -%}A{%- endfilter %}").unwrap();
776 let mut start_ws = WS::default();
777 start_ws.right = true;
778 let mut end_ws = WS::default();
779 end_ws.left = true;
780
781 let mut args = HashMap::new();
782 args.insert("attr".to_string(), Expr::new(ExprVal::Int(1)));
783
784 assert_eq!(
785 ast[0],
786 Node::FilterSection(
787 start_ws,
788 FilterSection {
789 filter: FunctionCall { name: "upper".to_string(), args },
790 body: vec![Node::Text("A".to_string())],
791 },
792 end_ws,
793 )
794 );
795 }
796
797 #[test]
798 fn parse_filter_section_preserves_ws() {
799 let ast = parse("{% filter upper %} {{a}} B {% endfilter %}").unwrap();
800
801 assert_eq!(
802 ast[0],
803 Node::FilterSection(
804 WS::default(),
805 FilterSection {
806 filter: FunctionCall { name: "upper".to_string(), args: HashMap::new() },
807 body: vec![
808 Node::Text(" ".to_string()),
809 Node::VariableBlock(WS::default(), Expr::new(ExprVal::Ident("a".to_string()))),
810 Node::Text(" B ".to_string())
811 ]
812 },
813 WS::default(),
814 )
815 );
816 }
817
818 #[test]
819 fn parse_block() {
820 let ast = parse("{% block hello %}{{super()}} hey{%- endblock hello %}").unwrap();
821 let start_ws = WS::default();
822 let mut end_ws = WS::default();
823 end_ws.left = true;
824
825 assert_eq!(
826 ast[0],
827 Node::Block(
828 start_ws,
829 Block {
830 name: "hello".to_string(),
831 body: vec![Node::Super, Node::Text(" hey".to_string())],
832 },
833 end_ws,
834 )
835 );
836 }
837
838 #[test]
839 fn parse_simple_macro_definition() {
840 let ast = parse("{% macro hello(a=1, b='hello', c) %}A: {{a}}{% endmacro %}").unwrap();
841 let mut args = HashMap::new();
842 args.insert("a".to_string(), Some(Expr::new(ExprVal::Int(1))));
843 args.insert("b".to_string(), Some(Expr::new(ExprVal::String("hello".to_string()))));
844 args.insert("c".to_string(), None);
845
846 assert_eq!(
847 ast[0],
848 Node::MacroDefinition(
849 WS::default(),
850 MacroDefinition {
851 name: "hello".to_string(),
852 args,
853 body: vec![
854 Node::Text("A: ".to_string()),
855 Node::VariableBlock(WS::default(), Expr::new(ExprVal::Ident("a".to_string()))),
856 ],
857 },
858 WS::default(),
859 )
860 );
861 }
862
863 #[test]
864 fn parse_value_forloop() {
865 let ast = parse("{% for item in items | reverse %}A{%- endfor %}").unwrap();
866 let start_ws = WS::default();
867 let mut end_ws = WS::default();
868 end_ws.left = true;
869
870 assert_eq!(
871 ast[0],
872 Node::Forloop(
873 start_ws,
874 Forloop {
875 key: None,
876 value: "item".to_string(),
877 container: Expr::with_filters(
878 ExprVal::Ident("items".to_string()),
879 vec![FunctionCall { name: "reverse".to_string(), args: HashMap::new() },],
880 ),
881 body: vec![Node::Text("A".to_string())],
882 empty_body: None,
883 },
884 end_ws,
885 )
886 );
887 }
888
889 #[test]
890 fn parse_key_value_forloop() {
891 let ast = parse("{% for key, item in get_map() %}A{%- endfor %}").unwrap();
892 let start_ws = WS::default();
893 let mut end_ws = WS::default();
894 end_ws.left = true;
895
896 assert_eq!(
897 ast[0],
898 Node::Forloop(
899 start_ws,
900 Forloop {
901 key: Some("key".to_string()),
902 value: "item".to_string(),
903 container: Expr::new(ExprVal::FunctionCall(FunctionCall {
904 name: "get_map".to_string(),
905 args: HashMap::new(),
906 },)),
907 body: vec![Node::Text("A".to_string())],
908 empty_body: None,
909 },
910 end_ws,
911 )
912 );
913 }
914
915 #[test]
916 fn parse_value_forloop_array() {
917 let ast = parse("{% for item in [1,2,] %}A{%- endfor %}").unwrap();
918 let start_ws = WS::default();
919 let mut end_ws = WS::default();
920 end_ws.left = true;
921
922 assert_eq!(
923 ast[0],
924 Node::Forloop(
925 start_ws,
926 Forloop {
927 key: None,
928 value: "item".to_string(),
929 container: Expr::new(ExprVal::Array(vec![
930 Expr::new(ExprVal::Int(1)),
931 Expr::new(ExprVal::Int(2)),
932 ])),
933 body: vec![Node::Text("A".to_string())],
934 empty_body: None,
935 },
936 end_ws,
937 )
938 );
939 }
940
941 #[test]
942 fn parse_value_forloop_array_with_filter() {
943 let ast = parse("{% for item in [1,2,] | reverse %}A{%- endfor %}").unwrap();
944 let start_ws = WS::default();
945 let mut end_ws = WS::default();
946 end_ws.left = true;
947
948 assert_eq!(
949 ast[0],
950 Node::Forloop(
951 start_ws,
952 Forloop {
953 key: None,
954 value: "item".to_string(),
955 container: Expr::with_filters(
956 ExprVal::Array(vec![Expr::new(ExprVal::Int(1)), Expr::new(ExprVal::Int(2)),]),
957 vec![FunctionCall { name: "reverse".to_string(), args: HashMap::new() },],
958 ),
959 body: vec![Node::Text("A".to_string())],
960 empty_body: None,
961 },
962 end_ws,
963 )
964 );
965 }
966
967 #[test]
968 fn parse_value_forloop_empty() {
969 let ast = parse("{% for item in [1,2,] %}A{% else %}B{%- endfor %}").unwrap();
970 let start_ws = WS::default();
971 let mut end_ws = WS::default();
972 end_ws.left = true;
973
974 assert_eq!(
975 ast[0],
976 Node::Forloop(
977 start_ws,
978 Forloop {
979 key: None,
980 value: "item".to_string(),
981 container: Expr::new(ExprVal::Array(vec![
982 Expr::new(ExprVal::Int(1)),
983 Expr::new(ExprVal::Int(2)),
984 ])),
985 body: vec![Node::Text("A".to_string())],
986 empty_body: Some(vec![Node::Text("B".to_string())]),
987 },
988 end_ws,
989 )
990 );
991 }
992
993 #[test]
994 fn parse_if() {
995 let ast = parse("{% if item or admin %}A {%- elif 1 > 2 %}B{% else -%} C{%- endif %}").unwrap();
996 let mut end_ws = WS::default();
997 end_ws.left = true;
998
999 let mut else_ws = WS::default();
1000 else_ws.right = true;
1001
1002 assert_eq!(
1003 ast[0],
1004 Node::If(
1005 If {
1006 conditions: vec![
1007 (
1008 WS::default(),
1009 Expr::new(ExprVal::Logic(LogicExpr {
1010 lhs: Box::new(Expr::new(ExprVal::Ident("item".to_string()))),
1011 operator: LogicOperator::Or,
1012 rhs: Box::new(Expr::new(ExprVal::Ident("admin".to_string()))),
1013 })),
1014 vec![Node::Text("A ".to_string())],
1015 ),
1016 (
1017 end_ws.clone(),
1018 Expr::new(ExprVal::Logic(LogicExpr {
1019 lhs: Box::new(Expr::new(ExprVal::Int(1))),
1020 operator: LogicOperator::Gt,
1021 rhs: Box::new(Expr::new(ExprVal::Int(2))),
1022 })),
1023 vec![Node::Text("B".to_string())],
1024 ),
1025 ],
1026 otherwise: Some((else_ws, vec![Node::Text(" C".to_string())])),
1027 },
1028 end_ws,
1029 )
1030 );
1031 }
1032
1033 #[test]
1034 fn parse_break() {
1035 let ast = parse("{% for item in items %}{% break -%}{% endfor %}").unwrap();
1036 let for_ws = WS::default();
1037 assert_eq!(
1038 ast[0],
1039 Node::Forloop(
1040 for_ws,
1041 Forloop {
1042 key: None,
1043 value: "item".to_string(),
1044 container: Expr::new(ExprVal::Ident("items".to_string())),
1045 body: vec![Node::Break(WS { left: false, right: true }),],
1046 empty_body: None,
1047 },
1048 for_ws,
1049 )
1050 );
1051 }
1052
1053 #[test]
1054 fn parse_continue() {
1055 let ast = parse("{% for item in items %}{% continue -%}{% endfor %}").unwrap();
1056 let for_ws = WS::default();
1057 assert_eq!(
1058 ast[0],
1059 Node::Forloop(
1060 for_ws,
1061 Forloop {
1062 key: None,
1063 value: "item".to_string(),
1064 container: Expr::new(ExprVal::Ident("items".to_string())),
1065 body: vec![Node::Continue(WS { left: false, right: true }),],
1066 empty_body: None,
1067 },
1068 for_ws,
1069 )
1070 );
1071 }
1072
1073 #[test]
1074 fn parse_string_concat_can_merge() {
1075 let ast = parse("{{ `hello` ~ 'hey' }}").unwrap();
1076 assert_eq!(
1077 ast[0],
1078 Node::VariableBlock(WS::default(), Expr::new(ExprVal::String("hellohey".to_string()))),
1079 );
1080 }
1081 #[test]
1082 fn parse_string_concat() {
1083 let ast = parse("{{ `hello` ~ ident }}").unwrap();
1084 assert_eq!(
1085 ast[0],
1086 Node::VariableBlock(
1087 WS::default(),
1088 Expr::new(ExprVal::StringConcat(StringConcat {
1089 values: vec![
1090 ExprVal::String("hello".to_string()),
1091 ExprVal::Ident("ident".to_string()),
1092 ]
1093 }))
1094 ),
1095 );
1096 }
1097
1098 #[test]
1099 fn parse_string_concat_multiple() {
1100 let ast = parse("{{ `hello` ~ ident ~ 'ho' }}").unwrap();
1101 assert_eq!(
1102 ast[0],
1103 Node::VariableBlock(
1104 WS::default(),
1105 Expr::new(ExprVal::StringConcat(StringConcat {
1106 values: vec![
1107 ExprVal::String("hello".to_string()),
1108 ExprVal::Ident("ident".to_string()),
1109 ExprVal::String("ho".to_string()),
1110 ]
1111 }))
1112 ),
1113 );
1114 }