Compare commits

...
Author SHA1 Message Date
Burke Libbey de603f07af Import Array and Hash tests, and make == blank match behaviour with AS
When ActiveSupport isn't loaded, `[] == blank` is false, but when it is
loaded, it (correctly?) matches the behaviour of `[] == empty`.

I think it's fair to say the intended behaviour is for == blank to match
the behaviour of when AS is loaded, so let's just special-case this.

We also import a bunch of Array and Hash tests here.
2024-06-12 12:12:59 -04:00
Samuel DoironandGitHub 0b9318222b Merge pull request #1735 from Shopify/marco-condition-to-liquid-value
Call to_liquid_value when short circuiting conditions
2023-07-19 15:05:00 -03:00
Marco Rudilosso 21d6197533 Call to_liquid_value when short circuiting conditions 2023-07-19 15:22:12 +00:00
Marco Concetto RudilossoandGitHub 5e92b3a89a Merge pull request #1731 from Shopify/allow-recursive-liquid-tags
Allow liquid tag inside liquid tag
2023-07-10 13:25:13 +01:00
Marco Concetto Rudilosso 7f2cf1fe67 Recursively parse for liquid tag 2023-07-07 11:20:34 +01:00
Marco Concetto Rudilosso 10e0fb795e Allow liquid tag inside liquid tag 2023-07-06 10:45:12 +01:00
Michelle VinciandGitHub 546dd9bc06 Merge pull request #1730 from Shopify/capitalize-desc-fix
[Liquid reference]: Update description of `capitalize`
2023-07-05 08:52:26 -07:00
Michelle Vinci 9a77e3e923 update desc 2023-07-05 08:44:06 -07:00
Michael GoandGitHub c44d1d9193 Merge pull request #1727 from Shopify/partial-cache-with-error-mode
include parse mode to partial cache key
2023-06-27 15:06:58 -03:00
Michael Go dd7bbf26bc include error mode to partial cache key 2023-06-23 18:48:07 -03:00
Adam KlingbaumandGitHub cca24a2226 Merge pull request #1726 from Shopify/klingbaum/ensure_sum_filter_calls_#to_liquid
Ensure `sum` filter calls `to_liquid` on evaluated property value
2023-06-22 15:47:36 -04:00
Adam Klingbaum 98ce25cb40 Ensure sum filter calls to_liquid 2023-06-22 16:25:11 +00:00
Adam KlingbaumandGitHub 77293d4524 Merge pull request #1722 from Shopify/klingbaum/sum-filter
Add `sum` filter to standard filters
2023-06-19 15:15:49 -04:00
Adam Klingbaum af66bc8a5f Add sum filter to standard filters 2023-06-19 19:11:05 +00:00
Guillaume MaletteandGitHub 42e5c52336 Merge pull request #1717 from Shopify/gm/fix-raw-trimmode-at-end-of-block
[trim] Fix trimming at end of raw block when specified in the opening tag
2023-05-19 14:08:02 -04:00
Guillaume Malette 649cca1349 [trim] Fix trimming at end of raw block when specified in the opening tag 2023-05-19 11:41:45 -04:00
Ian Ker-SeymerandGitHub 81ed65f2a1 Merge pull request #1688 from Shopify/fix-readme-docs-link
Fix broken documentantion link in README
2023-05-11 18:48:09 -04:00
Jeffrey LoppertandGitHub 6ca06c22b8 Merge pull request #1712 from Shopify/jloppert/update-readme-docs-link
Update Liquid Documentation from Shopify URL
2023-05-10 16:20:40 -04:00
Jeffrey LoppertandGitHub 80bc7ffdf2 Update Liquid Documentation from Shopify URL
Current url https://shopify.dev/docs/docs/api/liquid 404s. Updated to https://shopify.dev/docs/api/liquid
2023-05-10 14:47:16 -04:00
Michael GoandGitHub 48cb643c02 Merge pull request #1695 from Shopify/syntax-error-with-filename
render template name with Liquid Syntax errors
2023-03-02 17:08:27 -04:00
Michael Go 1d97389fb0 render template name with Liquid Syntax errors 2023-03-02 16:50:55 -04:00
Michael GoandGitHub 3ff4170cb0 Merge pull request #1692 from Shopify/error-message-with-filepath
set context's template_name with template.name in render and include tag
2023-02-28 10:57:24 -04:00
Robertas Godelis a75517e2c7 Fix broken documentantion link in README 2023-02-15 18:27:36 +02:00
15 changed files with 595 additions and 9 deletions
+2 -2
View File
@@ -5,7 +5,7 @@
* [Contributing guidelines](CONTRIBUTING.md)
* [Version history](History.md)
* [Liquid documentation from Shopify](https://shopify.dev/docs/docs/api/liquid)
* [Liquid documentation from Shopify](https://shopify.dev/docs/api/liquid)
* [Liquid Wiki at GitHub](https://github.com/Shopify/liquid/wiki)
* [Website](http://liquidmarkup.org/)
@@ -111,4 +111,4 @@ template.render!({ 'x' => 1}, { strict_variables: true })
To help track usages of a feature or code path in production, we have released opt-in usage tracking. To enable this, we provide an empty `Liquid:: Usage.increment` method which you can customize to your needs. The feature is well suited to https://github.com/Shopify/statsd-instrument. However, the choice of implementation is up to you.
Once you have enabled usage tracking, we recommend reporting any events through Github Issues that your system may be logging. It is highly likely this event has been added to consider deprecating or improving code specific to this event, so please raise any concerns.
Once you have enabled usage tracking, we recommend reporting any events through Github Issues that your system may be logging. It is highly likely this event has been added to consider deprecating or improving code specific to this event, so please raise any concerns.
+6
View File
@@ -45,6 +45,12 @@ module Liquid
end
tag_name = Regexp.last_match(1)
markup = Regexp.last_match(2)
if tag_name == 'liquid'
parse_context.line_number -= 1
next parse_liquid_tag(markup, parse_context)
end
unless (tag = registered_tags[tag_name])
# end parsing if we reach an unknown tag and let the caller decide
# determine how to proceed
+17 -2
View File
@@ -69,9 +69,9 @@ module Liquid
case condition.child_relation
when :or
break if result
break if Liquid::Utils.to_liquid_value(result)
when :and
break unless result
break unless Liquid::Utils.to_liquid_value(result)
else
break
end
@@ -112,6 +112,8 @@ module Liquid
if left.is_a?(MethodLiteral)
if right.respond_to?(left.method_name)
return right.send(left.method_name)
elsif (res = fallback_simulation_of_active_support(left.method_name, right))
return res
else
return nil
end
@@ -120,6 +122,8 @@ module Liquid
if right.is_a?(MethodLiteral)
if left.respond_to?(right.method_name)
return left.send(right.method_name)
elsif (res = fallback_simulation_of_active_support(right.method_name, left))
return res
else
return nil
end
@@ -128,6 +132,17 @@ module Liquid
left == right
end
# ActiveSupport creates #blank? as an alias for #empty? on Hash and Array.
# Without this simulation, [] == blank behaves differently when AS is loaded vs. not.
def fallback_simulation_of_active_support(method_name, obj)
return nil unless method_name == :blank?
case obj
when Array, Hash
obj.empty?
end # else nil
end
def interpret_condition(left, right, op, context)
# If the operator is empty this means that the decision statement is just
# a single variable. We can just poll this variable from the context and
+10 -3
View File
@@ -4,7 +4,8 @@ module Liquid
class PartialCache
def self.load(template_name, context:, parse_context:)
cached_partials = context.registers[:cached_partials]
cached = cached_partials[template_name]
cache_key = "#{template_name}:#{parse_context.error_mode}"
cached = cached_partials[cache_key]
return cached if cached
file_system = context.registers[:file_system]
@@ -15,10 +16,16 @@ module Liquid
template_factory = context.registers[:template_factory]
template = template_factory.for(template_name)
partial = template.parse(source, parse_context)
begin
partial = template.parse(source, parse_context)
rescue Liquid::Error => e
e.template_name = template&.name || template_name
raise e
end
partial.name ||= template_name
cached_partials[template_name] = partial
cached_partials[cache_key] = partial
ensure
parse_context.partial = false
end
+29 -1
View File
@@ -69,7 +69,7 @@ module Liquid
# @liquid_type filter
# @liquid_category string
# @liquid_summary
# Capitalizes the first word in a string.
# Capitalizes the first word in a string and downcases the remaining characters.
# @liquid_syntax string | capitalize
# @liquid_return [string]
def capitalize(input)
@@ -869,6 +869,34 @@ module Liquid
false_check || (input.respond_to?(:empty?) && input.empty?) ? default_value : input
end
# @liquid_public_docs
# @liquid_type filter
# @liquid_category array
# @liquid_summary
# Returns the sum of all elements in an array.
# @liquid_syntax array | sum
# @liquid_return [number]
def sum(input, property = nil)
ary = InputIterator.new(input, context)
return 0 if ary.empty?
values_for_sum = ary.map do |item|
if property.nil?
item
elsif item.respond_to?(:[])
item[property]
else
0
end
rescue TypeError
raise_property_error(property)
end
InputIterator.new(values_for_sum, context).sum do |item|
Utils.to_number(item)
end
end
private
attr_reader :context
+1
View File
@@ -26,6 +26,7 @@ module Liquid
@body = +''
while (token = tokens.shift)
if token =~ FullTokenPossiblyInvalid && block_delimiter == Regexp.last_match(2)
parse_context.trim_whitespace = (token[-3] == WhitespaceControl)
@body << Regexp.last_match(1) if Regexp.last_match(1) != ""
return
end
+2
View File
@@ -189,6 +189,8 @@ module Liquid
@profiler = context.profiler = Liquid::Profiler.new
end
context.template_name ||= name
begin
# render the nodelist.
@root.render_to_output_buffer(context, output || +'')
+103
View File
@@ -0,0 +1,103 @@
# frozen_string_literal: true
require 'test_helper'
class ArrayTest < Minitest::Test
include Liquid
def test_array_size
assert_template_result("0", "{{a.size}}", { 'a' => [] })
assert_template_result("2", "{{a.size}}", { 'a' => [1, 2] })
end
def test_array_first
assert_template_result("", "{{a.first}}", { 'a' => [] })
assert_template_result("1", "{{a.first}}", { 'a' => [1, 2] })
end
def test_array_last
assert_template_result("", "{{a.last}}", { 'a' => [] })
assert_template_result("2", "{{a.last}}", { 'a' => [1, 2] })
end
def test_array_index
assert_template_result("", "{{a[1]}}", { 'a' => [] })
assert_template_result("2", "{{a[1]}}", { 'a' => [1, 2] })
end
def test_negative_array_index
assert_template_result("3", "{{a[-1]}}", { 'a' => [1, 2, 3] })
assert_template_result("1", "{{a[-3]}}", { 'a' => [1, 2, 3] })
assert_template_result("", "{{a[-4]}}", { 'a' => [1, 2, 3] })
end
def test_array_to_s
arr = ["a", ["b", 1], "c"]
assert_template_result("ab1c", "{{a}}", { 'a' => arr })
end
def test_auto_methods
a1 = []
a2 = [1, 2, 3, "abc"]
assert_template_result("0,nonblank", "{{a.size}},{%if a['size'] == blank%}blank{%else%}nonblank{%endif%}", { 'a' => a1 })
assert_template_result("4,nonblank", "{{a.size}},{%if a['size'] == blank%}blank{%else%}nonblank{%endif%}", { 'a' => a2 })
assert_template_result(",", "{{a.first}},{{a['first']}}", { 'a' => a1 })
assert_template_result("1,", "{{a.first}},{{a['first']}}", { 'a' => a2 })
assert_template_result(",", "{{a.last}},{{a['last']}}", { 'a' => a1 })
assert_template_result("abc,", "{{a.last}},{{a['last']}}", { 'a' => a2 })
end
def test_array_equality
a0 = []
a1 = [1]
a2 = [1, 2]
a3 = [1]
arrays = [a0, a1, a2, a3]
arrays.each_with_index do |a, i|
arrays.each_with_index do |b, j|
prefix = "(#{i},#{j})"
assert_template_result(
prefix + (a == b ? "y" : "n"),
"#{prefix}{% if a == b %}y{%else%}n{%endif%}",
{ "a" => a, "b" => b },
)
end
end
end
def test_contains
a0 = [1, "a", ["b", "c"], true]
a1 = ["b", "c"]
a2 = ["B", "C"]
tpl = "{%if a contains b%}y{%else%}n{%endif%}"
assert_template_result("y", tpl, { "a" => a0, "b" => 1 })
assert_template_result("n", tpl, { "a" => a0, "b" => 2 })
assert_template_result("y", tpl, { "a" => a0, "b" => a1 })
assert_template_result("n", tpl, { "a" => a0, "b" => a2 })
end
def test_empty
assert_template_result("y", "{%if a == empty%}y{%else%}n{%endif%}", { 'a' => [] })
assert_template_result("n", "{%if a == empty%}y{%else%}n{%endif%}", { 'a' => [1, 2] })
end
def test_blank
assert_template_result("y", "{%if a == blank%}y{%else%}n{%endif%}", { 'a' => [] })
assert_template_result("n", "{%if a == blank%}y{%else%}n{%endif%}", { 'a' => [1, 2] })
end
def test_iter
a0 = [1, "a"]
assert_template_result("1a", "{%for i in a%}{{i}}{%endfor%}", { 'a' => a0 })
end
def test_output
a0 = []
a1 = [1, "a", ["b", "c"], true]
assert_template_result("", "{{a}}", { 'a' => a0 })
assert_template_result("1abctrue", "{{a}}", { 'a' => a1 })
end
end
+77
View File
@@ -263,4 +263,81 @@ class ErrorHandlingTest < Minitest::Test
output = Liquid::Template.parse("{% assign x = 0 %}{% if 1 < '2' %}{% assign x = 3 %}{% endif %}{{ x }}").render
assert_equal("0", output)
end
def test_syntax_error_is_raised_with_template_name
file_system = StubFileSystem.new("snippet" => "1\n2\n{{ 1")
context = Liquid::Context.build(
registers: { file_system: file_system },
)
template = Template.parse(
'{% render "snippet" %}',
line_numbers: true,
)
template.name = "template/index"
assert_equal(
"Liquid syntax error (snippet line 3): Variable '{{' was not properly terminated with regexp: /\\}\\}/",
template.render(context),
)
end
def test_syntax_error_is_raised_with_template_name_from_template_factory
file_system = StubFileSystem.new("snippet" => "1\n2\n{{ 1")
context = Liquid::Context.build(
registers: {
file_system: file_system,
template_factory: StubTemplateFactory.new,
},
)
template = Template.parse(
'{% render "snippet" %}',
line_numbers: true,
)
template.name = "template/index"
assert_equal(
"Liquid syntax error (some/path/snippet line 3): Variable '{{' was not properly terminated with regexp: /\\}\\}/",
template.render(context),
)
end
def test_error_is_raised_during_parse_with_template_name
depth = Liquid::Block::MAX_DEPTH + 1
code = "{% if true %}" * depth + "rendered" + "{% endif %}" * depth
template = Template.parse("{% render 'snippet' %}", line_numbers: true)
context = Liquid::Context.build(
registers: {
file_system: StubFileSystem.new("snippet" => code),
template_factory: StubTemplateFactory.new,
},
)
assert_equal("Liquid error (some/path/snippet line 1): Nesting too deep", template.render(context))
end
def test_internal_error_is_raised_with_template_name
template = Template.new
template.parse(
"{% render 'snippet' %}",
line_numbers: true,
)
template.name = "template/index"
context = Liquid::Context.build(
registers: {
file_system: StubFileSystem.new({}),
},
)
assert_equal(
"Liquid error (template/index line 1): internal",
template.render(context),
)
end
end
+223
View File
@@ -0,0 +1,223 @@
# frozen_string_literal: true
require "test_helper"
require "json"
class HashTest < Minitest::Test
include Liquid
class HashSubclass < Hash
def []=(key, value)
super(fmt_key(key), value)
end
def [](key)
super(fmt_key(key))
end
def key?(key)
super(fmt_key(key))
end
def include?(key)
super(fmt_key(key))
end
def to_s
super.upcase
end
private
def fmt_key(key)
return key unless key.is_a?(String)
key.upcase
end
end
def test_size
assert_template_result("0", "{{h.size}}", { "h" => {} })
assert_template_result("1", "{{h.size}}", { "h" => { "a" => 1 } })
end
def test_first
assert_template_result("", "{{h.first}}", { "h" => {} })
assert_template_result("a1", "{{h.first}}", { "h" => { "a" => 1 } })
end
def test_last
assert_template_result("", "{{h.last}}", { "h" => { "a" => 1 } })
end
def test_index
assert_template_result("", "{{h['a']}}", { "h" => {} })
assert_template_result("1", "{{h['a']}}", { "h" => { "a" => 1 } })
end
def test_to_s
h = { "a" => 1, "b" => [1, { "c" => 2 }] }
assert_template_result("{\"a\"=>1, \"b\"=>[1, {\"c\"=>2}]}", "{{h}}", { "h" => h })
end
def test_auto_methods
h1 = { "a" => 1 }
h2 = { "last" => 10, "first" => 11, "size" => 12 }
assert_template_result("1,nonblank", "{{h.size}},{%if h['size'] == blank%}blank{%else%}nonblank{%endif%}", { "h" => h1 })
assert_template_result("12,nonblank", "{{h.size}},{%if h['size'] == blank%}blank{%else%}nonblank{%endif%}", { "h" => h2 })
assert_template_result("a1,", "{{h.first}},{{h['first']}}", { "h" => h1 })
assert_template_result("11,11", "{{h.first}},{{h['first']}}", { "h" => h2 })
assert_template_result(",", "{{h.last}},{{h['last']}}", { "h" => h1 })
assert_template_result("10,10", "{{h.last}},{{h['last']}}", { "h" => h2 })
end
def test_equality
h0 = {}
h1 = { "a" => 1 }
h2 = { "a" => 1, "b" => 2 }
h3 = { "a" => 1 }
hashes = [h0, h1, h2, h3]
hashes.each_with_index do |a, i|
hashes.each_with_index do |b, j|
prefix = "(#{i},#{j})"
assert_template_result(
prefix + (a == b ? "y" : "n"),
"#{prefix}{% if a == b %}y{%else%}n{%endif%}",
{ "a" => a, "b" => b },
)
end
end
end
def test_contains
h = { "a" => 1, "b" => { "c" => "d" }, "3" => ["f", 2] }
tpl = "{%if h contains b%}y{%else%}n{%endif%}"
assert_template_result("y", tpl, { "h" => h, "b" => "a" })
# assert_template_result("y", tpl, h, { "h" => { "b" => "a".html_safe } })
assert_template_result("y", tpl, { "h" => h, "b" => "a".b })
assert_template_result("n", tpl, { "h" => h, "b" => "A" })
# assert_template_result("n", tpl, h, { "h" => { "b" => "A".html_safe } })
assert_template_result("n", tpl, { "h" => h, "b" => "A".b })
assert_template_result("n", tpl, { "h" => h, "b" => 1 })
assert_template_result("n", tpl, { "h" => h, "b" => "1" })
assert_template_result("n", tpl, { "h" => h, "b" => 3 })
assert_template_result("y", tpl, { "h" => h, "b" => "3" })
end
def test_empty
assert_template_result("y", "{%if h == empty%}y{%else%}n{%endif%}", { "h" => {} })
assert_template_result("n", "{%if h == empty%}y{%else%}n{%endif%}", { "h" => { "a" => 1 } })
end
def test_blank
assert_template_result("y", "{%if h == blank%}y{%else%}n{%endif%}", { "h" => {} })
assert_template_result("n", "{%if h == blank%}y{%else%}n{%endif%}", { "h" => { "a" => 1 } })
end
def test_iter
h0 = { "a" => 1, "b" => { "c" => "d" }, "3" => ["f", 2] }
assert_template_result("a1b{\"c\"=>\"d\"}3f2", "{%for i in h%}{{i}}{%endfor%}", { "h" => h0 })
end
def test_output
h0 = {}
h1 = { "a" => 1, "b" => { "c" => "d" }, "3" => ["f", 2] }
assert_template_result("{}", "{{h}}", { "h" => h0 })
assert_template_result("{\"a\"=>1, \"b\"=>{\"c\"=>\"d\"}, \"3\"=>[\"f\", 2]}", "{{h}}", { "h" => h1 })
end
def test_integer_key
h = { 2 => "huh" }
assert_template_result("huh", "{{h[2]}}", { "h" => h })
assert_template_result("huh", "{{h[b]}}", { "h" => h, "b" => 2 })
assert_template_result("", "{{h[b]}}", { "h" => h, "b" => "2" })
end
def test_nil_key
assert_hash_roundtrip(nil, nil)
refute_hash_roundtrip(nil, "nil")
refute_hash_roundtrip(nil, "null")
end
def test_bool_key
assert_hash_roundtrip(true, true)
refute_hash_roundtrip(true, false)
refute_hash_roundtrip(true, "true")
refute_hash_roundtrip(true, nil)
end
def test_int_key
assert_hash_roundtrip(1, 1)
refute_hash_roundtrip(1, 2)
refute_hash_roundtrip(1, "1")
refute_hash_roundtrip(1, 1.0000000000001)
end
def test_string_key
assert_hash_roundtrip("word", "word")
# assert_hash_roundtrip("word", "word".html_safe)
assert_hash_roundtrip("word", "word".b)
refute_hash_roundtrip("word", "word ")
refute_hash_roundtrip("word", nil)
refute_hash_roundtrip("word", true)
end
def test_weird_keys
assert_hash_roundtrip([1, 2], [1, 2])
refute_hash_roundtrip([1, 2], [1, 3])
assert_hash_roundtrip({ "a" => 1 }, { "a" => 1 })
refute_hash_roundtrip({ "a" => 1 }, { "a" => 2 })
o = Struct.new(:to_liquid).new(Object.new)
# failed_hash_roundtrip(o, o)
refute_hash_roundtrip(o, 1)
refute_hash_roundtrip(o, nil)
assert_hash_roundtrip("\xff".b, "\xff".b)
assert_hash_roundtrip(1..2, 1..2)
refute_hash_roundtrip(1..2, 1...2)
assert_hash_roundtrip(
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111,
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111,
)
# f64 hashing isn't perfect but we can make some basic assertions.
assert_hash_roundtrip(1.1234, 1.1234)
refute_hash_roundtrip(1.1234, 1.1)
end
def test_hash_html_key
# I mean this is probably not ideal but this is the way liquid works.
assert_template_result("{\"a<script>b\"=>\"y\"}", "{{h}}", { "h" => { "a<script>b" => "y" } })
end
def test_hash_subclass
hs = HashSubclass.new
hs["A"] = "b"
assert_template_result("b", "{{h['a']}}", { "h" => hs })
assert_template_result("b", "{{h['A']}}", { "h" => hs })
assert_template_result("", "{{h['b']}}", { "h" => hs })
assert_template_result("yes", "{% if h contains 'a' %}yes{%else%}no{%endif%}", { "h" => hs })
assert_template_result('{"A"=>"B"}', "{{h}}", { "h" => hs })
end
private
def failed_hash_roundtrip(key, test)
assert_template_result(
"Liquid error (templates/index line 1): internal",
"{{h[b]}}",
{ "h" => { key => "y" }, "b" => test },
)
end
def assert_hash_roundtrip(key, test)
assert_template_result("y", "{{h[b]}}", { "h" => { key => "y" }, "b" => test })
end
def refute_hash_roundtrip(key, test)
assert_template_result("", "{{h[b]}}", { "h" => { key => "y" }, "b" => test })
end
end
+66
View File
@@ -928,6 +928,72 @@ class StandardFiltersTest < Minitest::Test
assert_equal([{ "foo" => true }, { "foo" => "for sure" }], @filters.where(input, "foo"))
end
def test_sum_with_all_numbers
input = [1, 2]
assert_equal(3, @filters.sum(input))
assert_raises(Liquid::ArgumentError, "cannot select the property 'quantity'") do
@filters.sum(input, "quantity")
end
end
def test_sum_with_numeric_strings
input = [1, 2, "3", "4"]
assert_equal(10, @filters.sum(input))
assert_raises(Liquid::ArgumentError, "cannot select the property 'quantity'") do
@filters.sum(input, "quantity")
end
end
def test_sum_with_nested_arrays
input = [1, [2, [3, 4]]]
assert_equal(10, @filters.sum(input))
assert_raises(Liquid::ArgumentError, "cannot select the property 'quantity'") do
@filters.sum(input, "quantity")
end
end
def test_sum_with_indexable_map_values
input = [{ "quantity" => 1 }, { "quantity" => 2, "weight" => 3 }, { "weight" => 4 }]
assert_equal(0, @filters.sum(input))
assert_equal(3, @filters.sum(input, "quantity"))
assert_equal(7, @filters.sum(input, "weight"))
assert_equal(0, @filters.sum(input, "subtotal"))
end
def test_sum_with_indexable_non_map_values
input = [1, [2], "foo", { "quantity" => 3 }]
assert_equal(3, @filters.sum(input))
assert_raises(Liquid::ArgumentError, "cannot select the property 'quantity'") do
@filters.sum(input, "quantity")
end
end
def test_sum_with_unindexable_values
input = [1, true, nil, { "quantity" => 2 }]
assert_equal(1, @filters.sum(input))
assert_raises(Liquid::ArgumentError, "cannot select the property 'quantity'") do
@filters.sum(input, "quantity")
end
end
def test_sum_without_property_calls_to_liquid
t = TestThing.new
Liquid::Template.parse('{{ foo | sum }}').render("foo" => [t])
assert(t.foo > 0)
end
def test_sum_with_property_calls_to_liquid_on_property_values
t = TestThing.new
Liquid::Template.parse('{{ foo | sum: "quantity" }}').render("foo" => [{ "quantity" => t }])
assert(t.foo > 0)
end
private
def with_timezone(tz)
+33
View File
@@ -113,4 +113,37 @@ class LiquidTagTest < Minitest::Test
{% raw %}{% liquid echo 'test' %}{% endraw %}
LIQUID
end
def test_nested_liquid_tags
assert_template_result('good', <<~LIQUID)
{%- liquid
liquid
if true
echo "good"
endif
-%}
LIQUID
end
def test_nested_liquid_tags_on_same_line
assert_template_result('good', <<~LIQUID)
{%- liquid liquid liquid echo "good" -%}
LIQUID
end
def test_nested_liquid_liquid_is_not_skipped_if_used_in_non_tag_position
assert_template_result('liquid', <<~LIQUID, { 'liquid' => 'liquid' })
{%- liquid liquid liquid echo liquid -%}
LIQUID
end
def test_next_liquid_with_unclosed_if_tag
assert_match_syntax_error("Liquid syntax error (line 2): 'if' tag was never closed", <<~LIQUID)
{%- liquid
liquid if true
echo "good"
endif
-%}
LIQUID
end
end
+2 -1
View File
@@ -13,8 +13,9 @@ class RawTagTest < Minitest::Test
end
def test_output_in_raw
# assert_template_result('{{ test }}', '{% raw %}{{ test }}{% endraw %}')
assert_template_result('>{{ test }}<', '> {%- raw -%}{{ test }}{%- endraw -%} <')
assert_template_result("> inner <", "> {%- raw -%} inner {%- endraw %} <")
assert_template_result("> inner <", "> {%- raw -%} inner {%- endraw -%} <")
end
def test_open_tag_in_raw
+1
View File
@@ -34,6 +34,7 @@ class VariableTest < Minitest::Test
assert_template_result('', '{% if foo %}true{% endif %}', { 'foo' => BooleanDrop.new(false) })
assert_template_result('', '{% if foo == true %}True{% endif %}', { 'foo' => BooleanDrop.new(false) })
assert_template_result('', '{% if foo and true %}SHOULD NOT HAPPEN{% endif %}', { 'foo' => BooleanDrop.new(false) })
assert_template_result('one', '{% if a contains x %}one{% endif %}', { 'a' => [1], 'x' => IntegerDrop.new(1) })
end
+23
View File
@@ -174,4 +174,27 @@ class PartialCacheUnitTest < Minitest::Test
assert_equal('some/path/my_partial', partial.name)
end
def test_includes_error_mode_into_template_cache
template_factory = StubTemplateFactory.new
context = Liquid::Context.build(
registers: {
file_system: StubFileSystem.new('my_partial' => 'my partial body'),
template_factory: template_factory,
},
)
[:lax, :warn, :strict].each do |error_mode|
Liquid::PartialCache.load(
'my_partial',
context: context,
parse_context: Liquid::ParseContext.new(error_mode: error_mode),
)
end
assert_equal(
["my_partial:lax", "my_partial:warn", "my_partial:strict"],
context.registers[:cached_partials].keys,
)
end
end