liquid 2.6.3 → 3.0.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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +46 -13
  3. data/README.md +27 -2
  4. data/lib/liquid/block.rb +85 -51
  5. data/lib/liquid/block_body.rb +123 -0
  6. data/lib/liquid/condition.rb +26 -15
  7. data/lib/liquid/context.rb +106 -140
  8. data/lib/liquid/document.rb +3 -3
  9. data/lib/liquid/drop.rb +17 -1
  10. data/lib/liquid/errors.rb +50 -2
  11. data/lib/liquid/expression.rb +33 -0
  12. data/lib/liquid/file_system.rb +17 -6
  13. data/lib/liquid/i18n.rb +39 -0
  14. data/lib/liquid/interrupts.rb +1 -1
  15. data/lib/liquid/lexer.rb +51 -0
  16. data/lib/liquid/locales/en.yml +22 -0
  17. data/lib/liquid/parser.rb +90 -0
  18. data/lib/liquid/parser_switching.rb +31 -0
  19. data/lib/liquid/profiler/hooks.rb +23 -0
  20. data/lib/liquid/profiler.rb +159 -0
  21. data/lib/liquid/range_lookup.rb +22 -0
  22. data/lib/liquid/standardfilters.rb +143 -55
  23. data/lib/liquid/strainer.rb +14 -4
  24. data/lib/liquid/tag.rb +25 -9
  25. data/lib/liquid/tags/assign.rb +12 -9
  26. data/lib/liquid/tags/break.rb +1 -1
  27. data/lib/liquid/tags/capture.rb +10 -8
  28. data/lib/liquid/tags/case.rb +13 -13
  29. data/lib/liquid/tags/comment.rb +9 -2
  30. data/lib/liquid/tags/continue.rb +1 -4
  31. data/lib/liquid/tags/cycle.rb +5 -7
  32. data/lib/liquid/tags/decrement.rb +3 -4
  33. data/lib/liquid/tags/for.rb +69 -36
  34. data/lib/liquid/tags/if.rb +52 -25
  35. data/lib/liquid/tags/ifchanged.rb +3 -3
  36. data/lib/liquid/tags/include.rb +19 -8
  37. data/lib/liquid/tags/increment.rb +4 -8
  38. data/lib/liquid/tags/raw.rb +4 -7
  39. data/lib/liquid/tags/table_row.rb +73 -0
  40. data/lib/liquid/tags/unless.rb +2 -4
  41. data/lib/liquid/template.rb +124 -14
  42. data/lib/liquid/token.rb +18 -0
  43. data/lib/liquid/utils.rb +13 -4
  44. data/lib/liquid/variable.rb +103 -25
  45. data/lib/liquid/variable_lookup.rb +78 -0
  46. data/lib/liquid/version.rb +1 -1
  47. data/lib/liquid.rb +19 -11
  48. data/test/fixtures/en_locale.yml +9 -0
  49. data/test/{liquid → integration}/assign_test.rb +18 -1
  50. data/test/integration/blank_test.rb +106 -0
  51. data/test/{liquid → integration}/capture_test.rb +3 -3
  52. data/test/integration/context_test.rb +32 -0
  53. data/test/integration/drop_test.rb +271 -0
  54. data/test/integration/error_handling_test.rb +207 -0
  55. data/test/{liquid → integration}/filter_test.rb +11 -11
  56. data/test/integration/hash_ordering_test.rb +23 -0
  57. data/test/{liquid → integration}/output_test.rb +13 -13
  58. data/test/integration/parsing_quirks_test.rb +116 -0
  59. data/test/integration/render_profiling_test.rb +154 -0
  60. data/test/{liquid → integration}/security_test.rb +10 -10
  61. data/test/{liquid → integration}/standard_filter_test.rb +148 -32
  62. data/test/{liquid → integration}/tags/break_tag_test.rb +1 -1
  63. data/test/{liquid → integration}/tags/continue_tag_test.rb +1 -1
  64. data/test/{liquid → integration}/tags/for_tag_test.rb +80 -2
  65. data/test/{liquid → integration}/tags/if_else_tag_test.rb +24 -21
  66. data/test/integration/tags/include_tag_test.rb +234 -0
  67. data/test/{liquid → integration}/tags/increment_tag_test.rb +1 -1
  68. data/test/{liquid → integration}/tags/raw_tag_test.rb +2 -1
  69. data/test/{liquid → integration}/tags/standard_tag_test.rb +28 -26
  70. data/test/integration/tags/statements_test.rb +113 -0
  71. data/test/{liquid/tags/html_tag_test.rb → integration/tags/table_row_test.rb} +5 -5
  72. data/test/{liquid → integration}/tags/unless_else_tag_test.rb +1 -1
  73. data/test/{liquid → integration}/template_test.rb +81 -45
  74. data/test/integration/variable_test.rb +82 -0
  75. data/test/test_helper.rb +73 -20
  76. data/test/{liquid/block_test.rb → unit/block_unit_test.rb} +2 -5
  77. data/test/{liquid/condition_test.rb → unit/condition_unit_test.rb} +23 -1
  78. data/test/{liquid/context_test.rb → unit/context_unit_test.rb} +39 -25
  79. data/test/{liquid/file_system_test.rb → unit/file_system_unit_test.rb} +11 -5
  80. data/test/unit/i18n_unit_test.rb +37 -0
  81. data/test/unit/lexer_unit_test.rb +48 -0
  82. data/test/{liquid/module_ex_test.rb → unit/module_ex_unit_test.rb} +7 -7
  83. data/test/unit/parser_unit_test.rb +82 -0
  84. data/test/{liquid/regexp_test.rb → unit/regexp_unit_test.rb} +3 -3
  85. data/test/{liquid/strainer_test.rb → unit/strainer_unit_test.rb} +20 -1
  86. data/test/unit/tag_unit_test.rb +16 -0
  87. data/test/unit/tags/case_tag_unit_test.rb +10 -0
  88. data/test/unit/tags/for_tag_unit_test.rb +13 -0
  89. data/test/unit/tags/if_tag_unit_test.rb +8 -0
  90. data/test/unit/template_unit_test.rb +69 -0
  91. data/test/unit/tokenizer_unit_test.rb +38 -0
  92. data/test/unit/variable_unit_test.rb +139 -0
  93. metadata +135 -67
  94. data/lib/extras/liquid_view.rb +0 -51
  95. data/lib/liquid/htmltags.rb +0 -73
  96. data/test/liquid/drop_test.rb +0 -180
  97. data/test/liquid/error_handling_test.rb +0 -81
  98. data/test/liquid/hash_ordering_test.rb +0 -25
  99. data/test/liquid/parsing_quirks_test.rb +0 -52
  100. data/test/liquid/tags/include_tag_test.rb +0 -166
  101. data/test/liquid/tags/statements_test.rb +0 -134
  102. data/test/liquid/variable_test.rb +0 -186
@@ -14,86 +14,86 @@ class TemplateContextDrop < Liquid::Drop
14
14
  end
15
15
  end
16
16
 
17
- class TemplateTest < Test::Unit::TestCase
18
- include Liquid
19
-
20
- def test_tokenize_strings
21
- assert_equal [' '], Template.new.send(:tokenize, ' ')
22
- assert_equal ['hello world'], Template.new.send(:tokenize, 'hello world')
23
- end
24
-
25
- def test_tokenize_variables
26
- assert_equal ['{{funk}}'], Template.new.send(:tokenize, '{{funk}}')
27
- assert_equal [' ', '{{funk}}', ' '], Template.new.send(:tokenize, ' {{funk}} ')
28
- assert_equal [' ', '{{funk}}', ' ', '{{so}}', ' ', '{{brother}}', ' '], Template.new.send(:tokenize, ' {{funk}} {{so}} {{brother}} ')
29
- assert_equal [' ', '{{ funk }}', ' '], Template.new.send(:tokenize, ' {{ funk }} ')
17
+ class SomethingWithLength
18
+ def length
19
+ nil
30
20
  end
31
21
 
32
- def test_tokenize_blocks
33
- assert_equal ['{%comment%}'], Template.new.send(:tokenize, '{%comment%}')
34
- assert_equal [' ', '{%comment%}', ' '], Template.new.send(:tokenize, ' {%comment%} ')
22
+ liquid_methods :length
23
+ end
35
24
 
36
- assert_equal [' ', '{%comment%}', ' ', '{%endcomment%}', ' '], Template.new.send(:tokenize, ' {%comment%} {%endcomment%} ')
37
- assert_equal [' ', '{% comment %}', ' ', '{% endcomment %}', ' '], Template.new.send(:tokenize, " {% comment %} {% endcomment %} ")
25
+ class ErroneousDrop < Liquid::Drop
26
+ def bad_method
27
+ raise 'ruby error in drop'
38
28
  end
29
+ end
30
+
31
+ class TemplateTest < Minitest::Test
32
+ include Liquid
39
33
 
40
34
  def test_instance_assigns_persist_on_same_template_object_between_parses
41
35
  t = Template.new
42
- assert_equal 'from instance assigns', t.parse("{% assign foo = 'from instance assigns' %}{{ foo }}").render
43
- assert_equal 'from instance assigns', t.parse("{{ foo }}").render
36
+ assert_equal 'from instance assigns', t.parse("{% assign foo = 'from instance assigns' %}{{ foo }}").render!
37
+ assert_equal 'from instance assigns', t.parse("{{ foo }}").render!
44
38
  end
45
39
 
46
40
  def test_instance_assigns_persist_on_same_template_parsing_between_renders
47
41
  t = Template.new.parse("{{ foo }}{% assign foo = 'foo' %}{{ foo }}")
48
- assert_equal 'foo', t.render
49
- assert_equal 'foofoo', t.render
42
+ assert_equal 'foo', t.render!
43
+ assert_equal 'foofoo', t.render!
50
44
  end
51
45
 
52
46
  def test_custom_assigns_do_not_persist_on_same_template
53
47
  t = Template.new
54
- assert_equal 'from custom assigns', t.parse("{{ foo }}").render('foo' => 'from custom assigns')
55
- assert_equal '', t.parse("{{ foo }}").render
48
+ assert_equal 'from custom assigns', t.parse("{{ foo }}").render!('foo' => 'from custom assigns')
49
+ assert_equal '', t.parse("{{ foo }}").render!
56
50
  end
57
51
 
58
52
  def test_custom_assigns_squash_instance_assigns
59
53
  t = Template.new
60
- assert_equal 'from instance assigns', t.parse("{% assign foo = 'from instance assigns' %}{{ foo }}").render
61
- assert_equal 'from custom assigns', t.parse("{{ foo }}").render('foo' => 'from custom assigns')
54
+ assert_equal 'from instance assigns', t.parse("{% assign foo = 'from instance assigns' %}{{ foo }}").render!
55
+ assert_equal 'from custom assigns', t.parse("{{ foo }}").render!('foo' => 'from custom assigns')
62
56
  end
63
57
 
64
58
  def test_persistent_assigns_squash_instance_assigns
65
59
  t = Template.new
66
- assert_equal 'from instance assigns', t.parse("{% assign foo = 'from instance assigns' %}{{ foo }}").render
60
+ assert_equal 'from instance assigns', t.parse("{% assign foo = 'from instance assigns' %}{{ foo }}").render!
67
61
  t.assigns['foo'] = 'from persistent assigns'
68
- assert_equal 'from persistent assigns', t.parse("{{ foo }}").render
62
+ assert_equal 'from persistent assigns', t.parse("{{ foo }}").render!
69
63
  end
70
64
 
71
65
  def test_lambda_is_called_once_from_persistent_assigns_over_multiple_parses_and_renders
72
66
  t = Template.new
73
67
  t.assigns['number'] = lambda { @global ||= 0; @global += 1 }
74
- assert_equal '1', t.parse("{{number}}").render
75
- assert_equal '1', t.parse("{{number}}").render
76
- assert_equal '1', t.render
68
+ assert_equal '1', t.parse("{{number}}").render!
69
+ assert_equal '1', t.parse("{{number}}").render!
70
+ assert_equal '1', t.render!
77
71
  @global = nil
78
72
  end
79
73
 
80
74
  def test_lambda_is_called_once_from_custom_assigns_over_multiple_parses_and_renders
81
75
  t = Template.new
82
76
  assigns = {'number' => lambda { @global ||= 0; @global += 1 }}
83
- assert_equal '1', t.parse("{{number}}").render(assigns)
84
- assert_equal '1', t.parse("{{number}}").render(assigns)
85
- assert_equal '1', t.render(assigns)
77
+ assert_equal '1', t.parse("{{number}}").render!(assigns)
78
+ assert_equal '1', t.parse("{{number}}").render!(assigns)
79
+ assert_equal '1', t.render!(assigns)
86
80
  @global = nil
87
81
  end
88
82
 
83
+ def test_resource_limits_works_with_custom_length_method
84
+ t = Template.parse("{% assign foo = bar %}")
85
+ t.resource_limits = { :render_length_limit => 42 }
86
+ assert_equal "", t.render!("bar" => SomethingWithLength.new)
87
+ end
88
+
89
89
  def test_resource_limits_render_length
90
90
  t = Template.parse("0123456789")
91
91
  t.resource_limits = { :render_length_limit => 5 }
92
92
  assert_equal "Liquid error: Memory limits exceeded", t.render()
93
93
  assert t.resource_limits[:reached]
94
94
  t.resource_limits = { :render_length_limit => 10 }
95
- assert_equal "0123456789", t.render()
96
- assert_not_nil t.resource_limits[:render_length_current]
95
+ assert_equal "0123456789", t.render!()
96
+ refute_nil t.resource_limits[:render_length_current]
97
97
  end
98
98
 
99
99
  def test_resource_limits_render_score
@@ -106,8 +106,8 @@ class TemplateTest < Test::Unit::TestCase
106
106
  assert_equal "Liquid error: Memory limits exceeded", t.render()
107
107
  assert t.resource_limits[:reached]
108
108
  t.resource_limits = { :render_score_limit => 200 }
109
- assert_equal (" foo " * 100), t.render()
110
- assert_not_nil t.resource_limits[:render_score_current]
109
+ assert_equal (" foo " * 100), t.render!()
110
+ refute_nil t.resource_limits[:render_score_current]
111
111
  end
112
112
 
113
113
  def test_resource_limits_assign_score
@@ -116,8 +116,8 @@ class TemplateTest < Test::Unit::TestCase
116
116
  assert_equal "Liquid error: Memory limits exceeded", t.render()
117
117
  assert t.resource_limits[:reached]
118
118
  t.resource_limits = { :assign_score_limit => 2 }
119
- assert_equal "", t.render()
120
- assert_not_nil t.resource_limits[:assign_score_current]
119
+ assert_equal "", t.render!()
120
+ refute_nil t.resource_limits[:assign_score_current]
121
121
  end
122
122
 
123
123
  def test_resource_limits_aborts_rendering_after_first_error
@@ -129,18 +129,54 @@ class TemplateTest < Test::Unit::TestCase
129
129
 
130
130
  def test_resource_limits_hash_in_template_gets_updated_even_if_no_limits_are_set
131
131
  t = Template.parse("{% for a in (1..100) %} {% assign foo = 1 %} {% endfor %}")
132
- t.render()
132
+ t.render!()
133
133
  assert t.resource_limits[:assign_score_current] > 0
134
134
  assert t.resource_limits[:render_score_current] > 0
135
135
  assert t.resource_limits[:render_length_current] > 0
136
136
  end
137
137
 
138
+ def test_default_resource_limits_unaffected_by_render_with_context
139
+ context = Context.new
140
+ t = Template.parse("{% for a in (1..100) %} {% assign foo = 1 %} {% endfor %}")
141
+ t.render!(context)
142
+ assert context.resource_limits[:assign_score_current] > 0
143
+ assert context.resource_limits[:render_score_current] > 0
144
+ assert context.resource_limits[:render_length_current] > 0
145
+ refute Template.default_resource_limits.key?(:assign_score_current)
146
+ refute Template.default_resource_limits.key?(:render_score_current)
147
+ refute Template.default_resource_limits.key?(:render_length_current)
148
+ end
149
+
138
150
  def test_can_use_drop_as_context
139
151
  t = Template.new
140
152
  t.registers['lulz'] = 'haha'
141
153
  drop = TemplateContextDrop.new
142
- assert_equal 'fizzbuzz', t.parse('{{foo}}').render(drop)
143
- assert_equal 'bar', t.parse('{{bar}}').render(drop)
144
- assert_equal 'haha', t.parse("{{baz}}").render(drop)
154
+ assert_equal 'fizzbuzz', t.parse('{{foo}}').render!(drop)
155
+ assert_equal 'bar', t.parse('{{bar}}').render!(drop)
156
+ assert_equal 'haha', t.parse("{{baz}}").render!(drop)
157
+ end
158
+
159
+ def test_render_bang_force_rethrow_errors_on_passed_context
160
+ context = Context.new({'drop' => ErroneousDrop.new})
161
+ t = Template.new.parse('{{ drop.bad_method }}')
162
+
163
+ e = assert_raises RuntimeError do
164
+ t.render!(context)
165
+ end
166
+ assert_equal 'ruby error in drop', e.message
145
167
  end
146
- end # TemplateTest
168
+
169
+ def test_exception_handler_doesnt_reraise_if_it_returns_false
170
+ exception = nil
171
+ Template.parse("{{ 1 | divided_by: 0 }}").render({}, exception_handler: ->(e) { exception = e; false })
172
+ assert exception.is_a?(ZeroDivisionError)
173
+ end
174
+
175
+ def test_exception_handler_does_reraise_if_it_returns_true
176
+ exception = nil
177
+ assert_raises(ZeroDivisionError) do
178
+ Template.parse("{{ 1 | divided_by: 0 }}").render({}, exception_handler: ->(e) { exception = e; true })
179
+ end
180
+ assert exception.is_a?(ZeroDivisionError)
181
+ end
182
+ end
@@ -0,0 +1,82 @@
1
+ require 'test_helper'
2
+
3
+ class VariableTest < Minitest::Test
4
+ include Liquid
5
+
6
+ def test_simple_variable
7
+ template = Template.parse(%|{{test}}|)
8
+ assert_equal 'worked', template.render!('test' => 'worked')
9
+ assert_equal 'worked wonderfully', template.render!('test' => 'worked wonderfully')
10
+ end
11
+
12
+ def test_variable_render_calls_to_liquid
13
+ assert_template_result 'foobar', '{{ foo }}', 'foo' => ThingWithToLiquid.new
14
+ end
15
+
16
+ def test_simple_with_whitespaces
17
+ template = Template.parse(%| {{ test }} |)
18
+ assert_equal ' worked ', template.render!('test' => 'worked')
19
+ assert_equal ' worked wonderfully ', template.render!('test' => 'worked wonderfully')
20
+ end
21
+
22
+ def test_ignore_unknown
23
+ template = Template.parse(%|{{ test }}|)
24
+ assert_equal '', template.render!
25
+ end
26
+
27
+ def test_hash_scoping
28
+ template = Template.parse(%|{{ test.test }}|)
29
+ assert_equal 'worked', template.render!('test' => {'test' => 'worked'})
30
+ end
31
+
32
+ def test_false_renders_as_false
33
+ assert_equal 'false', Template.parse("{{ foo }}").render!('foo' => false)
34
+ assert_equal 'false', Template.parse("{{ false }}").render!
35
+ end
36
+
37
+ def test_nil_renders_as_empty_string
38
+ assert_equal '', Template.parse("{{ nil }}").render!
39
+ assert_equal 'cat', Template.parse("{{ nil | append: 'cat' }}").render!
40
+ end
41
+
42
+ def test_preset_assigns
43
+ template = Template.parse(%|{{ test }}|)
44
+ template.assigns['test'] = 'worked'
45
+ assert_equal 'worked', template.render!
46
+ end
47
+
48
+ def test_reuse_parsed_template
49
+ template = Template.parse(%|{{ greeting }} {{ name }}|)
50
+ template.assigns['greeting'] = 'Goodbye'
51
+ assert_equal 'Hello Tobi', template.render!('greeting' => 'Hello', 'name' => 'Tobi')
52
+ assert_equal 'Hello ', template.render!('greeting' => 'Hello', 'unknown' => 'Tobi')
53
+ assert_equal 'Hello Brian', template.render!('greeting' => 'Hello', 'name' => 'Brian')
54
+ assert_equal 'Goodbye Brian', template.render!('name' => 'Brian')
55
+ assert_equal({'greeting'=>'Goodbye'}, template.assigns)
56
+ end
57
+
58
+ def test_assigns_not_polluted_from_template
59
+ template = Template.parse(%|{{ test }}{% assign test = 'bar' %}{{ test }}|)
60
+ template.assigns['test'] = 'baz'
61
+ assert_equal 'bazbar', template.render!
62
+ assert_equal 'bazbar', template.render!
63
+ assert_equal 'foobar', template.render!('test' => 'foo')
64
+ assert_equal 'bazbar', template.render!
65
+ end
66
+
67
+ def test_hash_with_default_proc
68
+ template = Template.parse(%|Hello {{ test }}|)
69
+ assigns = Hash.new { |h,k| raise "Unknown variable '#{k}'" }
70
+ assigns['test'] = 'Tobi'
71
+ assert_equal 'Hello Tobi', template.render!(assigns)
72
+ assigns.delete('test')
73
+ e = assert_raises(RuntimeError) {
74
+ template.render!(assigns)
75
+ }
76
+ assert_equal "Unknown variable 'test'", e.message
77
+ end
78
+
79
+ def test_multiline_variable
80
+ assert_equal 'worked', Template.parse("{{\ntest\n}}").render!('test' => 'worked')
81
+ end
82
+ end
data/test/test_helper.rb CHANGED
@@ -1,29 +1,82 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'test/unit'
4
- require 'test/unit/assertions'
5
- begin
6
- require 'ruby-debug'
7
- rescue LoadError
8
- puts "Couldn't load ruby-debug. gem install ruby-debug if you need it."
3
+ require 'minitest/autorun'
4
+ require 'spy/integration'
5
+
6
+ $:.unshift(File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib'))
7
+ require 'liquid.rb'
8
+
9
+ mode = :strict
10
+ if env_mode = ENV['LIQUID_PARSER_MODE']
11
+ puts "-- #{env_mode.upcase} ERROR MODE"
12
+ mode = env_mode.to_sym
13
+ end
14
+ Liquid::Template.error_mode = mode
15
+
16
+ if Minitest.const_defined?('Test')
17
+ # We're on Minitest 5+. Nothing to do here.
18
+ else
19
+ # Minitest 4 doesn't have Minitest::Test yet.
20
+ Minitest::Test = MiniTest::Unit::TestCase
9
21
  end
10
- require File.join(File.dirname(__FILE__), '..', 'lib', 'liquid')
11
22
 
23
+ module Minitest
24
+ class Test
25
+ def fixture(name)
26
+ File.join(File.expand_path(File.dirname(__FILE__)), "fixtures", name)
27
+ end
28
+ end
12
29
 
13
- module Test
14
- module Unit
15
- module Assertions
16
- include Liquid
30
+ module Assertions
31
+ include Liquid
17
32
 
18
- def assert_template_result(expected, template, assigns = {}, message = nil)
19
- assert_equal expected, Template.parse(template).render(assigns)
20
- end
33
+ def assert_template_result(expected, template, assigns = {}, message = nil)
34
+ assert_equal expected, Template.parse(template).render!(assigns)
35
+ end
36
+
37
+ def assert_template_result_matches(expected, template, assigns = {}, message = nil)
38
+ return assert_template_result(expected, template, assigns, message) unless expected.is_a? Regexp
21
39
 
22
- def assert_template_result_matches(expected, template, assigns = {}, message = nil)
23
- return assert_template_result(expected, template, assigns, message) unless expected.is_a? Regexp
40
+ assert_match expected, Template.parse(template).render!(assigns)
41
+ end
24
42
 
25
- assert_match expected, Template.parse(template).render(assigns)
43
+ def assert_match_syntax_error(match, template, registers = {})
44
+ exception = assert_raises(Liquid::SyntaxError) {
45
+ Template.parse(template).render(assigns)
46
+ }
47
+ assert_match match, exception.message
48
+ end
49
+
50
+ def with_global_filter(*globals)
51
+ original_filters = Array.new(Liquid::Strainer.class_variable_get(:@@filters))
52
+ globals.each do |global|
53
+ Liquid::Template.register_filter(global)
26
54
  end
27
- end # Assertions
28
- end # Unit
29
- end # Test
55
+ yield
56
+ ensure
57
+ Liquid::Strainer.class_variable_set(:@@filters, original_filters)
58
+ end
59
+
60
+ def with_taint_mode(mode)
61
+ old_mode = Liquid::Template.taint_mode
62
+ Liquid::Template.taint_mode = mode
63
+ yield
64
+ ensure
65
+ Liquid::Template.taint_mode = old_mode
66
+ end
67
+
68
+ def with_error_mode(mode)
69
+ old_mode = Liquid::Template.error_mode
70
+ Liquid::Template.error_mode = mode
71
+ yield
72
+ ensure
73
+ Liquid::Template.error_mode = old_mode
74
+ end
75
+ end
76
+ end
77
+
78
+ class ThingWithToLiquid
79
+ def to_liquid
80
+ 'foobar'
81
+ end
82
+ end
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class BlockTest < Test::Unit::TestCase
3
+ class BlockUnitTest < Minitest::Test
4
4
  include Liquid
5
5
 
6
6
  def test_blankspace
@@ -45,10 +45,7 @@ class BlockTest < Test::Unit::TestCase
45
45
 
46
46
  def test_with_custom_tag
47
47
  Liquid::Template.register_tag("testtag", Block)
48
-
49
- assert_nothing_thrown do
50
- template = Liquid::Template.parse( "{% testtag %} {% endtesttag %}")
51
- end
48
+ assert Liquid::Template.parse( "{% testtag %} {% endtesttag %}")
52
49
  end
53
50
 
54
51
  private
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class ConditionTest < Test::Unit::TestCase
3
+ class ConditionUnitTest < Minitest::Test
4
4
  include Liquid
5
5
 
6
6
  def test_basic_condition
@@ -49,6 +49,17 @@ class ConditionTest < Test::Unit::TestCase
49
49
  assert_evalutes_false "'bob'", 'contains', "'---'"
50
50
  end
51
51
 
52
+ def test_invalid_comparation_operator
53
+ assert_evaluates_argument_error "1", '~~', '0'
54
+ end
55
+
56
+ def test_comparation_of_int_and_str
57
+ assert_evaluates_argument_error "'1'", '>', '0'
58
+ assert_evaluates_argument_error "'1'", '<', '0'
59
+ assert_evaluates_argument_error "'1'", '>=', '0'
60
+ assert_evaluates_argument_error "'1'", '<=', '0'
61
+ end
62
+
52
63
  def test_contains_works_on_arrays
53
64
  @context = Liquid::Context.new
54
65
  @context['array'] = [1,2,3,4,5]
@@ -69,6 +80,10 @@ class ConditionTest < Test::Unit::TestCase
69
80
  assert_evalutes_false "0", 'contains', 'not_assigned'
70
81
  end
71
82
 
83
+ def test_contains_return_false_on_wrong_data_type
84
+ assert_evalutes_false "1", 'contains', '0'
85
+ end
86
+
72
87
  def test_or_condition
73
88
  condition = Condition.new('1', '==', '2')
74
89
 
@@ -124,4 +139,11 @@ class ConditionTest < Test::Unit::TestCase
124
139
  assert !Condition.new(left, op, right).evaluate(@context || Liquid::Context.new),
125
140
  "Evaluated true: #{left} #{op} #{right}"
126
141
  end
142
+
143
+ def assert_evaluates_argument_error(left, op, right)
144
+ assert_raises(Liquid::ArgumentError) do
145
+ Condition.new(left, op, right).evaluate(@context || Liquid::Context.new)
146
+ end
147
+ end
148
+
127
149
  end # ConditionTest
@@ -63,13 +63,17 @@ class ArrayLike
63
63
  end
64
64
  end
65
65
 
66
- class ContextTest < Test::Unit::TestCase
66
+ class ContextUnitTest < Minitest::Test
67
67
  include Liquid
68
68
 
69
69
  def setup
70
70
  @context = Liquid::Context.new
71
71
  end
72
72
 
73
+ def teardown
74
+ Spy.teardown
75
+ end
76
+
73
77
  def test_variables
74
78
  @context['string'] = 'string'
75
79
  assert_equal 'string', @context['string']
@@ -103,16 +107,14 @@ class ContextTest < Test::Unit::TestCase
103
107
  end
104
108
 
105
109
  def test_scoping
106
- assert_nothing_raised do
107
- @context.push
108
- @context.pop
109
- end
110
+ @context.push
111
+ @context.pop
110
112
 
111
- assert_raise(Liquid::ContextError) do
113
+ assert_raises(Liquid::ContextError) do
112
114
  @context.pop
113
115
  end
114
116
 
115
- assert_raise(Liquid::ContextError) do
117
+ assert_raises(Liquid::ContextError) do
116
118
  @context.push
117
119
  @context.pop
118
120
  @context.pop
@@ -162,24 +164,6 @@ class ContextTest < Test::Unit::TestCase
162
164
 
163
165
  end
164
166
 
165
- def test_override_global_filter
166
- global = Module.new do
167
- def notice(output)
168
- "Global #{output}"
169
- end
170
- end
171
-
172
- local = Module.new do
173
- def notice(output)
174
- "Local #{output}"
175
- end
176
- end
177
-
178
- Template.register_filter(global)
179
- assert_equal 'Global test', Template.parse("{{'test' | notice }}").render
180
- assert_equal 'Local test', Template.parse("{{'test' | notice }}").render({}, :filters => [local])
181
- end
182
-
183
167
  def test_only_intended_filters_make_it_there
184
168
 
185
169
  filter = Module.new do
@@ -475,4 +459,34 @@ class ContextTest < Test::Unit::TestCase
475
459
  assert_kind_of CategoryDrop, @context['category']
476
460
  assert_equal @context, @context['category'].context
477
461
  end
462
+
463
+ def test_use_empty_instead_of_any_in_interrupt_handling_to_avoid_lots_of_unnecessary_object_allocations
464
+ mock_any = Spy.on_instance_method(Array, :any?)
465
+ mock_empty = Spy.on_instance_method(Array, :empty?)
466
+ mock_has_interrupt = Spy.on(@context, :has_interrupt?).and_call_through
467
+
468
+ @context.has_interrupt?
469
+
470
+ refute mock_any.has_been_called?
471
+ assert mock_empty.has_been_called?
472
+ end
473
+
474
+ def test_variable_lookup_caches_markup
475
+ mock_scan = Spy.on_instance_method(String, :scan).and_return(["string"])
476
+
477
+ @context['string'] = 'string'
478
+ @context['string']
479
+ @context['string']
480
+
481
+ assert_equal 1, mock_scan.calls.size
482
+ end
483
+
484
+ def test_context_initialization_with_a_proc_in_environment
485
+ contx = Context.new([:test => lambda { |c| c['poutine']}], {:test => :foo})
486
+
487
+ assert contx
488
+ assert_nil contx['poutine']
489
+ end
490
+
491
+
478
492
  end # ContextTest
@@ -1,10 +1,10 @@
1
1
  require 'test_helper'
2
2
 
3
- class FileSystemTest < Test::Unit::TestCase
3
+ class FileSystemUnitTest < Minitest::Test
4
4
  include Liquid
5
5
 
6
6
  def test_default
7
- assert_raise(FileSystemError) do
7
+ assert_raises(FileSystemError) do
8
8
  BlankFileSystem.new.read_template_file("dummy", {'dummy'=>'smarty'})
9
9
  end
10
10
  end
@@ -14,16 +14,22 @@ class FileSystemTest < Test::Unit::TestCase
14
14
  assert_equal "/some/path/_mypartial.liquid" , file_system.full_path("mypartial")
15
15
  assert_equal "/some/path/dir/_mypartial.liquid", file_system.full_path("dir/mypartial")
16
16
 
17
- assert_raise(FileSystemError) do
17
+ assert_raises(FileSystemError) do
18
18
  file_system.full_path("../dir/mypartial")
19
19
  end
20
20
 
21
- assert_raise(FileSystemError) do
21
+ assert_raises(FileSystemError) do
22
22
  file_system.full_path("/dir/../../dir/mypartial")
23
23
  end
24
24
 
25
- assert_raise(FileSystemError) do
25
+ assert_raises(FileSystemError) do
26
26
  file_system.full_path("/etc/passwd")
27
27
  end
28
28
  end
29
+
30
+ def test_custom_template_filename_patterns
31
+ file_system = Liquid::LocalFileSystem.new("/some/path", "%s.html")
32
+ assert_equal "/some/path/mypartial.html" , file_system.full_path("mypartial")
33
+ assert_equal "/some/path/dir/mypartial.html", file_system.full_path("dir/mypartial")
34
+ end
29
35
  end # FileSystemTest
@@ -0,0 +1,37 @@
1
+ require 'test_helper'
2
+
3
+ class I18nUnitTest < Minitest::Test
4
+ include Liquid
5
+
6
+ def setup
7
+ @i18n = I18n.new(fixture("en_locale.yml"))
8
+ end
9
+
10
+ def test_simple_translate_string
11
+ assert_equal "less is more", @i18n.translate("simple")
12
+ end
13
+
14
+ def test_nested_translate_string
15
+ assert_equal "something wasn't right", @i18n.translate("errors.syntax.oops")
16
+ end
17
+
18
+ def test_single_string_interpolation
19
+ assert_equal "something different", @i18n.translate("whatever", :something => "different")
20
+ end
21
+
22
+ # def test_raises_translation_error_on_undefined_interpolation_key
23
+ # assert_raises I18n::TranslationError do
24
+ # @i18n.translate("whatever", :oopstypos => "yes")
25
+ # end
26
+ # end
27
+
28
+ def test_raises_unknown_translation
29
+ assert_raises I18n::TranslationError do
30
+ @i18n.translate("doesnt_exist")
31
+ end
32
+ end
33
+
34
+ def test_sets_default_path_to_en
35
+ assert_equal I18n::DEFAULT_LOCALE, I18n.new.path
36
+ end
37
+ end