liquid 4.0.0 → 5.0.1
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 +101 -2
- data/README.md +8 -0
- data/lib/liquid.rb +18 -5
- data/lib/liquid/block.rb +47 -20
- data/lib/liquid/block_body.rb +192 -76
- data/lib/liquid/condition.rb +69 -29
- data/lib/liquid/context.rb +110 -53
- data/lib/liquid/document.rb +47 -9
- data/lib/liquid/drop.rb +4 -2
- data/lib/liquid/errors.rb +20 -18
- data/lib/liquid/expression.rb +30 -31
- data/lib/liquid/extensions.rb +8 -0
- data/lib/liquid/file_system.rb +6 -4
- data/lib/liquid/forloop_drop.rb +11 -4
- data/lib/liquid/i18n.rb +5 -3
- data/lib/liquid/interrupts.rb +3 -1
- data/lib/liquid/lexer.rb +35 -26
- data/lib/liquid/locales/en.yml +4 -2
- data/lib/liquid/parse_context.rb +21 -4
- data/lib/liquid/parse_tree_visitor.rb +42 -0
- data/lib/liquid/parser.rb +30 -18
- data/lib/liquid/parser_switching.rb +17 -3
- data/lib/liquid/partial_cache.rb +24 -0
- data/lib/liquid/profiler.rb +67 -86
- data/lib/liquid/profiler/hooks.rb +26 -14
- data/lib/liquid/range_lookup.rb +5 -3
- data/lib/liquid/register.rb +6 -0
- data/lib/liquid/resource_limits.rb +47 -8
- data/lib/liquid/standardfilters.rb +170 -63
- data/lib/liquid/static_registers.rb +44 -0
- data/lib/liquid/strainer_factory.rb +36 -0
- data/lib/liquid/strainer_template.rb +53 -0
- data/lib/liquid/tablerowloop_drop.rb +6 -4
- data/lib/liquid/tag.rb +28 -6
- data/lib/liquid/tag/disableable.rb +22 -0
- data/lib/liquid/tag/disabler.rb +21 -0
- data/lib/liquid/tags/assign.rb +32 -10
- data/lib/liquid/tags/break.rb +8 -3
- data/lib/liquid/tags/capture.rb +11 -8
- data/lib/liquid/tags/case.rb +41 -27
- data/lib/liquid/tags/comment.rb +5 -3
- data/lib/liquid/tags/continue.rb +8 -3
- data/lib/liquid/tags/cycle.rb +35 -16
- data/lib/liquid/tags/decrement.rb +6 -3
- data/lib/liquid/tags/echo.rb +34 -0
- data/lib/liquid/tags/for.rb +79 -47
- data/lib/liquid/tags/if.rb +53 -30
- data/lib/liquid/tags/ifchanged.rb +11 -10
- data/lib/liquid/tags/include.rb +42 -44
- data/lib/liquid/tags/increment.rb +7 -3
- data/lib/liquid/tags/raw.rb +14 -11
- data/lib/liquid/tags/render.rb +84 -0
- data/lib/liquid/tags/table_row.rb +32 -20
- data/lib/liquid/tags/unless.rb +15 -15
- data/lib/liquid/template.rb +53 -72
- data/lib/liquid/template_factory.rb +9 -0
- data/lib/liquid/tokenizer.rb +17 -9
- data/lib/liquid/usage.rb +8 -0
- data/lib/liquid/utils.rb +6 -4
- data/lib/liquid/variable.rb +55 -38
- data/lib/liquid/variable_lookup.rb +14 -6
- data/lib/liquid/version.rb +3 -1
- data/test/integration/assign_test.rb +74 -5
- data/test/integration/blank_test.rb +11 -8
- data/test/integration/block_test.rb +58 -0
- data/test/integration/capture_test.rb +18 -10
- data/test/integration/context_test.rb +609 -5
- data/test/integration/document_test.rb +4 -2
- data/test/integration/drop_test.rb +67 -83
- data/test/integration/error_handling_test.rb +73 -61
- data/test/integration/expression_test.rb +46 -0
- data/test/integration/filter_test.rb +53 -42
- data/test/integration/hash_ordering_test.rb +5 -3
- data/test/integration/output_test.rb +26 -24
- data/test/integration/parsing_quirks_test.rb +24 -8
- data/test/integration/{render_profiling_test.rb → profiler_test.rb} +84 -25
- data/test/integration/security_test.rb +41 -18
- data/test/integration/standard_filter_test.rb +513 -210
- data/test/integration/tag/disableable_test.rb +59 -0
- data/test/integration/tag_test.rb +45 -0
- data/test/integration/tags/break_tag_test.rb +4 -2
- data/test/integration/tags/continue_tag_test.rb +4 -2
- data/test/integration/tags/echo_test.rb +13 -0
- data/test/integration/tags/for_tag_test.rb +109 -53
- data/test/integration/tags/if_else_tag_test.rb +5 -3
- data/test/integration/tags/include_tag_test.rb +83 -52
- data/test/integration/tags/increment_tag_test.rb +4 -2
- data/test/integration/tags/liquid_tag_test.rb +116 -0
- data/test/integration/tags/raw_tag_test.rb +14 -11
- data/test/integration/tags/render_tag_test.rb +213 -0
- data/test/integration/tags/standard_tag_test.rb +38 -31
- data/test/integration/tags/statements_test.rb +23 -21
- data/test/integration/tags/table_row_test.rb +2 -0
- data/test/integration/tags/unless_else_tag_test.rb +4 -2
- data/test/integration/template_test.rb +123 -120
- data/test/integration/trim_mode_test.rb +82 -44
- data/test/integration/variable_test.rb +46 -31
- data/test/test_helper.rb +75 -23
- data/test/unit/block_unit_test.rb +19 -24
- data/test/unit/condition_unit_test.rb +82 -72
- data/test/unit/file_system_unit_test.rb +6 -4
- data/test/unit/i18n_unit_test.rb +7 -5
- data/test/unit/lexer_unit_test.rb +12 -10
- data/test/unit/parse_tree_visitor_test.rb +254 -0
- data/test/unit/parser_unit_test.rb +37 -35
- data/test/unit/partial_cache_unit_test.rb +128 -0
- data/test/unit/regexp_unit_test.rb +17 -15
- data/test/unit/static_registers_unit_test.rb +156 -0
- data/test/unit/strainer_factory_unit_test.rb +100 -0
- data/test/unit/strainer_template_unit_test.rb +82 -0
- data/test/unit/tag_unit_test.rb +5 -3
- data/test/unit/tags/case_tag_unit_test.rb +3 -1
- data/test/unit/tags/for_tag_unit_test.rb +4 -2
- data/test/unit/tags/if_tag_unit_test.rb +3 -1
- data/test/unit/template_factory_unit_test.rb +12 -0
- data/test/unit/template_unit_test.rb +19 -10
- data/test/unit/tokenizer_unit_test.rb +26 -19
- data/test/unit/variable_unit_test.rb +51 -49
- metadata +79 -46
- data/lib/liquid/strainer.rb +0 -66
- data/test/unit/context_unit_test.rb +0 -483
- data/test/unit/strainer_unit_test.rb +0 -148
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
|
3
5
|
class UnlessElseTagTest < Minitest::Test
|
@@ -17,10 +19,10 @@ class UnlessElseTagTest < Minitest::Test
|
|
17
19
|
end
|
18
20
|
|
19
21
|
def test_unless_in_loop
|
20
|
-
assert_template_result
|
22
|
+
assert_template_result('23', '{% for i in choices %}{% unless i %}{{ forloop.index }}{% endunless %}{% endfor %}', 'choices' => [1, nil, false])
|
21
23
|
end
|
22
24
|
|
23
25
|
def test_unless_else_in_loop
|
24
|
-
assert_template_result
|
26
|
+
assert_template_result(' TRUE 2 3 ', '{% for i in choices %}{% unless i %} {{ forloop.index }} {% else %} TRUE {% endunless %}{% endfor %}', 'choices' => [1, nil, false])
|
25
27
|
end
|
26
28
|
end # UnlessElseTest
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
require 'timeout'
|
3
5
|
|
@@ -38,8 +40,8 @@ class TemplateTest < Minitest::Test
|
|
38
40
|
|
39
41
|
def test_instance_assigns_persist_on_same_template_object_between_parses
|
40
42
|
t = Template.new
|
41
|
-
assert_equal
|
42
|
-
assert_equal
|
43
|
+
assert_equal('from instance assigns', t.parse("{% assign foo = 'from instance assigns' %}{{ foo }}").render!)
|
44
|
+
assert_equal('from instance assigns', t.parse("{{ foo }}").render!)
|
43
45
|
end
|
44
46
|
|
45
47
|
def test_warnings_is_not_exponential_time
|
@@ -49,242 +51,243 @@ class TemplateTest < Minitest::Test
|
|
49
51
|
end
|
50
52
|
|
51
53
|
t = Template.parse(str)
|
52
|
-
assert_equal
|
54
|
+
assert_equal([], Timeout.timeout(1) { t.warnings })
|
53
55
|
end
|
54
56
|
|
55
57
|
def test_instance_assigns_persist_on_same_template_parsing_between_renders
|
56
58
|
t = Template.new.parse("{{ foo }}{% assign foo = 'foo' %}{{ foo }}")
|
57
|
-
assert_equal
|
58
|
-
assert_equal
|
59
|
+
assert_equal('foo', t.render!)
|
60
|
+
assert_equal('foofoo', t.render!)
|
59
61
|
end
|
60
62
|
|
61
63
|
def test_custom_assigns_do_not_persist_on_same_template
|
62
64
|
t = Template.new
|
63
|
-
assert_equal
|
64
|
-
assert_equal
|
65
|
+
assert_equal('from custom assigns', t.parse("{{ foo }}").render!('foo' => 'from custom assigns'))
|
66
|
+
assert_equal('', t.parse("{{ foo }}").render!)
|
65
67
|
end
|
66
68
|
|
67
69
|
def test_custom_assigns_squash_instance_assigns
|
68
70
|
t = Template.new
|
69
|
-
assert_equal
|
70
|
-
assert_equal
|
71
|
+
assert_equal('from instance assigns', t.parse("{% assign foo = 'from instance assigns' %}{{ foo }}").render!)
|
72
|
+
assert_equal('from custom assigns', t.parse("{{ foo }}").render!('foo' => 'from custom assigns'))
|
71
73
|
end
|
72
74
|
|
73
75
|
def test_persistent_assigns_squash_instance_assigns
|
74
76
|
t = Template.new
|
75
|
-
assert_equal
|
77
|
+
assert_equal('from instance assigns', t.parse("{% assign foo = 'from instance assigns' %}{{ foo }}").render!)
|
76
78
|
t.assigns['foo'] = 'from persistent assigns'
|
77
|
-
assert_equal
|
79
|
+
assert_equal('from persistent assigns', t.parse("{{ foo }}").render!)
|
78
80
|
end
|
79
81
|
|
80
82
|
def test_lambda_is_called_once_from_persistent_assigns_over_multiple_parses_and_renders
|
81
83
|
t = Template.new
|
82
|
-
t.assigns['number'] = -> {
|
83
|
-
|
84
|
-
|
85
|
-
|
84
|
+
t.assigns['number'] = -> {
|
85
|
+
@global ||= 0
|
86
|
+
@global += 1
|
87
|
+
}
|
88
|
+
assert_equal('1', t.parse("{{number}}").render!)
|
89
|
+
assert_equal('1', t.parse("{{number}}").render!)
|
90
|
+
assert_equal('1', t.render!)
|
86
91
|
@global = nil
|
87
92
|
end
|
88
93
|
|
89
94
|
def test_lambda_is_called_once_from_custom_assigns_over_multiple_parses_and_renders
|
90
95
|
t = Template.new
|
91
|
-
assigns = { 'number' => -> {
|
92
|
-
|
93
|
-
|
94
|
-
|
96
|
+
assigns = { 'number' => -> {
|
97
|
+
@global ||= 0
|
98
|
+
@global += 1
|
99
|
+
} }
|
100
|
+
assert_equal('1', t.parse("{{number}}").render!(assigns))
|
101
|
+
assert_equal('1', t.parse("{{number}}").render!(assigns))
|
102
|
+
assert_equal('1', t.render!(assigns))
|
95
103
|
@global = nil
|
96
104
|
end
|
97
105
|
|
98
106
|
def test_resource_limits_works_with_custom_length_method
|
99
107
|
t = Template.parse("{% assign foo = bar %}")
|
100
108
|
t.resource_limits.render_length_limit = 42
|
101
|
-
assert_equal
|
109
|
+
assert_equal("", t.render!("bar" => SomethingWithLength.new))
|
102
110
|
end
|
103
111
|
|
104
112
|
def test_resource_limits_render_length
|
105
113
|
t = Template.parse("0123456789")
|
106
|
-
t.resource_limits.render_length_limit =
|
107
|
-
assert_equal
|
108
|
-
assert
|
114
|
+
t.resource_limits.render_length_limit = 9
|
115
|
+
assert_equal("Liquid error: Memory limits exceeded", t.render)
|
116
|
+
assert(t.resource_limits.reached?)
|
109
117
|
|
110
118
|
t.resource_limits.render_length_limit = 10
|
111
|
-
assert_equal
|
112
|
-
refute_nil t.resource_limits.render_length
|
119
|
+
assert_equal("0123456789", t.render!)
|
113
120
|
end
|
114
121
|
|
115
122
|
def test_resource_limits_render_score
|
116
123
|
t = Template.parse("{% for a in (1..10) %} {% for a in (1..10) %} foo {% endfor %} {% endfor %}")
|
117
124
|
t.resource_limits.render_score_limit = 50
|
118
|
-
assert_equal
|
119
|
-
assert
|
125
|
+
assert_equal("Liquid error: Memory limits exceeded", t.render)
|
126
|
+
assert(t.resource_limits.reached?)
|
120
127
|
|
121
128
|
t = Template.parse("{% for a in (1..100) %} foo {% endfor %}")
|
122
129
|
t.resource_limits.render_score_limit = 50
|
123
|
-
assert_equal
|
124
|
-
assert
|
130
|
+
assert_equal("Liquid error: Memory limits exceeded", t.render)
|
131
|
+
assert(t.resource_limits.reached?)
|
125
132
|
|
126
133
|
t.resource_limits.render_score_limit = 200
|
127
|
-
assert_equal
|
128
|
-
refute_nil
|
129
|
-
end
|
130
|
-
|
131
|
-
def test_resource_limits_assign_score
|
132
|
-
t = Template.parse("{% assign foo = 42 %}{% assign bar = 23 %}")
|
133
|
-
t.resource_limits.assign_score_limit = 1
|
134
|
-
assert_equal "Liquid error: Memory limits exceeded", t.render
|
135
|
-
assert t.resource_limits.reached?
|
136
|
-
|
137
|
-
t.resource_limits.assign_score_limit = 2
|
138
|
-
assert_equal "", t.render!
|
139
|
-
refute_nil t.resource_limits.assign_score
|
140
|
-
end
|
141
|
-
|
142
|
-
def test_resource_limits_assign_score_nested
|
143
|
-
t = Template.parse("{% assign foo = 'aaaa' | reverse %}")
|
144
|
-
|
145
|
-
t.resource_limits.assign_score_limit = 3
|
146
|
-
assert_equal "Liquid error: Memory limits exceeded", t.render
|
147
|
-
assert t.resource_limits.reached?
|
148
|
-
|
149
|
-
t.resource_limits.assign_score_limit = 5
|
150
|
-
assert_equal "", t.render!
|
134
|
+
assert_equal((" foo " * 100), t.render!)
|
135
|
+
refute_nil(t.resource_limits.render_score)
|
151
136
|
end
|
152
137
|
|
153
138
|
def test_resource_limits_aborts_rendering_after_first_error
|
154
139
|
t = Template.parse("{% for a in (1..100) %} foo1 {% endfor %} bar {% for a in (1..100) %} foo2 {% endfor %}")
|
155
140
|
t.resource_limits.render_score_limit = 50
|
156
|
-
assert_equal
|
157
|
-
assert
|
141
|
+
assert_equal("Liquid error: Memory limits exceeded", t.render)
|
142
|
+
assert(t.resource_limits.reached?)
|
158
143
|
end
|
159
144
|
|
160
145
|
def test_resource_limits_hash_in_template_gets_updated_even_if_no_limits_are_set
|
161
|
-
t = Template.parse("{% for a in (1..100) %}
|
146
|
+
t = Template.parse("{% for a in (1..100) %}x{% assign foo = 1 %} {% endfor %}")
|
162
147
|
t.render!
|
163
|
-
assert
|
164
|
-
assert
|
165
|
-
assert t.resource_limits.render_length > 0
|
148
|
+
assert(t.resource_limits.assign_score > 0)
|
149
|
+
assert(t.resource_limits.render_score > 0)
|
166
150
|
end
|
167
151
|
|
168
152
|
def test_render_length_persists_between_blocks
|
169
153
|
t = Template.parse("{% if true %}aaaa{% endif %}")
|
170
|
-
t.resource_limits.render_length_limit =
|
171
|
-
assert_equal
|
172
|
-
t.resource_limits.render_length_limit =
|
173
|
-
assert_equal
|
154
|
+
t.resource_limits.render_length_limit = 3
|
155
|
+
assert_equal("Liquid error: Memory limits exceeded", t.render)
|
156
|
+
t.resource_limits.render_length_limit = 4
|
157
|
+
assert_equal("aaaa", t.render)
|
174
158
|
|
175
159
|
t = Template.parse("{% if true %}aaaa{% endif %}{% if true %}bbb{% endif %}")
|
176
|
-
t.resource_limits.render_length_limit =
|
177
|
-
assert_equal
|
178
|
-
t.resource_limits.render_length_limit =
|
179
|
-
assert_equal
|
160
|
+
t.resource_limits.render_length_limit = 6
|
161
|
+
assert_equal("Liquid error: Memory limits exceeded", t.render)
|
162
|
+
t.resource_limits.render_length_limit = 7
|
163
|
+
assert_equal("aaaabbb", t.render)
|
180
164
|
|
181
165
|
t = Template.parse("{% if true %}a{% endif %}{% if true %}b{% endif %}{% if true %}a{% endif %}{% if true %}b{% endif %}{% if true %}a{% endif %}{% if true %}b{% endif %}")
|
182
166
|
t.resource_limits.render_length_limit = 5
|
183
|
-
assert_equal
|
184
|
-
t.resource_limits.render_length_limit =
|
185
|
-
assert_equal
|
186
|
-
|
187
|
-
|
167
|
+
assert_equal("Liquid error: Memory limits exceeded", t.render)
|
168
|
+
t.resource_limits.render_length_limit = 6
|
169
|
+
assert_equal("ababab", t.render)
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_render_length_uses_number_of_bytes_not_characters
|
173
|
+
t = Template.parse("{% if true %}すごい{% endif %}")
|
174
|
+
t.resource_limits.render_length_limit = 8
|
175
|
+
assert_equal("Liquid error: Memory limits exceeded", t.render)
|
176
|
+
t.resource_limits.render_length_limit = 9
|
177
|
+
assert_equal("すごい", t.render)
|
188
178
|
end
|
189
179
|
|
190
180
|
def test_default_resource_limits_unaffected_by_render_with_context
|
191
181
|
context = Context.new
|
192
|
-
t = Template.parse("{% for a in (1..100) %}
|
182
|
+
t = Template.parse("{% for a in (1..100) %}x{% assign foo = 1 %} {% endfor %}")
|
193
183
|
t.render!(context)
|
194
|
-
assert
|
195
|
-
assert
|
196
|
-
assert context.resource_limits.render_length > 0
|
184
|
+
assert(context.resource_limits.assign_score > 0)
|
185
|
+
assert(context.resource_limits.render_score > 0)
|
197
186
|
end
|
198
187
|
|
199
188
|
def test_can_use_drop_as_context
|
200
189
|
t = Template.new
|
201
190
|
t.registers['lulz'] = 'haha'
|
202
191
|
drop = TemplateContextDrop.new
|
203
|
-
assert_equal
|
204
|
-
assert_equal
|
205
|
-
assert_equal
|
192
|
+
assert_equal('fizzbuzz', t.parse('{{foo}}').render!(drop))
|
193
|
+
assert_equal('bar', t.parse('{{bar}}').render!(drop))
|
194
|
+
assert_equal('haha', t.parse("{{baz}}").render!(drop))
|
206
195
|
end
|
207
196
|
|
208
197
|
def test_render_bang_force_rethrow_errors_on_passed_context
|
209
|
-
context = Context.new(
|
198
|
+
context = Context.new('drop' => ErroneousDrop.new)
|
210
199
|
t = Template.new.parse('{{ drop.bad_method }}')
|
211
200
|
|
212
|
-
e = assert_raises
|
201
|
+
e = assert_raises(RuntimeError) do
|
213
202
|
t.render!(context)
|
214
203
|
end
|
215
|
-
assert_equal
|
204
|
+
assert_equal('ruby error in drop', e.message)
|
216
205
|
end
|
217
206
|
|
218
207
|
def test_exception_renderer_that_returns_string
|
219
208
|
exception = nil
|
220
|
-
handler
|
209
|
+
handler = ->(e) {
|
210
|
+
exception = e
|
211
|
+
'<!-- error -->'
|
212
|
+
}
|
221
213
|
|
222
214
|
output = Template.parse("{{ 1 | divided_by: 0 }}").render({}, exception_renderer: handler)
|
223
215
|
|
224
|
-
assert
|
225
|
-
assert_equal
|
216
|
+
assert(exception.is_a?(Liquid::ZeroDivisionError))
|
217
|
+
assert_equal('<!-- error -->', output)
|
226
218
|
end
|
227
219
|
|
228
220
|
def test_exception_renderer_that_raises
|
229
221
|
exception = nil
|
230
222
|
assert_raises(Liquid::ZeroDivisionError) do
|
231
|
-
Template.parse("{{ 1 | divided_by: 0 }}").render({}, exception_renderer: ->(e) {
|
223
|
+
Template.parse("{{ 1 | divided_by: 0 }}").render({}, exception_renderer: ->(e) {
|
224
|
+
exception = e
|
225
|
+
raise
|
226
|
+
})
|
232
227
|
end
|
233
|
-
assert
|
228
|
+
assert(exception.is_a?(Liquid::ZeroDivisionError))
|
234
229
|
end
|
235
230
|
|
236
231
|
def test_global_filter_option_on_render
|
237
232
|
global_filter_proc = ->(output) { "#{output} filtered" }
|
238
|
-
rendered_template
|
233
|
+
rendered_template = Template.parse("{{name}}").render({ "name" => "bob" }, global_filter: global_filter_proc)
|
239
234
|
|
240
|
-
assert_equal
|
235
|
+
assert_equal('bob filtered', rendered_template)
|
241
236
|
end
|
242
237
|
|
243
238
|
def test_global_filter_option_when_native_filters_exist
|
244
239
|
global_filter_proc = ->(output) { "#{output} filtered" }
|
245
|
-
rendered_template
|
240
|
+
rendered_template = Template.parse("{{name | upcase}}").render({ "name" => "bob" }, global_filter: global_filter_proc)
|
246
241
|
|
247
|
-
assert_equal
|
242
|
+
assert_equal('BOB filtered', rendered_template)
|
248
243
|
end
|
249
244
|
|
250
245
|
def test_undefined_variables
|
251
|
-
t
|
252
|
-
result = t.render({ 'x' => 33, 'z' => { 'a' => 32, 'c' => { 'e' => 31 } } },
|
246
|
+
t = Template.parse("{{x}} {{y}} {{z.a}} {{z.b}} {{z.c.d}}")
|
247
|
+
result = t.render({ 'x' => 33, 'z' => { 'a' => 32, 'c' => { 'e' => 31 } } }, strict_variables: true)
|
248
|
+
|
249
|
+
assert_equal('33 32 ', result)
|
250
|
+
assert_equal(3, t.errors.count)
|
251
|
+
assert_instance_of(Liquid::UndefinedVariable, t.errors[0])
|
252
|
+
assert_equal('Liquid error: undefined variable y', t.errors[0].message)
|
253
|
+
assert_instance_of(Liquid::UndefinedVariable, t.errors[1])
|
254
|
+
assert_equal('Liquid error: undefined variable b', t.errors[1].message)
|
255
|
+
assert_instance_of(Liquid::UndefinedVariable, t.errors[2])
|
256
|
+
assert_equal('Liquid error: undefined variable d', t.errors[2].message)
|
257
|
+
end
|
258
|
+
|
259
|
+
def test_nil_value_does_not_raise
|
260
|
+
t = Template.parse("some{{x}}thing", error_mode: :strict)
|
261
|
+
result = t.render!({ 'x' => nil }, strict_variables: true)
|
253
262
|
|
254
|
-
assert_equal
|
255
|
-
assert_equal
|
256
|
-
assert_instance_of Liquid::UndefinedVariable, t.errors[0]
|
257
|
-
assert_equal 'Liquid error: undefined variable y', t.errors[0].message
|
258
|
-
assert_instance_of Liquid::UndefinedVariable, t.errors[1]
|
259
|
-
assert_equal 'Liquid error: undefined variable b', t.errors[1].message
|
260
|
-
assert_instance_of Liquid::UndefinedVariable, t.errors[2]
|
261
|
-
assert_equal 'Liquid error: undefined variable d', t.errors[2].message
|
263
|
+
assert_equal(0, t.errors.count)
|
264
|
+
assert_equal('something', result)
|
262
265
|
end
|
263
266
|
|
264
267
|
def test_undefined_variables_raise
|
265
268
|
t = Template.parse("{{x}} {{y}} {{z.a}} {{z.b}} {{z.c.d}}")
|
266
269
|
|
267
|
-
assert_raises
|
268
|
-
t.render!({ 'x' => 33, 'z' => { 'a' => 32, 'c' => { 'e' => 31 } } },
|
270
|
+
assert_raises(UndefinedVariable) do
|
271
|
+
t.render!({ 'x' => 33, 'z' => { 'a' => 32, 'c' => { 'e' => 31 } } }, strict_variables: true)
|
269
272
|
end
|
270
273
|
end
|
271
274
|
|
272
275
|
def test_undefined_drop_methods
|
273
276
|
d = DropWithUndefinedMethod.new
|
274
277
|
t = Template.new.parse('{{ foo }} {{ woot }}')
|
275
|
-
result = t.render(d,
|
278
|
+
result = t.render(d, strict_variables: true)
|
276
279
|
|
277
|
-
assert_equal
|
278
|
-
assert_equal
|
279
|
-
assert_instance_of
|
280
|
+
assert_equal('foo ', result)
|
281
|
+
assert_equal(1, t.errors.count)
|
282
|
+
assert_instance_of(Liquid::UndefinedDropMethod, t.errors[0])
|
280
283
|
end
|
281
284
|
|
282
285
|
def test_undefined_drop_methods_raise
|
283
286
|
d = DropWithUndefinedMethod.new
|
284
287
|
t = Template.new.parse('{{ foo }} {{ woot }}')
|
285
288
|
|
286
|
-
assert_raises
|
287
|
-
t.render!(d,
|
289
|
+
assert_raises(UndefinedDropMethod) do
|
290
|
+
t.render!(d, strict_variables: true)
|
288
291
|
end
|
289
292
|
end
|
290
293
|
|
@@ -295,29 +298,29 @@ class TemplateTest < Minitest::Test
|
|
295
298
|
"-#{v}-"
|
296
299
|
end
|
297
300
|
end
|
298
|
-
result = t.render({ 'a' => 123, 'x' => 'foo' },
|
301
|
+
result = t.render({ 'a' => 123, 'x' => 'foo' }, filters: [filters], strict_filters: true)
|
299
302
|
|
300
|
-
assert_equal
|
301
|
-
assert_equal
|
302
|
-
assert_instance_of
|
303
|
-
assert_equal
|
303
|
+
assert_equal('123 ', result)
|
304
|
+
assert_equal(1, t.errors.count)
|
305
|
+
assert_instance_of(Liquid::UndefinedFilter, t.errors[0])
|
306
|
+
assert_equal('Liquid error: undefined filter somefilter1', t.errors[0].message)
|
304
307
|
end
|
305
308
|
|
306
309
|
def test_undefined_filters_raise
|
307
310
|
t = Template.parse("{{x | somefilter1 | upcase | somefilter2}}")
|
308
311
|
|
309
|
-
assert_raises
|
310
|
-
t.render!({ 'x' => 'foo' },
|
312
|
+
assert_raises(UndefinedFilter) do
|
313
|
+
t.render!({ 'x' => 'foo' }, strict_filters: true)
|
311
314
|
end
|
312
315
|
end
|
313
316
|
|
314
317
|
def test_using_range_literal_works_as_expected
|
315
318
|
t = Template.parse("{% assign foo = (x..y) %}{{ foo }}")
|
316
|
-
result = t.render(
|
317
|
-
assert_equal
|
319
|
+
result = t.render('x' => 1, 'y' => 5)
|
320
|
+
assert_equal('1..5', result)
|
318
321
|
|
319
322
|
t = Template.parse("{% assign nums = (x..y) %}{% for num in nums %}{{ num }}{% endfor %}")
|
320
|
-
result = t.render(
|
321
|
-
assert_equal
|
323
|
+
result = t.render('x' => 1, 'y' => 5)
|
324
|
+
assert_equal('12345', result)
|
322
325
|
end
|
323
326
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
|
3
5
|
class TrimModeTest < Minitest::Test
|
@@ -67,7 +69,7 @@ class TrimModeTest < Minitest::Test
|
|
67
69
|
# Make sure the trim isn't applied to standard tags
|
68
70
|
def test_standard_tags
|
69
71
|
whitespace = ' '
|
70
|
-
text
|
72
|
+
text = <<-END_TEMPLATE
|
71
73
|
<div>
|
72
74
|
<p>
|
73
75
|
{% if true %}
|
@@ -76,14 +78,14 @@ class TrimModeTest < Minitest::Test
|
|
76
78
|
</p>
|
77
79
|
</div>
|
78
80
|
END_TEMPLATE
|
79
|
-
expected =
|
80
|
-
|
81
|
-
|
82
|
-
#{whitespace}
|
83
|
-
|
84
|
-
#{whitespace}
|
85
|
-
|
86
|
-
|
81
|
+
expected = <<~END_EXPECTED
|
82
|
+
<div>
|
83
|
+
<p>
|
84
|
+
#{whitespace}
|
85
|
+
yes
|
86
|
+
#{whitespace}
|
87
|
+
</p>
|
88
|
+
</div>
|
87
89
|
END_EXPECTED
|
88
90
|
assert_template_result(expected, text)
|
89
91
|
|
@@ -96,70 +98,70 @@ class TrimModeTest < Minitest::Test
|
|
96
98
|
</p>
|
97
99
|
</div>
|
98
100
|
END_TEMPLATE
|
99
|
-
expected =
|
100
|
-
|
101
|
-
|
102
|
-
#{whitespace}
|
103
|
-
|
104
|
-
|
101
|
+
expected = <<~END_EXPECTED
|
102
|
+
<div>
|
103
|
+
<p>
|
104
|
+
#{whitespace}
|
105
|
+
</p>
|
106
|
+
</div>
|
105
107
|
END_EXPECTED
|
106
108
|
assert_template_result(expected, text)
|
107
109
|
end
|
108
110
|
|
109
111
|
# Make sure the trim isn't too agressive
|
110
112
|
def test_no_trim_output
|
111
|
-
text
|
113
|
+
text = '<p>{{- \'John\' -}}</p>'
|
112
114
|
expected = '<p>John</p>'
|
113
115
|
assert_template_result(expected, text)
|
114
116
|
end
|
115
117
|
|
116
118
|
# Make sure the trim isn't too agressive
|
117
119
|
def test_no_trim_tags
|
118
|
-
text
|
120
|
+
text = '<p>{%- if true -%}yes{%- endif -%}</p>'
|
119
121
|
expected = '<p>yes</p>'
|
120
122
|
assert_template_result(expected, text)
|
121
123
|
|
122
|
-
text
|
124
|
+
text = '<p>{%- if false -%}no{%- endif -%}</p>'
|
123
125
|
expected = '<p></p>'
|
124
126
|
assert_template_result(expected, text)
|
125
127
|
end
|
126
128
|
|
127
129
|
def test_single_line_outer_tag
|
128
|
-
text
|
130
|
+
text = '<p> {%- if true %} yes {% endif -%} </p>'
|
129
131
|
expected = '<p> yes </p>'
|
130
132
|
assert_template_result(expected, text)
|
131
133
|
|
132
|
-
text
|
134
|
+
text = '<p> {%- if false %} no {% endif -%} </p>'
|
133
135
|
expected = '<p></p>'
|
134
136
|
assert_template_result(expected, text)
|
135
137
|
end
|
136
138
|
|
137
139
|
def test_single_line_inner_tag
|
138
|
-
text
|
140
|
+
text = '<p> {% if true -%} yes {%- endif %} </p>'
|
139
141
|
expected = '<p> yes </p>'
|
140
142
|
assert_template_result(expected, text)
|
141
143
|
|
142
|
-
text
|
144
|
+
text = '<p> {% if false -%} no {%- endif %} </p>'
|
143
145
|
expected = '<p> </p>'
|
144
146
|
assert_template_result(expected, text)
|
145
147
|
end
|
146
148
|
|
147
149
|
def test_single_line_post_tag
|
148
|
-
text
|
150
|
+
text = '<p> {% if true -%} yes {% endif -%} </p>'
|
149
151
|
expected = '<p> yes </p>'
|
150
152
|
assert_template_result(expected, text)
|
151
153
|
|
152
|
-
text
|
154
|
+
text = '<p> {% if false -%} no {% endif -%} </p>'
|
153
155
|
expected = '<p> </p>'
|
154
156
|
assert_template_result(expected, text)
|
155
157
|
end
|
156
158
|
|
157
159
|
def test_single_line_pre_tag
|
158
|
-
text
|
160
|
+
text = '<p> {%- if true %} yes {%- endif %} </p>'
|
159
161
|
expected = '<p> yes </p>'
|
160
162
|
assert_template_result(expected, text)
|
161
163
|
|
162
|
-
text
|
164
|
+
text = '<p> {%- if false %} no {%- endif %} </p>'
|
163
165
|
expected = '<p> </p>'
|
164
166
|
assert_template_result(expected, text)
|
165
167
|
end
|
@@ -328,7 +330,7 @@ class TrimModeTest < Minitest::Test
|
|
328
330
|
assert_template_result(expected, text)
|
329
331
|
|
330
332
|
whitespace = ' '
|
331
|
-
text
|
333
|
+
text = <<-END_TEMPLATE
|
332
334
|
<div>
|
333
335
|
<p>
|
334
336
|
{% if false -%}
|
@@ -337,12 +339,12 @@ class TrimModeTest < Minitest::Test
|
|
337
339
|
</p>
|
338
340
|
</div>
|
339
341
|
END_TEMPLATE
|
340
|
-
expected =
|
341
|
-
|
342
|
-
|
343
|
-
#{whitespace}
|
344
|
-
|
345
|
-
|
342
|
+
expected = <<~END_EXPECTED
|
343
|
+
<div>
|
344
|
+
<p>
|
345
|
+
#{whitespace}
|
346
|
+
</p>
|
347
|
+
</div>
|
346
348
|
END_EXPECTED
|
347
349
|
assert_template_result(expected, text)
|
348
350
|
end
|
@@ -496,9 +498,13 @@ class TrimModeTest < Minitest::Test
|
|
496
498
|
assert_template_result(expected, text)
|
497
499
|
end
|
498
500
|
|
501
|
+
def test_right_trim_followed_by_tag
|
502
|
+
assert_template_result('ab c', '{{ "a" -}}{{ "b" }} c')
|
503
|
+
end
|
504
|
+
|
499
505
|
def test_raw_output
|
500
506
|
whitespace = ' '
|
501
|
-
text
|
507
|
+
text = <<-END_TEMPLATE
|
502
508
|
<div>
|
503
509
|
{% raw %}
|
504
510
|
{%- if true -%}
|
@@ -509,17 +515,49 @@ class TrimModeTest < Minitest::Test
|
|
509
515
|
{% endraw %}
|
510
516
|
</div>
|
511
517
|
END_TEMPLATE
|
512
|
-
expected =
|
513
|
-
|
514
|
-
#{whitespace}
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
#{whitespace}
|
521
|
-
|
518
|
+
expected = <<~END_EXPECTED
|
519
|
+
<div>
|
520
|
+
#{whitespace}
|
521
|
+
{%- if true -%}
|
522
|
+
<p>
|
523
|
+
{{- 'John' -}}
|
524
|
+
</p>
|
525
|
+
{%- endif -%}
|
526
|
+
#{whitespace}
|
527
|
+
</div>
|
522
528
|
END_EXPECTED
|
523
529
|
assert_template_result(expected, text)
|
524
530
|
end
|
531
|
+
|
532
|
+
def test_pre_trim_blank_preceding_text
|
533
|
+
template = Liquid::Template.parse("\n{%- raw %}{% endraw %}")
|
534
|
+
assert_equal("", template.render)
|
535
|
+
|
536
|
+
template = Liquid::Template.parse("\n{%- if true %}{% endif %}")
|
537
|
+
assert_equal("", template.render)
|
538
|
+
|
539
|
+
template = Liquid::Template.parse("{{ 'B' }} \n{%- if true %}C{% endif %}")
|
540
|
+
assert_equal("BC", template.render)
|
541
|
+
end
|
542
|
+
|
543
|
+
def test_bug_compatible_pre_trim
|
544
|
+
template = Liquid::Template.parse("\n {%- raw %}{% endraw %}", bug_compatible_whitespace_trimming: true)
|
545
|
+
assert_equal("\n", template.render)
|
546
|
+
|
547
|
+
template = Liquid::Template.parse("\n {%- if true %}{% endif %}", bug_compatible_whitespace_trimming: true)
|
548
|
+
assert_equal("\n", template.render)
|
549
|
+
|
550
|
+
template = Liquid::Template.parse("{{ 'B' }} \n{%- if true %}C{% endif %}", bug_compatible_whitespace_trimming: true)
|
551
|
+
assert_equal("B C", template.render)
|
552
|
+
|
553
|
+
template = Liquid::Template.parse("B\n {%- raw %}{% endraw %}", bug_compatible_whitespace_trimming: true)
|
554
|
+
assert_equal("B", template.render)
|
555
|
+
|
556
|
+
template = Liquid::Template.parse("B\n {%- if true %}{% endif %}", bug_compatible_whitespace_trimming: true)
|
557
|
+
assert_equal("B", template.render)
|
558
|
+
end
|
559
|
+
|
560
|
+
def test_trim_blank
|
561
|
+
assert_template_result('foobar', 'foo {{-}} bar')
|
562
|
+
end
|
525
563
|
end # TrimModeTest
|