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 VariableTest < Minitest::Test
|
@@ -5,88 +7,101 @@ class VariableTest < Minitest::Test
|
|
5
7
|
|
6
8
|
def test_simple_variable
|
7
9
|
template = Template.parse(%({{test}}))
|
8
|
-
assert_equal
|
9
|
-
assert_equal
|
10
|
+
assert_equal('worked', template.render!('test' => 'worked'))
|
11
|
+
assert_equal('worked wonderfully', template.render!('test' => 'worked wonderfully'))
|
10
12
|
end
|
11
13
|
|
12
14
|
def test_variable_render_calls_to_liquid
|
13
|
-
assert_template_result
|
15
|
+
assert_template_result('foobar', '{{ foo }}', 'foo' => ThingWithToLiquid.new)
|
14
16
|
end
|
15
17
|
|
16
18
|
def test_simple_with_whitespaces
|
17
19
|
template = Template.parse(%( {{ test }} ))
|
18
|
-
assert_equal
|
19
|
-
assert_equal
|
20
|
+
assert_equal(' worked ', template.render!('test' => 'worked'))
|
21
|
+
assert_equal(' worked wonderfully ', template.render!('test' => 'worked wonderfully'))
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_expression_with_whitespace_in_square_brackets
|
25
|
+
assert_template_result('result', "{{ a[ 'b' ] }}", 'a' => { 'b' => 'result' })
|
26
|
+
assert_template_result('result', "{{ a[ [ 'b' ] ] }}", 'b' => 'c', 'a' => { 'c' => 'result' })
|
20
27
|
end
|
21
28
|
|
22
29
|
def test_ignore_unknown
|
23
30
|
template = Template.parse(%({{ test }}))
|
24
|
-
assert_equal
|
31
|
+
assert_equal('', template.render!)
|
25
32
|
end
|
26
33
|
|
27
34
|
def test_using_blank_as_variable_name
|
28
35
|
template = Template.parse("{% assign foo = blank %}{{ foo }}")
|
29
|
-
assert_equal
|
36
|
+
assert_equal('', template.render!)
|
30
37
|
end
|
31
38
|
|
32
39
|
def test_using_empty_as_variable_name
|
33
40
|
template = Template.parse("{% assign foo = empty %}{{ foo }}")
|
34
|
-
assert_equal
|
41
|
+
assert_equal('', template.render!)
|
35
42
|
end
|
36
43
|
|
37
44
|
def test_hash_scoping
|
38
|
-
|
39
|
-
|
45
|
+
assert_template_result('worked', "{{ test.test }}", 'test' => { 'test' => 'worked' })
|
46
|
+
assert_template_result('worked', "{{ test . test }}", 'test' => { 'test' => 'worked' })
|
40
47
|
end
|
41
48
|
|
42
49
|
def test_false_renders_as_false
|
43
|
-
assert_equal
|
44
|
-
assert_equal
|
50
|
+
assert_equal('false', Template.parse("{{ foo }}").render!('foo' => false))
|
51
|
+
assert_equal('false', Template.parse("{{ false }}").render!)
|
45
52
|
end
|
46
53
|
|
47
54
|
def test_nil_renders_as_empty_string
|
48
|
-
assert_equal
|
49
|
-
assert_equal
|
55
|
+
assert_equal('', Template.parse("{{ nil }}").render!)
|
56
|
+
assert_equal('cat', Template.parse("{{ nil | append: 'cat' }}").render!)
|
50
57
|
end
|
51
58
|
|
52
59
|
def test_preset_assigns
|
53
|
-
template
|
60
|
+
template = Template.parse(%({{ test }}))
|
54
61
|
template.assigns['test'] = 'worked'
|
55
|
-
assert_equal
|
62
|
+
assert_equal('worked', template.render!)
|
56
63
|
end
|
57
64
|
|
58
65
|
def test_reuse_parsed_template
|
59
|
-
template
|
66
|
+
template = Template.parse(%({{ greeting }} {{ name }}))
|
60
67
|
template.assigns['greeting'] = 'Goodbye'
|
61
|
-
assert_equal
|
62
|
-
assert_equal
|
63
|
-
assert_equal
|
64
|
-
assert_equal
|
68
|
+
assert_equal('Hello Tobi', template.render!('greeting' => 'Hello', 'name' => 'Tobi'))
|
69
|
+
assert_equal('Hello ', template.render!('greeting' => 'Hello', 'unknown' => 'Tobi'))
|
70
|
+
assert_equal('Hello Brian', template.render!('greeting' => 'Hello', 'name' => 'Brian'))
|
71
|
+
assert_equal('Goodbye Brian', template.render!('name' => 'Brian'))
|
65
72
|
assert_equal({ 'greeting' => 'Goodbye' }, template.assigns)
|
66
73
|
end
|
67
74
|
|
68
75
|
def test_assigns_not_polluted_from_template
|
69
|
-
template
|
76
|
+
template = Template.parse(%({{ test }}{% assign test = 'bar' %}{{ test }}))
|
70
77
|
template.assigns['test'] = 'baz'
|
71
|
-
assert_equal
|
72
|
-
assert_equal
|
73
|
-
assert_equal
|
74
|
-
assert_equal
|
78
|
+
assert_equal('bazbar', template.render!)
|
79
|
+
assert_equal('bazbar', template.render!)
|
80
|
+
assert_equal('foobar', template.render!('test' => 'foo'))
|
81
|
+
assert_equal('bazbar', template.render!)
|
75
82
|
end
|
76
83
|
|
77
84
|
def test_hash_with_default_proc
|
78
|
-
template
|
79
|
-
assigns
|
85
|
+
template = Template.parse(%(Hello {{ test }}))
|
86
|
+
assigns = Hash.new { |_h, k| raise "Unknown variable '#{k}'" }
|
80
87
|
assigns['test'] = 'Tobi'
|
81
|
-
assert_equal
|
88
|
+
assert_equal('Hello Tobi', template.render!(assigns))
|
82
89
|
assigns.delete('test')
|
83
90
|
e = assert_raises(RuntimeError) do
|
84
91
|
template.render!(assigns)
|
85
92
|
end
|
86
|
-
assert_equal
|
93
|
+
assert_equal("Unknown variable 'test'", e.message)
|
87
94
|
end
|
88
95
|
|
89
96
|
def test_multiline_variable
|
90
|
-
assert_equal
|
97
|
+
assert_equal('worked', Template.parse("{{\ntest\n}}").render!('test' => 'worked'))
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_render_symbol
|
101
|
+
assert_template_result('bar', '{{ foo }}', 'foo' => :bar)
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_dynamic_find_var
|
105
|
+
assert_template_result('bar', '{{ [key] }}', 'key' => 'foo', 'foo' => 'bar')
|
91
106
|
end
|
92
107
|
end
|
data/test/test_helper.rb
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
ENV["MT_NO_EXPECTATIONS"] = "1"
|
4
5
|
require 'minitest/autorun'
|
5
|
-
require 'spy/integration'
|
6
6
|
|
7
7
|
$LOAD_PATH.unshift(File.join(File.expand_path(__dir__), '..', 'lib'))
|
8
8
|
require 'liquid.rb'
|
9
9
|
require 'liquid/profiler'
|
10
10
|
|
11
11
|
mode = :strict
|
12
|
-
if env_mode = ENV['LIQUID_PARSER_MODE']
|
12
|
+
if (env_mode = ENV['LIQUID_PARSER_MODE'])
|
13
13
|
puts "-- #{env_mode.upcase} ERROR MODE"
|
14
14
|
mode = env_mode.to_sym
|
15
15
|
end
|
16
16
|
Liquid::Template.error_mode = mode
|
17
17
|
|
18
|
-
if ENV['
|
18
|
+
if ENV['LIQUID_C'] == '1'
|
19
19
|
puts "-- LIQUID C"
|
20
20
|
require 'liquid/c'
|
21
21
|
end
|
@@ -38,44 +38,55 @@ module Minitest
|
|
38
38
|
include Liquid
|
39
39
|
|
40
40
|
def assert_template_result(expected, template, assigns = {}, message = nil)
|
41
|
-
assert_equal
|
41
|
+
assert_equal(expected, Template.parse(template, line_numbers: true).render!(assigns), message)
|
42
42
|
end
|
43
43
|
|
44
44
|
def assert_template_result_matches(expected, template, assigns = {}, message = nil)
|
45
|
-
return assert_template_result(expected, template, assigns, message) unless expected.is_a?
|
45
|
+
return assert_template_result(expected, template, assigns, message) unless expected.is_a?(Regexp)
|
46
46
|
|
47
|
-
assert_match
|
47
|
+
assert_match(expected, Template.parse(template, line_numbers: true).render!(assigns), message)
|
48
48
|
end
|
49
49
|
|
50
50
|
def assert_match_syntax_error(match, template, assigns = {})
|
51
51
|
exception = assert_raises(Liquid::SyntaxError) do
|
52
|
-
Template.parse(template).render(assigns)
|
52
|
+
Template.parse(template, line_numbers: true).render(assigns)
|
53
53
|
end
|
54
|
-
assert_match
|
54
|
+
assert_match(match, exception.message)
|
55
|
+
end
|
56
|
+
|
57
|
+
def assert_usage_increment(name, times: 1)
|
58
|
+
old_method = Liquid::Usage.method(:increment)
|
59
|
+
calls = 0
|
60
|
+
begin
|
61
|
+
Liquid::Usage.singleton_class.send(:remove_method, :increment)
|
62
|
+
Liquid::Usage.define_singleton_method(:increment) do |got_name|
|
63
|
+
calls += 1 if got_name == name
|
64
|
+
old_method.call(got_name)
|
65
|
+
end
|
66
|
+
yield
|
67
|
+
ensure
|
68
|
+
Liquid::Usage.singleton_class.send(:remove_method, :increment)
|
69
|
+
Liquid::Usage.define_singleton_method(:increment, old_method)
|
70
|
+
end
|
71
|
+
assert_equal(times, calls, "Number of calls to Usage.increment with #{name.inspect}")
|
55
72
|
end
|
56
73
|
|
57
74
|
def with_global_filter(*globals)
|
58
|
-
|
59
|
-
Liquid::
|
60
|
-
|
61
|
-
|
62
|
-
|
75
|
+
original_global_filters = Liquid::StrainerFactory.instance_variable_get(:@global_filters)
|
76
|
+
Liquid::StrainerFactory.instance_variable_set(:@global_filters, [])
|
77
|
+
globals.each do |global|
|
78
|
+
Liquid::StrainerFactory.add_global_filter(global)
|
79
|
+
end
|
80
|
+
|
81
|
+
Liquid::StrainerFactory.send(:strainer_class_cache).clear
|
63
82
|
|
64
83
|
globals.each do |global|
|
65
84
|
Liquid::Template.register_filter(global)
|
66
85
|
end
|
67
86
|
yield
|
68
87
|
ensure
|
69
|
-
Liquid::
|
70
|
-
Liquid::
|
71
|
-
end
|
72
|
-
|
73
|
-
def with_taint_mode(mode)
|
74
|
-
old_mode = Liquid::Template.taint_mode
|
75
|
-
Liquid::Template.taint_mode = mode
|
76
|
-
yield
|
77
|
-
ensure
|
78
|
-
Liquid::Template.taint_mode = old_mode
|
88
|
+
Liquid::StrainerFactory.send(:strainer_class_cache).clear
|
89
|
+
Liquid::StrainerFactory.instance_variable_set(:@global_filters, original_global_filters)
|
79
90
|
end
|
80
91
|
|
81
92
|
def with_error_mode(mode)
|
@@ -85,6 +96,20 @@ module Minitest
|
|
85
96
|
ensure
|
86
97
|
Liquid::Template.error_mode = old_mode
|
87
98
|
end
|
99
|
+
|
100
|
+
def with_custom_tag(tag_name, tag_class)
|
101
|
+
old_tag = Liquid::Template.tags[tag_name]
|
102
|
+
begin
|
103
|
+
Liquid::Template.register_tag(tag_name, tag_class)
|
104
|
+
yield
|
105
|
+
ensure
|
106
|
+
if old_tag
|
107
|
+
Liquid::Template.tags[tag_name] = old_tag
|
108
|
+
else
|
109
|
+
Liquid::Template.tags.delete(tag_name)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
88
113
|
end
|
89
114
|
end
|
90
115
|
|
@@ -115,3 +140,30 @@ class ErrorDrop < Liquid::Drop
|
|
115
140
|
raise Exception, 'exception'
|
116
141
|
end
|
117
142
|
end
|
143
|
+
|
144
|
+
class StubFileSystem
|
145
|
+
attr_reader :file_read_count
|
146
|
+
|
147
|
+
def initialize(values)
|
148
|
+
@file_read_count = 0
|
149
|
+
@values = values
|
150
|
+
end
|
151
|
+
|
152
|
+
def read_template_file(template_path)
|
153
|
+
@file_read_count += 1
|
154
|
+
@values.fetch(template_path)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
class StubTemplateFactory
|
159
|
+
attr_reader :count
|
160
|
+
|
161
|
+
def initialize
|
162
|
+
@count = 0
|
163
|
+
end
|
164
|
+
|
165
|
+
def for(_template_name)
|
166
|
+
@count += 1
|
167
|
+
Liquid::Template.new
|
168
|
+
end
|
169
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
|
3
5
|
class BlockUnitTest < Minitest::Test
|
@@ -5,49 +7,42 @@ class BlockUnitTest < Minitest::Test
|
|
5
7
|
|
6
8
|
def test_blankspace
|
7
9
|
template = Liquid::Template.parse(" ")
|
8
|
-
assert_equal
|
10
|
+
assert_equal([" "], template.root.nodelist)
|
9
11
|
end
|
10
12
|
|
11
13
|
def test_variable_beginning
|
12
14
|
template = Liquid::Template.parse("{{funk}} ")
|
13
|
-
assert_equal
|
14
|
-
assert_equal
|
15
|
-
assert_equal
|
15
|
+
assert_equal(2, template.root.nodelist.size)
|
16
|
+
assert_equal(Variable, template.root.nodelist[0].class)
|
17
|
+
assert_equal(String, template.root.nodelist[1].class)
|
16
18
|
end
|
17
19
|
|
18
20
|
def test_variable_end
|
19
21
|
template = Liquid::Template.parse(" {{funk}}")
|
20
|
-
assert_equal
|
21
|
-
assert_equal
|
22
|
-
assert_equal
|
22
|
+
assert_equal(2, template.root.nodelist.size)
|
23
|
+
assert_equal(String, template.root.nodelist[0].class)
|
24
|
+
assert_equal(Variable, template.root.nodelist[1].class)
|
23
25
|
end
|
24
26
|
|
25
27
|
def test_variable_middle
|
26
28
|
template = Liquid::Template.parse(" {{funk}} ")
|
27
|
-
assert_equal
|
28
|
-
assert_equal
|
29
|
-
assert_equal
|
30
|
-
assert_equal
|
29
|
+
assert_equal(3, template.root.nodelist.size)
|
30
|
+
assert_equal(String, template.root.nodelist[0].class)
|
31
|
+
assert_equal(Variable, template.root.nodelist[1].class)
|
32
|
+
assert_equal(String, template.root.nodelist[2].class)
|
31
33
|
end
|
32
34
|
|
33
35
|
def test_variable_many_embedded_fragments
|
34
36
|
template = Liquid::Template.parse(" {{funk}} {{so}} {{brother}} ")
|
35
|
-
assert_equal
|
36
|
-
assert_equal
|
37
|
-
block_types(template.root.nodelist)
|
37
|
+
assert_equal(7, template.root.nodelist.size)
|
38
|
+
assert_equal([String, Variable, String, Variable, String, Variable, String],
|
39
|
+
block_types(template.root.nodelist))
|
38
40
|
end
|
39
41
|
|
40
42
|
def test_with_block
|
41
43
|
template = Liquid::Template.parse(" {% comment %} {% endcomment %} ")
|
42
|
-
assert_equal
|
43
|
-
assert_equal
|
44
|
-
end
|
45
|
-
|
46
|
-
def test_with_custom_tag
|
47
|
-
Liquid::Template.register_tag("testtag", Block)
|
48
|
-
assert Liquid::Template.parse("{% testtag %} {% endtesttag %}")
|
49
|
-
ensure
|
50
|
-
Liquid::Template.tags.delete('testtag')
|
44
|
+
assert_equal([String, Comment, String], block_types(template.root.nodelist))
|
45
|
+
assert_equal(3, template.root.nodelist.size)
|
51
46
|
end
|
52
47
|
|
53
48
|
private
|
@@ -55,4 +50,4 @@ class BlockUnitTest < Minitest::Test
|
|
55
50
|
def block_types(nodelist)
|
56
51
|
nodelist.collect(&:class)
|
57
52
|
end
|
58
|
-
end
|
53
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
|
3
5
|
class ConditionUnitTest < Minitest::Test
|
@@ -8,146 +10,154 @@ class ConditionUnitTest < Minitest::Test
|
|
8
10
|
end
|
9
11
|
|
10
12
|
def test_basic_condition
|
11
|
-
assert_equal
|
12
|
-
assert_equal
|
13
|
+
assert_equal(false, Condition.new(1, '==', 2).evaluate)
|
14
|
+
assert_equal(true, Condition.new(1, '==', 1).evaluate)
|
13
15
|
end
|
14
16
|
|
15
17
|
def test_default_operators_evalute_true
|
16
|
-
assert_evaluates_true
|
17
|
-
assert_evaluates_true
|
18
|
-
assert_evaluates_true
|
19
|
-
assert_evaluates_true
|
20
|
-
assert_evaluates_true
|
21
|
-
assert_evaluates_true
|
22
|
-
assert_evaluates_true
|
23
|
-
assert_evaluates_true
|
24
|
-
assert_evaluates_true
|
18
|
+
assert_evaluates_true(1, '==', 1)
|
19
|
+
assert_evaluates_true(1, '!=', 2)
|
20
|
+
assert_evaluates_true(1, '<>', 2)
|
21
|
+
assert_evaluates_true(1, '<', 2)
|
22
|
+
assert_evaluates_true(2, '>', 1)
|
23
|
+
assert_evaluates_true(1, '>=', 1)
|
24
|
+
assert_evaluates_true(2, '>=', 1)
|
25
|
+
assert_evaluates_true(1, '<=', 2)
|
26
|
+
assert_evaluates_true(1, '<=', 1)
|
25
27
|
# negative numbers
|
26
|
-
assert_evaluates_true
|
27
|
-
assert_evaluates_true
|
28
|
-
assert_evaluates_true
|
29
|
-
assert_evaluates_true
|
28
|
+
assert_evaluates_true(1, '>', -1)
|
29
|
+
assert_evaluates_true(-1, '<', 1)
|
30
|
+
assert_evaluates_true(1.0, '>', -1.0)
|
31
|
+
assert_evaluates_true(-1.0, '<', 1.0)
|
30
32
|
end
|
31
33
|
|
32
34
|
def test_default_operators_evalute_false
|
33
|
-
assert_evaluates_false
|
34
|
-
assert_evaluates_false
|
35
|
-
assert_evaluates_false
|
36
|
-
assert_evaluates_false
|
37
|
-
assert_evaluates_false
|
38
|
-
assert_evaluates_false
|
39
|
-
assert_evaluates_false
|
40
|
-
assert_evaluates_false
|
41
|
-
assert_evaluates_false
|
35
|
+
assert_evaluates_false(1, '==', 2)
|
36
|
+
assert_evaluates_false(1, '!=', 1)
|
37
|
+
assert_evaluates_false(1, '<>', 1)
|
38
|
+
assert_evaluates_false(1, '<', 0)
|
39
|
+
assert_evaluates_false(2, '>', 4)
|
40
|
+
assert_evaluates_false(1, '>=', 3)
|
41
|
+
assert_evaluates_false(2, '>=', 4)
|
42
|
+
assert_evaluates_false(1, '<=', 0)
|
43
|
+
assert_evaluates_false(1, '<=', 0)
|
42
44
|
end
|
43
45
|
|
44
46
|
def test_contains_works_on_strings
|
45
|
-
assert_evaluates_true
|
46
|
-
assert_evaluates_true
|
47
|
-
assert_evaluates_true
|
48
|
-
assert_evaluates_true
|
49
|
-
assert_evaluates_true
|
47
|
+
assert_evaluates_true('bob', 'contains', 'o')
|
48
|
+
assert_evaluates_true('bob', 'contains', 'b')
|
49
|
+
assert_evaluates_true('bob', 'contains', 'bo')
|
50
|
+
assert_evaluates_true('bob', 'contains', 'ob')
|
51
|
+
assert_evaluates_true('bob', 'contains', 'bob')
|
50
52
|
|
51
|
-
assert_evaluates_false
|
52
|
-
assert_evaluates_false
|
53
|
-
assert_evaluates_false
|
53
|
+
assert_evaluates_false('bob', 'contains', 'bob2')
|
54
|
+
assert_evaluates_false('bob', 'contains', 'a')
|
55
|
+
assert_evaluates_false('bob', 'contains', '---')
|
54
56
|
end
|
55
57
|
|
56
58
|
def test_invalid_comparation_operator
|
57
|
-
assert_evaluates_argument_error
|
59
|
+
assert_evaluates_argument_error(1, '~~', 0)
|
58
60
|
end
|
59
61
|
|
60
62
|
def test_comparation_of_int_and_str
|
61
|
-
assert_evaluates_argument_error
|
62
|
-
assert_evaluates_argument_error
|
63
|
-
assert_evaluates_argument_error
|
64
|
-
assert_evaluates_argument_error
|
63
|
+
assert_evaluates_argument_error('1', '>', 0)
|
64
|
+
assert_evaluates_argument_error('1', '<', 0)
|
65
|
+
assert_evaluates_argument_error('1', '>=', 0)
|
66
|
+
assert_evaluates_argument_error('1', '<=', 0)
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_hash_compare_backwards_compatibility
|
70
|
+
assert_nil(Condition.new({}, '>', 2).evaluate)
|
71
|
+
assert_nil(Condition.new(2, '>', {}).evaluate)
|
72
|
+
assert_equal(false, Condition.new({}, '==', 2).evaluate)
|
73
|
+
assert_equal(true, Condition.new({ 'a' => 1 }, '==', 'a' => 1).evaluate)
|
74
|
+
assert_equal(true, Condition.new({ 'a' => 2 }, 'contains', 'a').evaluate)
|
65
75
|
end
|
66
76
|
|
67
77
|
def test_contains_works_on_arrays
|
68
|
-
@context
|
78
|
+
@context = Liquid::Context.new
|
69
79
|
@context['array'] = [1, 2, 3, 4, 5]
|
70
|
-
array_expr
|
80
|
+
array_expr = VariableLookup.new("array")
|
71
81
|
|
72
|
-
assert_evaluates_false
|
73
|
-
assert_evaluates_true
|
74
|
-
assert_evaluates_true
|
75
|
-
assert_evaluates_true
|
76
|
-
assert_evaluates_true
|
77
|
-
assert_evaluates_true
|
78
|
-
assert_evaluates_false
|
79
|
-
assert_evaluates_false
|
82
|
+
assert_evaluates_false(array_expr, 'contains', 0)
|
83
|
+
assert_evaluates_true(array_expr, 'contains', 1)
|
84
|
+
assert_evaluates_true(array_expr, 'contains', 2)
|
85
|
+
assert_evaluates_true(array_expr, 'contains', 3)
|
86
|
+
assert_evaluates_true(array_expr, 'contains', 4)
|
87
|
+
assert_evaluates_true(array_expr, 'contains', 5)
|
88
|
+
assert_evaluates_false(array_expr, 'contains', 6)
|
89
|
+
assert_evaluates_false(array_expr, 'contains', "1")
|
80
90
|
end
|
81
91
|
|
82
92
|
def test_contains_returns_false_for_nil_operands
|
83
93
|
@context = Liquid::Context.new
|
84
|
-
assert_evaluates_false
|
85
|
-
assert_evaluates_false
|
94
|
+
assert_evaluates_false(VariableLookup.new('not_assigned'), 'contains', '0')
|
95
|
+
assert_evaluates_false(0, 'contains', VariableLookup.new('not_assigned'))
|
86
96
|
end
|
87
97
|
|
88
98
|
def test_contains_return_false_on_wrong_data_type
|
89
|
-
assert_evaluates_false
|
99
|
+
assert_evaluates_false(1, 'contains', 0)
|
90
100
|
end
|
91
101
|
|
92
102
|
def test_contains_with_string_left_operand_coerces_right_operand_to_string
|
93
|
-
assert_evaluates_true
|
94
|
-
assert_evaluates_false
|
103
|
+
assert_evaluates_true(' 1 ', 'contains', 1)
|
104
|
+
assert_evaluates_false(' 1 ', 'contains', 2)
|
95
105
|
end
|
96
106
|
|
97
107
|
def test_or_condition
|
98
108
|
condition = Condition.new(1, '==', 2)
|
99
109
|
|
100
|
-
assert_equal
|
110
|
+
assert_equal(false, condition.evaluate)
|
101
111
|
|
102
|
-
condition.or
|
112
|
+
condition.or(Condition.new(2, '==', 1))
|
103
113
|
|
104
|
-
assert_equal
|
114
|
+
assert_equal(false, condition.evaluate)
|
105
115
|
|
106
|
-
condition.or
|
116
|
+
condition.or(Condition.new(1, '==', 1))
|
107
117
|
|
108
|
-
assert_equal
|
118
|
+
assert_equal(true, condition.evaluate)
|
109
119
|
end
|
110
120
|
|
111
121
|
def test_and_condition
|
112
122
|
condition = Condition.new(1, '==', 1)
|
113
123
|
|
114
|
-
assert_equal
|
124
|
+
assert_equal(true, condition.evaluate)
|
115
125
|
|
116
|
-
condition.and
|
126
|
+
condition.and(Condition.new(2, '==', 2))
|
117
127
|
|
118
|
-
assert_equal
|
128
|
+
assert_equal(true, condition.evaluate)
|
119
129
|
|
120
|
-
condition.and
|
130
|
+
condition.and(Condition.new(2, '==', 1))
|
121
131
|
|
122
|
-
assert_equal
|
132
|
+
assert_equal(false, condition.evaluate)
|
123
133
|
end
|
124
134
|
|
125
135
|
def test_should_allow_custom_proc_operator
|
126
|
-
Condition.operators['starts_with'] = proc { |
|
136
|
+
Condition.operators['starts_with'] = proc { |_cond, left, right| left =~ /^#{right}/ }
|
127
137
|
|
128
|
-
assert_evaluates_true
|
129
|
-
assert_evaluates_false
|
138
|
+
assert_evaluates_true('bob', 'starts_with', 'b')
|
139
|
+
assert_evaluates_false('bob', 'starts_with', 'o')
|
130
140
|
ensure
|
131
|
-
Condition.operators.delete
|
141
|
+
Condition.operators.delete('starts_with')
|
132
142
|
end
|
133
143
|
|
134
144
|
def test_left_or_right_may_contain_operators
|
135
|
-
@context
|
145
|
+
@context = Liquid::Context.new
|
136
146
|
@context['one'] = @context['another'] = "gnomeslab-and-or-liquid"
|
137
147
|
|
138
|
-
assert_evaluates_true
|
148
|
+
assert_evaluates_true(VariableLookup.new("one"), '==', VariableLookup.new("another"))
|
139
149
|
end
|
140
150
|
|
141
151
|
private
|
142
152
|
|
143
153
|
def assert_evaluates_true(left, op, right)
|
144
|
-
assert
|
145
|
-
"Evaluated false: #{left} #{op} #{right}"
|
154
|
+
assert(Condition.new(left, op, right).evaluate(@context),
|
155
|
+
"Evaluated false: #{left} #{op} #{right}")
|
146
156
|
end
|
147
157
|
|
148
158
|
def assert_evaluates_false(left, op, right)
|
149
|
-
assert
|
150
|
-
"Evaluated true: #{left} #{op} #{right}"
|
159
|
+
assert(!Condition.new(left, op, right).evaluate(@context),
|
160
|
+
"Evaluated true: #{left} #{op} #{right}")
|
151
161
|
end
|
152
162
|
|
153
163
|
def assert_evaluates_argument_error(left, op, right)
|