Skip to content

Commit 807d45a

Browse files
committed
Surface blank-body inline errors in strict2
Keep the historical blank-body inline-error suppression for lax and strict parse modes, but stop suppressing the rendered error text when the template was parsed in strict2. Raised-error rendering continues to raise in all modes. Store the resolved template error mode on the render context while a template renders so BlockBody can distinguish strict2 from compatibility modes when deciding whether a blank tag should hide inline error text. Add integration coverage for lax/strict suppression, strict2 non-suppression across blank body forms, nonblank bodies, and raised-error behavior.
1 parent 7a5e45f commit 807d45a

3 files changed

Lines changed: 97 additions & 1 deletion

File tree

lib/liquid/block_body.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,9 @@ def self.rescue_render_node(context, output, line_number, exc, blank_tag)
9999
context.handle_error(exc, line_number)
100100
else
101101
error_message = context.handle_error(exc, line_number)
102-
unless blank_tag # conditional for backwards compatibility
102+
error_mode = context.registers.static[:template_error_mode]
103+
suppress_error_text = blank_tag && error_mode != :strict2 && error_mode != :rigid
104+
unless suppress_error_text # blank-tag suppression is kept for backwards compatibility outside strict2
103105
output << error_message
104106
end
105107
end

lib/liquid/template.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,12 +189,20 @@ def render(*args)
189189

190190
context.template_name ||= name
191191

192+
previous_error_mode = context.registers.static[:template_error_mode]
193+
context.registers.static[:template_error_mode] = @error_mode
194+
192195
begin
193196
# render the nodelist.
194197
@root.render_to_output_buffer(context, output || +'')
195198
rescue Liquid::MemoryError => e
196199
context.handle_error(e)
197200
ensure
201+
if previous_error_mode
202+
context.registers.static[:template_error_mode] = previous_error_mode
203+
else
204+
context.registers.static.delete(:template_error_mode)
205+
end
198206
@errors = context.errors
199207
end
200208
end
@@ -226,6 +234,7 @@ def configure_options(options)
226234
end
227235

228236
@warnings = parse_context.warnings
237+
@error_mode = parse_context.error_mode
229238
parse_context
230239
end
231240

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# frozen_string_literal: true
2+
3+
require 'test_helper'
4+
5+
class BlankBodyErrorHandlingTest < Minitest::Test
6+
COMPARISON_ERROR = 'Liquid error (line 1): comparison of Integer with String failed'
7+
INVALID_INTEGER_ERROR = 'Liquid error (line 1): invalid integer'
8+
9+
def render_inline(source, error_mode:, assigns: {})
10+
Liquid::Template.parse(source, line_numbers: true, error_mode: error_mode).render(assigns, render_errors: true)
11+
end
12+
13+
def assert_render_raises(source, error_mode:, assigns: {}, message: nil)
14+
error = assert_raises(Liquid::ArgumentError) do
15+
Liquid::Template.parse(source, line_numbers: true, error_mode: error_mode).render!(assigns)
16+
end
17+
assert_includes error.message, message if message
18+
end
19+
20+
def test_blank_if_body_suppresses_inline_error_text_in_lax_and_strict
21+
[:lax, :strict].each do |mode|
22+
assert_equal '', render_inline('{% if 5 > "x" %}{% endif %}', error_mode: mode)
23+
end
24+
end
25+
26+
def test_blank_unless_body_suppresses_inline_error_text_in_lax_and_strict
27+
[:lax, :strict].each do |mode|
28+
assert_equal '', render_inline('{% unless 5 > "x" %} {% endunless %}', error_mode: mode)
29+
end
30+
end
31+
32+
def test_blank_for_body_suppresses_inline_error_text_in_lax_and_strict
33+
[:lax, :strict].each do |mode|
34+
assert_equal '', render_inline('{% for i in (1..3) offset: xs %}{% endfor %}', error_mode: mode, assigns: { 'xs' => 'bad' })
35+
end
36+
end
37+
38+
def test_strict2_blank_if_body_shows_inline_error_text
39+
assert_equal COMPARISON_ERROR, render_inline('{% if 5 > "x" %}{% endif %}', error_mode: :strict2)
40+
end
41+
42+
def test_strict2_whitespace_if_body_shows_inline_error_text
43+
assert_equal COMPARISON_ERROR, render_inline('{% if 5 > "x" %} {% endif %}', error_mode: :strict2)
44+
end
45+
46+
def test_strict2_assign_if_body_shows_inline_error_text
47+
assert_equal COMPARISON_ERROR, render_inline('{% if 5 > "x" %}{% assign a = 1 %}{% endif %}', error_mode: :strict2)
48+
end
49+
50+
def test_strict2_comment_if_body_shows_inline_error_text
51+
assert_equal COMPARISON_ERROR, render_inline('{% if 5 > "x" %}{% comment %}c{% endcomment %}{% endif %}', error_mode: :strict2)
52+
end
53+
54+
def test_strict2_capture_if_body_shows_inline_error_text
55+
assert_equal COMPARISON_ERROR, render_inline('{% if 5 > "x" %}{% capture c %}text{% endcapture %}{% endif %}', error_mode: :strict2)
56+
end
57+
58+
def test_strict2_blank_unless_body_shows_inline_error_text
59+
assert_equal COMPARISON_ERROR, render_inline('{% unless 5 > "x" %} {% endunless %}', error_mode: :strict2)
60+
end
61+
62+
def test_strict2_blank_for_body_shows_inline_error_text
63+
assert_equal INVALID_INTEGER_ERROR, render_inline('{% for i in (1..3) offset: xs %}{% endfor %}', error_mode: :strict2, assigns: { 'xs' => 'bad' })
64+
end
65+
66+
def test_nonblank_bodies_show_inline_error_text_in_all_modes
67+
[:lax, :strict, :strict2].each do |mode|
68+
assert_equal COMPARISON_ERROR, render_inline('{% if 5 > "x" %}{% echo 1 %}{% endif %}', error_mode: mode)
69+
assert_equal COMPARISON_ERROR, render_inline('{% if 5 > "x" %}{{ "" }}{% endif %}', error_mode: mode)
70+
assert_equal COMPARISON_ERROR, render_inline('{% if 5 > "x" %}{% else %}E{% endif %}', error_mode: mode)
71+
end
72+
end
73+
74+
def test_raised_errors_are_not_swallowed_by_blank_if_body
75+
[:lax, :strict, :strict2].each do |mode|
76+
assert_render_raises('{% if 5 > "x" %}{% endif %}', error_mode: mode, message: 'comparison of Integer with String failed')
77+
end
78+
end
79+
80+
def test_raised_errors_are_not_swallowed_by_blank_for_body
81+
[:lax, :strict, :strict2].each do |mode|
82+
assert_render_raises('{% for i in (1..3) offset: xs %}{% endfor %}', error_mode: mode, assigns: { 'xs' => 'bad' }, message: 'invalid integer')
83+
end
84+
end
85+
end

0 commit comments

Comments
 (0)