liquid 5.1.0 → 5.4.0

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.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +35 -0
  3. data/README.md +4 -4
  4. data/lib/liquid/block_body.rb +6 -6
  5. data/lib/liquid/condition.rb +7 -1
  6. data/lib/liquid/context.rb +6 -2
  7. data/lib/liquid/expression.rb +11 -10
  8. data/lib/liquid/forloop_drop.rb +44 -1
  9. data/lib/liquid/locales/en.yml +6 -5
  10. data/lib/liquid/partial_cache.rb +3 -3
  11. data/lib/liquid/registers.rb +51 -0
  12. data/lib/liquid/standardfilters.rb +463 -75
  13. data/lib/liquid/strainer_factory.rb +15 -10
  14. data/lib/liquid/strainer_template.rb +9 -0
  15. data/lib/liquid/tablerowloop_drop.rb +58 -1
  16. data/lib/liquid/tags/assign.rb +12 -8
  17. data/lib/liquid/tags/break.rb +8 -0
  18. data/lib/liquid/tags/capture.rb +13 -10
  19. data/lib/liquid/tags/case.rb +21 -0
  20. data/lib/liquid/tags/comment.rb +13 -0
  21. data/lib/liquid/tags/continue.rb +8 -9
  22. data/lib/liquid/tags/cycle.rb +12 -11
  23. data/lib/liquid/tags/decrement.rb +16 -17
  24. data/lib/liquid/tags/echo.rb +16 -9
  25. data/lib/liquid/tags/for.rb +22 -43
  26. data/lib/liquid/tags/if.rb +11 -9
  27. data/lib/liquid/tags/include.rb +15 -13
  28. data/lib/liquid/tags/increment.rb +16 -14
  29. data/lib/liquid/tags/inline_comment.rb +43 -0
  30. data/lib/liquid/tags/raw.rb +11 -0
  31. data/lib/liquid/tags/render.rb +29 -4
  32. data/lib/liquid/tags/table_row.rb +22 -0
  33. data/lib/liquid/tags/unless.rb +15 -4
  34. data/lib/liquid/template.rb +2 -3
  35. data/lib/liquid/variable.rb +4 -4
  36. data/lib/liquid/variable_lookup.rb +10 -7
  37. data/lib/liquid/version.rb +1 -1
  38. data/lib/liquid.rb +4 -4
  39. metadata +7 -121
  40. data/lib/liquid/register.rb +0 -6
  41. data/lib/liquid/static_registers.rb +0 -44
  42. data/test/fixtures/en_locale.yml +0 -9
  43. data/test/integration/assign_test.rb +0 -117
  44. data/test/integration/blank_test.rb +0 -109
  45. data/test/integration/block_test.rb +0 -58
  46. data/test/integration/capture_test.rb +0 -58
  47. data/test/integration/context_test.rb +0 -636
  48. data/test/integration/document_test.rb +0 -21
  49. data/test/integration/drop_test.rb +0 -257
  50. data/test/integration/error_handling_test.rb +0 -272
  51. data/test/integration/expression_test.rb +0 -46
  52. data/test/integration/filter_test.rb +0 -189
  53. data/test/integration/hash_ordering_test.rb +0 -25
  54. data/test/integration/output_test.rb +0 -125
  55. data/test/integration/parsing_quirks_test.rb +0 -134
  56. data/test/integration/profiler_test.rb +0 -213
  57. data/test/integration/security_test.rb +0 -89
  58. data/test/integration/standard_filter_test.rb +0 -880
  59. data/test/integration/tag/disableable_test.rb +0 -59
  60. data/test/integration/tag_test.rb +0 -45
  61. data/test/integration/tags/break_tag_test.rb +0 -17
  62. data/test/integration/tags/continue_tag_test.rb +0 -17
  63. data/test/integration/tags/echo_test.rb +0 -13
  64. data/test/integration/tags/for_tag_test.rb +0 -466
  65. data/test/integration/tags/if_else_tag_test.rb +0 -190
  66. data/test/integration/tags/include_tag_test.rb +0 -269
  67. data/test/integration/tags/increment_tag_test.rb +0 -25
  68. data/test/integration/tags/liquid_tag_test.rb +0 -116
  69. data/test/integration/tags/raw_tag_test.rb +0 -34
  70. data/test/integration/tags/render_tag_test.rb +0 -213
  71. data/test/integration/tags/standard_tag_test.rb +0 -303
  72. data/test/integration/tags/statements_test.rb +0 -113
  73. data/test/integration/tags/table_row_test.rb +0 -66
  74. data/test/integration/tags/unless_else_tag_test.rb +0 -28
  75. data/test/integration/template_test.rb +0 -340
  76. data/test/integration/trim_mode_test.rb +0 -563
  77. data/test/integration/variable_test.rb +0 -138
  78. data/test/test_helper.rb +0 -207
  79. data/test/unit/block_unit_test.rb +0 -53
  80. data/test/unit/condition_unit_test.rb +0 -168
  81. data/test/unit/file_system_unit_test.rb +0 -37
  82. data/test/unit/i18n_unit_test.rb +0 -39
  83. data/test/unit/lexer_unit_test.rb +0 -53
  84. data/test/unit/parse_tree_visitor_test.rb +0 -261
  85. data/test/unit/parser_unit_test.rb +0 -84
  86. data/test/unit/partial_cache_unit_test.rb +0 -128
  87. data/test/unit/regexp_unit_test.rb +0 -46
  88. data/test/unit/static_registers_unit_test.rb +0 -156
  89. data/test/unit/strainer_factory_unit_test.rb +0 -100
  90. data/test/unit/strainer_template_unit_test.rb +0 -82
  91. data/test/unit/tag_unit_test.rb +0 -23
  92. data/test/unit/tags/case_tag_unit_test.rb +0 -12
  93. data/test/unit/tags/for_tag_unit_test.rb +0 -15
  94. data/test/unit/tags/if_tag_unit_test.rb +0 -10
  95. data/test/unit/template_factory_unit_test.rb +0 -12
  96. data/test/unit/template_unit_test.rb +0 -87
  97. data/test/unit/tokenizer_unit_test.rb +0 -62
  98. data/test/unit/variable_unit_test.rb +0 -164
@@ -1,257 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
-
5
- class ContextDrop < Liquid::Drop
6
- def scopes
7
- @context.scopes.size
8
- end
9
-
10
- def scopes_as_array
11
- (1..@context.scopes.size).to_a
12
- end
13
-
14
- def loop_pos
15
- @context['forloop.index']
16
- end
17
-
18
- def liquid_method_missing(method)
19
- @context[method]
20
- end
21
- end
22
-
23
- class ProductDrop < Liquid::Drop
24
- class TextDrop < Liquid::Drop
25
- def array
26
- ['text1', 'text2']
27
- end
28
-
29
- def text
30
- 'text1'
31
- end
32
- end
33
-
34
- class CatchallDrop < Liquid::Drop
35
- def liquid_method_missing(method)
36
- "catchall_method: #{method}"
37
- end
38
- end
39
-
40
- def texts
41
- TextDrop.new
42
- end
43
-
44
- def catchall
45
- CatchallDrop.new
46
- end
47
-
48
- def context
49
- ContextDrop.new
50
- end
51
-
52
- protected
53
-
54
- def callmenot
55
- "protected"
56
- end
57
- end
58
-
59
- class EnumerableDrop < Liquid::Drop
60
- def liquid_method_missing(method)
61
- method
62
- end
63
-
64
- def size
65
- 3
66
- end
67
-
68
- def first
69
- 1
70
- end
71
-
72
- def count
73
- 3
74
- end
75
-
76
- def min
77
- 1
78
- end
79
-
80
- def max
81
- 3
82
- end
83
-
84
- def each
85
- yield 1
86
- yield 2
87
- yield 3
88
- end
89
- end
90
-
91
- class RealEnumerableDrop < Liquid::Drop
92
- include Enumerable
93
-
94
- def liquid_method_missing(method)
95
- method
96
- end
97
-
98
- def each
99
- yield 1
100
- yield 2
101
- yield 3
102
- end
103
- end
104
-
105
- class DropsTest < Minitest::Test
106
- include Liquid
107
-
108
- def test_product_drop
109
- tpl = Liquid::Template.parse(' ')
110
- assert_equal(' ', tpl.render!('product' => ProductDrop.new))
111
- end
112
-
113
- def test_drop_does_only_respond_to_whitelisted_methods
114
- assert_equal("", Liquid::Template.parse("{{ product.inspect }}").render!('product' => ProductDrop.new))
115
- assert_equal("", Liquid::Template.parse("{{ product.pretty_inspect }}").render!('product' => ProductDrop.new))
116
- assert_equal("", Liquid::Template.parse("{{ product.whatever }}").render!('product' => ProductDrop.new))
117
- assert_equal("", Liquid::Template.parse('{{ product | map: "inspect" }}').render!('product' => ProductDrop.new))
118
- assert_equal("", Liquid::Template.parse('{{ product | map: "pretty_inspect" }}').render!('product' => ProductDrop.new))
119
- assert_equal("", Liquid::Template.parse('{{ product | map: "whatever" }}').render!('product' => ProductDrop.new))
120
- end
121
-
122
- def test_drops_respond_to_to_liquid
123
- assert_equal("text1", Liquid::Template.parse("{{ product.to_liquid.texts.text }}").render!('product' => ProductDrop.new))
124
- assert_equal("text1", Liquid::Template.parse('{{ product | map: "to_liquid" | map: "texts" | map: "text" }}').render!('product' => ProductDrop.new))
125
- end
126
-
127
- def test_text_drop
128
- output = Liquid::Template.parse(' {{ product.texts.text }} ').render!('product' => ProductDrop.new)
129
- assert_equal(' text1 ', output)
130
- end
131
-
132
- def test_catchall_unknown_method
133
- output = Liquid::Template.parse(' {{ product.catchall.unknown }} ').render!('product' => ProductDrop.new)
134
- assert_equal(' catchall_method: unknown ', output)
135
- end
136
-
137
- def test_catchall_integer_argument_drop
138
- output = Liquid::Template.parse(' {{ product.catchall[8] }} ').render!('product' => ProductDrop.new)
139
- assert_equal(' catchall_method: 8 ', output)
140
- end
141
-
142
- def test_text_array_drop
143
- output = Liquid::Template.parse('{% for text in product.texts.array %} {{text}} {% endfor %}').render!('product' => ProductDrop.new)
144
- assert_equal(' text1 text2 ', output)
145
- end
146
-
147
- def test_context_drop
148
- output = Liquid::Template.parse(' {{ context.bar }} ').render!('context' => ContextDrop.new, 'bar' => "carrot")
149
- assert_equal(' carrot ', output)
150
- end
151
-
152
- def test_context_drop_array_with_map
153
- output = Liquid::Template.parse(' {{ contexts | map: "bar" }} ').render!('contexts' => [ContextDrop.new, ContextDrop.new], 'bar' => "carrot")
154
- assert_equal(' carrotcarrot ', output)
155
- end
156
-
157
- def test_nested_context_drop
158
- output = Liquid::Template.parse(' {{ product.context.foo }} ').render!('product' => ProductDrop.new, 'foo' => "monkey")
159
- assert_equal(' monkey ', output)
160
- end
161
-
162
- def test_protected
163
- output = Liquid::Template.parse(' {{ product.callmenot }} ').render!('product' => ProductDrop.new)
164
- assert_equal(' ', output)
165
- end
166
-
167
- def test_object_methods_not_allowed
168
- [:dup, :clone, :singleton_class, :eval, :class_eval, :inspect].each do |method|
169
- output = Liquid::Template.parse(" {{ product.#{method} }} ").render!('product' => ProductDrop.new)
170
- assert_equal(' ', output)
171
- end
172
- end
173
-
174
- def test_scope
175
- assert_equal('1', Liquid::Template.parse('{{ context.scopes }}').render!('context' => ContextDrop.new))
176
- assert_equal('2', Liquid::Template.parse('{%for i in dummy%}{{ context.scopes }}{%endfor%}').render!('context' => ContextDrop.new, 'dummy' => [1]))
177
- assert_equal('3', Liquid::Template.parse('{%for i in dummy%}{%for i in dummy%}{{ context.scopes }}{%endfor%}{%endfor%}').render!('context' => ContextDrop.new, 'dummy' => [1]))
178
- end
179
-
180
- def test_scope_though_proc
181
- assert_equal('1', Liquid::Template.parse('{{ s }}').render!('context' => ContextDrop.new, 's' => proc { |c| c['context.scopes'] }))
182
- assert_equal('2', Liquid::Template.parse('{%for i in dummy%}{{ s }}{%endfor%}').render!('context' => ContextDrop.new, 's' => proc { |c| c['context.scopes'] }, 'dummy' => [1]))
183
- assert_equal('3', Liquid::Template.parse('{%for i in dummy%}{%for i in dummy%}{{ s }}{%endfor%}{%endfor%}').render!('context' => ContextDrop.new, 's' => proc { |c| c['context.scopes'] }, 'dummy' => [1]))
184
- end
185
-
186
- def test_scope_with_assigns
187
- assert_equal('variable', Liquid::Template.parse('{% assign a = "variable"%}{{a}}').render!('context' => ContextDrop.new))
188
- assert_equal('variable', Liquid::Template.parse('{% assign a = "variable"%}{%for i in dummy%}{{a}}{%endfor%}').render!('context' => ContextDrop.new, 'dummy' => [1]))
189
- assert_equal('test', Liquid::Template.parse('{% assign header_gif = "test"%}{{header_gif}}').render!('context' => ContextDrop.new))
190
- assert_equal('test', Liquid::Template.parse("{% assign header_gif = 'test'%}{{header_gif}}").render!('context' => ContextDrop.new))
191
- end
192
-
193
- def test_scope_from_tags
194
- assert_equal('1', Liquid::Template.parse('{% for i in context.scopes_as_array %}{{i}}{% endfor %}').render!('context' => ContextDrop.new, 'dummy' => [1]))
195
- assert_equal('12', Liquid::Template.parse('{%for a in dummy%}{% for i in context.scopes_as_array %}{{i}}{% endfor %}{% endfor %}').render!('context' => ContextDrop.new, 'dummy' => [1]))
196
- assert_equal('123', Liquid::Template.parse('{%for a in dummy%}{%for a in dummy%}{% for i in context.scopes_as_array %}{{i}}{% endfor %}{% endfor %}{% endfor %}').render!('context' => ContextDrop.new, 'dummy' => [1]))
197
- end
198
-
199
- def test_access_context_from_drop
200
- assert_equal('123', Liquid::Template.parse('{%for a in dummy%}{{ context.loop_pos }}{% endfor %}').render!('context' => ContextDrop.new, 'dummy' => [1, 2, 3]))
201
- end
202
-
203
- def test_enumerable_drop
204
- assert_equal('123', Liquid::Template.parse('{% for c in collection %}{{c}}{% endfor %}').render!('collection' => EnumerableDrop.new))
205
- end
206
-
207
- def test_enumerable_drop_size
208
- assert_equal('3', Liquid::Template.parse('{{collection.size}}').render!('collection' => EnumerableDrop.new))
209
- end
210
-
211
- def test_enumerable_drop_will_invoke_liquid_method_missing_for_clashing_method_names
212
- ["select", "each", "map", "cycle"].each do |method|
213
- assert_equal(method.to_s, Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => EnumerableDrop.new))
214
- assert_equal(method.to_s, Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => EnumerableDrop.new))
215
- assert_equal(method.to_s, Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => RealEnumerableDrop.new))
216
- assert_equal(method.to_s, Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => RealEnumerableDrop.new))
217
- end
218
- end
219
-
220
- def test_some_enumerable_methods_still_get_invoked
221
- [:count, :max].each do |method|
222
- assert_equal("3", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => RealEnumerableDrop.new))
223
- assert_equal("3", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => RealEnumerableDrop.new))
224
- assert_equal("3", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => EnumerableDrop.new))
225
- assert_equal("3", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => EnumerableDrop.new))
226
- end
227
-
228
- assert_equal("yes", Liquid::Template.parse("{% if collection contains 3 %}yes{% endif %}").render!('collection' => RealEnumerableDrop.new))
229
-
230
- [:min, :first].each do |method|
231
- assert_equal("1", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => RealEnumerableDrop.new))
232
- assert_equal("1", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => RealEnumerableDrop.new))
233
- assert_equal("1", Liquid::Template.parse("{{collection.#{method}}}").render!('collection' => EnumerableDrop.new))
234
- assert_equal("1", Liquid::Template.parse("{{collection[\"#{method}\"]}}").render!('collection' => EnumerableDrop.new))
235
- end
236
- end
237
-
238
- def test_empty_string_value_access
239
- assert_equal('', Liquid::Template.parse('{{ product[value] }}').render!('product' => ProductDrop.new, 'value' => ''))
240
- end
241
-
242
- def test_nil_value_access
243
- assert_equal('', Liquid::Template.parse('{{ product[value] }}').render!('product' => ProductDrop.new, 'value' => nil))
244
- end
245
-
246
- def test_default_to_s_on_drops
247
- assert_equal('ProductDrop', Liquid::Template.parse("{{ product }}").render!('product' => ProductDrop.new))
248
- assert_equal('EnumerableDrop', Liquid::Template.parse('{{ collection }}').render!('collection' => EnumerableDrop.new))
249
- end
250
-
251
- def test_invokable_methods
252
- assert_equal(%w(to_liquid catchall context texts).to_set, ProductDrop.invokable_methods)
253
- assert_equal(%w(to_liquid scopes_as_array loop_pos scopes).to_set, ContextDrop.invokable_methods)
254
- assert_equal(%w(to_liquid size max min first count).to_set, EnumerableDrop.invokable_methods)
255
- assert_equal(%w(to_liquid max min sort count first).to_set, RealEnumerableDrop.invokable_methods)
256
- end
257
- end # DropsTest
@@ -1,272 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
-
5
- class ErrorHandlingTest < Minitest::Test
6
- include Liquid
7
-
8
- def test_templates_parsed_with_line_numbers_renders_them_in_errors
9
- template = <<-LIQUID
10
- Hello,
11
-
12
- {{ errors.standard_error }} will raise a standard error.
13
-
14
- Bla bla test.
15
-
16
- {{ errors.syntax_error }} will raise a syntax error.
17
-
18
- This is an argument error: {{ errors.argument_error }}
19
-
20
- Bla.
21
- LIQUID
22
-
23
- expected = <<-TEXT
24
- Hello,
25
-
26
- Liquid error (line 3): standard error will raise a standard error.
27
-
28
- Bla bla test.
29
-
30
- Liquid syntax error (line 7): syntax error will raise a syntax error.
31
-
32
- This is an argument error: Liquid error (line 9): argument error
33
-
34
- Bla.
35
- TEXT
36
-
37
- output = Liquid::Template.parse(template, line_numbers: true).render('errors' => ErrorDrop.new)
38
- assert_equal(expected, output)
39
- end
40
-
41
- def test_standard_error
42
- template = Liquid::Template.parse(' {{ errors.standard_error }} ')
43
- assert_equal(' Liquid error: standard error ', template.render('errors' => ErrorDrop.new))
44
-
45
- assert_equal(1, template.errors.size)
46
- assert_equal(StandardError, template.errors.first.class)
47
- end
48
-
49
- def test_syntax
50
- template = Liquid::Template.parse(' {{ errors.syntax_error }} ')
51
- assert_equal(' Liquid syntax error: syntax error ', template.render('errors' => ErrorDrop.new))
52
-
53
- assert_equal(1, template.errors.size)
54
- assert_equal(SyntaxError, template.errors.first.class)
55
- end
56
-
57
- def test_argument
58
- template = Liquid::Template.parse(' {{ errors.argument_error }} ')
59
- assert_equal(' Liquid error: argument error ', template.render('errors' => ErrorDrop.new))
60
-
61
- assert_equal(1, template.errors.size)
62
- assert_equal(ArgumentError, template.errors.first.class)
63
- end
64
-
65
- def test_missing_endtag_parse_time_error
66
- assert_raises(Liquid::SyntaxError) do
67
- Liquid::Template.parse(' {% for a in b %} ... ')
68
- end
69
- end
70
-
71
- def test_unrecognized_operator
72
- with_error_mode(:strict) do
73
- assert_raises(SyntaxError) do
74
- Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ')
75
- end
76
- end
77
- end
78
-
79
- def test_lax_unrecognized_operator
80
- template = Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ', error_mode: :lax)
81
- assert_equal(' Liquid error: Unknown operator =! ', template.render)
82
- assert_equal(1, template.errors.size)
83
- assert_equal(Liquid::ArgumentError, template.errors.first.class)
84
- end
85
-
86
- def test_with_line_numbers_adds_numbers_to_parser_errors
87
- err = assert_raises(SyntaxError) do
88
- Liquid::Template.parse('
89
- foobar
90
-
91
- {% "cat" | foobar %}
92
-
93
- bla
94
- ',
95
- line_numbers: true)
96
- end
97
-
98
- assert_match(/Liquid syntax error \(line 4\)/, err.message)
99
- end
100
-
101
- def test_with_line_numbers_adds_numbers_to_parser_errors_with_whitespace_trim
102
- err = assert_raises(SyntaxError) do
103
- Liquid::Template.parse('
104
- foobar
105
-
106
- {%- "cat" | foobar -%}
107
-
108
- bla
109
- ',
110
- line_numbers: true)
111
- end
112
-
113
- assert_match(/Liquid syntax error \(line 4\)/, err.message)
114
- end
115
-
116
- def test_parsing_warn_with_line_numbers_adds_numbers_to_lexer_errors
117
- template = Liquid::Template.parse('
118
- foobar
119
-
120
- {% if 1 =! 2 %}ok{% endif %}
121
-
122
- bla
123
- ',
124
- error_mode: :warn,
125
- line_numbers: true)
126
-
127
- assert_equal(['Liquid syntax error (line 4): Unexpected character = in "1 =! 2"'],
128
- template.warnings.map(&:message))
129
- end
130
-
131
- def test_parsing_strict_with_line_numbers_adds_numbers_to_lexer_errors
132
- err = assert_raises(SyntaxError) do
133
- Liquid::Template.parse('
134
- foobar
135
-
136
- {% if 1 =! 2 %}ok{% endif %}
137
-
138
- bla
139
- ',
140
- error_mode: :strict,
141
- line_numbers: true)
142
- end
143
-
144
- assert_equal('Liquid syntax error (line 4): Unexpected character = in "1 =! 2"', err.message)
145
- end
146
-
147
- def test_syntax_errors_in_nested_blocks_have_correct_line_number
148
- err = assert_raises(SyntaxError) do
149
- Liquid::Template.parse('
150
- foobar
151
-
152
- {% if 1 != 2 %}
153
- {% foo %}
154
- {% endif %}
155
-
156
- bla
157
- ',
158
- line_numbers: true)
159
- end
160
-
161
- assert_equal("Liquid syntax error (line 5): Unknown tag 'foo'", err.message)
162
- end
163
-
164
- def test_strict_error_messages
165
- err = assert_raises(SyntaxError) do
166
- Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ', error_mode: :strict)
167
- end
168
- assert_equal('Liquid syntax error: Unexpected character = in "1 =! 2"', err.message)
169
-
170
- err = assert_raises(SyntaxError) do
171
- Liquid::Template.parse('{{%%%}}', error_mode: :strict)
172
- end
173
- assert_equal('Liquid syntax error: Unexpected character % in "{{%%%}}"', err.message)
174
- end
175
-
176
- def test_warnings
177
- template = Liquid::Template.parse('{% if ~~~ %}{{%%%}}{% else %}{{ hello. }}{% endif %}', error_mode: :warn)
178
- assert_equal(3, template.warnings.size)
179
- assert_equal('Unexpected character ~ in "~~~"', template.warnings[0].to_s(false))
180
- assert_equal('Unexpected character % in "{{%%%}}"', template.warnings[1].to_s(false))
181
- assert_equal('Expected id but found end_of_string in "{{ hello. }}"', template.warnings[2].to_s(false))
182
- assert_equal('', template.render)
183
- end
184
-
185
- def test_warning_line_numbers
186
- template = Liquid::Template.parse("{% if ~~~ %}\n{{%%%}}{% else %}\n{{ hello. }}{% endif %}", error_mode: :warn, line_numbers: true)
187
- assert_equal('Liquid syntax error (line 1): Unexpected character ~ in "~~~"', template.warnings[0].message)
188
- assert_equal('Liquid syntax error (line 2): Unexpected character % in "{{%%%}}"', template.warnings[1].message)
189
- assert_equal('Liquid syntax error (line 3): Expected id but found end_of_string in "{{ hello. }}"', template.warnings[2].message)
190
- assert_equal(3, template.warnings.size)
191
- assert_equal([1, 2, 3], template.warnings.map(&:line_number))
192
- end
193
-
194
- # Liquid should not catch Exceptions that are not subclasses of StandardError, like Interrupt and NoMemoryError
195
- def test_exceptions_propagate
196
- assert_raises(Exception) do
197
- template = Liquid::Template.parse('{{ errors.exception }}')
198
- template.render('errors' => ErrorDrop.new)
199
- end
200
- end
201
-
202
- def test_default_exception_renderer_with_internal_error
203
- template = Liquid::Template.parse('This is a runtime error: {{ errors.runtime_error }}', line_numbers: true)
204
-
205
- output = template.render('errors' => ErrorDrop.new)
206
-
207
- assert_equal('This is a runtime error: Liquid error (line 1): internal', output)
208
- assert_equal([Liquid::InternalError], template.errors.map(&:class))
209
- end
210
-
211
- def test_setting_default_exception_renderer
212
- old_exception_renderer = Liquid::Template.default_exception_renderer
213
- exceptions = []
214
- Liquid::Template.default_exception_renderer = ->(e) {
215
- exceptions << e
216
- ''
217
- }
218
- template = Liquid::Template.parse('This is a runtime error: {{ errors.argument_error }}')
219
-
220
- output = template.render('errors' => ErrorDrop.new)
221
-
222
- assert_equal('This is a runtime error: ', output)
223
- assert_equal([Liquid::ArgumentError], template.errors.map(&:class))
224
- ensure
225
- Liquid::Template.default_exception_renderer = old_exception_renderer if old_exception_renderer
226
- end
227
-
228
- def test_exception_renderer_exposing_non_liquid_error
229
- template = Liquid::Template.parse('This is a runtime error: {{ errors.runtime_error }}', line_numbers: true)
230
- exceptions = []
231
- handler = ->(e) {
232
- exceptions << e
233
- e.cause
234
- }
235
-
236
- output = template.render({ 'errors' => ErrorDrop.new }, exception_renderer: handler)
237
-
238
- assert_equal('This is a runtime error: runtime error', output)
239
- assert_equal([Liquid::InternalError], exceptions.map(&:class))
240
- assert_equal(exceptions, template.errors)
241
- assert_equal('#<RuntimeError: runtime error>', exceptions.first.cause.inspect)
242
- end
243
-
244
- class TestFileSystem
245
- def read_template_file(_template_path)
246
- "{{ errors.argument_error }}"
247
- end
248
- end
249
-
250
- def test_included_template_name_with_line_numbers
251
- old_file_system = Liquid::Template.file_system
252
-
253
- begin
254
- Liquid::Template.file_system = TestFileSystem.new
255
-
256
- template = Liquid::Template.parse("Argument error:\n{% include 'product' %}", line_numbers: true)
257
- page = template.render('errors' => ErrorDrop.new)
258
- ensure
259
- Liquid::Template.file_system = old_file_system
260
- end
261
- assert_equal("Argument error:\nLiquid error (product line 1): argument error", page)
262
- assert_equal("product", template.errors.first.template_name)
263
- end
264
-
265
- def test_bug_compatible_silencing_of_errors_in_blank_nodes
266
- output = Liquid::Template.parse("{% assign x = 0 %}{% if 1 < '2' %}not blank{% assign x = 3 %}{% endif %}{{ x }}").render
267
- assert_equal("Liquid error: comparison of Integer with String failed0", output)
268
-
269
- output = Liquid::Template.parse("{% assign x = 0 %}{% if 1 < '2' %}{% assign x = 3 %}{% endif %}{{ x }}").render
270
- assert_equal("0", output)
271
- end
272
- end
@@ -1,46 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
-
5
- class ExpressionTest < Minitest::Test
6
- def test_keyword_literals
7
- assert_equal(true, parse_and_eval("true"))
8
- assert_equal(true, parse_and_eval(" true "))
9
- end
10
-
11
- def test_string
12
- assert_equal("single quoted", parse_and_eval("'single quoted'"))
13
- assert_equal("double quoted", parse_and_eval('"double quoted"'))
14
- assert_equal("spaced", parse_and_eval(" 'spaced' "))
15
- assert_equal("spaced2", parse_and_eval(' "spaced2" '))
16
- end
17
-
18
- def test_int
19
- assert_equal(123, parse_and_eval("123"))
20
- assert_equal(456, parse_and_eval(" 456 "))
21
- assert_equal(12, parse_and_eval("012"))
22
- end
23
-
24
- def test_float
25
- assert_equal(1.5, parse_and_eval("1.5"))
26
- assert_equal(2.5, parse_and_eval(" 2.5 "))
27
- end
28
-
29
- def test_range
30
- assert_equal(1..2, parse_and_eval("(1..2)"))
31
- assert_equal(3..4, parse_and_eval(" ( 3 .. 4 ) "))
32
- end
33
-
34
- private
35
-
36
- def parse_and_eval(markup, **assigns)
37
- if Liquid::Template.error_mode == :strict
38
- p = Liquid::Parser.new(markup)
39
- markup = p.expression
40
- p.consume(:end_of_string)
41
- end
42
- expression = Liquid::Expression.parse(markup)
43
- context = Liquid::Context.new(assigns)
44
- context.evaluate(expression)
45
- end
46
- end