1 #[test]
test_for()2 fn test_for() {
3     assert_template_result!(
4         " yo  yo  yo  yo ",
5         "{%for item in array%} yo {%endfor%}",
6         o!({"array": [1, 2, 3, 4]}),
7     );
8     assert_template_result!(
9         "yoyo",
10         "{%for item in array%}yo{%endfor%}",
11         o!({"array": [1, 2]}),
12     );
13     assert_template_result!(
14         " yo ",
15         "{%for item in array%} yo {%endfor%}",
16         o!({"array": [1]}),
17     );
18     assert_template_result!("", "{%for item in array%}{%endfor%}", o!({"array": [1, 2]}));
19     let expected = r#"
20 
21   yo
22 
23   yo
24 
25   yo
26 
27 "#;
28     let template = r#"
29 {%for item in array%}
30   yo
31 {%endfor%}
32 "#;
33     assert_template_result!(expected, template, o!({"array": [1, 2, 3]}));
34 }
35 
36 #[test]
test_for_reversed()37 fn test_for_reversed() {
38     let assigns = o!({ "array": [ 1, 2, 3] });
39     assert_template_result!(
40         "321",
41         "{%for item in array reversed %}{{item}}{%endfor%}",
42         assigns,
43     );
44 }
45 
46 #[test]
47 #[should_panic] // liquid-rust#273
test_for_with_range()48 fn test_for_with_range() {
49     assert_template_result!(
50         " 1  2  3 ",
51         "{%for item in (1..3) %} {{item}} {%endfor%}",
52         o!({}),
53     );
54 
55     assert_render_error!("{% for i in (a..2) %}{% endfor %}", o!({"a": [1, 2]}));
56 
57     assert_template_result!(
58         " 0  1  2  3 ",
59         "{% for item in (a..3) %} {{item}} {% endfor %}",
60         o!({"a": "invalid integer"}),
61     );
62 }
63 
64 #[test]
test_for_with_variable_range()65 fn test_for_with_variable_range() {
66     assert_template_result!(
67         " 1  2  3 ",
68         "{%for item in (1..foobar) %} {{item}} {%endfor%}",
69         o!({"foobar": 3}),
70     );
71 }
72 
73 #[test]
test_for_with_hash_value_range()74 fn test_for_with_hash_value_range() {
75     let foobar = o!({ "value": 3 });
76     assert_template_result!(
77         " 1  2  3 ",
78         "{%for item in (1..foobar.value) %} {{item}} {%endfor%}",
79         o!({ "foobar": foobar }),
80     );
81 }
82 
83 #[test]
84 #[should_panic]
test_for_with_drop_value_range()85 fn test_for_with_drop_value_range() {
86     panic!("Implementation specific: docs");
87 }
88 
89 #[test]
test_for_with_variable()90 fn test_for_with_variable() {
91     assert_template_result!(
92         " 1  2  3 ",
93         "{%for item in array%} {{item}} {%endfor%}",
94         o!({"array": [1, 2, 3]}),
95     );
96     assert_template_result!(
97         "123",
98         "{%for item in array%}{{item}}{%endfor%}",
99         o!({"array": [1, 2, 3]}),
100     );
101     assert_template_result!(
102         "123",
103         "{% for item in array %}{{item}}{% endfor %}",
104         o!({"array": [1, 2, 3]}),
105     );
106     assert_template_result!(
107         "abcd",
108         "{%for item in array%}{{item}}{%endfor%}",
109         o!({"array": ["a", "b", "c", "d"]}),
110     );
111     assert_template_result!(
112         "a b c",
113         "{%for item in array%}{{item}}{%endfor%}",
114         o!({"array": ["a", " ", "b", " ", "c"]}),
115     );
116     assert_template_result!(
117         "abc",
118         "{%for item in array%}{{item}}{%endfor%}",
119         o!({"array": ["a", "", "b", "", "c"]}),
120     );
121 }
122 
123 #[test]
test_for_helpers()124 fn test_for_helpers() {
125     let assigns = o!({ "array": [1, 2, 3] });
126     assert_template_result!(
127         " 1/3  2/3  3/3 ",
128         "{%for item in array%} {{forloop.index}}/{{forloop.length}} {%endfor%}",
129         assigns,
130     );
131     assert_template_result!(
132         " 1  2  3 ",
133         "{%for item in array%} {{forloop.index}} {%endfor%}",
134         assigns,
135     );
136     assert_template_result!(
137         " 0  1  2 ",
138         "{%for item in array%} {{forloop.index0}} {%endfor%}",
139         assigns,
140     );
141     assert_template_result!(
142         " 2  1  0 ",
143         "{%for item in array%} {{forloop.rindex0}} {%endfor%}",
144         assigns,
145     );
146     assert_template_result!(
147         " 3  2  1 ",
148         "{%for item in array%} {{forloop.rindex}} {%endfor%}",
149         assigns,
150     );
151     assert_template_result!(
152         " true  false  false ",
153         "{%for item in array%} {{forloop.first}} {%endfor%}",
154         assigns,
155     );
156     assert_template_result!(
157         " false  false  true ",
158         "{%for item in array%} {{forloop.last}} {%endfor%}",
159         assigns,
160     );
161 }
162 
163 #[test]
test_for_and_if()164 fn test_for_and_if() {
165     let assigns = o!({ "array": [1, 2, 3] });
166     assert_template_result!(
167         "+--",
168         "{%for item in array%}{% if forloop.first %}+{% else %}-{% endif %}{%endfor%}",
169         assigns,
170     );
171 }
172 
173 #[test]
test_for_else()174 fn test_for_else() {
175     assert_template_result!(
176         "+++",
177         "{%for item in array%}+{%else%}-{%endfor%}",
178         o!({"array": [1, 2, 3]}),
179     );
180     assert_template_result!(
181         "-",
182         "{%for item in array%}+{%else%}-{%endfor%}",
183         o!({"array": []}),
184     );
185     assert_template_result!(
186         "-",
187         "{%for item in array%}+{%else%}-{%endfor%}",
188         o!({ "array": nil }),
189     );
190 }
191 
192 #[test]
test_limiting()193 fn test_limiting() {
194     let assigns = o!({ "array": [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] });
195     assert_template_result!(
196         "12",
197         "{%for i in array limit:2 %}{{ i }}{%endfor%}",
198         assigns,
199     );
200     assert_template_result!(
201         "1234",
202         "{%for i in array limit:4 %}{{ i }}{%endfor%}",
203         assigns,
204     );
205     assert_template_result!(
206         "3456",
207         "{%for i in array limit:4 offset:2 %}{{ i }}{%endfor%}",
208         assigns,
209     );
210     assert_template_result!(
211         "3456",
212         "{%for i in array limit: 4 offset: 2 %}{{ i }}{%endfor%}",
213         assigns,
214     );
215 }
216 
217 #[test]
test_dynamic_variable_limiting()218 fn test_dynamic_variable_limiting() {
219     let assigns = o!({ "array": [1, 2, 3, 4, 5, 6, 7, 8, 9, 0], "limit": 2, "offset": 2 });
220 
221     assert_template_result!(
222         "34",
223         "{%for i in array limit: limit offset: offset %}{{ i }}{%endfor%}",
224         assigns,
225     );
226 }
227 
228 #[test]
test_nested_for()229 fn test_nested_for() {
230     let assigns = o!({ "array": [[1, 2], [3, 4], [5, 6]] });
231     assert_template_result!(
232         "123456",
233         "{%for item in array%}{%for i in item%}{{ i }}{%endfor%}{%endfor%}",
234         assigns,
235     );
236 }
237 
238 #[test]
test_offset_only()239 fn test_offset_only() {
240     let assigns = o!({ "array": [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] });
241     assert_template_result!(
242         "890",
243         "{%for i in array offset:7 %}{{ i }}{%endfor%}",
244         assigns,
245     );
246 }
247 
248 #[test]
249 #[should_panic] // liquid-rust#274
test_pause_resume()250 fn test_pause_resume() {
251     let assigns = o!({ "array": { "items": [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] } });
252     let markup = r#"
253       {%for i in array.items limit: 3 %}{{i}}{%endfor%}
254       next
255       {%for i in array.items offset:continue limit: 3 %}{{i}}{%endfor%}
256       next
257       {%for i in array.items offset:continue limit: 3 %}{{i}}{%endfor%}
258       "#;
259     let expected = r#"
260       123
261       next
262       456
263       next
264       789
265       "#;
266     assert_template_result!(expected, markup, assigns);
267 }
268 
269 #[test]
270 #[should_panic] // liquid-rust#274
test_pause_resume_limit()271 fn test_pause_resume_limit() {
272     let assigns = o!({ "array": { "items": [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] } });
273     let markup = r#"
274       {%for i in array.items limit:3 %}{{i}}{%endfor%}
275       next
276       {%for i in array.items offset:continue limit:3 %}{{i}}{%endfor%}
277       next
278       {%for i in array.items offset:continue limit:1 %}{{i}}{%endfor%}
279       "#;
280     let expected = r#"
281       123
282       next
283       456
284       next
285       7
286       "#;
287     assert_template_result!(expected, markup, assigns);
288 }
289 
290 #[test]
291 #[should_panic] // liquid-rust#274
test_pause_resume_big_limit()292 fn test_pause_resume_big_limit() {
293     let assigns = o!({ "array": { "items": [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] } });
294     let markup = r#"
295       {%for i in array.items limit:3 %}{{i}}{%endfor%}
296       next
297       {%for i in array.items offset:continue limit:3 %}{{i}}{%endfor%}
298       next
299       {%for i in array.items offset:continue limit:1000 %}{{i}}{%endfor%}
300       "#;
301     let expected = r#"
302       123
303       next
304       456
305       next
306       7890
307       "#;
308     assert_template_result!(expected, markup, assigns);
309 }
310 
311 #[test]
312 #[should_panic] // liquid-rust#274
test_pause_resume_big_offset()313 fn test_pause_resume_big_offset() {
314     let assigns = o!({ "array": { "items": [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] } });
315     let markup = "{%for i in array.items limit:3 %}{{i}}{%endfor%}
316       next
317       {%for i in array.items offset:continue limit:3 %}{{i}}{%endfor%}
318       next
319       {%for i in array.items offset:continue limit:3 offset:1000 %}{{i}}{%endfor%}";
320     let expected = "123
321       next
322       456
323       next
324       ";
325     assert_template_result!(expected, markup, assigns);
326 }
327 
328 #[test]
test_for_with_break()329 fn test_for_with_break() {
330     let assigns = o!({ "array": { "items": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] } });
331 
332     let markup = "{% for i in array.items %}{% break %}{% endfor %}";
333     let expected = "";
334     assert_template_result!(expected, markup, assigns);
335 
336     let markup = "{% for i in array.items %}{{ i }}{% break %}{% endfor %}";
337     let expected = "1";
338     assert_template_result!(expected, markup, assigns);
339 
340     let markup = "{% for i in array.items %}{% break %}{{ i }}{% endfor %}";
341     let expected = "";
342     assert_template_result!(expected, markup, assigns);
343 
344     let markup =
345         "{% for i in array.items %}{{ i }}{% if i > 3 %}{% break %}{% endif %}{% endfor %}";
346     let expected = "1234";
347     assert_template_result!(expected, markup, assigns);
348 
349     // tests to ensure it only breaks out of the local for loop
350     // and not all of them.
351     let assigns = o!({ "array": [[1, 2], [3, 4], [5, 6]] });
352     let markup = concat!(
353         "{% for item in array %}",
354         "{% for i in item %}",
355         "{% if i == 1 %}",
356         "{% break %}",
357         "{% endif %}",
358         "{{ i }}",
359         "{% endfor %}",
360         "{% endfor %}"
361     );
362     let expected = "3456";
363     assert_template_result!(expected, markup, assigns);
364 
365     // test break does nothing when unreached
366     let assigns = o!({ "array": { "items": [1, 2, 3, 4, 5] } });
367     let markup =
368         "{% for i in array.items %}{% if i == 9999 %}{% break %}{% endif %}{{ i }}{% endfor %}";
369     let expected = "12345";
370     assert_template_result!(expected, markup, assigns);
371 }
372 
373 #[test]
test_for_with_continue()374 fn test_for_with_continue() {
375     let assigns = o!({ "array": { "items": [1, 2, 3, 4, 5] } });
376 
377     let markup = "{% for i in array.items %}{% continue %}{% endfor %}";
378     let expected = "";
379     assert_template_result!(expected, markup, assigns);
380 
381     let markup = "{% for i in array.items %}{{ i }}{% continue %}{% endfor %}";
382     let expected = "12345";
383     assert_template_result!(expected, markup, assigns);
384 
385     let markup = "{% for i in array.items %}{% continue %}{{ i }}{% endfor %}";
386     let expected = "";
387     assert_template_result!(expected, markup, assigns);
388 
389     let markup =
390         "{% for i in array.items %}{% if i > 3 %}{% continue %}{% endif %}{{ i }}{% endfor %}";
391     let expected = "123";
392     assert_template_result!(expected, markup, assigns);
393 
394     let markup = "{% for i in array.items %}{% if i == 3 %}{% continue %}{% else %}{{ i }}{% endif %}{% endfor %}";
395     let expected = "1245";
396     assert_template_result!(expected, markup, assigns);
397 
398     // tests to ensure it only continues the local for loop and not all of them.
399     let assigns = o!({ "array": [[1, 2], [3, 4], [5, 6]] });
400     let markup = concat!(
401         "{% for item in array %}",
402         "{% for i in item %}",
403         "{% if i == 1 %}",
404         "{% continue %}",
405         "{% endif %}",
406         "{{ i }}",
407         "{% endfor %}",
408         "{% endfor %}"
409     );
410     let expected = "23456";
411     assert_template_result!(expected, markup, assigns);
412 
413     // test continue does nothing when unreached
414     let assigns = o!({ "array": { "items": [1, 2, 3, 4, 5] } });
415     let markup =
416         "{% for i in array.items %}{% if i == 9999 %}{% continue %}{% endif %}{{ i }}{% endfor %}";
417     let expected = "12345";
418     assert_template_result!(expected, markup, assigns);
419 }
420 
421 #[test]
422 #[should_panic] // liquid-rust#270
test_for_tag_string()423 fn test_for_tag_string() {
424     // ruby 1.8.7 "String".each: Enumerator with single "String" element.
425     // ruby 1.9.3 no longer supports .each on String though we mimic
426     // the functionality for backwards compatibility
427 
428     assert_template_result!(
429         "test string",
430         "{%for val in string%}{{val}}{%endfor%}",
431         o!({"string": "test string"}),
432     );
433 
434     assert_template_result!(
435         "test string",
436         "{%for val in string limit:1%}{{val}}{%endfor%}",
437         o!({"string": "test string"}),
438     );
439 
440     assert_template_result!(
441         "val-string-1-1-0-1-0-true-true-test string",
442         concat!(
443             "{%for val in string%}",
444             "{{forloop.name}}-",
445             "{{forloop.index}}-",
446             "{{forloop.length}}-",
447             "{{forloop.index0}}-",
448             "{{forloop.rindex}}-",
449             "{{forloop.rindex0}}-",
450             "{{forloop.first}}-",
451             "{{forloop.last}}-",
452             "{{val}}{%endfor%}"
453         ),
454         o!({"string": "test string"}),
455     );
456 }
457 
458 #[test]
test_for_parentloop_references_parent_loop()459 fn test_for_parentloop_references_parent_loop() {
460     assert_template_result!(
461         "1.1 1.2 1.3 2.1 2.2 2.3 ",
462         concat!(
463             "{% for inner in outer %}{% for k in inner %}",
464             "{{ forloop.parentloop.index }}.{{ forloop.index }} ",
465             "{% endfor %}{% endfor %}"
466         ),
467         o!({"outer": [[1, 1, 1], [1, 1, 1]]}),
468     );
469 }
470 
471 #[test]
472 #[should_panic] // liquid-rust#271
test_for_parentloop_nil_when_not_present()473 fn test_for_parentloop_nil_when_not_present() {
474     assert_template_result!(
475         ".1 .2 ",
476         concat!(
477             "{% for inner in outer %}",
478             "{{ forloop.parentloop.index }}.{{ forloop.index }} ",
479             "{% endfor %}"
480         ),
481         o!({"outer": [[1, 1, 1], [1, 1, 1]]}),
482     );
483 }
484 
485 #[test]
test_inner_for_over_empty_input()486 fn test_inner_for_over_empty_input() {
487     assert_template_result!(
488         "oo",
489         "{% for a in (1..2) %}o{% for b in empty %}{% endfor %}{% endfor %}",
490         o!({}),
491     );
492 }
493 
494 #[test]
495 #[should_panic] // liquid-rust#270
test_blank_string_not_iterable()496 fn test_blank_string_not_iterable() {
497     assert_template_result!(
498         "",
499         "{% for char in characters %}I WILL NOT BE OUTPUT{% endfor %}",
500         o!({"characters": ""}),
501     );
502 }
503 
504 #[test]
test_bad_variable_naming_in_for_loop()505 fn test_bad_variable_naming_in_for_loop() {
506     assert_parse_error!("{% for a/b in x %}{% endfor %}");
507 }
508 
509 #[test]
test_spacing_with_variable_naming_in_for_loop()510 fn test_spacing_with_variable_naming_in_for_loop() {
511     let expected = "12345";
512     let template = "{% for       item   in   items %}{{item}}{% endfor %}";
513     let assigns = o!({ "items": [1, 2, 3, 4, 5] });
514     assert_template_result!(expected, template, assigns);
515 }
516 
517 #[test]
518 #[should_panic]
test_iterate_with_each_when_no_limit_applied()519 fn test_iterate_with_each_when_no_limit_applied() {
520     panic!("Implementation specific: `each` is a ruby thing");
521 }
522 
523 #[test]
524 #[should_panic]
test_iterate_with_load_slice_when_limit_applied()525 fn test_iterate_with_load_slice_when_limit_applied() {
526     panic!("Implementation specific: `each` is a ruby thing");
527 }
528 
529 #[test]
530 #[should_panic]
test_iterate_with_load_slice_when_limit_and_offset_applied()531 fn test_iterate_with_load_slice_when_limit_and_offset_applied() {
532     panic!("Implementation specific: `each` is a ruby thing");
533 }
534 
535 #[test]
536 #[should_panic]
test_iterate_with_load_slice_returns_same_results_as_without()537 fn test_iterate_with_load_slice_returns_same_results_as_without() {
538     panic!("Implementation specific: `each` is a ruby thing");
539 }
540 
541 #[test]
542 #[should_panic]
test_for_cleans_up_registers()543 fn test_for_cleans_up_registers() {
544     panic!("Implementation specific: API detail");
545 }
546