liquid 5.3.0 → 5.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +16 -1
  3. data/README.md +2 -2
  4. data/lib/liquid/block_body.rb +4 -4
  5. data/lib/liquid/context.rb +6 -2
  6. data/lib/liquid/forloop_drop.rb +44 -1
  7. data/lib/liquid/locales/en.yml +6 -5
  8. data/lib/liquid/partial_cache.rb +3 -3
  9. data/lib/liquid/{static_registers.rb → registers.rb} +13 -10
  10. data/lib/liquid/standardfilters.rb +406 -57
  11. data/lib/liquid/strainer_factory.rb +4 -0
  12. data/lib/liquid/strainer_template.rb +4 -0
  13. data/lib/liquid/tablerowloop_drop.rb +58 -1
  14. data/lib/liquid/tags/assign.rb +12 -8
  15. data/lib/liquid/tags/break.rb +8 -0
  16. data/lib/liquid/tags/capture.rb +13 -10
  17. data/lib/liquid/tags/case.rb +21 -0
  18. data/lib/liquid/tags/comment.rb +13 -0
  19. data/lib/liquid/tags/continue.rb +8 -9
  20. data/lib/liquid/tags/cycle.rb +12 -11
  21. data/lib/liquid/tags/decrement.rb +16 -17
  22. data/lib/liquid/tags/echo.rb +16 -9
  23. data/lib/liquid/tags/for.rb +22 -43
  24. data/lib/liquid/tags/if.rb +11 -9
  25. data/lib/liquid/tags/include.rb +15 -13
  26. data/lib/liquid/tags/increment.rb +16 -14
  27. data/lib/liquid/tags/inline_comment.rb +43 -0
  28. data/lib/liquid/tags/raw.rb +11 -0
  29. data/lib/liquid/tags/render.rb +29 -4
  30. data/lib/liquid/tags/table_row.rb +22 -0
  31. data/lib/liquid/tags/unless.rb +15 -4
  32. data/lib/liquid/template.rb +2 -3
  33. data/lib/liquid/variable.rb +4 -4
  34. data/lib/liquid/variable_lookup.rb +10 -7
  35. data/lib/liquid/version.rb +1 -1
  36. data/lib/liquid.rb +2 -2
  37. metadata +7 -123
  38. data/lib/liquid/register.rb +0 -6
  39. data/test/fixtures/en_locale.yml +0 -9
  40. data/test/integration/assign_test.rb +0 -117
  41. data/test/integration/blank_test.rb +0 -109
  42. data/test/integration/block_test.rb +0 -58
  43. data/test/integration/capture_test.rb +0 -58
  44. data/test/integration/context_test.rb +0 -634
  45. data/test/integration/document_test.rb +0 -21
  46. data/test/integration/drop_test.rb +0 -257
  47. data/test/integration/error_handling_test.rb +0 -272
  48. data/test/integration/expression_test.rb +0 -46
  49. data/test/integration/filter_kwarg_test.rb +0 -24
  50. data/test/integration/filter_test.rb +0 -189
  51. data/test/integration/hash_ordering_test.rb +0 -25
  52. data/test/integration/output_test.rb +0 -125
  53. data/test/integration/parsing_quirks_test.rb +0 -134
  54. data/test/integration/profiler_test.rb +0 -240
  55. data/test/integration/security_test.rb +0 -89
  56. data/test/integration/standard_filter_test.rb +0 -925
  57. data/test/integration/tag/disableable_test.rb +0 -59
  58. data/test/integration/tag_test.rb +0 -45
  59. data/test/integration/tags/break_tag_test.rb +0 -17
  60. data/test/integration/tags/continue_tag_test.rb +0 -17
  61. data/test/integration/tags/echo_test.rb +0 -13
  62. data/test/integration/tags/for_tag_test.rb +0 -466
  63. data/test/integration/tags/if_else_tag_test.rb +0 -190
  64. data/test/integration/tags/include_tag_test.rb +0 -269
  65. data/test/integration/tags/increment_tag_test.rb +0 -25
  66. data/test/integration/tags/liquid_tag_test.rb +0 -116
  67. data/test/integration/tags/raw_tag_test.rb +0 -34
  68. data/test/integration/tags/render_tag_test.rb +0 -213
  69. data/test/integration/tags/standard_tag_test.rb +0 -303
  70. data/test/integration/tags/statements_test.rb +0 -113
  71. data/test/integration/tags/table_row_test.rb +0 -66
  72. data/test/integration/tags/unless_else_tag_test.rb +0 -28
  73. data/test/integration/template_test.rb +0 -340
  74. data/test/integration/trim_mode_test.rb +0 -563
  75. data/test/integration/variable_test.rb +0 -138
  76. data/test/test_helper.rb +0 -207
  77. data/test/unit/block_unit_test.rb +0 -53
  78. data/test/unit/condition_unit_test.rb +0 -181
  79. data/test/unit/file_system_unit_test.rb +0 -37
  80. data/test/unit/i18n_unit_test.rb +0 -39
  81. data/test/unit/lexer_unit_test.rb +0 -53
  82. data/test/unit/parse_tree_visitor_test.rb +0 -261
  83. data/test/unit/parser_unit_test.rb +0 -84
  84. data/test/unit/partial_cache_unit_test.rb +0 -128
  85. data/test/unit/regexp_unit_test.rb +0 -46
  86. data/test/unit/static_registers_unit_test.rb +0 -156
  87. data/test/unit/strainer_factory_unit_test.rb +0 -101
  88. data/test/unit/strainer_template_unit_test.rb +0 -82
  89. data/test/unit/tag_unit_test.rb +0 -23
  90. data/test/unit/tags/case_tag_unit_test.rb +0 -12
  91. data/test/unit/tags/for_tag_unit_test.rb +0 -15
  92. data/test/unit/tags/if_tag_unit_test.rb +0 -10
  93. data/test/unit/template_factory_unit_test.rb +0 -12
  94. data/test/unit/template_unit_test.rb +0 -87
  95. data/test/unit/tokenizer_unit_test.rb +0 -62
  96. data/test/unit/variable_unit_test.rb +0 -164
@@ -1,925 +0,0 @@
1
- # encoding: utf-8
2
- # frozen_string_literal: true
3
-
4
- require 'test_helper'
5
-
6
- class TestThing
7
- attr_reader :foo
8
-
9
- def initialize
10
- @foo = 0
11
- end
12
-
13
- def to_s
14
- "woot: #{@foo}"
15
- end
16
-
17
- def [](_whatever)
18
- to_s
19
- end
20
-
21
- def to_liquid
22
- @foo += 1
23
- self
24
- end
25
- end
26
-
27
- class TestDrop < Liquid::Drop
28
- def initialize(value:)
29
- @value = value
30
- end
31
-
32
- attr_reader :value
33
-
34
- def registers
35
- @context.registers
36
- end
37
- end
38
-
39
- class TestModel
40
- def initialize(value:)
41
- @value = value
42
- end
43
-
44
- def to_liquid
45
- TestDrop.new(value: @value)
46
- end
47
- end
48
-
49
- class TestEnumerable < Liquid::Drop
50
- include Enumerable
51
-
52
- def each(&block)
53
- [{ "foo" => 1, "bar" => 2 }, { "foo" => 2, "bar" => 1 }, { "foo" => 3, "bar" => 3 }].each(&block)
54
- end
55
- end
56
-
57
- class NumberLikeThing < Liquid::Drop
58
- def initialize(amount)
59
- @amount = amount
60
- end
61
-
62
- def to_number
63
- @amount
64
- end
65
- end
66
-
67
- class StandardFiltersTest < Minitest::Test
68
- Filters = Class.new(Liquid::StrainerTemplate)
69
- Filters.add_filter(Liquid::StandardFilters)
70
-
71
- include Liquid
72
-
73
- def setup
74
- @filters = Filters.new(Context.new)
75
- end
76
-
77
- def test_size
78
- assert_equal(3, @filters.size([1, 2, 3]))
79
- assert_equal(0, @filters.size([]))
80
- assert_equal(0, @filters.size(nil))
81
- end
82
-
83
- def test_downcase
84
- assert_equal('testing', @filters.downcase("Testing"))
85
- assert_equal('', @filters.downcase(nil))
86
- end
87
-
88
- def test_upcase
89
- assert_equal('TESTING', @filters.upcase("Testing"))
90
- assert_equal('', @filters.upcase(nil))
91
- end
92
-
93
- def test_slice
94
- assert_equal('oob', @filters.slice('foobar', 1, 3))
95
- assert_equal('oobar', @filters.slice('foobar', 1, 1000))
96
- assert_equal('', @filters.slice('foobar', 1, 0))
97
- assert_equal('o', @filters.slice('foobar', 1, 1))
98
- assert_equal('bar', @filters.slice('foobar', 3, 3))
99
- assert_equal('ar', @filters.slice('foobar', -2, 2))
100
- assert_equal('ar', @filters.slice('foobar', -2, 1000))
101
- assert_equal('r', @filters.slice('foobar', -1))
102
- assert_equal('', @filters.slice(nil, 0))
103
- assert_equal('', @filters.slice('foobar', 100, 10))
104
- assert_equal('', @filters.slice('foobar', -100, 10))
105
- assert_equal('oob', @filters.slice('foobar', '1', '3'))
106
- assert_raises(Liquid::ArgumentError) do
107
- @filters.slice('foobar', nil)
108
- end
109
- assert_raises(Liquid::ArgumentError) do
110
- @filters.slice('foobar', 0, "")
111
- end
112
- end
113
-
114
- def test_slice_on_arrays
115
- input = 'foobar'.split(//)
116
- assert_equal(%w(o o b), @filters.slice(input, 1, 3))
117
- assert_equal(%w(o o b a r), @filters.slice(input, 1, 1000))
118
- assert_equal(%w(), @filters.slice(input, 1, 0))
119
- assert_equal(%w(o), @filters.slice(input, 1, 1))
120
- assert_equal(%w(b a r), @filters.slice(input, 3, 3))
121
- assert_equal(%w(a r), @filters.slice(input, -2, 2))
122
- assert_equal(%w(a r), @filters.slice(input, -2, 1000))
123
- assert_equal(%w(r), @filters.slice(input, -1))
124
- assert_equal(%w(), @filters.slice(input, 100, 10))
125
- assert_equal(%w(), @filters.slice(input, -100, 10))
126
- end
127
-
128
- def test_truncate
129
- assert_equal('1234...', @filters.truncate('1234567890', 7))
130
- assert_equal('1234567890', @filters.truncate('1234567890', 20))
131
- assert_equal('...', @filters.truncate('1234567890', 0))
132
- assert_equal('1234567890', @filters.truncate('1234567890'))
133
- assert_equal("测试...", @filters.truncate("测试测试测试测试", 5))
134
- assert_equal('12341', @filters.truncate("1234567890", 5, 1))
135
- end
136
-
137
- def test_split
138
- assert_equal(['12', '34'], @filters.split('12~34', '~'))
139
- assert_equal(['A? ', ' ,Z'], @filters.split('A? ~ ~ ~ ,Z', '~ ~ ~'))
140
- assert_equal(['A?Z'], @filters.split('A?Z', '~'))
141
- assert_equal([], @filters.split(nil, ' '))
142
- assert_equal(['A', 'Z'], @filters.split('A1Z', 1))
143
- end
144
-
145
- def test_escape
146
- assert_equal('&lt;strong&gt;', @filters.escape('<strong>'))
147
- assert_equal('1', @filters.escape(1))
148
- assert_equal('2001-02-03', @filters.escape(Date.new(2001, 2, 3)))
149
- assert_nil(@filters.escape(nil))
150
- end
151
-
152
- def test_h
153
- assert_equal('&lt;strong&gt;', @filters.h('<strong>'))
154
- assert_equal('1', @filters.h(1))
155
- assert_equal('2001-02-03', @filters.h(Date.new(2001, 2, 3)))
156
- assert_nil(@filters.h(nil))
157
- end
158
-
159
- def test_escape_once
160
- assert_equal('&lt;strong&gt;Hulk&lt;/strong&gt;', @filters.escape_once('&lt;strong&gt;Hulk</strong>'))
161
- end
162
-
163
- def test_base64_encode
164
- assert_equal('b25lIHR3byB0aHJlZQ==', @filters.base64_encode('one two three'))
165
- assert_equal('', @filters.base64_encode(nil))
166
- end
167
-
168
- def test_base64_decode
169
- assert_equal('one two three', @filters.base64_decode('b25lIHR3byB0aHJlZQ=='))
170
-
171
- exception = assert_raises(Liquid::ArgumentError) do
172
- @filters.base64_decode("invalidbase64")
173
- end
174
-
175
- assert_equal('Liquid error: invalid base64 provided to base64_decode', exception.message)
176
- end
177
-
178
- def test_base64_url_safe_encode
179
- assert_equal(
180
- 'YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXogQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVogMTIzNDU2Nzg5MCAhQCMkJV4mKigpLT1fKy8_Ljo7W117fVx8',
181
- @filters.base64_url_safe_encode('abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890 !@#$%^&*()-=_+/?.:;[]{}\|')
182
- )
183
- assert_equal('', @filters.base64_url_safe_encode(nil))
184
- end
185
-
186
- def test_base64_url_safe_decode
187
- assert_equal(
188
- 'abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890 !@#$%^&*()-=_+/?.:;[]{}\|',
189
- @filters.base64_url_safe_decode('YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXogQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVogMTIzNDU2Nzg5MCAhQCMkJV4mKigpLT1fKy8_Ljo7W117fVx8')
190
- )
191
- exception = assert_raises(Liquid::ArgumentError) do
192
- @filters.base64_url_safe_decode("invalidbase64")
193
- end
194
- assert_equal('Liquid error: invalid base64 provided to base64_url_safe_decode', exception.message)
195
- end
196
-
197
- def test_url_encode
198
- assert_equal('foo%2B1%40example.com', @filters.url_encode('foo+1@example.com'))
199
- assert_equal('1', @filters.url_encode(1))
200
- assert_equal('2001-02-03', @filters.url_encode(Date.new(2001, 2, 3)))
201
- assert_nil(@filters.url_encode(nil))
202
- end
203
-
204
- def test_url_decode
205
- assert_equal('foo bar', @filters.url_decode('foo+bar'))
206
- assert_equal('foo bar', @filters.url_decode('foo%20bar'))
207
- assert_equal('foo+1@example.com', @filters.url_decode('foo%2B1%40example.com'))
208
- assert_equal('1', @filters.url_decode(1))
209
- assert_equal('2001-02-03', @filters.url_decode(Date.new(2001, 2, 3)))
210
- assert_nil(@filters.url_decode(nil))
211
- exception = assert_raises(Liquid::ArgumentError) do
212
- @filters.url_decode('%ff')
213
- end
214
- assert_equal('Liquid error: invalid byte sequence in UTF-8', exception.message)
215
- end
216
-
217
- def test_truncatewords
218
- assert_equal('one two three', @filters.truncatewords('one two three', 4))
219
- assert_equal('one two...', @filters.truncatewords('one two three', 2))
220
- assert_equal('one two three', @filters.truncatewords('one two three'))
221
- assert_equal(
222
- 'Two small (13&#8221; x 5.5&#8221; x 10&#8221; high) baskets fit inside one large basket (13&#8221;...',
223
- @filters.truncatewords('Two small (13&#8221; x 5.5&#8221; x 10&#8221; high) baskets fit inside one large basket (13&#8221; x 16&#8221; x 10.5&#8221; high) with cover.', 15)
224
- )
225
- assert_equal("测试测试测试测试", @filters.truncatewords('测试测试测试测试', 5))
226
- assert_equal('one two1', @filters.truncatewords("one two three", 2, 1))
227
- assert_equal('one two three...', @filters.truncatewords("one two\tthree\nfour", 3))
228
- assert_equal('one two...', @filters.truncatewords("one two three four", 2))
229
- assert_equal('one...', @filters.truncatewords("one two three four", 0))
230
- exception = assert_raises(Liquid::ArgumentError) do
231
- @filters.truncatewords("one two three four", 1 << 31)
232
- end
233
- assert_equal("Liquid error: integer #{1 << 31} too big for truncatewords", exception.message)
234
- end
235
-
236
- def test_strip_html
237
- assert_equal('test', @filters.strip_html("<div>test</div>"))
238
- assert_equal('test', @filters.strip_html("<div id='test'>test</div>"))
239
- assert_equal('', @filters.strip_html("<script type='text/javascript'>document.write('some stuff');</script>"))
240
- assert_equal('', @filters.strip_html("<style type='text/css'>foo bar</style>"))
241
- assert_equal('test', @filters.strip_html("<div\nclass='multiline'>test</div>"))
242
- assert_equal('test', @filters.strip_html("<!-- foo bar \n test -->test"))
243
- assert_equal('', @filters.strip_html(nil))
244
-
245
- # Quirk of the existing implementation
246
- assert_equal('foo;', @filters.strip_html("<<<script </script>script>foo;</script>"))
247
- end
248
-
249
- def test_join
250
- assert_equal('1 2 3 4', @filters.join([1, 2, 3, 4]))
251
- assert_equal('1 - 2 - 3 - 4', @filters.join([1, 2, 3, 4], ' - '))
252
- assert_equal('1121314', @filters.join([1, 2, 3, 4], 1))
253
- end
254
-
255
- def test_sort
256
- assert_equal([1, 2, 3, 4], @filters.sort([4, 3, 2, 1]))
257
- assert_equal([{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }], @filters.sort([{ "a" => 4 }, { "a" => 3 }, { "a" => 1 }, { "a" => 2 }], "a"))
258
- end
259
-
260
- def test_sort_with_nils
261
- assert_equal([1, 2, 3, 4, nil], @filters.sort([nil, 4, 3, 2, 1]))
262
- assert_equal([{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }, {}], @filters.sort([{ "a" => 4 }, { "a" => 3 }, {}, { "a" => 1 }, { "a" => 2 }], "a"))
263
- end
264
-
265
- def test_sort_when_property_is_sometimes_missing_puts_nils_last
266
- input = [
267
- { "price" => 4, "handle" => "alpha" },
268
- { "handle" => "beta" },
269
- { "price" => 1, "handle" => "gamma" },
270
- { "handle" => "delta" },
271
- { "price" => 2, "handle" => "epsilon" },
272
- ]
273
- expectation = [
274
- { "price" => 1, "handle" => "gamma" },
275
- { "price" => 2, "handle" => "epsilon" },
276
- { "price" => 4, "handle" => "alpha" },
277
- { "handle" => "beta" },
278
- { "handle" => "delta" },
279
- ]
280
- assert_equal(expectation, @filters.sort(input, "price"))
281
- end
282
-
283
- def test_sort_natural
284
- assert_equal(["a", "B", "c", "D"], @filters.sort_natural(["c", "D", "a", "B"]))
285
- assert_equal([{ "a" => "a" }, { "a" => "B" }, { "a" => "c" }, { "a" => "D" }], @filters.sort_natural([{ "a" => "D" }, { "a" => "c" }, { "a" => "a" }, { "a" => "B" }], "a"))
286
- end
287
-
288
- def test_sort_natural_with_nils
289
- assert_equal(["a", "B", "c", "D", nil], @filters.sort_natural([nil, "c", "D", "a", "B"]))
290
- assert_equal([{ "a" => "a" }, { "a" => "B" }, { "a" => "c" }, { "a" => "D" }, {}], @filters.sort_natural([{ "a" => "D" }, { "a" => "c" }, {}, { "a" => "a" }, { "a" => "B" }], "a"))
291
- end
292
-
293
- def test_sort_natural_when_property_is_sometimes_missing_puts_nils_last
294
- input = [
295
- { "price" => "4", "handle" => "alpha" },
296
- { "handle" => "beta" },
297
- { "price" => "1", "handle" => "gamma" },
298
- { "handle" => "delta" },
299
- { "price" => 2, "handle" => "epsilon" },
300
- ]
301
- expectation = [
302
- { "price" => "1", "handle" => "gamma" },
303
- { "price" => 2, "handle" => "epsilon" },
304
- { "price" => "4", "handle" => "alpha" },
305
- { "handle" => "delta" },
306
- { "handle" => "beta" },
307
- ]
308
- assert_equal(expectation, @filters.sort_natural(input, "price"))
309
- end
310
-
311
- def test_sort_natural_case_check
312
- input = [
313
- { "key" => "X" },
314
- { "key" => "Y" },
315
- { "key" => "Z" },
316
- { "fake" => "t" },
317
- { "key" => "a" },
318
- { "key" => "b" },
319
- { "key" => "c" },
320
- ]
321
- expectation = [
322
- { "key" => "a" },
323
- { "key" => "b" },
324
- { "key" => "c" },
325
- { "key" => "X" },
326
- { "key" => "Y" },
327
- { "key" => "Z" },
328
- { "fake" => "t" },
329
- ]
330
- assert_equal(expectation, @filters.sort_natural(input, "key"))
331
- assert_equal(["a", "b", "c", "X", "Y", "Z"], @filters.sort_natural(["X", "Y", "Z", "a", "b", "c"]))
332
- end
333
-
334
- def test_sort_empty_array
335
- assert_equal([], @filters.sort([], "a"))
336
- end
337
-
338
- def test_sort_invalid_property
339
- foo = [
340
- [1],
341
- [2],
342
- [3],
343
- ]
344
-
345
- assert_raises(Liquid::ArgumentError) do
346
- @filters.sort(foo, "bar")
347
- end
348
- end
349
-
350
- def test_sort_natural_empty_array
351
- assert_equal([], @filters.sort_natural([], "a"))
352
- end
353
-
354
- def test_sort_natural_invalid_property
355
- foo = [
356
- [1],
357
- [2],
358
- [3],
359
- ]
360
-
361
- assert_raises(Liquid::ArgumentError) do
362
- @filters.sort_natural(foo, "bar")
363
- end
364
- end
365
-
366
- def test_legacy_sort_hash
367
- assert_equal([{ a: 1, b: 2 }], @filters.sort(a: 1, b: 2))
368
- end
369
-
370
- def test_numerical_vs_lexicographical_sort
371
- assert_equal([2, 10], @filters.sort([10, 2]))
372
- assert_equal([{ "a" => 2 }, { "a" => 10 }], @filters.sort([{ "a" => 10 }, { "a" => 2 }], "a"))
373
- assert_equal(["10", "2"], @filters.sort(["10", "2"]))
374
- assert_equal([{ "a" => "10" }, { "a" => "2" }], @filters.sort([{ "a" => "10" }, { "a" => "2" }], "a"))
375
- end
376
-
377
- def test_uniq
378
- assert_equal(["foo"], @filters.uniq("foo"))
379
- assert_equal([1, 3, 2, 4], @filters.uniq([1, 1, 3, 2, 3, 1, 4, 3, 2, 1]))
380
- assert_equal([{ "a" => 1 }, { "a" => 3 }, { "a" => 2 }], @filters.uniq([{ "a" => 1 }, { "a" => 3 }, { "a" => 1 }, { "a" => 2 }], "a"))
381
- test_drop = TestDrop.new(value: "test")
382
- test_drop_alternate = TestDrop.new(value: "test")
383
- assert_equal([test_drop], @filters.uniq([test_drop, test_drop_alternate], 'value'))
384
- end
385
-
386
- def test_uniq_empty_array
387
- assert_equal([], @filters.uniq([], "a"))
388
- end
389
-
390
- def test_uniq_invalid_property
391
- foo = [
392
- [1],
393
- [2],
394
- [3],
395
- ]
396
-
397
- assert_raises(Liquid::ArgumentError) do
398
- @filters.uniq(foo, "bar")
399
- end
400
- end
401
-
402
- def test_compact_empty_array
403
- assert_equal([], @filters.compact([], "a"))
404
- end
405
-
406
- def test_compact_invalid_property
407
- foo = [
408
- [1],
409
- [2],
410
- [3],
411
- ]
412
-
413
- assert_raises(Liquid::ArgumentError) do
414
- @filters.compact(foo, "bar")
415
- end
416
- end
417
-
418
- def test_reverse
419
- assert_equal([4, 3, 2, 1], @filters.reverse([1, 2, 3, 4]))
420
- end
421
-
422
- def test_legacy_reverse_hash
423
- assert_equal([{ a: 1, b: 2 }], @filters.reverse(a: 1, b: 2))
424
- end
425
-
426
- def test_map
427
- assert_equal([1, 2, 3, 4], @filters.map([{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }], 'a'))
428
- assert_template_result('abc', "{{ ary | map:'foo' | map:'bar' }}",
429
- 'ary' => [{ 'foo' => { 'bar' => 'a' } }, { 'foo' => { 'bar' => 'b' } }, { 'foo' => { 'bar' => 'c' } }])
430
- end
431
-
432
- def test_map_doesnt_call_arbitrary_stuff
433
- assert_template_result("", '{{ "foo" | map: "__id__" }}')
434
- assert_template_result("", '{{ "foo" | map: "inspect" }}')
435
- end
436
-
437
- def test_map_calls_to_liquid
438
- t = TestThing.new
439
- assert_template_result("woot: 1", '{{ foo | map: "whatever" }}', "foo" => [t])
440
- end
441
-
442
- def test_map_calls_context=
443
- model = TestModel.new(value: "test")
444
-
445
- template = Template.parse('{{ foo | map: "registers" }}')
446
- template.registers[:test] = 1234
447
- template.assigns['foo'] = [model]
448
-
449
- assert_template_result("{:test=>1234}", template.render!)
450
- end
451
-
452
- def test_map_on_hashes
453
- assert_template_result("4217", '{{ thing | map: "foo" | map: "bar" }}',
454
- "thing" => { "foo" => [{ "bar" => 42 }, { "bar" => 17 }] })
455
- end
456
-
457
- def test_legacy_map_on_hashes_with_dynamic_key
458
- template = "{% assign key = 'foo' %}{{ thing | map: key | map: 'bar' }}"
459
- hash = { "foo" => { "bar" => 42 } }
460
- assert_template_result("42", template, "thing" => hash)
461
- end
462
-
463
- def test_sort_calls_to_liquid
464
- t = TestThing.new
465
- Liquid::Template.parse('{{ foo | sort: "whatever" }}').render("foo" => [t])
466
- assert(t.foo > 0)
467
- end
468
-
469
- def test_map_over_proc
470
- drop = TestDrop.new(value: "testfoo")
471
- p = proc { drop }
472
- templ = '{{ procs | map: "value" }}'
473
- assert_template_result("testfoo", templ, "procs" => [p])
474
- end
475
-
476
- def test_map_over_drops_returning_procs
477
- drops = [
478
- {
479
- "proc" => -> { "foo" },
480
- },
481
- {
482
- "proc" => -> { "bar" },
483
- },
484
- ]
485
- templ = '{{ drops | map: "proc" }}'
486
- assert_template_result("foobar", templ, "drops" => drops)
487
- end
488
-
489
- def test_map_works_on_enumerables
490
- assert_template_result("123", '{{ foo | map: "foo" }}', "foo" => TestEnumerable.new)
491
- end
492
-
493
- def test_map_returns_empty_on_2d_input_array
494
- foo = [
495
- [1],
496
- [2],
497
- [3],
498
- ]
499
-
500
- assert_raises(Liquid::ArgumentError) do
501
- @filters.map(foo, "bar")
502
- end
503
- end
504
-
505
- def test_map_returns_empty_with_no_property
506
- foo = [
507
- [1],
508
- [2],
509
- [3],
510
- ]
511
- assert_raises(Liquid::ArgumentError) do
512
- @filters.map(foo, nil)
513
- end
514
- end
515
-
516
- def test_sort_works_on_enumerables
517
- assert_template_result("213", '{{ foo | sort: "bar" | map: "foo" }}', "foo" => TestEnumerable.new)
518
- end
519
-
520
- def test_first_and_last_call_to_liquid
521
- assert_template_result('foobar', '{{ foo | first }}', 'foo' => [ThingWithToLiquid.new])
522
- assert_template_result('foobar', '{{ foo | last }}', 'foo' => [ThingWithToLiquid.new])
523
- end
524
-
525
- def test_truncate_calls_to_liquid
526
- assert_template_result("wo...", '{{ foo | truncate: 5 }}', "foo" => TestThing.new)
527
- end
528
-
529
- def test_date
530
- assert_equal('May', @filters.date(Time.parse("2006-05-05 10:00:00"), "%B"))
531
- assert_equal('June', @filters.date(Time.parse("2006-06-05 10:00:00"), "%B"))
532
- assert_equal('July', @filters.date(Time.parse("2006-07-05 10:00:00"), "%B"))
533
-
534
- assert_equal('May', @filters.date("2006-05-05 10:00:00", "%B"))
535
- assert_equal('June', @filters.date("2006-06-05 10:00:00", "%B"))
536
- assert_equal('July', @filters.date("2006-07-05 10:00:00", "%B"))
537
-
538
- assert_equal('2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", ""))
539
- assert_equal('2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", ""))
540
- assert_equal('2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", ""))
541
- assert_equal('2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", nil))
542
-
543
- assert_equal('07/05/2006', @filters.date("2006-07-05 10:00:00", "%m/%d/%Y"))
544
-
545
- assert_equal("07/16/2004", @filters.date("Fri Jul 16 01:00:00 2004", "%m/%d/%Y"))
546
- assert_equal(Date.today.year.to_s, @filters.date('now', '%Y'))
547
- assert_equal(Date.today.year.to_s, @filters.date('today', '%Y'))
548
- assert_equal(Date.today.year.to_s, @filters.date('Today', '%Y'))
549
-
550
- assert_nil(@filters.date(nil, "%B"))
551
-
552
- assert_equal('', @filters.date('', "%B"))
553
-
554
- with_timezone("UTC") do
555
- assert_equal("07/05/2006", @filters.date(1152098955, "%m/%d/%Y"))
556
- assert_equal("07/05/2006", @filters.date("1152098955", "%m/%d/%Y"))
557
- end
558
- end
559
-
560
- def test_first_last
561
- assert_equal(1, @filters.first([1, 2, 3]))
562
- assert_equal(3, @filters.last([1, 2, 3]))
563
- assert_nil(@filters.first([]))
564
- assert_nil(@filters.last([]))
565
- end
566
-
567
- def test_replace
568
- assert_equal('b b b b', @filters.replace('a a a a', 'a', 'b'))
569
- assert_equal('2 2 2 2', @filters.replace('1 1 1 1', 1, 2))
570
- assert_equal('1 1 1 1', @filters.replace('1 1 1 1', 2, 3))
571
- assert_template_result('2 2 2 2', "{{ '1 1 1 1' | replace: '1', 2 }}")
572
-
573
- assert_equal('b a a a', @filters.replace_first('a a a a', 'a', 'b'))
574
- assert_equal('2 1 1 1', @filters.replace_first('1 1 1 1', 1, 2))
575
- assert_equal('1 1 1 1', @filters.replace_first('1 1 1 1', 2, 3))
576
- assert_template_result('2 1 1 1', "{{ '1 1 1 1' | replace_first: '1', 2 }}")
577
-
578
- assert_equal('a a a b', @filters.replace_last('a a a a', 'a', 'b'))
579
- assert_equal('1 1 1 2', @filters.replace_last('1 1 1 1', 1, 2))
580
- assert_equal('1 1 1 1', @filters.replace_last('1 1 1 1', 2, 3))
581
- assert_template_result('1 1 1 2', "{{ '1 1 1 1' | replace_last: '1', 2 }}")
582
- end
583
-
584
- def test_remove
585
- assert_equal(' ', @filters.remove("a a a a", 'a'))
586
- assert_template_result(' ', "{{ '1 1 1 1' | remove: 1 }}")
587
-
588
- assert_equal('b a a', @filters.remove_first("a b a a", 'a '))
589
- assert_template_result(' 1 1 1', "{{ '1 1 1 1' | remove_first: 1 }}")
590
-
591
- assert_equal('a a b', @filters.remove_last("a a b a", ' a'))
592
- assert_template_result('1 1 1 ', "{{ '1 1 1 1' | remove_last: 1 }}")
593
- end
594
-
595
- def test_pipes_in_string_arguments
596
- assert_template_result('foobar', "{{ 'foo|bar' | remove: '|' }}")
597
- end
598
-
599
- def test_strip
600
- assert_template_result('ab c', "{{ source | strip }}", 'source' => " ab c ")
601
- assert_template_result('ab c', "{{ source | strip }}", 'source' => " \tab c \n \t")
602
- end
603
-
604
- def test_lstrip
605
- assert_template_result('ab c ', "{{ source | lstrip }}", 'source' => " ab c ")
606
- assert_template_result("ab c \n \t", "{{ source | lstrip }}", 'source' => " \tab c \n \t")
607
- end
608
-
609
- def test_rstrip
610
- assert_template_result(" ab c", "{{ source | rstrip }}", 'source' => " ab c ")
611
- assert_template_result(" \tab c", "{{ source | rstrip }}", 'source' => " \tab c \n \t")
612
- end
613
-
614
- def test_strip_newlines
615
- assert_template_result('abc', "{{ source | strip_newlines }}", 'source' => "a\nb\nc")
616
- assert_template_result('abc', "{{ source | strip_newlines }}", 'source' => "a\r\nb\nc")
617
- end
618
-
619
- def test_newlines_to_br
620
- assert_template_result("a<br />\nb<br />\nc", "{{ source | newline_to_br }}", 'source' => "a\nb\nc")
621
- assert_template_result("a<br />\nb<br />\nc", "{{ source | newline_to_br }}", 'source' => "a\r\nb\nc")
622
- end
623
-
624
- def test_plus
625
- assert_template_result("2", "{{ 1 | plus:1 }}")
626
- assert_template_result("2.0", "{{ '1' | plus:'1.0' }}")
627
-
628
- assert_template_result("5", "{{ price | plus:'2' }}", 'price' => NumberLikeThing.new(3))
629
- end
630
-
631
- def test_minus
632
- assert_template_result("4", "{{ input | minus:operand }}", 'input' => 5, 'operand' => 1)
633
- assert_template_result("2.3", "{{ '4.3' | minus:'2' }}")
634
-
635
- assert_template_result("5", "{{ price | minus:'2' }}", 'price' => NumberLikeThing.new(7))
636
- end
637
-
638
- def test_abs
639
- assert_template_result("17", "{{ 17 | abs }}")
640
- assert_template_result("17", "{{ -17 | abs }}")
641
- assert_template_result("17", "{{ '17' | abs }}")
642
- assert_template_result("17", "{{ '-17' | abs }}")
643
- assert_template_result("0", "{{ 0 | abs }}")
644
- assert_template_result("0", "{{ '0' | abs }}")
645
- assert_template_result("17.42", "{{ 17.42 | abs }}")
646
- assert_template_result("17.42", "{{ -17.42 | abs }}")
647
- assert_template_result("17.42", "{{ '17.42' | abs }}")
648
- assert_template_result("17.42", "{{ '-17.42' | abs }}")
649
- end
650
-
651
- def test_times
652
- assert_template_result("12", "{{ 3 | times:4 }}")
653
- assert_template_result("0", "{{ 'foo' | times:4 }}")
654
- assert_template_result("6", "{{ '2.1' | times:3 | replace: '.','-' | plus:0}}")
655
- assert_template_result("7.25", "{{ 0.0725 | times:100 }}")
656
- assert_template_result("-7.25", '{{ "-0.0725" | times:100 }}')
657
- assert_template_result("7.25", '{{ "-0.0725" | times: -100 }}')
658
- assert_template_result("4", "{{ price | times:2 }}", 'price' => NumberLikeThing.new(2))
659
- end
660
-
661
- def test_divided_by
662
- assert_template_result("4", "{{ 12 | divided_by:3 }}")
663
- assert_template_result("4", "{{ 14 | divided_by:3 }}")
664
-
665
- assert_template_result("5", "{{ 15 | divided_by:3 }}")
666
- assert_equal("Liquid error: divided by 0", Template.parse("{{ 5 | divided_by:0 }}").render)
667
-
668
- assert_template_result("0.5", "{{ 2.0 | divided_by:4 }}")
669
- assert_raises(Liquid::ZeroDivisionError) do
670
- assert_template_result("4", "{{ 1 | modulo: 0 }}")
671
- end
672
-
673
- assert_template_result("5", "{{ price | divided_by:2 }}", 'price' => NumberLikeThing.new(10))
674
- end
675
-
676
- def test_modulo
677
- assert_template_result("1", "{{ 3 | modulo:2 }}")
678
- assert_raises(Liquid::ZeroDivisionError) do
679
- assert_template_result("4", "{{ 1 | modulo: 0 }}")
680
- end
681
-
682
- assert_template_result("1", "{{ price | modulo:2 }}", 'price' => NumberLikeThing.new(3))
683
- end
684
-
685
- def test_round
686
- assert_template_result("5", "{{ input | round }}", 'input' => 4.6)
687
- assert_template_result("4", "{{ '4.3' | round }}")
688
- assert_template_result("4.56", "{{ input | round: 2 }}", 'input' => 4.5612)
689
- assert_raises(Liquid::FloatDomainError) do
690
- assert_template_result("4", "{{ 1.0 | divided_by: 0.0 | round }}")
691
- end
692
-
693
- assert_template_result("5", "{{ price | round }}", 'price' => NumberLikeThing.new(4.6))
694
- assert_template_result("4", "{{ price | round }}", 'price' => NumberLikeThing.new(4.3))
695
- end
696
-
697
- def test_ceil
698
- assert_template_result("5", "{{ input | ceil }}", 'input' => 4.6)
699
- assert_template_result("5", "{{ '4.3' | ceil }}")
700
- assert_raises(Liquid::FloatDomainError) do
701
- assert_template_result("4", "{{ 1.0 | divided_by: 0.0 | ceil }}")
702
- end
703
-
704
- assert_template_result("5", "{{ price | ceil }}", 'price' => NumberLikeThing.new(4.6))
705
- end
706
-
707
- def test_floor
708
- assert_template_result("4", "{{ input | floor }}", 'input' => 4.6)
709
- assert_template_result("4", "{{ '4.3' | floor }}")
710
- assert_raises(Liquid::FloatDomainError) do
711
- assert_template_result("4", "{{ 1.0 | divided_by: 0.0 | floor }}")
712
- end
713
-
714
- assert_template_result("5", "{{ price | floor }}", 'price' => NumberLikeThing.new(5.4))
715
- end
716
-
717
- def test_at_most
718
- assert_template_result("4", "{{ 5 | at_most:4 }}")
719
- assert_template_result("5", "{{ 5 | at_most:5 }}")
720
- assert_template_result("5", "{{ 5 | at_most:6 }}")
721
-
722
- assert_template_result("4.5", "{{ 4.5 | at_most:5 }}")
723
- assert_template_result("5", "{{ width | at_most:5 }}", 'width' => NumberLikeThing.new(6))
724
- assert_template_result("4", "{{ width | at_most:5 }}", 'width' => NumberLikeThing.new(4))
725
- assert_template_result("4", "{{ 5 | at_most: width }}", 'width' => NumberLikeThing.new(4))
726
- end
727
-
728
- def test_at_least
729
- assert_template_result("5", "{{ 5 | at_least:4 }}")
730
- assert_template_result("5", "{{ 5 | at_least:5 }}")
731
- assert_template_result("6", "{{ 5 | at_least:6 }}")
732
-
733
- assert_template_result("5", "{{ 4.5 | at_least:5 }}")
734
- assert_template_result("6", "{{ width | at_least:5 }}", 'width' => NumberLikeThing.new(6))
735
- assert_template_result("5", "{{ width | at_least:5 }}", 'width' => NumberLikeThing.new(4))
736
- assert_template_result("6", "{{ 5 | at_least: width }}", 'width' => NumberLikeThing.new(6))
737
- end
738
-
739
- def test_append
740
- assigns = { 'a' => 'bc', 'b' => 'd' }
741
- assert_template_result('bcd', "{{ a | append: 'd'}}", assigns)
742
- assert_template_result('bcd', "{{ a | append: b}}", assigns)
743
- end
744
-
745
- def test_concat
746
- assert_equal([1, 2, 3, 4], @filters.concat([1, 2], [3, 4]))
747
- assert_equal([1, 2, 'a'], @filters.concat([1, 2], ['a']))
748
- assert_equal([1, 2, 10], @filters.concat([1, 2], [10]))
749
-
750
- assert_raises(Liquid::ArgumentError, "concat filter requires an array argument") do
751
- @filters.concat([1, 2], 10)
752
- end
753
- end
754
-
755
- def test_prepend
756
- assigns = { 'a' => 'bc', 'b' => 'a' }
757
- assert_template_result('abc', "{{ a | prepend: 'a'}}", assigns)
758
- assert_template_result('abc', "{{ a | prepend: b}}", assigns)
759
- end
760
-
761
- def test_default
762
- assert_equal("foo", @filters.default("foo", "bar"))
763
- assert_equal("bar", @filters.default(nil, "bar"))
764
- assert_equal("bar", @filters.default("", "bar"))
765
- assert_equal("bar", @filters.default(false, "bar"))
766
- assert_equal("bar", @filters.default([], "bar"))
767
- assert_equal("bar", @filters.default({}, "bar"))
768
- assert_template_result('bar', "{{ false | default: 'bar' }}")
769
- assert_template_result('bar', "{{ drop | default: 'bar' }}", 'drop' => BooleanDrop.new(false))
770
- assert_template_result('Yay', "{{ drop | default: 'bar' }}", 'drop' => BooleanDrop.new(true))
771
- end
772
-
773
- def test_default_handle_false
774
- assert_equal("foo", @filters.default("foo", "bar", "allow_false" => true))
775
- assert_equal("bar", @filters.default(nil, "bar", "allow_false" => true))
776
- assert_equal("bar", @filters.default("", "bar", "allow_false" => true))
777
- assert_equal(false, @filters.default(false, "bar", "allow_false" => true))
778
- assert_equal("bar", @filters.default([], "bar", "allow_false" => true))
779
- assert_equal("bar", @filters.default({}, "bar", "allow_false" => true))
780
- assert_template_result('false', "{{ false | default: 'bar', allow_false: true }}")
781
- assert_template_result('Nay', "{{ drop | default: 'bar', allow_false: true }}", 'drop' => BooleanDrop.new(false))
782
- assert_template_result('Yay', "{{ drop | default: 'bar', allow_false: true }}", 'drop' => BooleanDrop.new(true))
783
- end
784
-
785
- def test_cannot_access_private_methods
786
- assert_template_result('a', "{{ 'a' | to_number }}")
787
- end
788
-
789
- def test_date_raises_nothing
790
- assert_template_result('', "{{ '' | date: '%D' }}")
791
- assert_template_result('abc', "{{ 'abc' | date: '%D' }}")
792
- end
793
-
794
- def test_where
795
- input = [
796
- { "handle" => "alpha", "ok" => true },
797
- { "handle" => "beta", "ok" => false },
798
- { "handle" => "gamma", "ok" => false },
799
- { "handle" => "delta", "ok" => true },
800
- ]
801
-
802
- expectation = [
803
- { "handle" => "alpha", "ok" => true },
804
- { "handle" => "delta", "ok" => true },
805
- ]
806
-
807
- assert_equal(expectation, @filters.where(input, "ok", true))
808
- assert_equal(expectation, @filters.where(input, "ok"))
809
- end
810
-
811
- def test_where_string_keys
812
- input = [
813
- "alpha", "beta", "gamma", "delta"
814
- ]
815
-
816
- expectation = [
817
- "beta",
818
- ]
819
-
820
- assert_equal(expectation, @filters.where(input, "be"))
821
- end
822
-
823
- def test_where_no_key_set
824
- input = [
825
- { "handle" => "alpha", "ok" => true },
826
- { "handle" => "beta" },
827
- { "handle" => "gamma" },
828
- { "handle" => "delta", "ok" => true },
829
- ]
830
-
831
- expectation = [
832
- { "handle" => "alpha", "ok" => true },
833
- { "handle" => "delta", "ok" => true },
834
- ]
835
-
836
- assert_equal(expectation, @filters.where(input, "ok", true))
837
- assert_equal(expectation, @filters.where(input, "ok"))
838
- end
839
-
840
- def test_where_non_array_map_input
841
- assert_equal([{ "a" => "ok" }], @filters.where({ "a" => "ok" }, "a", "ok"))
842
- assert_equal([], @filters.where({ "a" => "not ok" }, "a", "ok"))
843
- end
844
-
845
- def test_where_indexable_but_non_map_value
846
- assert_raises(Liquid::ArgumentError) { @filters.where(1, "ok", true) }
847
- assert_raises(Liquid::ArgumentError) { @filters.where(1, "ok") }
848
- end
849
-
850
- def test_where_non_boolean_value
851
- input = [
852
- { "message" => "Bonjour!", "language" => "French" },
853
- { "message" => "Hello!", "language" => "English" },
854
- { "message" => "Hallo!", "language" => "German" },
855
- ]
856
-
857
- assert_equal([{ "message" => "Bonjour!", "language" => "French" }], @filters.where(input, "language", "French"))
858
- assert_equal([{ "message" => "Hallo!", "language" => "German" }], @filters.where(input, "language", "German"))
859
- assert_equal([{ "message" => "Hello!", "language" => "English" }], @filters.where(input, "language", "English"))
860
- end
861
-
862
- def test_where_array_of_only_unindexable_values
863
- assert_nil(@filters.where([nil], "ok", true))
864
- assert_nil(@filters.where([nil], "ok"))
865
- end
866
-
867
- def test_all_filters_never_raise_non_liquid_exception
868
- test_drop = TestDrop.new(value: "test")
869
- test_drop.context = Context.new
870
- test_enum = TestEnumerable.new
871
- test_enum.context = Context.new
872
- test_types = [
873
- "foo",
874
- 123,
875
- 0,
876
- 0.0,
877
- -1234.003030303,
878
- -99999999,
879
- 1234.38383000383830003838300,
880
- nil,
881
- true,
882
- false,
883
- TestThing.new,
884
- test_drop,
885
- test_enum,
886
- ["foo", "bar"],
887
- { "foo" => "bar" },
888
- { foo: "bar" },
889
- [{ "foo" => "bar" }, { "foo" => 123 }, { "foo" => nil }, { "foo" => true }, { "foo" => ["foo", "bar"] }],
890
- { 1 => "bar" },
891
- ["foo", 123, nil, true, false, Drop, ["foo"], { foo: "bar" }],
892
- ]
893
- StandardFilters.public_instance_methods(false).each do |method|
894
- arg_count = @filters.method(method).arity
895
- arg_count *= -1 if arg_count < 0
896
-
897
- test_types.repeated_permutation(arg_count) do |args|
898
- @filters.send(method, *args)
899
- rescue Liquid::Error
900
- nil
901
- end
902
- end
903
- end
904
-
905
- def test_where_no_target_value
906
- input = [
907
- { "foo" => false },
908
- { "foo" => true },
909
- { "foo" => "for sure" },
910
- { "bar" => true },
911
- ]
912
-
913
- assert_equal([{ "foo" => true }, { "foo" => "for sure" }], @filters.where(input, "foo"))
914
- end
915
-
916
- private
917
-
918
- def with_timezone(tz)
919
- old_tz = ENV['TZ']
920
- ENV['TZ'] = tz
921
- yield
922
- ensure
923
- ENV['TZ'] = old_tz
924
- end
925
- end # StandardFiltersTest