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,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
|
3
|
-
class
|
5
|
+
class ProfilerTest < Minitest::Test
|
4
6
|
include Liquid
|
5
7
|
|
6
8
|
class ProfilingFileSystem
|
@@ -17,35 +19,35 @@ class RenderProfilingTest < Minitest::Test
|
|
17
19
|
t = Template.parse("{{ 'a string' | upcase }}")
|
18
20
|
t.render!
|
19
21
|
|
20
|
-
assert_nil
|
22
|
+
assert_nil(t.profiler)
|
21
23
|
end
|
22
24
|
|
23
25
|
def test_parse_makes_available_simple_profiling
|
24
26
|
t = Template.parse("{{ 'a string' | upcase }}", profile: true)
|
25
27
|
t.render!
|
26
28
|
|
27
|
-
assert_equal
|
29
|
+
assert_equal(1, t.profiler.length)
|
28
30
|
|
29
31
|
node = t.profiler[0]
|
30
|
-
assert_equal
|
32
|
+
assert_equal(" 'a string' | upcase ", node.code)
|
31
33
|
end
|
32
34
|
|
33
35
|
def test_render_ignores_raw_strings_when_profiling
|
34
36
|
t = Template.parse("This is raw string\nstuff\nNewline", profile: true)
|
35
37
|
t.render!
|
36
38
|
|
37
|
-
assert_equal
|
39
|
+
assert_equal(0, t.profiler.length)
|
38
40
|
end
|
39
41
|
|
40
42
|
def test_profiling_includes_line_numbers_of_liquid_nodes
|
41
43
|
t = Template.parse("{{ 'a string' | upcase }}\n{% increment test %}", profile: true)
|
42
44
|
t.render!
|
43
|
-
assert_equal
|
45
|
+
assert_equal(2, t.profiler.length)
|
44
46
|
|
45
47
|
# {{ 'a string' | upcase }}
|
46
|
-
assert_equal
|
48
|
+
assert_equal(1, t.profiler[0].line_number)
|
47
49
|
# {{ increment test }}
|
48
|
-
assert_equal
|
50
|
+
assert_equal(2, t.profiler[1].line_number)
|
49
51
|
end
|
50
52
|
|
51
53
|
def test_profiling_includes_line_numbers_of_included_partials
|
@@ -55,9 +57,20 @@ class RenderProfilingTest < Minitest::Test
|
|
55
57
|
included_children = t.profiler[0].children
|
56
58
|
|
57
59
|
# {% assign template_name = 'a_template' %}
|
58
|
-
assert_equal
|
60
|
+
assert_equal(1, included_children[0].line_number)
|
59
61
|
# {{ template_name }}
|
60
|
-
assert_equal
|
62
|
+
assert_equal(2, included_children[1].line_number)
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_profiling_render_tag
|
66
|
+
t = Template.parse("{% render 'a_template' %}", profile: true)
|
67
|
+
t.render!
|
68
|
+
|
69
|
+
render_children = t.profiler[0].children
|
70
|
+
render_children.each do |timing|
|
71
|
+
assert_equal('a_template', timing.partial)
|
72
|
+
end
|
73
|
+
assert_equal([1, 2], render_children.map(&:line_number))
|
61
74
|
end
|
62
75
|
|
63
76
|
def test_profiling_times_the_rendering_of_tokens
|
@@ -65,14 +78,45 @@ class RenderProfilingTest < Minitest::Test
|
|
65
78
|
t.render!
|
66
79
|
|
67
80
|
node = t.profiler[0]
|
68
|
-
refute_nil
|
81
|
+
refute_nil(node.render_time)
|
69
82
|
end
|
70
83
|
|
71
84
|
def test_profiling_times_the_entire_render
|
72
85
|
t = Template.parse("{% include 'a_template' %}", profile: true)
|
73
86
|
t.render!
|
74
87
|
|
75
|
-
assert
|
88
|
+
assert(t.profiler.total_render_time >= 0, "Total render time was not calculated")
|
89
|
+
end
|
90
|
+
|
91
|
+
class SleepTag < Liquid::Tag
|
92
|
+
def initialize(tag_name, markup, parse_context)
|
93
|
+
super
|
94
|
+
@duration = Float(markup)
|
95
|
+
end
|
96
|
+
|
97
|
+
def render_to_output_buffer(_context, _output)
|
98
|
+
sleep(@duration)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_profiling_multiple_renders
|
103
|
+
with_custom_tag('sleep', SleepTag) do
|
104
|
+
context = Liquid::Context.new
|
105
|
+
t = Liquid::Template.parse("{% sleep 0.001 %}", profile: true)
|
106
|
+
context.template_name = 'index'
|
107
|
+
t.render!(context)
|
108
|
+
context.template_name = 'layout'
|
109
|
+
first_render_time = context.profiler.total_time
|
110
|
+
t.render!(context)
|
111
|
+
|
112
|
+
profiler = context.profiler
|
113
|
+
children = profiler.children
|
114
|
+
assert_operator(first_render_time, :>=, 0.001)
|
115
|
+
assert_operator(profiler.total_time, :>=, 0.001 + first_render_time)
|
116
|
+
assert_equal(["index", "layout"], children.map(&:template_name))
|
117
|
+
assert_equal([nil, nil], children.map(&:code))
|
118
|
+
assert_equal(profiler.total_time, children.map(&:total_time).reduce(&:+))
|
119
|
+
end
|
76
120
|
end
|
77
121
|
|
78
122
|
def test_profiling_uses_include_to_mark_children
|
@@ -80,7 +124,7 @@ class RenderProfilingTest < Minitest::Test
|
|
80
124
|
t.render!
|
81
125
|
|
82
126
|
include_node = t.profiler[1]
|
83
|
-
assert_equal
|
127
|
+
assert_equal(2, include_node.children.length)
|
84
128
|
end
|
85
129
|
|
86
130
|
def test_profiling_marks_children_with_the_name_of_included_partial
|
@@ -89,7 +133,7 @@ class RenderProfilingTest < Minitest::Test
|
|
89
133
|
|
90
134
|
include_node = t.profiler[1]
|
91
135
|
include_node.children.each do |child|
|
92
|
-
assert_equal
|
136
|
+
assert_equal("a_template", child.partial)
|
93
137
|
end
|
94
138
|
end
|
95
139
|
|
@@ -99,12 +143,12 @@ class RenderProfilingTest < Minitest::Test
|
|
99
143
|
|
100
144
|
a_template = t.profiler[1]
|
101
145
|
a_template.children.each do |child|
|
102
|
-
assert_equal
|
146
|
+
assert_equal("a_template", child.partial)
|
103
147
|
end
|
104
148
|
|
105
149
|
b_template = t.profiler[2]
|
106
150
|
b_template.children.each do |child|
|
107
|
-
assert_equal
|
151
|
+
assert_equal("b_template", child.partial)
|
108
152
|
end
|
109
153
|
end
|
110
154
|
|
@@ -114,12 +158,12 @@ class RenderProfilingTest < Minitest::Test
|
|
114
158
|
|
115
159
|
a_template1 = t.profiler[1]
|
116
160
|
a_template1.children.each do |child|
|
117
|
-
assert_equal
|
161
|
+
assert_equal("a_template", child.partial)
|
118
162
|
end
|
119
163
|
|
120
164
|
a_template2 = t.profiler[2]
|
121
165
|
a_template2.children.each do |child|
|
122
|
-
assert_equal
|
166
|
+
assert_equal("a_template", child.partial)
|
123
167
|
end
|
124
168
|
end
|
125
169
|
|
@@ -128,27 +172,42 @@ class RenderProfilingTest < Minitest::Test
|
|
128
172
|
t.render!
|
129
173
|
|
130
174
|
timing_count = 0
|
131
|
-
t.profiler.each do |
|
175
|
+
t.profiler.each do |_timing|
|
132
176
|
timing_count += 1
|
133
177
|
end
|
134
178
|
|
135
|
-
assert_equal
|
179
|
+
assert_equal(2, timing_count)
|
136
180
|
end
|
137
181
|
|
138
182
|
def test_profiling_marks_children_of_if_blocks
|
139
183
|
t = Template.parse("{% if true %} {% increment test %} {{ test }} {% endif %}", profile: true)
|
140
184
|
t.render!
|
141
185
|
|
142
|
-
assert_equal
|
143
|
-
assert_equal
|
186
|
+
assert_equal(1, t.profiler.length)
|
187
|
+
assert_equal(2, t.profiler[0].children.length)
|
144
188
|
end
|
145
189
|
|
146
190
|
def test_profiling_marks_children_of_for_blocks
|
147
191
|
t = Template.parse("{% for item in collection %} {{ item }} {% endfor %}", profile: true)
|
148
|
-
t.render!(
|
192
|
+
t.render!("collection" => ["one", "two"])
|
149
193
|
|
150
|
-
assert_equal
|
194
|
+
assert_equal(1, t.profiler.length)
|
151
195
|
# Will profile each invocation of the for block
|
152
|
-
assert_equal
|
196
|
+
assert_equal(2, t.profiler[0].children.length)
|
197
|
+
end
|
198
|
+
|
199
|
+
def test_profiling_supports_self_time
|
200
|
+
t = Template.parse("{% for item in collection %} {{ item }} {% endfor %}", profile: true)
|
201
|
+
t.render!("collection" => ["one", "two"])
|
202
|
+
leaf = t.profiler[0].children[0]
|
203
|
+
|
204
|
+
assert_operator(leaf.self_time, :>, 0)
|
205
|
+
end
|
206
|
+
|
207
|
+
def test_profiling_supports_total_time
|
208
|
+
t = Template.parse("{% if true %} {% increment test %} {{ test }} {% endif %}", profile: true)
|
209
|
+
t.render!
|
210
|
+
|
211
|
+
assert_operator(t.profiler[0].total_time, :>, 0)
|
153
212
|
end
|
154
213
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
|
3
5
|
module SecurityFilter
|
@@ -14,53 +16,74 @@ class SecurityTest < Minitest::Test
|
|
14
16
|
end
|
15
17
|
|
16
18
|
def test_no_instance_eval
|
17
|
-
text
|
19
|
+
text = %( {{ '1+1' | instance_eval }} )
|
18
20
|
expected = %( 1+1 )
|
19
21
|
|
20
|
-
assert_equal
|
22
|
+
assert_equal(expected, Template.parse(text).render!(@assigns))
|
21
23
|
end
|
22
24
|
|
23
25
|
def test_no_existing_instance_eval
|
24
|
-
text
|
26
|
+
text = %( {{ '1+1' | __instance_eval__ }} )
|
25
27
|
expected = %( 1+1 )
|
26
28
|
|
27
|
-
assert_equal
|
29
|
+
assert_equal(expected, Template.parse(text).render!(@assigns))
|
28
30
|
end
|
29
31
|
|
30
32
|
def test_no_instance_eval_after_mixing_in_new_filter
|
31
|
-
text
|
33
|
+
text = %( {{ '1+1' | instance_eval }} )
|
32
34
|
expected = %( 1+1 )
|
33
35
|
|
34
|
-
assert_equal
|
36
|
+
assert_equal(expected, Template.parse(text).render!(@assigns))
|
35
37
|
end
|
36
38
|
|
37
39
|
def test_no_instance_eval_later_in_chain
|
38
|
-
text
|
40
|
+
text = %( {{ '1+1' | add_one | instance_eval }} )
|
39
41
|
expected = %( 1+1 + 1 )
|
40
42
|
|
41
|
-
assert_equal
|
43
|
+
assert_equal(expected, Template.parse(text).render!(@assigns, filters: SecurityFilter))
|
42
44
|
end
|
43
45
|
|
44
|
-
def
|
46
|
+
def test_does_not_permanently_add_filters_to_symbol_table
|
45
47
|
current_symbols = Symbol.all_symbols
|
46
48
|
|
47
|
-
|
49
|
+
# MRI imprecisely marks objects found on the C stack, which can result
|
50
|
+
# in uninitialized memory being marked. This can even result in the test failing
|
51
|
+
# deterministically for a given compilation of ruby. Using a separate thread will
|
52
|
+
# keep these writes of the symbol pointer on a separate stack that will be garbage
|
53
|
+
# collected after Thread#join.
|
54
|
+
Thread.new do
|
55
|
+
test = %( {{ "some_string" | a_bad_filter }} )
|
56
|
+
Template.parse(test).render!
|
57
|
+
nil
|
58
|
+
end.join
|
48
59
|
|
49
|
-
|
50
|
-
assert_equal [], (Symbol.all_symbols - current_symbols)
|
60
|
+
GC.start
|
51
61
|
|
52
|
-
|
53
|
-
assert_equal [], (Symbol.all_symbols - current_symbols)
|
62
|
+
assert_equal([], (Symbol.all_symbols - current_symbols))
|
54
63
|
end
|
55
64
|
|
56
65
|
def test_does_not_add_drop_methods_to_symbol_table
|
57
66
|
current_symbols = Symbol.all_symbols
|
58
67
|
|
59
68
|
assigns = { 'drop' => Drop.new }
|
60
|
-
assert_equal
|
61
|
-
assert_equal
|
62
|
-
assert_equal
|
69
|
+
assert_equal("", Template.parse("{{ drop.custom_method_1 }}", assigns).render!)
|
70
|
+
assert_equal("", Template.parse("{{ drop.custom_method_2 }}", assigns).render!)
|
71
|
+
assert_equal("", Template.parse("{{ drop.custom_method_3 }}", assigns).render!)
|
72
|
+
|
73
|
+
assert_equal([], (Symbol.all_symbols - current_symbols))
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_max_depth_nested_blocks_does_not_raise_exception
|
77
|
+
depth = Liquid::Block::MAX_DEPTH
|
78
|
+
code = "{% if true %}" * depth + "rendered" + "{% endif %}" * depth
|
79
|
+
assert_equal("rendered", Template.parse(code).render!)
|
80
|
+
end
|
63
81
|
|
64
|
-
|
82
|
+
def test_more_than_max_depth_nested_blocks_raises_exception
|
83
|
+
depth = Liquid::Block::MAX_DEPTH + 1
|
84
|
+
code = "{% if true %}" * depth + "rendered" + "{% endif %}" * depth
|
85
|
+
assert_raises(Liquid::StackLevelError) do
|
86
|
+
Template.parse(code).render!
|
87
|
+
end
|
65
88
|
end
|
66
89
|
end # SecurityTest
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'test_helper'
|
4
5
|
|
@@ -17,7 +18,7 @@ class TestThing
|
|
17
18
|
"woot: #{@foo}"
|
18
19
|
end
|
19
20
|
|
20
|
-
def [](
|
21
|
+
def [](_whatever)
|
21
22
|
to_s
|
22
23
|
end
|
23
24
|
|
@@ -37,7 +38,7 @@ class TestEnumerable < Liquid::Drop
|
|
37
38
|
include Enumerable
|
38
39
|
|
39
40
|
def each(&block)
|
40
|
-
[
|
41
|
+
[{ "foo" => 1, "bar" => 2 }, { "foo" => 2, "bar" => 1 }, { "foo" => 3, "bar" => 3 }].each(&block)
|
41
42
|
end
|
42
43
|
end
|
43
44
|
|
@@ -59,34 +60,34 @@ class StandardFiltersTest < Minitest::Test
|
|
59
60
|
end
|
60
61
|
|
61
62
|
def test_size
|
62
|
-
assert_equal
|
63
|
-
assert_equal
|
64
|
-
assert_equal
|
63
|
+
assert_equal(3, @filters.size([1, 2, 3]))
|
64
|
+
assert_equal(0, @filters.size([]))
|
65
|
+
assert_equal(0, @filters.size(nil))
|
65
66
|
end
|
66
67
|
|
67
68
|
def test_downcase
|
68
|
-
assert_equal
|
69
|
-
assert_equal
|
69
|
+
assert_equal('testing', @filters.downcase("Testing"))
|
70
|
+
assert_equal('', @filters.downcase(nil))
|
70
71
|
end
|
71
72
|
|
72
73
|
def test_upcase
|
73
|
-
assert_equal
|
74
|
-
assert_equal
|
74
|
+
assert_equal('TESTING', @filters.upcase("Testing"))
|
75
|
+
assert_equal('', @filters.upcase(nil))
|
75
76
|
end
|
76
77
|
|
77
78
|
def test_slice
|
78
|
-
assert_equal
|
79
|
-
assert_equal
|
80
|
-
assert_equal
|
81
|
-
assert_equal
|
82
|
-
assert_equal
|
83
|
-
assert_equal
|
84
|
-
assert_equal
|
85
|
-
assert_equal
|
86
|
-
assert_equal
|
87
|
-
assert_equal
|
88
|
-
assert_equal
|
89
|
-
assert_equal
|
79
|
+
assert_equal('oob', @filters.slice('foobar', 1, 3))
|
80
|
+
assert_equal('oobar', @filters.slice('foobar', 1, 1000))
|
81
|
+
assert_equal('', @filters.slice('foobar', 1, 0))
|
82
|
+
assert_equal('o', @filters.slice('foobar', 1, 1))
|
83
|
+
assert_equal('bar', @filters.slice('foobar', 3, 3))
|
84
|
+
assert_equal('ar', @filters.slice('foobar', -2, 2))
|
85
|
+
assert_equal('ar', @filters.slice('foobar', -2, 1000))
|
86
|
+
assert_equal('r', @filters.slice('foobar', -1))
|
87
|
+
assert_equal('', @filters.slice(nil, 0))
|
88
|
+
assert_equal('', @filters.slice('foobar', 100, 10))
|
89
|
+
assert_equal('', @filters.slice('foobar', -100, 10))
|
90
|
+
assert_equal('oob', @filters.slice('foobar', '1', '3'))
|
90
91
|
assert_raises(Liquid::ArgumentError) do
|
91
92
|
@filters.slice('foobar', nil)
|
92
93
|
end
|
@@ -97,390 +98,566 @@ class StandardFiltersTest < Minitest::Test
|
|
97
98
|
|
98
99
|
def test_slice_on_arrays
|
99
100
|
input = 'foobar'.split(//)
|
100
|
-
assert_equal
|
101
|
-
assert_equal
|
102
|
-
assert_equal
|
103
|
-
assert_equal
|
104
|
-
assert_equal
|
105
|
-
assert_equal
|
106
|
-
assert_equal
|
107
|
-
assert_equal
|
108
|
-
assert_equal
|
109
|
-
assert_equal
|
101
|
+
assert_equal(%w(o o b), @filters.slice(input, 1, 3))
|
102
|
+
assert_equal(%w(o o b a r), @filters.slice(input, 1, 1000))
|
103
|
+
assert_equal(%w(), @filters.slice(input, 1, 0))
|
104
|
+
assert_equal(%w(o), @filters.slice(input, 1, 1))
|
105
|
+
assert_equal(%w(b a r), @filters.slice(input, 3, 3))
|
106
|
+
assert_equal(%w(a r), @filters.slice(input, -2, 2))
|
107
|
+
assert_equal(%w(a r), @filters.slice(input, -2, 1000))
|
108
|
+
assert_equal(%w(r), @filters.slice(input, -1))
|
109
|
+
assert_equal(%w(), @filters.slice(input, 100, 10))
|
110
|
+
assert_equal(%w(), @filters.slice(input, -100, 10))
|
110
111
|
end
|
111
112
|
|
112
113
|
def test_truncate
|
113
|
-
assert_equal
|
114
|
-
assert_equal
|
115
|
-
assert_equal
|
116
|
-
assert_equal
|
117
|
-
assert_equal
|
118
|
-
assert_equal
|
114
|
+
assert_equal('1234...', @filters.truncate('1234567890', 7))
|
115
|
+
assert_equal('1234567890', @filters.truncate('1234567890', 20))
|
116
|
+
assert_equal('...', @filters.truncate('1234567890', 0))
|
117
|
+
assert_equal('1234567890', @filters.truncate('1234567890'))
|
118
|
+
assert_equal("测试...", @filters.truncate("测试测试测试测试", 5))
|
119
|
+
assert_equal('12341', @filters.truncate("1234567890", 5, 1))
|
119
120
|
end
|
120
121
|
|
121
122
|
def test_split
|
122
|
-
assert_equal
|
123
|
-
assert_equal
|
124
|
-
assert_equal
|
125
|
-
assert_equal
|
126
|
-
assert_equal
|
123
|
+
assert_equal(['12', '34'], @filters.split('12~34', '~'))
|
124
|
+
assert_equal(['A? ', ' ,Z'], @filters.split('A? ~ ~ ~ ,Z', '~ ~ ~'))
|
125
|
+
assert_equal(['A?Z'], @filters.split('A?Z', '~'))
|
126
|
+
assert_equal([], @filters.split(nil, ' '))
|
127
|
+
assert_equal(['A', 'Z'], @filters.split('A1Z', 1))
|
127
128
|
end
|
128
129
|
|
129
130
|
def test_escape
|
130
|
-
assert_equal
|
131
|
-
assert_equal
|
132
|
-
assert_equal
|
131
|
+
assert_equal('<strong>', @filters.escape('<strong>'))
|
132
|
+
assert_equal('1', @filters.escape(1))
|
133
|
+
assert_equal('2001-02-03', @filters.escape(Date.new(2001, 2, 3)))
|
134
|
+
assert_nil(@filters.escape(nil))
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_h
|
138
|
+
assert_equal('<strong>', @filters.h('<strong>'))
|
139
|
+
assert_equal('1', @filters.h(1))
|
140
|
+
assert_equal('2001-02-03', @filters.h(Date.new(2001, 2, 3)))
|
141
|
+
assert_nil(@filters.h(nil))
|
133
142
|
end
|
134
143
|
|
135
144
|
def test_escape_once
|
136
|
-
assert_equal
|
145
|
+
assert_equal('<strong>Hulk</strong>', @filters.escape_once('<strong>Hulk</strong>'))
|
137
146
|
end
|
138
147
|
|
139
148
|
def test_url_encode
|
140
|
-
assert_equal
|
141
|
-
assert_equal
|
149
|
+
assert_equal('foo%2B1%40example.com', @filters.url_encode('foo+1@example.com'))
|
150
|
+
assert_equal('1', @filters.url_encode(1))
|
151
|
+
assert_equal('2001-02-03', @filters.url_encode(Date.new(2001, 2, 3)))
|
152
|
+
assert_nil(@filters.url_encode(nil))
|
142
153
|
end
|
143
154
|
|
144
155
|
def test_url_decode
|
145
|
-
assert_equal
|
146
|
-
assert_equal
|
147
|
-
assert_equal
|
148
|
-
assert_equal
|
156
|
+
assert_equal('foo bar', @filters.url_decode('foo+bar'))
|
157
|
+
assert_equal('foo bar', @filters.url_decode('foo%20bar'))
|
158
|
+
assert_equal('foo+1@example.com', @filters.url_decode('foo%2B1%40example.com'))
|
159
|
+
assert_equal('1', @filters.url_decode(1))
|
160
|
+
assert_equal('2001-02-03', @filters.url_decode(Date.new(2001, 2, 3)))
|
161
|
+
assert_nil(@filters.url_decode(nil))
|
162
|
+
exception = assert_raises(Liquid::ArgumentError) do
|
163
|
+
@filters.url_decode('%ff')
|
164
|
+
end
|
165
|
+
assert_equal('Liquid error: invalid byte sequence in UTF-8', exception.message)
|
149
166
|
end
|
150
167
|
|
151
168
|
def test_truncatewords
|
152
|
-
assert_equal
|
153
|
-
assert_equal
|
154
|
-
assert_equal
|
155
|
-
assert_equal
|
156
|
-
|
157
|
-
|
169
|
+
assert_equal('one two three', @filters.truncatewords('one two three', 4))
|
170
|
+
assert_equal('one two...', @filters.truncatewords('one two three', 2))
|
171
|
+
assert_equal('one two three', @filters.truncatewords('one two three'))
|
172
|
+
assert_equal(
|
173
|
+
'Two small (13” x 5.5” x 10” high) baskets fit inside one large basket (13”...',
|
174
|
+
@filters.truncatewords('Two small (13” x 5.5” x 10” high) baskets fit inside one large basket (13” x 16” x 10.5” high) with cover.', 15)
|
175
|
+
)
|
176
|
+
assert_equal("测试测试测试测试", @filters.truncatewords('测试测试测试测试', 5))
|
177
|
+
assert_equal('one two1', @filters.truncatewords("one two three", 2, 1))
|
178
|
+
assert_equal('one two three...', @filters.truncatewords("one two\tthree\nfour", 3))
|
179
|
+
assert_equal('one two...', @filters.truncatewords("one two three four", 2))
|
180
|
+
assert_equal('one...', @filters.truncatewords("one two three four", 0))
|
158
181
|
end
|
159
182
|
|
160
183
|
def test_strip_html
|
161
|
-
assert_equal
|
162
|
-
assert_equal
|
163
|
-
assert_equal
|
164
|
-
assert_equal
|
165
|
-
assert_equal
|
166
|
-
assert_equal
|
167
|
-
assert_equal
|
184
|
+
assert_equal('test', @filters.strip_html("<div>test</div>"))
|
185
|
+
assert_equal('test', @filters.strip_html("<div id='test'>test</div>"))
|
186
|
+
assert_equal('', @filters.strip_html("<script type='text/javascript'>document.write('some stuff');</script>"))
|
187
|
+
assert_equal('', @filters.strip_html("<style type='text/css'>foo bar</style>"))
|
188
|
+
assert_equal('test', @filters.strip_html("<div\nclass='multiline'>test</div>"))
|
189
|
+
assert_equal('test', @filters.strip_html("<!-- foo bar \n test -->test"))
|
190
|
+
assert_equal('', @filters.strip_html(nil))
|
191
|
+
|
192
|
+
# Quirk of the existing implementation
|
193
|
+
assert_equal('foo;', @filters.strip_html("<<<script </script>script>foo;</script>"))
|
168
194
|
end
|
169
195
|
|
170
196
|
def test_join
|
171
|
-
assert_equal
|
172
|
-
assert_equal
|
197
|
+
assert_equal('1 2 3 4', @filters.join([1, 2, 3, 4]))
|
198
|
+
assert_equal('1 - 2 - 3 - 4', @filters.join([1, 2, 3, 4], ' - '))
|
199
|
+
assert_equal('1121314', @filters.join([1, 2, 3, 4], 1))
|
173
200
|
end
|
174
201
|
|
175
202
|
def test_sort
|
176
|
-
assert_equal
|
177
|
-
assert_equal
|
203
|
+
assert_equal([1, 2, 3, 4], @filters.sort([4, 3, 2, 1]))
|
204
|
+
assert_equal([{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }], @filters.sort([{ "a" => 4 }, { "a" => 3 }, { "a" => 1 }, { "a" => 2 }], "a"))
|
205
|
+
end
|
206
|
+
|
207
|
+
def test_sort_with_nils
|
208
|
+
assert_equal([1, 2, 3, 4, nil], @filters.sort([nil, 4, 3, 2, 1]))
|
209
|
+
assert_equal([{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }, {}], @filters.sort([{ "a" => 4 }, { "a" => 3 }, {}, { "a" => 1 }, { "a" => 2 }], "a"))
|
178
210
|
end
|
179
211
|
|
180
212
|
def test_sort_when_property_is_sometimes_missing_puts_nils_last
|
181
|
-
input
|
213
|
+
input = [
|
182
214
|
{ "price" => 4, "handle" => "alpha" },
|
183
215
|
{ "handle" => "beta" },
|
184
216
|
{ "price" => 1, "handle" => "gamma" },
|
185
217
|
{ "handle" => "delta" },
|
186
|
-
{ "price" => 2, "handle" => "epsilon" }
|
218
|
+
{ "price" => 2, "handle" => "epsilon" },
|
187
219
|
]
|
188
220
|
expectation = [
|
189
221
|
{ "price" => 1, "handle" => "gamma" },
|
190
222
|
{ "price" => 2, "handle" => "epsilon" },
|
191
223
|
{ "price" => 4, "handle" => "alpha" },
|
192
224
|
{ "handle" => "delta" },
|
193
|
-
{ "handle" => "beta" }
|
225
|
+
{ "handle" => "beta" },
|
194
226
|
]
|
195
|
-
assert_equal
|
227
|
+
assert_equal(expectation, @filters.sort(input, "price"))
|
228
|
+
end
|
229
|
+
|
230
|
+
def test_sort_natural
|
231
|
+
assert_equal(["a", "B", "c", "D"], @filters.sort_natural(["c", "D", "a", "B"]))
|
232
|
+
assert_equal([{ "a" => "a" }, { "a" => "B" }, { "a" => "c" }, { "a" => "D" }], @filters.sort_natural([{ "a" => "D" }, { "a" => "c" }, { "a" => "a" }, { "a" => "B" }], "a"))
|
233
|
+
end
|
234
|
+
|
235
|
+
def test_sort_natural_with_nils
|
236
|
+
assert_equal(["a", "B", "c", "D", nil], @filters.sort_natural([nil, "c", "D", "a", "B"]))
|
237
|
+
assert_equal([{ "a" => "a" }, { "a" => "B" }, { "a" => "c" }, { "a" => "D" }, {}], @filters.sort_natural([{ "a" => "D" }, { "a" => "c" }, {}, { "a" => "a" }, { "a" => "B" }], "a"))
|
238
|
+
end
|
239
|
+
|
240
|
+
def test_sort_natural_when_property_is_sometimes_missing_puts_nils_last
|
241
|
+
input = [
|
242
|
+
{ "price" => "4", "handle" => "alpha" },
|
243
|
+
{ "handle" => "beta" },
|
244
|
+
{ "price" => "1", "handle" => "gamma" },
|
245
|
+
{ "handle" => "delta" },
|
246
|
+
{ "price" => 2, "handle" => "epsilon" },
|
247
|
+
]
|
248
|
+
expectation = [
|
249
|
+
{ "price" => "1", "handle" => "gamma" },
|
250
|
+
{ "price" => 2, "handle" => "epsilon" },
|
251
|
+
{ "price" => "4", "handle" => "alpha" },
|
252
|
+
{ "handle" => "delta" },
|
253
|
+
{ "handle" => "beta" },
|
254
|
+
]
|
255
|
+
assert_equal(expectation, @filters.sort_natural(input, "price"))
|
256
|
+
end
|
257
|
+
|
258
|
+
def test_sort_natural_case_check
|
259
|
+
input = [
|
260
|
+
{ "key" => "X" },
|
261
|
+
{ "key" => "Y" },
|
262
|
+
{ "key" => "Z" },
|
263
|
+
{ "fake" => "t" },
|
264
|
+
{ "key" => "a" },
|
265
|
+
{ "key" => "b" },
|
266
|
+
{ "key" => "c" },
|
267
|
+
]
|
268
|
+
expectation = [
|
269
|
+
{ "key" => "a" },
|
270
|
+
{ "key" => "b" },
|
271
|
+
{ "key" => "c" },
|
272
|
+
{ "key" => "X" },
|
273
|
+
{ "key" => "Y" },
|
274
|
+
{ "key" => "Z" },
|
275
|
+
{ "fake" => "t" },
|
276
|
+
]
|
277
|
+
assert_equal(expectation, @filters.sort_natural(input, "key"))
|
278
|
+
assert_equal(["a", "b", "c", "X", "Y", "Z"], @filters.sort_natural(["X", "Y", "Z", "a", "b", "c"]))
|
196
279
|
end
|
197
280
|
|
198
281
|
def test_sort_empty_array
|
199
|
-
assert_equal
|
282
|
+
assert_equal([], @filters.sort([], "a"))
|
283
|
+
end
|
284
|
+
|
285
|
+
def test_sort_invalid_property
|
286
|
+
foo = [
|
287
|
+
[1],
|
288
|
+
[2],
|
289
|
+
[3],
|
290
|
+
]
|
291
|
+
|
292
|
+
assert_raises(Liquid::ArgumentError) do
|
293
|
+
@filters.sort(foo, "bar")
|
294
|
+
end
|
200
295
|
end
|
201
296
|
|
202
297
|
def test_sort_natural_empty_array
|
203
|
-
assert_equal
|
298
|
+
assert_equal([], @filters.sort_natural([], "a"))
|
299
|
+
end
|
300
|
+
|
301
|
+
def test_sort_natural_invalid_property
|
302
|
+
foo = [
|
303
|
+
[1],
|
304
|
+
[2],
|
305
|
+
[3],
|
306
|
+
]
|
307
|
+
|
308
|
+
assert_raises(Liquid::ArgumentError) do
|
309
|
+
@filters.sort_natural(foo, "bar")
|
310
|
+
end
|
204
311
|
end
|
205
312
|
|
206
313
|
def test_legacy_sort_hash
|
207
|
-
assert_equal
|
314
|
+
assert_equal([{ a: 1, b: 2 }], @filters.sort(a: 1, b: 2))
|
208
315
|
end
|
209
316
|
|
210
317
|
def test_numerical_vs_lexicographical_sort
|
211
|
-
assert_equal
|
212
|
-
assert_equal
|
213
|
-
assert_equal
|
214
|
-
assert_equal
|
318
|
+
assert_equal([2, 10], @filters.sort([10, 2]))
|
319
|
+
assert_equal([{ "a" => 2 }, { "a" => 10 }], @filters.sort([{ "a" => 10 }, { "a" => 2 }], "a"))
|
320
|
+
assert_equal(["10", "2"], @filters.sort(["10", "2"]))
|
321
|
+
assert_equal([{ "a" => "10" }, { "a" => "2" }], @filters.sort([{ "a" => "10" }, { "a" => "2" }], "a"))
|
215
322
|
end
|
216
323
|
|
217
324
|
def test_uniq
|
218
|
-
assert_equal
|
219
|
-
assert_equal
|
220
|
-
assert_equal
|
325
|
+
assert_equal(["foo"], @filters.uniq("foo"))
|
326
|
+
assert_equal([1, 3, 2, 4], @filters.uniq([1, 1, 3, 2, 3, 1, 4, 3, 2, 1]))
|
327
|
+
assert_equal([{ "a" => 1 }, { "a" => 3 }, { "a" => 2 }], @filters.uniq([{ "a" => 1 }, { "a" => 3 }, { "a" => 1 }, { "a" => 2 }], "a"))
|
221
328
|
testdrop = TestDrop.new
|
222
|
-
assert_equal
|
329
|
+
assert_equal([testdrop], @filters.uniq([testdrop, TestDrop.new], 'test'))
|
223
330
|
end
|
224
331
|
|
225
332
|
def test_uniq_empty_array
|
226
|
-
assert_equal
|
333
|
+
assert_equal([], @filters.uniq([], "a"))
|
334
|
+
end
|
335
|
+
|
336
|
+
def test_uniq_invalid_property
|
337
|
+
foo = [
|
338
|
+
[1],
|
339
|
+
[2],
|
340
|
+
[3],
|
341
|
+
]
|
342
|
+
|
343
|
+
assert_raises(Liquid::ArgumentError) do
|
344
|
+
@filters.uniq(foo, "bar")
|
345
|
+
end
|
227
346
|
end
|
228
347
|
|
229
348
|
def test_compact_empty_array
|
230
|
-
assert_equal
|
349
|
+
assert_equal([], @filters.compact([], "a"))
|
350
|
+
end
|
351
|
+
|
352
|
+
def test_compact_invalid_property
|
353
|
+
foo = [
|
354
|
+
[1],
|
355
|
+
[2],
|
356
|
+
[3],
|
357
|
+
]
|
358
|
+
|
359
|
+
assert_raises(Liquid::ArgumentError) do
|
360
|
+
@filters.compact(foo, "bar")
|
361
|
+
end
|
231
362
|
end
|
232
363
|
|
233
364
|
def test_reverse
|
234
|
-
assert_equal
|
365
|
+
assert_equal([4, 3, 2, 1], @filters.reverse([1, 2, 3, 4]))
|
235
366
|
end
|
236
367
|
|
237
368
|
def test_legacy_reverse_hash
|
238
|
-
assert_equal
|
369
|
+
assert_equal([{ a: 1, b: 2 }], @filters.reverse(a: 1, b: 2))
|
239
370
|
end
|
240
371
|
|
241
372
|
def test_map
|
242
|
-
assert_equal
|
243
|
-
assert_template_result
|
244
|
-
'ary' => [{ 'foo' => { 'bar' => 'a' } }, { 'foo' => { 'bar' => 'b' } }, { 'foo' => { 'bar' => 'c' } }]
|
373
|
+
assert_equal([1, 2, 3, 4], @filters.map([{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }], 'a'))
|
374
|
+
assert_template_result('abc', "{{ ary | map:'foo' | map:'bar' }}",
|
375
|
+
'ary' => [{ 'foo' => { 'bar' => 'a' } }, { 'foo' => { 'bar' => 'b' } }, { 'foo' => { 'bar' => 'c' } }])
|
245
376
|
end
|
246
377
|
|
247
378
|
def test_map_doesnt_call_arbitrary_stuff
|
248
|
-
assert_template_result
|
249
|
-
assert_template_result
|
379
|
+
assert_template_result("", '{{ "foo" | map: "__id__" }}')
|
380
|
+
assert_template_result("", '{{ "foo" | map: "inspect" }}')
|
250
381
|
end
|
251
382
|
|
252
383
|
def test_map_calls_to_liquid
|
253
384
|
t = TestThing.new
|
254
|
-
assert_template_result
|
385
|
+
assert_template_result("woot: 1", '{{ foo | map: "whatever" }}', "foo" => [t])
|
255
386
|
end
|
256
387
|
|
257
388
|
def test_map_on_hashes
|
258
|
-
assert_template_result
|
259
|
-
"thing" => { "foo" => [
|
389
|
+
assert_template_result("4217", '{{ thing | map: "foo" | map: "bar" }}',
|
390
|
+
"thing" => { "foo" => [{ "bar" => 42 }, { "bar" => 17 }] })
|
260
391
|
end
|
261
392
|
|
262
393
|
def test_legacy_map_on_hashes_with_dynamic_key
|
263
394
|
template = "{% assign key = 'foo' %}{{ thing | map: key | map: 'bar' }}"
|
264
|
-
hash
|
265
|
-
assert_template_result
|
395
|
+
hash = { "foo" => { "bar" => 42 } }
|
396
|
+
assert_template_result("42", template, "thing" => hash)
|
266
397
|
end
|
267
398
|
|
268
399
|
def test_sort_calls_to_liquid
|
269
400
|
t = TestThing.new
|
270
401
|
Liquid::Template.parse('{{ foo | sort: "whatever" }}').render("foo" => [t])
|
271
|
-
assert
|
402
|
+
assert(t.foo > 0)
|
272
403
|
end
|
273
404
|
|
274
405
|
def test_map_over_proc
|
275
|
-
drop
|
276
|
-
p
|
406
|
+
drop = TestDrop.new
|
407
|
+
p = proc { drop }
|
277
408
|
templ = '{{ procs | map: "test" }}'
|
278
|
-
assert_template_result
|
409
|
+
assert_template_result("testfoo", templ, "procs" => [p])
|
279
410
|
end
|
280
411
|
|
281
412
|
def test_map_over_drops_returning_procs
|
282
413
|
drops = [
|
283
414
|
{
|
284
|
-
"proc" => ->{ "foo" },
|
415
|
+
"proc" => -> { "foo" },
|
285
416
|
},
|
286
417
|
{
|
287
|
-
"proc" => ->{ "bar" },
|
418
|
+
"proc" => -> { "bar" },
|
288
419
|
},
|
289
420
|
]
|
290
421
|
templ = '{{ drops | map: "proc" }}'
|
291
|
-
assert_template_result
|
422
|
+
assert_template_result("foobar", templ, "drops" => drops)
|
292
423
|
end
|
293
424
|
|
294
425
|
def test_map_works_on_enumerables
|
295
|
-
assert_template_result
|
426
|
+
assert_template_result("123", '{{ foo | map: "foo" }}', "foo" => TestEnumerable.new)
|
427
|
+
end
|
428
|
+
|
429
|
+
def test_map_returns_empty_on_2d_input_array
|
430
|
+
foo = [
|
431
|
+
[1],
|
432
|
+
[2],
|
433
|
+
[3],
|
434
|
+
]
|
435
|
+
|
436
|
+
assert_raises(Liquid::ArgumentError) do
|
437
|
+
@filters.map(foo, "bar")
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
def test_map_returns_empty_with_no_property
|
442
|
+
foo = [
|
443
|
+
[1],
|
444
|
+
[2],
|
445
|
+
[3],
|
446
|
+
]
|
447
|
+
assert_raises(Liquid::ArgumentError) do
|
448
|
+
@filters.map(foo, nil)
|
449
|
+
end
|
296
450
|
end
|
297
451
|
|
298
452
|
def test_sort_works_on_enumerables
|
299
|
-
assert_template_result
|
453
|
+
assert_template_result("213", '{{ foo | sort: "bar" | map: "foo" }}', "foo" => TestEnumerable.new)
|
300
454
|
end
|
301
455
|
|
302
456
|
def test_first_and_last_call_to_liquid
|
303
|
-
assert_template_result
|
304
|
-
assert_template_result
|
457
|
+
assert_template_result('foobar', '{{ foo | first }}', 'foo' => [ThingWithToLiquid.new])
|
458
|
+
assert_template_result('foobar', '{{ foo | last }}', 'foo' => [ThingWithToLiquid.new])
|
305
459
|
end
|
306
460
|
|
307
461
|
def test_truncate_calls_to_liquid
|
308
|
-
assert_template_result
|
462
|
+
assert_template_result("wo...", '{{ foo | truncate: 5 }}', "foo" => TestThing.new)
|
309
463
|
end
|
310
464
|
|
311
465
|
def test_date
|
312
|
-
assert_equal
|
313
|
-
assert_equal
|
314
|
-
assert_equal
|
466
|
+
assert_equal('May', @filters.date(Time.parse("2006-05-05 10:00:00"), "%B"))
|
467
|
+
assert_equal('June', @filters.date(Time.parse("2006-06-05 10:00:00"), "%B"))
|
468
|
+
assert_equal('July', @filters.date(Time.parse("2006-07-05 10:00:00"), "%B"))
|
315
469
|
|
316
|
-
assert_equal
|
317
|
-
assert_equal
|
318
|
-
assert_equal
|
470
|
+
assert_equal('May', @filters.date("2006-05-05 10:00:00", "%B"))
|
471
|
+
assert_equal('June', @filters.date("2006-06-05 10:00:00", "%B"))
|
472
|
+
assert_equal('July', @filters.date("2006-07-05 10:00:00", "%B"))
|
319
473
|
|
320
|
-
assert_equal
|
321
|
-
assert_equal
|
322
|
-
assert_equal
|
323
|
-
assert_equal
|
474
|
+
assert_equal('2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", ""))
|
475
|
+
assert_equal('2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", ""))
|
476
|
+
assert_equal('2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", ""))
|
477
|
+
assert_equal('2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", nil))
|
324
478
|
|
325
|
-
assert_equal
|
479
|
+
assert_equal('07/05/2006', @filters.date("2006-07-05 10:00:00", "%m/%d/%Y"))
|
326
480
|
|
327
|
-
assert_equal
|
328
|
-
assert_equal
|
329
|
-
assert_equal
|
330
|
-
assert_equal
|
481
|
+
assert_equal("07/16/2004", @filters.date("Fri Jul 16 01:00:00 2004", "%m/%d/%Y"))
|
482
|
+
assert_equal(Date.today.year.to_s, @filters.date('now', '%Y'))
|
483
|
+
assert_equal(Date.today.year.to_s, @filters.date('today', '%Y'))
|
484
|
+
assert_equal(Date.today.year.to_s, @filters.date('Today', '%Y'))
|
331
485
|
|
332
|
-
|
486
|
+
assert_nil(@filters.date(nil, "%B"))
|
333
487
|
|
334
|
-
assert_equal
|
488
|
+
assert_equal('', @filters.date('', "%B"))
|
335
489
|
|
336
490
|
with_timezone("UTC") do
|
337
|
-
assert_equal
|
338
|
-
assert_equal
|
491
|
+
assert_equal("07/05/2006", @filters.date(1152098955, "%m/%d/%Y"))
|
492
|
+
assert_equal("07/05/2006", @filters.date("1152098955", "%m/%d/%Y"))
|
339
493
|
end
|
340
494
|
end
|
341
495
|
|
342
496
|
def test_first_last
|
343
|
-
assert_equal
|
344
|
-
assert_equal
|
345
|
-
|
346
|
-
|
497
|
+
assert_equal(1, @filters.first([1, 2, 3]))
|
498
|
+
assert_equal(3, @filters.last([1, 2, 3]))
|
499
|
+
assert_nil(@filters.first([]))
|
500
|
+
assert_nil(@filters.last([]))
|
347
501
|
end
|
348
502
|
|
349
503
|
def test_replace
|
350
|
-
assert_equal
|
351
|
-
assert_equal
|
352
|
-
assert_equal
|
353
|
-
assert_equal
|
354
|
-
assert_template_result
|
504
|
+
assert_equal('2 2 2 2', @filters.replace('1 1 1 1', '1', 2))
|
505
|
+
assert_equal('2 2 2 2', @filters.replace('1 1 1 1', 1, 2))
|
506
|
+
assert_equal('2 1 1 1', @filters.replace_first('1 1 1 1', '1', 2))
|
507
|
+
assert_equal('2 1 1 1', @filters.replace_first('1 1 1 1', 1, 2))
|
508
|
+
assert_template_result('2 1 1 1', "{{ '1 1 1 1' | replace_first: '1', 2 }}")
|
355
509
|
end
|
356
510
|
|
357
511
|
def test_remove
|
358
|
-
assert_equal
|
359
|
-
assert_equal
|
360
|
-
assert_equal
|
361
|
-
assert_equal
|
362
|
-
assert_template_result
|
512
|
+
assert_equal(' ', @filters.remove("a a a a", 'a'))
|
513
|
+
assert_equal(' ', @filters.remove("1 1 1 1", 1))
|
514
|
+
assert_equal('a a a', @filters.remove_first("a a a a", 'a '))
|
515
|
+
assert_equal(' 1 1 1', @filters.remove_first("1 1 1 1", 1))
|
516
|
+
assert_template_result('a a a', "{{ 'a a a a' | remove_first: 'a ' }}")
|
363
517
|
end
|
364
518
|
|
365
519
|
def test_pipes_in_string_arguments
|
366
|
-
assert_template_result
|
520
|
+
assert_template_result('foobar', "{{ 'foo|bar' | remove: '|' }}")
|
367
521
|
end
|
368
522
|
|
369
523
|
def test_strip
|
370
|
-
assert_template_result
|
371
|
-
assert_template_result
|
524
|
+
assert_template_result('ab c', "{{ source | strip }}", 'source' => " ab c ")
|
525
|
+
assert_template_result('ab c', "{{ source | strip }}", 'source' => " \tab c \n \t")
|
372
526
|
end
|
373
527
|
|
374
528
|
def test_lstrip
|
375
|
-
assert_template_result
|
376
|
-
assert_template_result
|
529
|
+
assert_template_result('ab c ', "{{ source | lstrip }}", 'source' => " ab c ")
|
530
|
+
assert_template_result("ab c \n \t", "{{ source | lstrip }}", 'source' => " \tab c \n \t")
|
377
531
|
end
|
378
532
|
|
379
533
|
def test_rstrip
|
380
|
-
assert_template_result
|
381
|
-
assert_template_result
|
534
|
+
assert_template_result(" ab c", "{{ source | rstrip }}", 'source' => " ab c ")
|
535
|
+
assert_template_result(" \tab c", "{{ source | rstrip }}", 'source' => " \tab c \n \t")
|
382
536
|
end
|
383
537
|
|
384
538
|
def test_strip_newlines
|
385
|
-
assert_template_result
|
386
|
-
assert_template_result
|
539
|
+
assert_template_result('abc', "{{ source | strip_newlines }}", 'source' => "a\nb\nc")
|
540
|
+
assert_template_result('abc', "{{ source | strip_newlines }}", 'source' => "a\r\nb\nc")
|
387
541
|
end
|
388
542
|
|
389
543
|
def test_newlines_to_br
|
390
|
-
assert_template_result
|
544
|
+
assert_template_result("a<br />\nb<br />\nc", "{{ source | newline_to_br }}", 'source' => "a\nb\nc")
|
545
|
+
assert_template_result("a<br />\nb<br />\nc", "{{ source | newline_to_br }}", 'source' => "a\r\nb\nc")
|
391
546
|
end
|
392
547
|
|
393
548
|
def test_plus
|
394
|
-
assert_template_result
|
395
|
-
assert_template_result
|
549
|
+
assert_template_result("2", "{{ 1 | plus:1 }}")
|
550
|
+
assert_template_result("2.0", "{{ '1' | plus:'1.0' }}")
|
396
551
|
|
397
|
-
assert_template_result
|
552
|
+
assert_template_result("5", "{{ price | plus:'2' }}", 'price' => NumberLikeThing.new(3))
|
398
553
|
end
|
399
554
|
|
400
555
|
def test_minus
|
401
|
-
assert_template_result
|
402
|
-
assert_template_result
|
556
|
+
assert_template_result("4", "{{ input | minus:operand }}", 'input' => 5, 'operand' => 1)
|
557
|
+
assert_template_result("2.3", "{{ '4.3' | minus:'2' }}")
|
403
558
|
|
404
|
-
assert_template_result
|
559
|
+
assert_template_result("5", "{{ price | minus:'2' }}", 'price' => NumberLikeThing.new(7))
|
405
560
|
end
|
406
561
|
|
407
562
|
def test_abs
|
408
|
-
assert_template_result
|
409
|
-
assert_template_result
|
410
|
-
assert_template_result
|
411
|
-
assert_template_result
|
412
|
-
assert_template_result
|
413
|
-
assert_template_result
|
414
|
-
assert_template_result
|
415
|
-
assert_template_result
|
416
|
-
assert_template_result
|
417
|
-
assert_template_result
|
563
|
+
assert_template_result("17", "{{ 17 | abs }}")
|
564
|
+
assert_template_result("17", "{{ -17 | abs }}")
|
565
|
+
assert_template_result("17", "{{ '17' | abs }}")
|
566
|
+
assert_template_result("17", "{{ '-17' | abs }}")
|
567
|
+
assert_template_result("0", "{{ 0 | abs }}")
|
568
|
+
assert_template_result("0", "{{ '0' | abs }}")
|
569
|
+
assert_template_result("17.42", "{{ 17.42 | abs }}")
|
570
|
+
assert_template_result("17.42", "{{ -17.42 | abs }}")
|
571
|
+
assert_template_result("17.42", "{{ '17.42' | abs }}")
|
572
|
+
assert_template_result("17.42", "{{ '-17.42' | abs }}")
|
418
573
|
end
|
419
574
|
|
420
575
|
def test_times
|
421
|
-
assert_template_result
|
422
|
-
assert_template_result
|
423
|
-
assert_template_result
|
424
|
-
assert_template_result
|
425
|
-
assert_template_result
|
426
|
-
assert_template_result
|
427
|
-
assert_template_result
|
576
|
+
assert_template_result("12", "{{ 3 | times:4 }}")
|
577
|
+
assert_template_result("0", "{{ 'foo' | times:4 }}")
|
578
|
+
assert_template_result("6", "{{ '2.1' | times:3 | replace: '.','-' | plus:0}}")
|
579
|
+
assert_template_result("7.25", "{{ 0.0725 | times:100 }}")
|
580
|
+
assert_template_result("-7.25", '{{ "-0.0725" | times:100 }}')
|
581
|
+
assert_template_result("7.25", '{{ "-0.0725" | times: -100 }}')
|
582
|
+
assert_template_result("4", "{{ price | times:2 }}", 'price' => NumberLikeThing.new(2))
|
428
583
|
end
|
429
584
|
|
430
585
|
def test_divided_by
|
431
|
-
assert_template_result
|
432
|
-
assert_template_result
|
586
|
+
assert_template_result("4", "{{ 12 | divided_by:3 }}")
|
587
|
+
assert_template_result("4", "{{ 14 | divided_by:3 }}")
|
433
588
|
|
434
|
-
assert_template_result
|
435
|
-
assert_equal
|
589
|
+
assert_template_result("5", "{{ 15 | divided_by:3 }}")
|
590
|
+
assert_equal("Liquid error: divided by 0", Template.parse("{{ 5 | divided_by:0 }}").render)
|
436
591
|
|
437
|
-
assert_template_result
|
592
|
+
assert_template_result("0.5", "{{ 2.0 | divided_by:4 }}")
|
438
593
|
assert_raises(Liquid::ZeroDivisionError) do
|
439
|
-
assert_template_result
|
594
|
+
assert_template_result("4", "{{ 1 | modulo: 0 }}")
|
440
595
|
end
|
441
596
|
|
442
|
-
assert_template_result
|
597
|
+
assert_template_result("5", "{{ price | divided_by:2 }}", 'price' => NumberLikeThing.new(10))
|
443
598
|
end
|
444
599
|
|
445
600
|
def test_modulo
|
446
|
-
assert_template_result
|
601
|
+
assert_template_result("1", "{{ 3 | modulo:2 }}")
|
447
602
|
assert_raises(Liquid::ZeroDivisionError) do
|
448
|
-
assert_template_result
|
603
|
+
assert_template_result("4", "{{ 1 | modulo: 0 }}")
|
449
604
|
end
|
450
605
|
|
451
|
-
assert_template_result
|
606
|
+
assert_template_result("1", "{{ price | modulo:2 }}", 'price' => NumberLikeThing.new(3))
|
452
607
|
end
|
453
608
|
|
454
609
|
def test_round
|
455
|
-
assert_template_result
|
456
|
-
assert_template_result
|
457
|
-
assert_template_result
|
610
|
+
assert_template_result("5", "{{ input | round }}", 'input' => 4.6)
|
611
|
+
assert_template_result("4", "{{ '4.3' | round }}")
|
612
|
+
assert_template_result("4.56", "{{ input | round: 2 }}", 'input' => 4.5612)
|
458
613
|
assert_raises(Liquid::FloatDomainError) do
|
459
|
-
assert_template_result
|
614
|
+
assert_template_result("4", "{{ 1.0 | divided_by: 0.0 | round }}")
|
460
615
|
end
|
461
616
|
|
462
|
-
assert_template_result
|
463
|
-
assert_template_result
|
617
|
+
assert_template_result("5", "{{ price | round }}", 'price' => NumberLikeThing.new(4.6))
|
618
|
+
assert_template_result("4", "{{ price | round }}", 'price' => NumberLikeThing.new(4.3))
|
464
619
|
end
|
465
620
|
|
466
621
|
def test_ceil
|
467
|
-
assert_template_result
|
468
|
-
assert_template_result
|
622
|
+
assert_template_result("5", "{{ input | ceil }}", 'input' => 4.6)
|
623
|
+
assert_template_result("5", "{{ '4.3' | ceil }}")
|
469
624
|
assert_raises(Liquid::FloatDomainError) do
|
470
|
-
assert_template_result
|
625
|
+
assert_template_result("4", "{{ 1.0 | divided_by: 0.0 | ceil }}")
|
471
626
|
end
|
472
627
|
|
473
|
-
assert_template_result
|
628
|
+
assert_template_result("5", "{{ price | ceil }}", 'price' => NumberLikeThing.new(4.6))
|
474
629
|
end
|
475
630
|
|
476
631
|
def test_floor
|
477
|
-
assert_template_result
|
478
|
-
assert_template_result
|
632
|
+
assert_template_result("4", "{{ input | floor }}", 'input' => 4.6)
|
633
|
+
assert_template_result("4", "{{ '4.3' | floor }}")
|
479
634
|
assert_raises(Liquid::FloatDomainError) do
|
480
|
-
assert_template_result
|
635
|
+
assert_template_result("4", "{{ 1.0 | divided_by: 0.0 | floor }}")
|
481
636
|
end
|
482
637
|
|
483
|
-
assert_template_result
|
638
|
+
assert_template_result("5", "{{ price | floor }}", 'price' => NumberLikeThing.new(5.4))
|
639
|
+
end
|
640
|
+
|
641
|
+
def test_at_most
|
642
|
+
assert_template_result("4", "{{ 5 | at_most:4 }}")
|
643
|
+
assert_template_result("5", "{{ 5 | at_most:5 }}")
|
644
|
+
assert_template_result("5", "{{ 5 | at_most:6 }}")
|
645
|
+
|
646
|
+
assert_template_result("4.5", "{{ 4.5 | at_most:5 }}")
|
647
|
+
assert_template_result("5", "{{ width | at_most:5 }}", 'width' => NumberLikeThing.new(6))
|
648
|
+
assert_template_result("4", "{{ width | at_most:5 }}", 'width' => NumberLikeThing.new(4))
|
649
|
+
assert_template_result("4", "{{ 5 | at_most: width }}", 'width' => NumberLikeThing.new(4))
|
650
|
+
end
|
651
|
+
|
652
|
+
def test_at_least
|
653
|
+
assert_template_result("5", "{{ 5 | at_least:4 }}")
|
654
|
+
assert_template_result("5", "{{ 5 | at_least:5 }}")
|
655
|
+
assert_template_result("6", "{{ 5 | at_least:6 }}")
|
656
|
+
|
657
|
+
assert_template_result("5", "{{ 4.5 | at_least:5 }}")
|
658
|
+
assert_template_result("6", "{{ width | at_least:5 }}", 'width' => NumberLikeThing.new(6))
|
659
|
+
assert_template_result("5", "{{ width | at_least:5 }}", 'width' => NumberLikeThing.new(4))
|
660
|
+
assert_template_result("6", "{{ 5 | at_least: width }}", 'width' => NumberLikeThing.new(6))
|
484
661
|
end
|
485
662
|
|
486
663
|
def test_append
|
@@ -490,9 +667,9 @@ class StandardFiltersTest < Minitest::Test
|
|
490
667
|
end
|
491
668
|
|
492
669
|
def test_concat
|
493
|
-
assert_equal
|
494
|
-
assert_equal
|
495
|
-
assert_equal
|
670
|
+
assert_equal([1, 2, 3, 4], @filters.concat([1, 2], [3, 4]))
|
671
|
+
assert_equal([1, 2, 'a'], @filters.concat([1, 2], ['a']))
|
672
|
+
assert_equal([1, 2, 10], @filters.concat([1, 2], [10]))
|
496
673
|
|
497
674
|
assert_raises(Liquid::ArgumentError, "concat filter requires an array argument") do
|
498
675
|
@filters.concat([1, 2], 10)
|
@@ -506,12 +683,23 @@ class StandardFiltersTest < Minitest::Test
|
|
506
683
|
end
|
507
684
|
|
508
685
|
def test_default
|
509
|
-
assert_equal
|
510
|
-
assert_equal
|
511
|
-
assert_equal
|
512
|
-
assert_equal
|
513
|
-
assert_equal
|
514
|
-
assert_equal
|
686
|
+
assert_equal("foo", @filters.default("foo", "bar"))
|
687
|
+
assert_equal("bar", @filters.default(nil, "bar"))
|
688
|
+
assert_equal("bar", @filters.default("", "bar"))
|
689
|
+
assert_equal("bar", @filters.default(false, "bar"))
|
690
|
+
assert_equal("bar", @filters.default([], "bar"))
|
691
|
+
assert_equal("bar", @filters.default({}, "bar"))
|
692
|
+
assert_template_result('bar', "{{ false | default: 'bar' }}")
|
693
|
+
end
|
694
|
+
|
695
|
+
def test_default_handle_false
|
696
|
+
assert_equal("foo", @filters.default("foo", "bar", "allow_false" => true))
|
697
|
+
assert_equal("bar", @filters.default(nil, "bar", "allow_false" => true))
|
698
|
+
assert_equal("bar", @filters.default("", "bar", "allow_false" => true))
|
699
|
+
assert_equal(false, @filters.default(false, "bar", "allow_false" => true))
|
700
|
+
assert_equal("bar", @filters.default([], "bar", "allow_false" => true))
|
701
|
+
assert_equal("bar", @filters.default({}, "bar", "allow_false" => true))
|
702
|
+
assert_template_result('false', "{{ false | default: 'bar', allow_false: true }}")
|
515
703
|
end
|
516
704
|
|
517
705
|
def test_cannot_access_private_methods
|
@@ -523,10 +711,125 @@ class StandardFiltersTest < Minitest::Test
|
|
523
711
|
assert_template_result('abc', "{{ 'abc' | date: '%D' }}")
|
524
712
|
end
|
525
713
|
|
714
|
+
def test_where
|
715
|
+
input = [
|
716
|
+
{ "handle" => "alpha", "ok" => true },
|
717
|
+
{ "handle" => "beta", "ok" => false },
|
718
|
+
{ "handle" => "gamma", "ok" => false },
|
719
|
+
{ "handle" => "delta", "ok" => true },
|
720
|
+
]
|
721
|
+
|
722
|
+
expectation = [
|
723
|
+
{ "handle" => "alpha", "ok" => true },
|
724
|
+
{ "handle" => "delta", "ok" => true },
|
725
|
+
]
|
726
|
+
|
727
|
+
assert_equal(expectation, @filters.where(input, "ok", true))
|
728
|
+
assert_equal(expectation, @filters.where(input, "ok"))
|
729
|
+
end
|
730
|
+
|
731
|
+
def test_where_no_key_set
|
732
|
+
input = [
|
733
|
+
{ "handle" => "alpha", "ok" => true },
|
734
|
+
{ "handle" => "beta" },
|
735
|
+
{ "handle" => "gamma" },
|
736
|
+
{ "handle" => "delta", "ok" => true },
|
737
|
+
]
|
738
|
+
|
739
|
+
expectation = [
|
740
|
+
{ "handle" => "alpha", "ok" => true },
|
741
|
+
{ "handle" => "delta", "ok" => true },
|
742
|
+
]
|
743
|
+
|
744
|
+
assert_equal(expectation, @filters.where(input, "ok", true))
|
745
|
+
assert_equal(expectation, @filters.where(input, "ok"))
|
746
|
+
end
|
747
|
+
|
748
|
+
def test_where_non_array_map_input
|
749
|
+
assert_equal([{ "a" => "ok" }], @filters.where({ "a" => "ok" }, "a", "ok"))
|
750
|
+
assert_equal([], @filters.where({ "a" => "not ok" }, "a", "ok"))
|
751
|
+
end
|
752
|
+
|
753
|
+
def test_where_indexable_but_non_map_value
|
754
|
+
assert_raises(Liquid::ArgumentError) { @filters.where(1, "ok", true) }
|
755
|
+
assert_raises(Liquid::ArgumentError) { @filters.where(1, "ok") }
|
756
|
+
end
|
757
|
+
|
758
|
+
def test_where_non_boolean_value
|
759
|
+
input = [
|
760
|
+
{ "message" => "Bonjour!", "language" => "French" },
|
761
|
+
{ "message" => "Hello!", "language" => "English" },
|
762
|
+
{ "message" => "Hallo!", "language" => "German" },
|
763
|
+
]
|
764
|
+
|
765
|
+
assert_equal([{ "message" => "Bonjour!", "language" => "French" }], @filters.where(input, "language", "French"))
|
766
|
+
assert_equal([{ "message" => "Hallo!", "language" => "German" }], @filters.where(input, "language", "German"))
|
767
|
+
assert_equal([{ "message" => "Hello!", "language" => "English" }], @filters.where(input, "language", "English"))
|
768
|
+
end
|
769
|
+
|
770
|
+
def test_where_array_of_only_unindexable_values
|
771
|
+
assert_nil(@filters.where([nil], "ok", true))
|
772
|
+
assert_nil(@filters.where([nil], "ok"))
|
773
|
+
end
|
774
|
+
|
775
|
+
def test_all_filters_never_raise_non_liquid_exception
|
776
|
+
test_drop = TestDrop.new
|
777
|
+
test_drop.context = Context.new
|
778
|
+
test_enum = TestEnumerable.new
|
779
|
+
test_enum.context = Context.new
|
780
|
+
test_types = [
|
781
|
+
"foo",
|
782
|
+
123,
|
783
|
+
0,
|
784
|
+
0.0,
|
785
|
+
-1234.003030303,
|
786
|
+
-99999999,
|
787
|
+
1234.38383000383830003838300,
|
788
|
+
nil,
|
789
|
+
true,
|
790
|
+
false,
|
791
|
+
TestThing.new,
|
792
|
+
test_drop,
|
793
|
+
test_enum,
|
794
|
+
["foo", "bar"],
|
795
|
+
{ "foo" => "bar" },
|
796
|
+
{ foo: "bar" },
|
797
|
+
[{ "foo" => "bar" }, { "foo" => 123 }, { "foo" => nil }, { "foo" => true }, { "foo" => ["foo", "bar"] }],
|
798
|
+
{ 1 => "bar" },
|
799
|
+
["foo", 123, nil, true, false, Drop, ["foo"], { foo: "bar" }],
|
800
|
+
]
|
801
|
+
test_types.each do |first|
|
802
|
+
test_types.each do |other|
|
803
|
+
(@filters.methods - Object.methods).each do |method|
|
804
|
+
arg_count = @filters.method(method).arity
|
805
|
+
arg_count *= -1 if arg_count < 0
|
806
|
+
inputs = [first]
|
807
|
+
inputs << ([other] * (arg_count - 1)) if arg_count > 1
|
808
|
+
begin
|
809
|
+
@filters.send(method, *inputs)
|
810
|
+
rescue Liquid::ArgumentError, Liquid::ZeroDivisionError
|
811
|
+
nil
|
812
|
+
end
|
813
|
+
end
|
814
|
+
end
|
815
|
+
end
|
816
|
+
end
|
817
|
+
|
818
|
+
def test_where_no_target_value
|
819
|
+
input = [
|
820
|
+
{ "foo" => false },
|
821
|
+
{ "foo" => true },
|
822
|
+
{ "foo" => "for sure" },
|
823
|
+
{ "bar" => true },
|
824
|
+
]
|
825
|
+
|
826
|
+
assert_equal([{ "foo" => true }, { "foo" => "for sure" }], @filters.where(input, "foo"))
|
827
|
+
end
|
828
|
+
|
526
829
|
private
|
527
830
|
|
528
831
|
def with_timezone(tz)
|
529
|
-
old_tz
|
832
|
+
old_tz = ENV['TZ']
|
530
833
|
ENV['TZ'] = tz
|
531
834
|
yield
|
532
835
|
ensure
|