liquid 4.0.3 → 5.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.
- checksums.yaml +4 -4
- data/History.md +33 -0
- data/README.md +6 -0
- data/lib/liquid.rb +17 -5
- data/lib/liquid/block.rb +31 -14
- data/lib/liquid/block_body.rb +164 -54
- data/lib/liquid/condition.rb +39 -18
- data/lib/liquid/context.rb +106 -51
- 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 +29 -34
- data/lib/liquid/extensions.rb +2 -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 +30 -23
- data/lib/liquid/locales/en.yml +3 -1
- data/lib/liquid/parse_context.rb +16 -4
- data/lib/liquid/parse_tree_visitor.rb +2 -2
- 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 +63 -44
- 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 +24 -10
- data/lib/liquid/tags/break.rb +8 -3
- data/lib/liquid/tags/capture.rb +11 -8
- data/lib/liquid/tags/case.rb +33 -27
- data/lib/liquid/tags/comment.rb +5 -3
- data/lib/liquid/tags/continue.rb +8 -3
- data/lib/liquid/tags/cycle.rb +25 -14
- data/lib/liquid/tags/decrement.rb +6 -3
- data/lib/liquid/tags/echo.rb +26 -0
- data/lib/liquid/tags/for.rb +68 -44
- data/lib/liquid/tags/if.rb +35 -23
- data/lib/liquid/tags/ifchanged.rb +11 -10
- data/lib/liquid/tags/include.rb +34 -47
- 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 +23 -19
- data/lib/liquid/tags/unless.rb +15 -15
- data/lib/liquid/template.rb +55 -71
- 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 +5 -3
- data/lib/liquid/variable.rb +46 -41
- data/lib/liquid/variable_lookup.rb +8 -6
- data/lib/liquid/version.rb +2 -1
- data/test/integration/assign_test.rb +74 -5
- data/test/integration/blank_test.rb +11 -8
- data/test/integration/block_test.rb +47 -1
- data/test/integration/capture_test.rb +18 -10
- data/test/integration/context_test.rb +608 -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 +19 -7
- data/test/integration/{render_profiling_test.rb → profiler_test.rb} +84 -25
- data/test/integration/security_test.rb +30 -21
- data/test/integration/standard_filter_test.rb +339 -281
- 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 +107 -51
- data/test/integration/tags/if_else_tag_test.rb +5 -3
- data/test/integration/tags/include_tag_test.rb +70 -54
- 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 +118 -124
- data/test/integration/trim_mode_test.rb +78 -44
- data/test/integration/variable_test.rb +43 -32
- data/test/test_helper.rb +75 -22
- data/test/unit/block_unit_test.rb +19 -24
- data/test/unit/condition_unit_test.rb +79 -77
- 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 +11 -9
- data/test/{integration → unit}/parse_tree_visitor_test.rb +2 -2
- 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 +19 -17
- data/test/unit/variable_unit_test.rb +51 -49
- metadata +73 -47
- data/lib/liquid/strainer.rb +0 -66
- data/lib/liquid/truffle.rb +0 -5
- data/test/truffle/truffle_test.rb +0 -9
- data/test/unit/context_unit_test.rb +0 -489
- data/test/unit/strainer_unit_test.rb +0 -164
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
|
3
5
|
class VariableTest < Minitest::Test
|
@@ -5,92 +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'))
|
91
98
|
end
|
92
99
|
|
93
100
|
def test_render_symbol
|
94
|
-
assert_template_result
|
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')
|
95
106
|
end
|
96
107
|
end
|
data/test/test_helper.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
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'
|
@@ -8,13 +9,13 @@ require 'liquid.rb'
|
|
8
9
|
require 'liquid/profiler'
|
9
10
|
|
10
11
|
mode = :strict
|
11
|
-
if env_mode = ENV['LIQUID_PARSER_MODE']
|
12
|
+
if (env_mode = ENV['LIQUID_PARSER_MODE'])
|
12
13
|
puts "-- #{env_mode.upcase} ERROR MODE"
|
13
14
|
mode = env_mode.to_sym
|
14
15
|
end
|
15
16
|
Liquid::Template.error_mode = mode
|
16
17
|
|
17
|
-
if ENV['
|
18
|
+
if ENV['LIQUID_C'] == '1'
|
18
19
|
puts "-- LIQUID C"
|
19
20
|
require 'liquid/c'
|
20
21
|
end
|
@@ -37,44 +38,55 @@ module Minitest
|
|
37
38
|
include Liquid
|
38
39
|
|
39
40
|
def assert_template_result(expected, template, assigns = {}, message = nil)
|
40
|
-
assert_equal
|
41
|
+
assert_equal(expected, Template.parse(template, line_numbers: true).render!(assigns), message)
|
41
42
|
end
|
42
43
|
|
43
44
|
def assert_template_result_matches(expected, template, assigns = {}, message = nil)
|
44
|
-
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)
|
45
46
|
|
46
|
-
assert_match
|
47
|
+
assert_match(expected, Template.parse(template, line_numbers: true).render!(assigns), message)
|
47
48
|
end
|
48
49
|
|
49
50
|
def assert_match_syntax_error(match, template, assigns = {})
|
50
51
|
exception = assert_raises(Liquid::SyntaxError) do
|
51
|
-
Template.parse(template).render(assigns)
|
52
|
+
Template.parse(template, line_numbers: true).render(assigns)
|
52
53
|
end
|
53
|
-
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}")
|
54
72
|
end
|
55
73
|
|
56
74
|
def with_global_filter(*globals)
|
57
|
-
|
58
|
-
Liquid::
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|
62
82
|
|
63
83
|
globals.each do |global|
|
64
84
|
Liquid::Template.register_filter(global)
|
65
85
|
end
|
66
86
|
yield
|
67
87
|
ensure
|
68
|
-
Liquid::
|
69
|
-
Liquid::
|
70
|
-
end
|
71
|
-
|
72
|
-
def with_taint_mode(mode)
|
73
|
-
old_mode = Liquid::Template.taint_mode
|
74
|
-
Liquid::Template.taint_mode = mode
|
75
|
-
yield
|
76
|
-
ensure
|
77
|
-
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)
|
78
90
|
end
|
79
91
|
|
80
92
|
def with_error_mode(mode)
|
@@ -84,6 +96,20 @@ module Minitest
|
|
84
96
|
ensure
|
85
97
|
Liquid::Template.error_mode = old_mode
|
86
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
|
87
113
|
end
|
88
114
|
end
|
89
115
|
|
@@ -114,3 +140,30 @@ class ErrorDrop < Liquid::Drop
|
|
114
140
|
raise Exception, 'exception'
|
115
141
|
end
|
116
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,154 +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)
|
65
67
|
end
|
66
68
|
|
67
69
|
def test_hash_compare_backwards_compatibility
|
68
|
-
assert_nil
|
69
|
-
assert_nil
|
70
|
-
assert_equal
|
71
|
-
assert_equal
|
72
|
-
assert_equal
|
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)
|
73
75
|
end
|
74
76
|
|
75
77
|
def test_contains_works_on_arrays
|
76
|
-
@context
|
78
|
+
@context = Liquid::Context.new
|
77
79
|
@context['array'] = [1, 2, 3, 4, 5]
|
78
|
-
array_expr
|
80
|
+
array_expr = VariableLookup.new("array")
|
79
81
|
|
80
|
-
assert_evaluates_false
|
81
|
-
assert_evaluates_true
|
82
|
-
assert_evaluates_true
|
83
|
-
assert_evaluates_true
|
84
|
-
assert_evaluates_true
|
85
|
-
assert_evaluates_true
|
86
|
-
assert_evaluates_false
|
87
|
-
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")
|
88
90
|
end
|
89
91
|
|
90
92
|
def test_contains_returns_false_for_nil_operands
|
91
93
|
@context = Liquid::Context.new
|
92
|
-
assert_evaluates_false
|
93
|
-
assert_evaluates_false
|
94
|
+
assert_evaluates_false(VariableLookup.new('not_assigned'), 'contains', '0')
|
95
|
+
assert_evaluates_false(0, 'contains', VariableLookup.new('not_assigned'))
|
94
96
|
end
|
95
97
|
|
96
98
|
def test_contains_return_false_on_wrong_data_type
|
97
|
-
assert_evaluates_false
|
99
|
+
assert_evaluates_false(1, 'contains', 0)
|
98
100
|
end
|
99
101
|
|
100
102
|
def test_contains_with_string_left_operand_coerces_right_operand_to_string
|
101
|
-
assert_evaluates_true
|
102
|
-
assert_evaluates_false
|
103
|
+
assert_evaluates_true(' 1 ', 'contains', 1)
|
104
|
+
assert_evaluates_false(' 1 ', 'contains', 2)
|
103
105
|
end
|
104
106
|
|
105
107
|
def test_or_condition
|
106
108
|
condition = Condition.new(1, '==', 2)
|
107
109
|
|
108
|
-
assert_equal
|
110
|
+
assert_equal(false, condition.evaluate)
|
109
111
|
|
110
|
-
condition.or
|
112
|
+
condition.or(Condition.new(2, '==', 1))
|
111
113
|
|
112
|
-
assert_equal
|
114
|
+
assert_equal(false, condition.evaluate)
|
113
115
|
|
114
|
-
condition.or
|
116
|
+
condition.or(Condition.new(1, '==', 1))
|
115
117
|
|
116
|
-
assert_equal
|
118
|
+
assert_equal(true, condition.evaluate)
|
117
119
|
end
|
118
120
|
|
119
121
|
def test_and_condition
|
120
122
|
condition = Condition.new(1, '==', 1)
|
121
123
|
|
122
|
-
assert_equal
|
124
|
+
assert_equal(true, condition.evaluate)
|
123
125
|
|
124
|
-
condition.and
|
126
|
+
condition.and(Condition.new(2, '==', 2))
|
125
127
|
|
126
|
-
assert_equal
|
128
|
+
assert_equal(true, condition.evaluate)
|
127
129
|
|
128
|
-
condition.and
|
130
|
+
condition.and(Condition.new(2, '==', 1))
|
129
131
|
|
130
|
-
assert_equal
|
132
|
+
assert_equal(false, condition.evaluate)
|
131
133
|
end
|
132
134
|
|
133
135
|
def test_should_allow_custom_proc_operator
|
134
|
-
Condition.operators['starts_with'] = proc { |
|
136
|
+
Condition.operators['starts_with'] = proc { |_cond, left, right| left =~ /^#{right}/ }
|
135
137
|
|
136
|
-
assert_evaluates_true
|
137
|
-
assert_evaluates_false
|
138
|
+
assert_evaluates_true('bob', 'starts_with', 'b')
|
139
|
+
assert_evaluates_false('bob', 'starts_with', 'o')
|
138
140
|
ensure
|
139
|
-
Condition.operators.delete
|
141
|
+
Condition.operators.delete('starts_with')
|
140
142
|
end
|
141
143
|
|
142
144
|
def test_left_or_right_may_contain_operators
|
143
|
-
@context
|
145
|
+
@context = Liquid::Context.new
|
144
146
|
@context['one'] = @context['another'] = "gnomeslab-and-or-liquid"
|
145
147
|
|
146
|
-
assert_evaluates_true
|
148
|
+
assert_evaluates_true(VariableLookup.new("one"), '==', VariableLookup.new("another"))
|
147
149
|
end
|
148
150
|
|
149
151
|
private
|
150
152
|
|
151
153
|
def assert_evaluates_true(left, op, right)
|
152
|
-
assert
|
153
|
-
"Evaluated false: #{left} #{op} #{right}"
|
154
|
+
assert(Condition.new(left, op, right).evaluate(@context),
|
155
|
+
"Evaluated false: #{left} #{op} #{right}")
|
154
156
|
end
|
155
157
|
|
156
158
|
def assert_evaluates_false(left, op, right)
|
157
|
-
assert
|
158
|
-
"Evaluated true: #{left} #{op} #{right}"
|
159
|
+
assert(!Condition.new(left, op, right).evaluate(@context),
|
160
|
+
"Evaluated true: #{left} #{op} #{right}")
|
159
161
|
end
|
160
162
|
|
161
163
|
def assert_evaluates_argument_error(left, op, right)
|