liquid 3.0.0.rc1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +4 -0
  3. data/README.md +2 -2
  4. data/lib/liquid.rb +8 -0
  5. data/lib/liquid/block.rb +50 -46
  6. data/lib/liquid/block_body.rb +123 -0
  7. data/lib/liquid/condition.rb +12 -5
  8. data/lib/liquid/context.rb +75 -148
  9. data/lib/liquid/errors.rb +50 -2
  10. data/lib/liquid/expression.rb +33 -0
  11. data/lib/liquid/parser_switching.rb +31 -0
  12. data/lib/liquid/profiler.rb +159 -0
  13. data/lib/liquid/profiler/hooks.rb +23 -0
  14. data/lib/liquid/range_lookup.rb +22 -0
  15. data/lib/liquid/standardfilters.rb +29 -4
  16. data/lib/liquid/tag.rb +6 -25
  17. data/lib/liquid/tags/assign.rb +2 -1
  18. data/lib/liquid/tags/case.rb +1 -1
  19. data/lib/liquid/tags/if.rb +5 -5
  20. data/lib/liquid/tags/ifchanged.rb +1 -1
  21. data/lib/liquid/tags/include.rb +11 -1
  22. data/lib/liquid/tags/raw.rb +1 -4
  23. data/lib/liquid/tags/table_row.rb +1 -1
  24. data/lib/liquid/template.rb +55 -4
  25. data/lib/liquid/token.rb +18 -0
  26. data/lib/liquid/variable.rb +68 -41
  27. data/lib/liquid/variable_lookup.rb +78 -0
  28. data/lib/liquid/version.rb +1 -1
  29. data/test/integration/assign_test.rb +12 -1
  30. data/test/integration/blank_test.rb +1 -1
  31. data/test/integration/capture_test.rb +1 -1
  32. data/test/integration/context_test.rb +10 -11
  33. data/test/integration/drop_test.rb +29 -3
  34. data/test/integration/error_handling_test.rb +138 -41
  35. data/test/integration/filter_test.rb +7 -7
  36. data/test/integration/hash_ordering_test.rb +6 -8
  37. data/test/integration/output_test.rb +1 -1
  38. data/test/integration/parsing_quirks_test.rb +40 -18
  39. data/test/integration/render_profiling_test.rb +154 -0
  40. data/test/integration/security_test.rb +1 -1
  41. data/test/integration/standard_filter_test.rb +47 -1
  42. data/test/integration/tags/break_tag_test.rb +1 -1
  43. data/test/integration/tags/continue_tag_test.rb +1 -1
  44. data/test/integration/tags/for_tag_test.rb +2 -2
  45. data/test/integration/tags/if_else_tag_test.rb +23 -20
  46. data/test/integration/tags/include_tag_test.rb +24 -2
  47. data/test/integration/tags/increment_tag_test.rb +1 -1
  48. data/test/integration/tags/raw_tag_test.rb +1 -1
  49. data/test/integration/tags/standard_tag_test.rb +4 -4
  50. data/test/integration/tags/statements_test.rb +1 -1
  51. data/test/integration/tags/table_row_test.rb +1 -1
  52. data/test/integration/tags/unless_else_tag_test.rb +1 -1
  53. data/test/integration/template_test.rb +16 -4
  54. data/test/integration/variable_test.rb +11 -1
  55. data/test/test_helper.rb +59 -31
  56. data/test/unit/block_unit_test.rb +2 -5
  57. data/test/unit/condition_unit_test.rb +5 -1
  58. data/test/unit/context_unit_test.rb +13 -7
  59. data/test/unit/file_system_unit_test.rb +5 -5
  60. data/test/unit/i18n_unit_test.rb +3 -3
  61. data/test/unit/lexer_unit_test.rb +1 -1
  62. data/test/unit/module_ex_unit_test.rb +1 -1
  63. data/test/unit/parser_unit_test.rb +1 -1
  64. data/test/unit/regexp_unit_test.rb +1 -1
  65. data/test/unit/strainer_unit_test.rb +3 -2
  66. data/test/unit/tag_unit_test.rb +6 -1
  67. data/test/unit/tags/case_tag_unit_test.rb +1 -1
  68. data/test/unit/tags/for_tag_unit_test.rb +1 -1
  69. data/test/unit/tags/if_tag_unit_test.rb +1 -1
  70. data/test/unit/template_unit_test.rb +1 -1
  71. data/test/unit/tokenizer_unit_test.rb +10 -1
  72. data/test/unit/variable_unit_test.rb +49 -46
  73. metadata +71 -47
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Liquid
3
- VERSION = "3.0.0.rc1"
3
+ VERSION = "3.0.0"
4
4
  end
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class AssignTest < Test::Unit::TestCase
3
+ class AssignTest < Minitest::Test
4
4
  include Liquid
5
5
 
6
6
  def test_assigned_variable
@@ -24,4 +24,15 @@ class AssignTest < Test::Unit::TestCase
24
24
  '{% assign foo not values %}.',
25
25
  'values' => "foo,bar,baz")
26
26
  end
27
+
28
+ def test_assign_uses_error_mode
29
+ with_error_mode(:strict) do
30
+ assert_raises(SyntaxError) do
31
+ Template.parse("{% assign foo = ('X' | downcase) %}")
32
+ end
33
+ end
34
+ with_error_mode(:lax) do
35
+ assert Template.parse("{% assign foo = ('X' | downcase) %}")
36
+ end
37
+ end
27
38
  end # AssignTest
@@ -14,7 +14,7 @@ class BlankTestFileSystem
14
14
  end
15
15
  end
16
16
 
17
- class BlankTest < Test::Unit::TestCase
17
+ class BlankTest < Minitest::Test
18
18
  include Liquid
19
19
  N = 10
20
20
 
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class CaptureTest < Test::Unit::TestCase
3
+ class CaptureTest < Minitest::Test
4
4
  include Liquid
5
5
 
6
6
  def test_captures_block_content_in_variable
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class ContextTest < Test::Unit::TestCase
3
+ class ContextTest < Minitest::Test
4
4
  include Liquid
5
5
 
6
6
  def test_override_global_filter
@@ -16,18 +16,17 @@ class ContextTest < Test::Unit::TestCase
16
16
  end
17
17
  end
18
18
 
19
- Template.register_filter(global)
20
- assert_equal 'Global test', Template.parse("{{'test' | notice }}").render!
21
- assert_equal 'Local test', Template.parse("{{'test' | notice }}").render!({}, :filters => [local])
19
+ with_global_filter(global) do
20
+ assert_equal 'Global test', Template.parse("{{'test' | notice }}").render!
21
+ assert_equal 'Local test', Template.parse("{{'test' | notice }}").render!({}, :filters => [local])
22
+ end
22
23
  end
23
24
 
24
25
  def test_has_key_will_not_add_an_error_for_missing_keys
25
- Template.error_mode = :strict
26
-
27
- context = Context.new
28
-
29
- context.has_key?('unknown')
30
-
31
- assert_empty context.errors
26
+ with_error_mode :strict do
27
+ context = Context.new
28
+ context.has_key?('unknown')
29
+ assert_empty context.errors
30
+ end
32
31
  end
33
32
  end
@@ -48,6 +48,10 @@ class ProductDrop < Liquid::Drop
48
48
  ContextDrop.new
49
49
  end
50
50
 
51
+ def user_input
52
+ "foo".taint
53
+ end
54
+
51
55
  protected
52
56
  def callmenot
53
57
  "protected"
@@ -100,12 +104,34 @@ class RealEnumerableDrop < Liquid::Drop
100
104
  end
101
105
  end
102
106
 
103
- class DropsTest < Test::Unit::TestCase
107
+ class DropsTest < Minitest::Test
104
108
  include Liquid
105
109
 
106
110
  def test_product_drop
107
- assert_nothing_raised do
108
- tpl = Liquid::Template.parse( ' ' )
111
+ tpl = Liquid::Template.parse(' ')
112
+ assert_equal ' ', tpl.render!('product' => ProductDrop.new)
113
+ end
114
+
115
+ def test_rendering_raises_on_tainted_attr
116
+ with_taint_mode(:error) do
117
+ tpl = Liquid::Template.parse('{{ product.user_input }}')
118
+ assert_raises TaintedError do
119
+ tpl.render!('product' => ProductDrop.new)
120
+ end
121
+ end
122
+ end
123
+
124
+ def test_rendering_warns_on_tainted_attr
125
+ with_taint_mode(:warn) do
126
+ tpl = Liquid::Template.parse('{{ product.user_input }}')
127
+ tpl.render!('product' => ProductDrop.new)
128
+ assert_match /tainted/, tpl.warnings.first
129
+ end
130
+ end
131
+
132
+ def test_rendering_doesnt_raise_on_escaped_tainted_attr
133
+ with_taint_mode(:error) do
134
+ tpl = Liquid::Template.parse('{{ product.user_input | escape }}')
109
135
  tpl.render!('product' => ProductDrop.new)
110
136
  end
111
137
  end
@@ -19,92 +19,189 @@ class ErrorDrop < Liquid::Drop
19
19
 
20
20
  end
21
21
 
22
- class ErrorHandlingTest < Test::Unit::TestCase
22
+ class ErrorHandlingTest < Minitest::Test
23
23
  include Liquid
24
24
 
25
- def test_standard_error
26
- assert_nothing_raised do
27
- template = Liquid::Template.parse( ' {{ errors.standard_error }} ' )
28
- assert_equal ' Liquid error: standard error ', template.render('errors' => ErrorDrop.new)
25
+ def test_templates_parsed_with_line_numbers_renders_them_in_errors
26
+ template = <<-LIQUID
27
+ Hello,
29
28
 
30
- assert_equal 1, template.errors.size
31
- assert_equal StandardError, template.errors.first.class
32
- end
33
- end
29
+ {{ errors.standard_error }} will raise a standard error.
34
30
 
35
- def test_syntax
31
+ Bla bla test.
36
32
 
37
- assert_nothing_raised do
33
+ {{ errors.syntax_error }} will raise a syntax error.
38
34
 
39
- template = Liquid::Template.parse( ' {{ errors.syntax_error }} ' )
40
- assert_equal ' Liquid syntax error: syntax error ', template.render('errors' => ErrorDrop.new)
35
+ This is an argument error: {{ errors.argument_error }}
41
36
 
42
- assert_equal 1, template.errors.size
43
- assert_equal SyntaxError, template.errors.first.class
37
+ Bla.
38
+ LIQUID
44
39
 
45
- end
40
+ expected = <<-TEXT
41
+ Hello,
42
+
43
+ Liquid error (line 3): standard error will raise a standard error.
44
+
45
+ Bla bla test.
46
+
47
+ Liquid syntax error (line 7): syntax error will raise a syntax error.
48
+
49
+ This is an argument error: Liquid error (line 9): argument error
50
+
51
+ Bla.
52
+ TEXT
53
+
54
+ output = Liquid::Template.parse(template, line_numbers: true).render('errors' => ErrorDrop.new)
55
+ assert_equal expected, output
46
56
  end
47
57
 
48
- def test_argument
49
- assert_nothing_raised do
58
+ def test_standard_error
59
+ template = Liquid::Template.parse( ' {{ errors.standard_error }} ' )
60
+ assert_equal ' Liquid error: standard error ', template.render('errors' => ErrorDrop.new)
50
61
 
51
- template = Liquid::Template.parse( ' {{ errors.argument_error }} ' )
52
- assert_equal ' Liquid error: argument error ', template.render('errors' => ErrorDrop.new)
62
+ assert_equal 1, template.errors.size
63
+ assert_equal StandardError, template.errors.first.class
64
+ end
53
65
 
54
- assert_equal 1, template.errors.size
55
- assert_equal ArgumentError, template.errors.first.class
56
- end
66
+ def test_syntax
67
+ template = Liquid::Template.parse( ' {{ errors.syntax_error }} ' )
68
+ assert_equal ' Liquid syntax error: syntax error ', template.render('errors' => ErrorDrop.new)
69
+
70
+ assert_equal 1, template.errors.size
71
+ assert_equal SyntaxError, template.errors.first.class
72
+ end
73
+
74
+ def test_argument
75
+ template = Liquid::Template.parse( ' {{ errors.argument_error }} ' )
76
+ assert_equal ' Liquid error: argument error ', template.render('errors' => ErrorDrop.new)
77
+
78
+ assert_equal 1, template.errors.size
79
+ assert_equal ArgumentError, template.errors.first.class
57
80
  end
58
81
 
59
82
  def test_missing_endtag_parse_time_error
60
- assert_raise(Liquid::SyntaxError) do
83
+ assert_raises(Liquid::SyntaxError) do
61
84
  Liquid::Template.parse(' {% for a in b %} ... ')
62
85
  end
63
86
  end
64
87
 
65
88
  def test_unrecognized_operator
66
89
  with_error_mode(:strict) do
67
- assert_raise(SyntaxError) do
90
+ assert_raises(SyntaxError) do
68
91
  Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ')
69
92
  end
70
93
  end
71
94
  end
72
-
95
+
73
96
  def test_lax_unrecognized_operator
74
- assert_nothing_raised do
75
- template = Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ', :error_mode => :lax)
76
- assert_equal ' Liquid error: Unknown operator =! ', template.render
77
- assert_equal 1, template.errors.size
78
- assert_equal Liquid::ArgumentError, template.errors.first.class
97
+ template = Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ', :error_mode => :lax)
98
+ assert_equal ' Liquid error: Unknown operator =! ', template.render
99
+ assert_equal 1, template.errors.size
100
+ assert_equal Liquid::ArgumentError, template.errors.first.class
101
+ end
102
+
103
+ def test_with_line_numbers_adds_numbers_to_parser_errors
104
+ err = assert_raises(SyntaxError) do
105
+ template = Liquid::Template.parse(%q{
106
+ foobar
107
+
108
+ {% "cat" | foobar %}
109
+
110
+ bla
111
+ },
112
+ :line_numbers => true
113
+ )
114
+ end
115
+
116
+ assert_match /Liquid syntax error \(line 4\)/, err.message
117
+ end
118
+
119
+ def test_parsing_warn_with_line_numbers_adds_numbers_to_lexer_errors
120
+ template = Liquid::Template.parse(%q{
121
+ foobar
122
+
123
+ {% if 1 =! 2 %}ok{% endif %}
124
+
125
+ bla
126
+ },
127
+ :error_mode => :warn,
128
+ :line_numbers => true
129
+ )
130
+
131
+ assert_equal ['Liquid syntax error (line 4): Unexpected character = in "1 =! 2"'],
132
+ template.warnings.map(&:message)
133
+ end
134
+
135
+ def test_parsing_strict_with_line_numbers_adds_numbers_to_lexer_errors
136
+ err = assert_raises(SyntaxError) do
137
+ Liquid::Template.parse(%q{
138
+ foobar
139
+
140
+ {% if 1 =! 2 %}ok{% endif %}
141
+
142
+ bla
143
+ },
144
+ :error_mode => :strict,
145
+ :line_numbers => true
146
+ )
147
+ end
148
+
149
+ assert_equal 'Liquid syntax error (line 4): Unexpected character = in "1 =! 2"', err.message
150
+ end
151
+
152
+ def test_syntax_errors_in_nested_blocks_have_correct_line_number
153
+ err = assert_raises(SyntaxError) do
154
+ Liquid::Template.parse(%q{
155
+ foobar
156
+
157
+ {% if 1 != 2 %}
158
+ {% foo %}
159
+ {% endif %}
160
+
161
+ bla
162
+ },
163
+ :line_numbers => true
164
+ )
79
165
  end
166
+
167
+ assert_equal "Liquid syntax error (line 5): Unknown tag 'foo'", err.message
80
168
  end
81
169
 
82
170
  def test_strict_error_messages
83
- err = assert_raise(SyntaxError) do
171
+ err = assert_raises(SyntaxError) do
84
172
  Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ', :error_mode => :strict)
85
173
  end
86
- assert_equal 'Unexpected character = in "1 =! 2"', err.message
174
+ assert_equal 'Liquid syntax error: Unexpected character = in "1 =! 2"', err.message
87
175
 
88
- err = assert_raise(SyntaxError) do
176
+ err = assert_raises(SyntaxError) do
89
177
  Liquid::Template.parse('{{%%%}}', :error_mode => :strict)
90
178
  end
91
- assert_equal 'Unexpected character % in "{{%%%}}"', err.message
179
+ assert_equal 'Liquid syntax error: Unexpected character % in "{{%%%}}"', err.message
92
180
  end
93
181
 
94
182
  def test_warnings
95
183
  template = Liquid::Template.parse('{% if ~~~ %}{{%%%}}{% else %}{{ hello. }}{% endif %}', :error_mode => :warn)
96
184
  assert_equal 3, template.warnings.size
97
- assert_equal 'Unexpected character ~ in "~~~"', template.warnings[0].message
98
- assert_equal 'Unexpected character % in "{{%%%}}"', template.warnings[1].message
99
- assert_equal 'Expected id but found end_of_string in "{{ hello. }}"', template.warnings[2].message
185
+ assert_equal 'Unexpected character ~ in "~~~"', template.warnings[0].to_s(false)
186
+ assert_equal 'Unexpected character % in "{{%%%}}"', template.warnings[1].to_s(false)
187
+ assert_equal 'Expected id but found end_of_string in "{{ hello. }}"', template.warnings[2].to_s(false)
100
188
  assert_equal '', template.render
101
189
  end
102
190
 
191
+ def test_warning_line_numbers
192
+ template = Liquid::Template.parse("{% if ~~~ %}\n{{%%%}}{% else %}\n{{ hello. }}{% endif %}", :error_mode => :warn, :line_numbers => true)
193
+ assert_equal 'Liquid syntax error (line 1): Unexpected character ~ in "~~~"', template.warnings[0].message
194
+ assert_equal 'Liquid syntax error (line 2): Unexpected character % in "{{%%%}}"', template.warnings[1].message
195
+ assert_equal 'Liquid syntax error (line 3): Expected id but found end_of_string in "{{ hello. }}"', template.warnings[2].message
196
+ assert_equal 3, template.warnings.size
197
+ assert_equal [1,2,3], template.warnings.map(&:line_number)
198
+ end
199
+
103
200
  # Liquid should not catch Exceptions that are not subclasses of StandardError, like Interrupt and NoMemoryError
104
201
  def test_exceptions_propagate
105
- assert_raise Exception do
106
- template = Liquid::Template.parse( ' {{ errors.exception }} ' )
202
+ assert_raises Exception do
203
+ template = Liquid::Template.parse('{{ errors.exception }}')
107
204
  template.render('errors' => ErrorDrop.new)
108
205
  end
109
206
  end
110
- end # ErrorHandlingTest
207
+ end
@@ -22,7 +22,7 @@ module SubstituteFilter
22
22
  end
23
23
  end
24
24
 
25
- class FiltersTest < Test::Unit::TestCase
25
+ class FiltersTest < Minitest::Test
26
26
  include Liquid
27
27
 
28
28
  def setup
@@ -107,15 +107,15 @@ class FiltersTest < Test::Unit::TestCase
107
107
  end
108
108
  end
109
109
 
110
- class FiltersInTemplate < Test::Unit::TestCase
110
+ class FiltersInTemplate < Minitest::Test
111
111
  include Liquid
112
112
 
113
113
  def test_local_global
114
- Template.register_filter(MoneyFilter)
115
-
116
- assert_equal " 1000$ ", Template.parse("{{1000 | money}}").render!(nil, nil)
117
- assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, :filters => CanadianMoneyFilter)
118
- assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, :filters => [CanadianMoneyFilter])
114
+ with_global_filter(MoneyFilter) do
115
+ assert_equal " 1000$ ", Template.parse("{{1000 | money}}").render!(nil, nil)
116
+ assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, :filters => CanadianMoneyFilter)
117
+ assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, :filters => [CanadianMoneyFilter])
118
+ end
119
119
  end
120
120
 
121
121
  def test_local_filter_with_deprecated_syntax
@@ -12,14 +12,12 @@ module CanadianMoneyFilter
12
12
  end
13
13
  end
14
14
 
15
- class HashOrderingTest < Test::Unit::TestCase
15
+ class HashOrderingTest < Minitest::Test
16
16
  include Liquid
17
17
 
18
- def test_global_register_order
19
- Template.register_filter(MoneyFilter)
20
- Template.register_filter(CanadianMoneyFilter)
21
-
22
- assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render(nil, nil)
23
- end
24
-
18
+ def test_global_register_order
19
+ with_global_filter(MoneyFilter, CanadianMoneyFilter) do
20
+ assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render(nil, nil)
21
+ end
22
+ end
25
23
  end
@@ -27,7 +27,7 @@ module FunnyFilter
27
27
 
28
28
  end
29
29
 
30
- class OutputTest < Test::Unit::TestCase
30
+ class OutputTest < Minitest::Test
31
31
  include Liquid
32
32
 
33
33
  def setup
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class ParsingQuirksTest < Test::Unit::TestCase
3
+ class ParsingQuirksTest < Minitest::Test
4
4
  include Liquid
5
5
 
6
6
  def test_parsing_css
@@ -9,30 +9,28 @@ class ParsingQuirksTest < Test::Unit::TestCase
9
9
  end
10
10
 
11
11
  def test_raise_on_single_close_bracet
12
- assert_raise(SyntaxError) do
12
+ assert_raises(SyntaxError) do
13
13
  Template.parse("text {{method} oh nos!")
14
14
  end
15
15
  end
16
16
 
17
17
  def test_raise_on_label_and_no_close_bracets
18
- assert_raise(SyntaxError) do
18
+ assert_raises(SyntaxError) do
19
19
  Template.parse("TEST {{ ")
20
20
  end
21
21
  end
22
22
 
23
23
  def test_raise_on_label_and_no_close_bracets_percent
24
- assert_raise(SyntaxError) do
24
+ assert_raises(SyntaxError) do
25
25
  Template.parse("TEST {% ")
26
26
  end
27
27
  end
28
28
 
29
29
  def test_error_on_empty_filter
30
- assert_nothing_raised do
31
- Template.parse("{{test}}")
32
- Template.parse("{{|test}}")
33
- end
30
+ assert Template.parse("{{test}}")
31
+ assert Template.parse("{{|test}}")
34
32
  with_error_mode(:strict) do
35
- assert_raise(SyntaxError) do
33
+ assert_raises(SyntaxError) do
36
34
  Template.parse("{{test |a|b|}}")
37
35
  end
38
36
  end
@@ -40,7 +38,7 @@ class ParsingQuirksTest < Test::Unit::TestCase
40
38
 
41
39
  def test_meaningless_parens_error
42
40
  with_error_mode(:strict) do
43
- assert_raise(SyntaxError) do
41
+ assert_raises(SyntaxError) do
44
42
  markup = "a == 'foo' or (b == 'bar' and c == 'baz') or false"
45
43
  Template.parse("{% if #{markup} %} YES {% endif %}")
46
44
  end
@@ -49,11 +47,11 @@ class ParsingQuirksTest < Test::Unit::TestCase
49
47
 
50
48
  def test_unexpected_characters_syntax_error
51
49
  with_error_mode(:strict) do
52
- assert_raise(SyntaxError) do
50
+ assert_raises(SyntaxError) do
53
51
  markup = "true && false"
54
52
  Template.parse("{% if #{markup} %} YES {% endif %}")
55
53
  end
56
- assert_raise(SyntaxError) do
54
+ assert_raises(SyntaxError) do
57
55
  markup = "false || true"
58
56
  Template.parse("{% if #{markup} %} YES {% endif %}")
59
57
  end
@@ -61,11 +59,9 @@ class ParsingQuirksTest < Test::Unit::TestCase
61
59
  end
62
60
 
63
61
  def test_no_error_on_lax_empty_filter
64
- assert_nothing_raised do
65
- Template.parse("{{test |a|b|}}", :error_mode => :lax)
66
- Template.parse("{{test}}", :error_mode => :lax)
67
- Template.parse("{{|test|}}", :error_mode => :lax)
68
- end
62
+ assert Template.parse("{{test |a|b|}}", :error_mode => :lax)
63
+ assert Template.parse("{{test}}", :error_mode => :lax)
64
+ assert Template.parse("{{|test|}}", :error_mode => :lax)
69
65
  end
70
66
 
71
67
  def test_meaningless_parens_lax
@@ -86,9 +82,35 @@ class ParsingQuirksTest < Test::Unit::TestCase
86
82
  end
87
83
 
88
84
  def test_raise_on_invalid_tag_delimiter
89
- assert_raise(Liquid::SyntaxError) do
85
+ assert_raises(Liquid::SyntaxError) do
90
86
  Template.new.parse('{% end %}')
91
87
  end
92
88
  end
93
89
 
90
+ def test_unanchored_filter_arguments
91
+ with_error_mode(:lax) do
92
+ assert_template_result('hi',"{{ 'hi there' | split$$$:' ' | first }}")
93
+
94
+ assert_template_result('x', "{{ 'X' | downcase) }}")
95
+
96
+ # After the messed up quotes a filter without parameters (reverse) should work
97
+ # but one with parameters (remove) shouldn't be detected.
98
+ assert_template_result('here', "{{ 'hi there' | split:\"t\"\" | reverse | first}}")
99
+ assert_template_result('hi ', "{{ 'hi there' | split:\"t\"\" | remove:\"i\" | first}}")
100
+ end
101
+ end
102
+
103
+ def test_invalid_variables_work
104
+ with_error_mode(:lax) do
105
+ assert_template_result('bar', "{% assign 123foo = 'bar' %}{{ 123foo }}")
106
+ assert_template_result('123', "{% assign 123 = 'bar' %}{{ 123 }}")
107
+ end
108
+ end
109
+
110
+ def test_extra_dots_in_ranges
111
+ with_error_mode(:lax) do
112
+ assert_template_result('12345', "{% for i in (1...5) %}{{ i }}{% endfor %}")
113
+ end
114
+ end
115
+
94
116
  end # ParsingQuirksTest