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