liquid 3.0.6 → 4.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/History.md +154 -58
- data/{MIT-LICENSE → LICENSE} +0 -0
- data/README.md +33 -0
- data/lib/liquid/block.rb +42 -125
- data/lib/liquid/block_body.rb +99 -79
- data/lib/liquid/condition.rb +52 -32
- data/lib/liquid/context.rb +57 -51
- data/lib/liquid/document.rb +19 -9
- data/lib/liquid/drop.rb +17 -16
- data/lib/liquid/errors.rb +20 -24
- data/lib/liquid/expression.rb +26 -10
- data/lib/liquid/extensions.rb +19 -7
- data/lib/liquid/file_system.rb +11 -11
- data/lib/liquid/forloop_drop.rb +42 -0
- data/lib/liquid/i18n.rb +6 -6
- data/lib/liquid/interrupts.rb +1 -2
- data/lib/liquid/lexer.rb +12 -8
- data/lib/liquid/locales/en.yml +6 -2
- data/lib/liquid/parse_context.rb +38 -0
- data/lib/liquid/parse_tree_visitor.rb +42 -0
- data/lib/liquid/parser_switching.rb +4 -4
- data/lib/liquid/profiler/hooks.rb +7 -7
- data/lib/liquid/profiler.rb +18 -19
- data/lib/liquid/range_lookup.rb +16 -1
- data/lib/liquid/resource_limits.rb +23 -0
- data/lib/liquid/standardfilters.rb +207 -61
- data/lib/liquid/strainer.rb +15 -8
- data/lib/liquid/tablerowloop_drop.rb +62 -0
- data/lib/liquid/tag.rb +9 -8
- data/lib/liquid/tags/assign.rb +25 -4
- data/lib/liquid/tags/break.rb +0 -3
- data/lib/liquid/tags/capture.rb +1 -1
- data/lib/liquid/tags/case.rb +27 -12
- data/lib/liquid/tags/comment.rb +2 -2
- data/lib/liquid/tags/cycle.rb +16 -8
- data/lib/liquid/tags/decrement.rb +1 -4
- data/lib/liquid/tags/for.rb +103 -75
- data/lib/liquid/tags/if.rb +60 -44
- data/lib/liquid/tags/ifchanged.rb +0 -2
- data/lib/liquid/tags/include.rb +71 -51
- data/lib/liquid/tags/raw.rb +32 -4
- data/lib/liquid/tags/table_row.rb +21 -31
- data/lib/liquid/tags/unless.rb +3 -4
- data/lib/liquid/template.rb +42 -54
- data/lib/liquid/tokenizer.rb +31 -0
- data/lib/liquid/truffle.rb +5 -0
- data/lib/liquid/utils.rb +52 -8
- data/lib/liquid/variable.rb +59 -46
- data/lib/liquid/variable_lookup.rb +14 -6
- data/lib/liquid/version.rb +2 -1
- data/lib/liquid.rb +10 -7
- data/test/integration/assign_test.rb +8 -8
- data/test/integration/blank_test.rb +14 -14
- data/test/integration/block_test.rb +12 -0
- data/test/integration/context_test.rb +2 -2
- data/test/integration/document_test.rb +19 -0
- data/test/integration/drop_test.rb +42 -40
- data/test/integration/error_handling_test.rb +96 -43
- data/test/integration/filter_test.rb +60 -20
- data/test/integration/hash_ordering_test.rb +9 -9
- data/test/integration/output_test.rb +26 -27
- data/test/integration/parse_tree_visitor_test.rb +247 -0
- data/test/integration/parsing_quirks_test.rb +19 -13
- data/test/integration/render_profiling_test.rb +20 -20
- data/test/integration/security_test.rb +23 -7
- data/test/integration/standard_filter_test.rb +426 -46
- data/test/integration/tags/break_tag_test.rb +1 -2
- data/test/integration/tags/continue_tag_test.rb +0 -1
- data/test/integration/tags/for_tag_test.rb +135 -100
- data/test/integration/tags/if_else_tag_test.rb +75 -77
- data/test/integration/tags/include_tag_test.rb +50 -31
- data/test/integration/tags/increment_tag_test.rb +10 -11
- data/test/integration/tags/raw_tag_test.rb +7 -1
- data/test/integration/tags/standard_tag_test.rb +121 -122
- data/test/integration/tags/statements_test.rb +3 -5
- data/test/integration/tags/table_row_test.rb +20 -19
- data/test/integration/tags/unless_else_tag_test.rb +6 -6
- data/test/integration/template_test.rb +199 -49
- data/test/integration/trim_mode_test.rb +529 -0
- data/test/integration/variable_test.rb +27 -13
- data/test/test_helper.rb +33 -6
- data/test/truffle/truffle_test.rb +9 -0
- data/test/unit/block_unit_test.rb +8 -5
- data/test/unit/condition_unit_test.rb +94 -77
- data/test/unit/context_unit_test.rb +69 -72
- data/test/unit/file_system_unit_test.rb +3 -3
- data/test/unit/i18n_unit_test.rb +2 -2
- data/test/unit/lexer_unit_test.rb +12 -9
- data/test/unit/parser_unit_test.rb +2 -2
- data/test/unit/regexp_unit_test.rb +1 -1
- data/test/unit/strainer_unit_test.rb +96 -1
- data/test/unit/tag_unit_test.rb +7 -2
- data/test/unit/tags/case_tag_unit_test.rb +1 -1
- data/test/unit/tags/for_tag_unit_test.rb +2 -2
- data/test/unit/tags/if_tag_unit_test.rb +1 -1
- data/test/unit/template_unit_test.rb +14 -5
- data/test/unit/tokenizer_unit_test.rb +24 -7
- data/test/unit/variable_unit_test.rb +60 -43
- metadata +62 -50
- data/lib/liquid/module_ex.rb +0 -62
- data/lib/liquid/token.rb +0 -18
- data/test/unit/module_ex_unit_test.rb +0 -87
@@ -14,7 +14,7 @@ module FunnyFilter
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def add_tag(input, tag = "p", id = "foo")
|
17
|
-
|
17
|
+
%(<#{tag} id="#{id}">#{input}</#{tag}>)
|
18
18
|
end
|
19
19
|
|
20
20
|
def paragraph(input)
|
@@ -22,9 +22,8 @@ module FunnyFilter
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def link_to(name, url)
|
25
|
-
|
25
|
+
%(<a href="#{url}">#{name}</a>)
|
26
26
|
end
|
27
|
-
|
28
27
|
end
|
29
28
|
|
30
29
|
class OutputTest < Minitest::Test
|
@@ -33,14 +32,14 @@ class OutputTest < Minitest::Test
|
|
33
32
|
def setup
|
34
33
|
@assigns = {
|
35
34
|
'best_cars' => 'bmw',
|
36
|
-
'car' => {'bmw' => 'good', 'gm' => 'bad'}
|
37
|
-
|
35
|
+
'car' => { 'bmw' => 'good', 'gm' => 'bad' }
|
36
|
+
}
|
38
37
|
end
|
39
38
|
|
40
39
|
def test_variable
|
41
|
-
text =
|
40
|
+
text = %( {{best_cars}} )
|
42
41
|
|
43
|
-
expected =
|
42
|
+
expected = %( bmw )
|
44
43
|
assert_equal expected, Template.parse(text).render!(@assigns)
|
45
44
|
end
|
46
45
|
|
@@ -53,72 +52,72 @@ class OutputTest < Minitest::Test
|
|
53
52
|
end
|
54
53
|
|
55
54
|
def test_variable_traversing
|
56
|
-
text =
|
55
|
+
text = %( {{car.bmw}} {{car.gm}} {{car.bmw}} )
|
57
56
|
|
58
|
-
expected =
|
57
|
+
expected = %( good bad good )
|
59
58
|
assert_equal expected, Template.parse(text).render!(@assigns)
|
60
59
|
end
|
61
60
|
|
62
61
|
def test_variable_piping
|
63
62
|
text = %( {{ car.gm | make_funny }} )
|
64
|
-
expected =
|
63
|
+
expected = %( LOL )
|
65
64
|
|
66
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
65
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
67
66
|
end
|
68
67
|
|
69
68
|
def test_variable_piping_with_input
|
70
69
|
text = %( {{ car.gm | cite_funny }} )
|
71
|
-
expected =
|
70
|
+
expected = %( LOL: bad )
|
72
71
|
|
73
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
72
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
74
73
|
end
|
75
74
|
|
76
75
|
def test_variable_piping_with_args
|
77
76
|
text = %! {{ car.gm | add_smiley : ':-(' }} !
|
78
77
|
expected = %| bad :-( |
|
79
78
|
|
80
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
79
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
81
80
|
end
|
82
81
|
|
83
82
|
def test_variable_piping_with_no_args
|
84
|
-
text =
|
83
|
+
text = %( {{ car.gm | add_smiley }} )
|
85
84
|
expected = %| bad :-) |
|
86
85
|
|
87
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
86
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
88
87
|
end
|
89
88
|
|
90
89
|
def test_multiple_variable_piping_with_args
|
91
90
|
text = %! {{ car.gm | add_smiley : ':-(' | add_smiley : ':-('}} !
|
92
91
|
expected = %| bad :-( :-( |
|
93
92
|
|
94
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
93
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
95
94
|
end
|
96
95
|
|
97
96
|
def test_variable_piping_with_multiple_args
|
98
|
-
text =
|
99
|
-
expected =
|
97
|
+
text = %( {{ car.gm | add_tag : 'span', 'bar'}} )
|
98
|
+
expected = %( <span id="bar">bad</span> )
|
100
99
|
|
101
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
100
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
102
101
|
end
|
103
102
|
|
104
103
|
def test_variable_piping_with_variable_args
|
105
|
-
text =
|
106
|
-
expected =
|
104
|
+
text = %( {{ car.gm | add_tag : 'span', car.bmw}} )
|
105
|
+
expected = %( <span id="good">bad</span> )
|
107
106
|
|
108
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
107
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
109
108
|
end
|
110
109
|
|
111
110
|
def test_multiple_pipings
|
112
111
|
text = %( {{ best_cars | cite_funny | paragraph }} )
|
113
|
-
expected =
|
112
|
+
expected = %( <p>LOL: bmw</p> )
|
114
113
|
|
115
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
114
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
116
115
|
end
|
117
116
|
|
118
117
|
def test_link_to
|
119
118
|
text = %( {{ 'Typo' | link_to: 'http://typo.leetsoft.com' }} )
|
120
|
-
expected =
|
119
|
+
expected = %( <a href="http://typo.leetsoft.com">Typo</a> )
|
121
120
|
|
122
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
121
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter])
|
123
122
|
end
|
124
123
|
end # OutputTest
|
@@ -0,0 +1,247 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class ParseTreeVisitorTest < Minitest::Test
|
6
|
+
include Liquid
|
7
|
+
|
8
|
+
def test_variable
|
9
|
+
assert_equal(
|
10
|
+
["test"],
|
11
|
+
visit(%({{ test }}))
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_varible_with_filter
|
16
|
+
assert_equal(
|
17
|
+
["test", "infilter"],
|
18
|
+
visit(%({{ test | split: infilter }}))
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_dynamic_variable
|
23
|
+
assert_equal(
|
24
|
+
["test", "inlookup"],
|
25
|
+
visit(%({{ test[inlookup] }}))
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_if_condition
|
30
|
+
assert_equal(
|
31
|
+
["test"],
|
32
|
+
visit(%({% if test %}{% endif %}))
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_complex_if_condition
|
37
|
+
assert_equal(
|
38
|
+
["test"],
|
39
|
+
visit(%({% if 1 == 1 and 2 == test %}{% endif %}))
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_if_body
|
44
|
+
assert_equal(
|
45
|
+
["test"],
|
46
|
+
visit(%({% if 1 == 1 %}{{ test }}{% endif %}))
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_unless_condition
|
51
|
+
assert_equal(
|
52
|
+
["test"],
|
53
|
+
visit(%({% unless test %}{% endunless %}))
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_complex_unless_condition
|
58
|
+
assert_equal(
|
59
|
+
["test"],
|
60
|
+
visit(%({% unless 1 == 1 and 2 == test %}{% endunless %}))
|
61
|
+
)
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_unless_body
|
65
|
+
assert_equal(
|
66
|
+
["test"],
|
67
|
+
visit(%({% unless 1 == 1 %}{{ test }}{% endunless %}))
|
68
|
+
)
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_elsif_condition
|
72
|
+
assert_equal(
|
73
|
+
["test"],
|
74
|
+
visit(%({% if 1 == 1 %}{% elsif test %}{% endif %}))
|
75
|
+
)
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_complex_elsif_condition
|
79
|
+
assert_equal(
|
80
|
+
["test"],
|
81
|
+
visit(%({% if 1 == 1 %}{% elsif 1 == 1 and 2 == test %}{% endif %}))
|
82
|
+
)
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_elsif_body
|
86
|
+
assert_equal(
|
87
|
+
["test"],
|
88
|
+
visit(%({% if 1 == 1 %}{% elsif 2 == 2 %}{{ test }}{% endif %}))
|
89
|
+
)
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_else_body
|
93
|
+
assert_equal(
|
94
|
+
["test"],
|
95
|
+
visit(%({% if 1 == 1 %}{% else %}{{ test }}{% endif %}))
|
96
|
+
)
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_case_left
|
100
|
+
assert_equal(
|
101
|
+
["test"],
|
102
|
+
visit(%({% case test %}{% endcase %}))
|
103
|
+
)
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_case_condition
|
107
|
+
assert_equal(
|
108
|
+
["test"],
|
109
|
+
visit(%({% case 1 %}{% when test %}{% endcase %}))
|
110
|
+
)
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_case_when_body
|
114
|
+
assert_equal(
|
115
|
+
["test"],
|
116
|
+
visit(%({% case 1 %}{% when 2 %}{{ test }}{% endcase %}))
|
117
|
+
)
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_case_else_body
|
121
|
+
assert_equal(
|
122
|
+
["test"],
|
123
|
+
visit(%({% case 1 %}{% else %}{{ test }}{% endcase %}))
|
124
|
+
)
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_for_in
|
128
|
+
assert_equal(
|
129
|
+
["test"],
|
130
|
+
visit(%({% for x in test %}{% endfor %}))
|
131
|
+
)
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_for_limit
|
135
|
+
assert_equal(
|
136
|
+
["test"],
|
137
|
+
visit(%({% for x in (1..5) limit: test %}{% endfor %}))
|
138
|
+
)
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_for_offset
|
142
|
+
assert_equal(
|
143
|
+
["test"],
|
144
|
+
visit(%({% for x in (1..5) offset: test %}{% endfor %}))
|
145
|
+
)
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_for_body
|
149
|
+
assert_equal(
|
150
|
+
["test"],
|
151
|
+
visit(%({% for x in (1..5) %}{{ test }}{% endfor %}))
|
152
|
+
)
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_tablerow_in
|
156
|
+
assert_equal(
|
157
|
+
["test"],
|
158
|
+
visit(%({% tablerow x in test %}{% endtablerow %}))
|
159
|
+
)
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_tablerow_limit
|
163
|
+
assert_equal(
|
164
|
+
["test"],
|
165
|
+
visit(%({% tablerow x in (1..5) limit: test %}{% endtablerow %}))
|
166
|
+
)
|
167
|
+
end
|
168
|
+
|
169
|
+
def test_tablerow_offset
|
170
|
+
assert_equal(
|
171
|
+
["test"],
|
172
|
+
visit(%({% tablerow x in (1..5) offset: test %}{% endtablerow %}))
|
173
|
+
)
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_tablerow_body
|
177
|
+
assert_equal(
|
178
|
+
["test"],
|
179
|
+
visit(%({% tablerow x in (1..5) %}{{ test }}{% endtablerow %}))
|
180
|
+
)
|
181
|
+
end
|
182
|
+
|
183
|
+
def test_cycle
|
184
|
+
assert_equal(
|
185
|
+
["test"],
|
186
|
+
visit(%({% cycle test %}))
|
187
|
+
)
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_assign
|
191
|
+
assert_equal(
|
192
|
+
["test"],
|
193
|
+
visit(%({% assign x = test %}))
|
194
|
+
)
|
195
|
+
end
|
196
|
+
|
197
|
+
def test_capture
|
198
|
+
assert_equal(
|
199
|
+
["test"],
|
200
|
+
visit(%({% capture x %}{{ test }}{% endcapture %}))
|
201
|
+
)
|
202
|
+
end
|
203
|
+
|
204
|
+
def test_include
|
205
|
+
assert_equal(
|
206
|
+
["test"],
|
207
|
+
visit(%({% include test %}))
|
208
|
+
)
|
209
|
+
end
|
210
|
+
|
211
|
+
def test_include_with
|
212
|
+
assert_equal(
|
213
|
+
["test"],
|
214
|
+
visit(%({% include "hai" with test %}))
|
215
|
+
)
|
216
|
+
end
|
217
|
+
|
218
|
+
def test_include_for
|
219
|
+
assert_equal(
|
220
|
+
["test"],
|
221
|
+
visit(%({% include "hai" for test %}))
|
222
|
+
)
|
223
|
+
end
|
224
|
+
|
225
|
+
def test_preserve_tree_structure
|
226
|
+
assert_equal(
|
227
|
+
[[nil, [
|
228
|
+
[nil, [[nil, [["other", []]]]]],
|
229
|
+
["test", []],
|
230
|
+
["xs", []]
|
231
|
+
]]],
|
232
|
+
traversal(%({% for x in xs offset: test %}{{ other }}{% endfor %})).visit
|
233
|
+
)
|
234
|
+
end
|
235
|
+
|
236
|
+
private
|
237
|
+
|
238
|
+
def traversal(template)
|
239
|
+
ParseTreeVisitor
|
240
|
+
.for(Template.parse(template).root)
|
241
|
+
.add_callback_for(VariableLookup, &:name)
|
242
|
+
end
|
243
|
+
|
244
|
+
def visit(template)
|
245
|
+
traversal(template).visit.flatten.compact
|
246
|
+
end
|
247
|
+
end
|
@@ -28,11 +28,14 @@ class ParsingQuirksTest < Minitest::Test
|
|
28
28
|
|
29
29
|
def test_error_on_empty_filter
|
30
30
|
assert Template.parse("{{test}}")
|
31
|
-
|
31
|
+
|
32
|
+
with_error_mode(:lax) do
|
33
|
+
assert Template.parse("{{|test}}")
|
34
|
+
end
|
35
|
+
|
32
36
|
with_error_mode(:strict) do
|
33
|
-
assert_raises(SyntaxError)
|
34
|
-
|
35
|
-
end
|
37
|
+
assert_raises(SyntaxError) { Template.parse("{{|test}}") }
|
38
|
+
assert_raises(SyntaxError) { Template.parse("{{test |a|b|}}") }
|
36
39
|
end
|
37
40
|
end
|
38
41
|
|
@@ -59,25 +62,25 @@ class ParsingQuirksTest < Minitest::Test
|
|
59
62
|
end
|
60
63
|
|
61
64
|
def test_no_error_on_lax_empty_filter
|
62
|
-
assert Template.parse("{{test |a|b|}}", :
|
63
|
-
assert Template.parse("{{test}}", :
|
64
|
-
assert Template.parse("{{|test|}}", :
|
65
|
+
assert Template.parse("{{test |a|b|}}", error_mode: :lax)
|
66
|
+
assert Template.parse("{{test}}", error_mode: :lax)
|
67
|
+
assert Template.parse("{{|test|}}", error_mode: :lax)
|
65
68
|
end
|
66
69
|
|
67
70
|
def test_meaningless_parens_lax
|
68
71
|
with_error_mode(:lax) do
|
69
|
-
assigns = {'b' => 'bar', 'c' => 'baz'}
|
72
|
+
assigns = { 'b' => 'bar', 'c' => 'baz' }
|
70
73
|
markup = "a == 'foo' or (b == 'bar' and c == 'baz') or false"
|
71
|
-
assert_template_result(' YES ',"{% if #{markup} %} YES {% endif %}", assigns)
|
74
|
+
assert_template_result(' YES ', "{% if #{markup} %} YES {% endif %}", assigns)
|
72
75
|
end
|
73
76
|
end
|
74
77
|
|
75
78
|
def test_unexpected_characters_silently_eat_logic_lax
|
76
79
|
with_error_mode(:lax) do
|
77
80
|
markup = "true && false"
|
78
|
-
assert_template_result(' YES ',"{% if #{markup} %} YES {% endif %}")
|
81
|
+
assert_template_result(' YES ', "{% if #{markup} %} YES {% endif %}")
|
79
82
|
markup = "false || true"
|
80
|
-
assert_template_result('',"{% if #{markup} %} YES {% endif %}")
|
83
|
+
assert_template_result('', "{% if #{markup} %} YES {% endif %}")
|
81
84
|
end
|
82
85
|
end
|
83
86
|
|
@@ -89,14 +92,14 @@ class ParsingQuirksTest < Minitest::Test
|
|
89
92
|
|
90
93
|
def test_unanchored_filter_arguments
|
91
94
|
with_error_mode(:lax) do
|
92
|
-
assert_template_result('hi',"{{ 'hi there' | split$$$:' ' | first }}")
|
95
|
+
assert_template_result('hi', "{{ 'hi there' | split$$$:' ' | first }}")
|
93
96
|
|
94
97
|
assert_template_result('x', "{{ 'X' | downcase) }}")
|
95
98
|
|
96
99
|
# After the messed up quotes a filter without parameters (reverse) should work
|
97
100
|
# but one with parameters (remove) shouldn't be detected.
|
98
101
|
assert_template_result('here', "{{ 'hi there' | split:\"t\"\" | reverse | first}}")
|
99
|
-
assert_template_result('hi ',
|
102
|
+
assert_template_result('hi ', "{{ 'hi there' | split:\"t\"\" | remove:\"i\" | first}}")
|
100
103
|
end
|
101
104
|
end
|
102
105
|
|
@@ -113,4 +116,7 @@ class ParsingQuirksTest < Minitest::Test
|
|
113
116
|
end
|
114
117
|
end
|
115
118
|
|
119
|
+
def test_contains_in_id
|
120
|
+
assert_template_result(' YES ', '{% if containsallshipments == true %} YES {% endif %}', 'containsallshipments' => true)
|
121
|
+
end
|
116
122
|
end # ParsingQuirksTest
|
@@ -4,7 +4,7 @@ class RenderProfilingTest < Minitest::Test
|
|
4
4
|
include Liquid
|
5
5
|
|
6
6
|
class ProfilingFileSystem
|
7
|
-
def read_template_file(template_path
|
7
|
+
def read_template_file(template_path)
|
8
8
|
"Rendering template {% assign template_name = '#{template_path}'%}\n{{ template_name }}"
|
9
9
|
end
|
10
10
|
end
|
@@ -21,7 +21,7 @@ class RenderProfilingTest < Minitest::Test
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def test_parse_makes_available_simple_profiling
|
24
|
-
t = Template.parse("{{ 'a string' | upcase }}", :
|
24
|
+
t = Template.parse("{{ 'a string' | upcase }}", profile: true)
|
25
25
|
t.render!
|
26
26
|
|
27
27
|
assert_equal 1, t.profiler.length
|
@@ -31,14 +31,14 @@ class RenderProfilingTest < Minitest::Test
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def test_render_ignores_raw_strings_when_profiling
|
34
|
-
t = Template.parse("This is raw string\nstuff\nNewline", :
|
34
|
+
t = Template.parse("This is raw string\nstuff\nNewline", profile: true)
|
35
35
|
t.render!
|
36
36
|
|
37
37
|
assert_equal 0, t.profiler.length
|
38
38
|
end
|
39
39
|
|
40
40
|
def test_profiling_includes_line_numbers_of_liquid_nodes
|
41
|
-
t = Template.parse("{{ 'a string' | upcase }}\n{% increment test %}", :
|
41
|
+
t = Template.parse("{{ 'a string' | upcase }}\n{% increment test %}", profile: true)
|
42
42
|
t.render!
|
43
43
|
assert_equal 2, t.profiler.length
|
44
44
|
|
@@ -49,7 +49,7 @@ class RenderProfilingTest < Minitest::Test
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def test_profiling_includes_line_numbers_of_included_partials
|
52
|
-
t = Template.parse("{% include 'a_template' %}", :
|
52
|
+
t = Template.parse("{% include 'a_template' %}", profile: true)
|
53
53
|
t.render!
|
54
54
|
|
55
55
|
included_children = t.profiler[0].children
|
@@ -61,7 +61,7 @@ class RenderProfilingTest < Minitest::Test
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def test_profiling_times_the_rendering_of_tokens
|
64
|
-
t = Template.parse("{% include 'a_template' %}", :
|
64
|
+
t = Template.parse("{% include 'a_template' %}", profile: true)
|
65
65
|
t.render!
|
66
66
|
|
67
67
|
node = t.profiler[0]
|
@@ -69,14 +69,14 @@ class RenderProfilingTest < Minitest::Test
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def test_profiling_times_the_entire_render
|
72
|
-
t = Template.parse("{% include 'a_template' %}", :
|
72
|
+
t = Template.parse("{% include 'a_template' %}", profile: true)
|
73
73
|
t.render!
|
74
74
|
|
75
75
|
assert t.profiler.total_render_time >= 0, "Total render time was not calculated"
|
76
76
|
end
|
77
77
|
|
78
78
|
def test_profiling_uses_include_to_mark_children
|
79
|
-
t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}", :
|
79
|
+
t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}", profile: true)
|
80
80
|
t.render!
|
81
81
|
|
82
82
|
include_node = t.profiler[1]
|
@@ -84,47 +84,47 @@ class RenderProfilingTest < Minitest::Test
|
|
84
84
|
end
|
85
85
|
|
86
86
|
def test_profiling_marks_children_with_the_name_of_included_partial
|
87
|
-
t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}", :
|
87
|
+
t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}", profile: true)
|
88
88
|
t.render!
|
89
89
|
|
90
90
|
include_node = t.profiler[1]
|
91
91
|
include_node.children.each do |child|
|
92
|
-
assert_equal "
|
92
|
+
assert_equal "a_template", child.partial
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
96
|
def test_profiling_supports_multiple_templates
|
97
|
-
t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}\n{% include 'b_template' %}", :
|
97
|
+
t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}\n{% include 'b_template' %}", profile: true)
|
98
98
|
t.render!
|
99
99
|
|
100
100
|
a_template = t.profiler[1]
|
101
101
|
a_template.children.each do |child|
|
102
|
-
assert_equal "
|
102
|
+
assert_equal "a_template", child.partial
|
103
103
|
end
|
104
104
|
|
105
105
|
b_template = t.profiler[2]
|
106
106
|
b_template.children.each do |child|
|
107
|
-
assert_equal "
|
107
|
+
assert_equal "b_template", child.partial
|
108
108
|
end
|
109
109
|
end
|
110
110
|
|
111
111
|
def test_profiling_supports_rendering_the_same_partial_multiple_times
|
112
|
-
t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}\n{% include 'a_template' %}", :
|
112
|
+
t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}\n{% include 'a_template' %}", profile: true)
|
113
113
|
t.render!
|
114
114
|
|
115
115
|
a_template1 = t.profiler[1]
|
116
116
|
a_template1.children.each do |child|
|
117
|
-
assert_equal "
|
117
|
+
assert_equal "a_template", child.partial
|
118
118
|
end
|
119
119
|
|
120
120
|
a_template2 = t.profiler[2]
|
121
121
|
a_template2.children.each do |child|
|
122
|
-
assert_equal "
|
122
|
+
assert_equal "a_template", child.partial
|
123
123
|
end
|
124
124
|
end
|
125
125
|
|
126
126
|
def test_can_iterate_over_each_profiling_entry
|
127
|
-
t = Template.parse("{{ 'a string' | upcase }}\n{% increment test %}", :
|
127
|
+
t = Template.parse("{{ 'a string' | upcase }}\n{% increment test %}", profile: true)
|
128
128
|
t.render!
|
129
129
|
|
130
130
|
timing_count = 0
|
@@ -136,7 +136,7 @@ class RenderProfilingTest < Minitest::Test
|
|
136
136
|
end
|
137
137
|
|
138
138
|
def test_profiling_marks_children_of_if_blocks
|
139
|
-
t = Template.parse("{% if true %} {% increment test %} {{ test }} {% endif %}", :
|
139
|
+
t = Template.parse("{% if true %} {% increment test %} {{ test }} {% endif %}", profile: true)
|
140
140
|
t.render!
|
141
141
|
|
142
142
|
assert_equal 1, t.profiler.length
|
@@ -144,8 +144,8 @@ class RenderProfilingTest < Minitest::Test
|
|
144
144
|
end
|
145
145
|
|
146
146
|
def test_profiling_marks_children_of_for_blocks
|
147
|
-
t = Template.parse("{% for item in collection %} {{ item }} {% endfor %}", :
|
148
|
-
t.render!({"collection" => ["one", "two"]})
|
147
|
+
t = Template.parse("{% for item in collection %} {{ item }} {% endfor %}", profile: true)
|
148
|
+
t.render!({ "collection" => ["one", "two"] })
|
149
149
|
|
150
150
|
assert_equal 1, t.profiler.length
|
151
151
|
# Will profile each invocation of the for block
|
@@ -9,34 +9,36 @@ end
|
|
9
9
|
class SecurityTest < Minitest::Test
|
10
10
|
include Liquid
|
11
11
|
|
12
|
+
def setup
|
13
|
+
@assigns = {}
|
14
|
+
end
|
15
|
+
|
12
16
|
def test_no_instance_eval
|
13
17
|
text = %( {{ '1+1' | instance_eval }} )
|
14
|
-
expected =
|
18
|
+
expected = %( 1+1 )
|
15
19
|
|
16
20
|
assert_equal expected, Template.parse(text).render!(@assigns)
|
17
21
|
end
|
18
22
|
|
19
23
|
def test_no_existing_instance_eval
|
20
24
|
text = %( {{ '1+1' | __instance_eval__ }} )
|
21
|
-
expected =
|
25
|
+
expected = %( 1+1 )
|
22
26
|
|
23
27
|
assert_equal expected, Template.parse(text).render!(@assigns)
|
24
28
|
end
|
25
29
|
|
26
|
-
|
27
30
|
def test_no_instance_eval_after_mixing_in_new_filter
|
28
31
|
text = %( {{ '1+1' | instance_eval }} )
|
29
|
-
expected =
|
32
|
+
expected = %( 1+1 )
|
30
33
|
|
31
34
|
assert_equal expected, Template.parse(text).render!(@assigns)
|
32
35
|
end
|
33
36
|
|
34
|
-
|
35
37
|
def test_no_instance_eval_later_in_chain
|
36
38
|
text = %( {{ '1+1' | add_one | instance_eval }} )
|
37
|
-
expected =
|
39
|
+
expected = %( 1+1 + 1 )
|
38
40
|
|
39
|
-
assert_equal expected, Template.parse(text).render!(@assigns, :
|
41
|
+
assert_equal expected, Template.parse(text).render!(@assigns, filters: SecurityFilter)
|
40
42
|
end
|
41
43
|
|
42
44
|
def test_does_not_add_filters_to_symbol_table
|
@@ -61,4 +63,18 @@ class SecurityTest < Minitest::Test
|
|
61
63
|
|
62
64
|
assert_equal [], (Symbol.all_symbols - current_symbols)
|
63
65
|
end
|
66
|
+
|
67
|
+
def test_max_depth_nested_blocks_does_not_raise_exception
|
68
|
+
depth = Liquid::Block::MAX_DEPTH
|
69
|
+
code = "{% if true %}" * depth + "rendered" + "{% endif %}" * depth
|
70
|
+
assert_equal "rendered", Template.parse(code).render!
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_more_than_max_depth_nested_blocks_raises_exception
|
74
|
+
depth = Liquid::Block::MAX_DEPTH + 1
|
75
|
+
code = "{% if true %}" * depth + "rendered" + "{% endif %}" * depth
|
76
|
+
assert_raises(Liquid::StackLevelError) do
|
77
|
+
Template.parse(code).render!
|
78
|
+
end
|
79
|
+
end
|
64
80
|
end # SecurityTest
|