Compare commits

...
Author SHA1 Message Date
Marco Concetto Rudilosso 177a7e9c23 rubocop 2022-09-08 16:48:01 +02:00
44d93e2c9b Update lib/liquid/tags/render.rb
Co-authored-by: Dylan Thacker-Smith <[email protected]>
2022-09-08 16:30:10 +02:00
Marco Concetto RudilossoandGitHub 753015d8fc remove question mark 2022-09-08 15:59:46 +02:00
Marco Concetto RudilossoandGitHub f4e32d2214 Expose alias_name and for_loop? in render tag 2022-09-08 15:38:18 +02:00
Dylan Thacker-SmithandGitHub 8adbbfeaa6 Merge pull request #1614 from Shopify/extend-assert-tempate-result
Add partials, error_mode and render_errors options to assert_template_result
2022-09-07 13:17:08 -04:00
Dylan Thacker-Smith 4648f0fa64 Add sample usage of render_errors: true assert_template_result option 2022-09-06 16:54:38 -04:00
Dylan Thacker-Smith 3a64b3741f Add sample usage of error_mode test helper option 2022-09-06 16:44:40 -04:00
Dylan Thacker-Smith 2c51a1922a Add error_mode option to assert_match_syntax_error 2022-09-06 16:44:40 -04:00
Dylan Thacker-Smith 57fdc1b5fb Add sample use of partials assert_template_result options 2022-09-06 16:44:39 -04:00
Dylan Thacker-Smith 308dfc3cb6 Add partials, error_mode and render_errors options to assert_template_result 2022-09-06 16:44:39 -04:00
Dylan Thacker-SmithandGitHub 2515f3be09 Use assert_template_result & assert_match_syntax_error in more places (#1611) 2022-09-01 17:40:39 -04:00
Dylan Thacker-SmithandGitHub 433ed0fff2 Merge pull request #1612 from Shopify/assert-template-result-reserve-kwargs
Reserve keyword arguments for new options in assert_template_result
2022-09-01 17:39:28 -04:00
Dylan Thacker-Smith 0787660603 Reserve keyword arguments for new options in assert_template_result 2022-09-01 17:38:09 -04:00
Dylan Thacker-Smith 93c252fe5a Stop passing unnecessary assigns to assert_match_syntax_error 2022-09-01 17:38:09 -04:00
Dylan Thacker-Smith df13389940 Stop passing assigns as keyword arguments to assert_template_result 2022-09-01 17:38:08 -04:00
Dylan Thacker-SmithandGitHub ca2d850eea Stop using Liquid::Expression.parse for integration testing (#1610)
Since liquid-c no longer monkey patches it, so we need a higher-level
tests to ensure they are shared across liquid implementations.
2022-09-01 17:37:47 -04:00
Dylan Thacker-SmithandGitHub 3a736da222 Add a variable_name method Increment and Decrement tags objects (#1609)
In order to expose this state when using the parse tree.
2022-08-31 09:18:33 -04:00
Dylan Thacker-SmithandGitHub eb89f22d93 Raise Liquid::SyntaxError instead of NoMethodError for invalid range (#1607) 2022-08-25 12:03:56 -04:00
Dylan Thacker-SmithandGitHub 98e146ebf7 Merge pull request #1606 from Watson1978/performance-lexer-tokenize
Increase performance in Liquid::Lexer#tokenize
2022-08-24 15:03:41 -04:00
Watson 7611463f02 Increase performance in Liquid::Lexer#tokenize
To obtain String Literal, the regular expression might be executed at two times.
It would be slightly faster to run them all at once using `Regexp.union`.

−               | before   | after   | result
--               | --       | --      | --
parse            | 63.418   | 65.183  | 1.028x
render           | 195.389  | 195.648 | -
parse & render   | 46.091   | 46.917  | 1.018x

### Environment
- MacBook Pro (14 inch, 2021)
- macOS 13.0 Beta
- Apple M1 Max
- Ruby 3.1.2

### Before
```
Running benchmark for 10 seconds (with 5 seconds warmup).

Warming up --------------------------------------
              parse:     6.000  i/100ms
             render:    19.000  i/100ms
     parse & render:     4.000  i/100ms
Calculating -------------------------------------
              parse:     63.418  (± 0.0%) i/s -    636.000  in  10.028939s
             render:    195.389  (± 0.5%) i/s -      1.957k in  10.016466s
     parse & render:     46.091  (± 0.0%) i/s -    464.000  in  10.067445s
```

### After
```
Running benchmark for 10 seconds (with 5 seconds warmup).

Warming up --------------------------------------
              parse:     6.000  i/100ms
             render:    19.000  i/100ms
     parse & render:     4.000  i/100ms
Calculating -------------------------------------
              parse:     65.183  (± 0.0%) i/s -    654.000  in  10.033549s
             render:    195.648  (± 1.0%) i/s -      1.957k in  10.003511s
     parse & render:     46.917  (± 0.0%) i/s -    472.000  in  10.060782s
```
2022-08-24 04:23:05 +09:00
Dylan Thacker-SmithandGitHub f1846d63a3 Merge pull request #1597 from Shopify/replace-cla-probot-with-action
Migrate off probot-CLA to new GitHub Action
2022-07-29 13:01:24 -04:00
CP ClermontandGitHub af3f8612bf Merge pull request #1601 from Shopify/bump/5.4.0
Bump version to 5.4.0 for release
2022-07-29 10:29:21 -04:00
Charles-P. Clermont 6f8722a6d3 Bump version to 5.4.0 for release 2022-07-28 13:47:53 -04:00
Zoey LanandGitHub 81f44e36be Merge pull request #1600 from Shopify/zoey/expose-filter-names
Expose global filter names
2022-07-21 12:55:02 -06:00
Zoey Lan c9ec8f4635 Expose global filter names 2022-07-21 12:34:41 -06:00
CP ClermontandGitHub 3fb467f069 Merge pull request #1596 from Shopify/fix/theme-check-582-render-with-parse-tree-visitor
Add variable_name_expr to render's ParseTreeVisitor
2022-07-18 08:49:47 -04:00
Charles-P. Clermont 992e15a173 Add variable_name_expr to render's ParseTreeVisitor
Solves Shopify/theme-check#582

`icon` should be visited in the render tag for the following snippet:

```liquid
{% assign icon = 'warning' }
{% render 'icon' with icon %}
```
2022-07-18 08:48:18 -04:00
Yevhenii Huselietov 0bb6539dce Remove CLA from probot and use new GitHub action 2022-07-16 11:59:44 -04:00
NadaMarawanandGitHub 1fdc577246 Merge pull request #1595 from Shopify/jake-clarify-sort-natural
Clarify sort_natural and fix unless syntax
2022-07-13 15:17:15 -04:00
Jake Olney 74245cd396 clarify sort_natural and fix unless syntax 2022-07-12 18:33:15 -07:00
Dylan Thacker-SmithandGitHub 86605016e1 Add Liquid::VariableLookup#lookup_command? to expose this parse node state (#1583) 2022-07-04 14:42:05 -04:00
NadaMarawanandGitHub 6981305736 Merge pull request #1588 from Shopify/jake-add-forloop-parentloop
document forloop.parentloop
2022-06-30 10:16:25 -04:00
42 changed files with 558 additions and 550 deletions
-2
View File
@@ -1,2 +0,0 @@
enabled:
- cla
+22
View File
@@ -0,0 +1,22 @@
name: Contributor License Agreement (CLA)
on:
pull_request_target:
types: [opened, synchronize]
issue_comment:
types: [created]
jobs:
cla:
runs-on: ubuntu-latest
if: |
(github.event.issue.pull_request
&& !github.event.issue.pull_request.merged_at
&& contains(github.event.comment.body, 'signed')
)
|| (github.event.pull_request && !github.event.pull_request.merged)
steps:
- uses: Shopify/shopify-cla-action@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
cla-token: ${{ secrets.CLA_TOKEN }}
+2 -1
View File
@@ -1,6 +1,6 @@
# Liquid Change Log
## 5.4.0 (unreleased)
## 5.4.0 2022-07-29
### Breaking Changes
* Drop support for end-of-life Ruby versions (2.5 and 2.6) (#1578) [Andy Waite]
@@ -11,6 +11,7 @@
### Fixes
* `PartialCache` now shares snippet cache with subcontexts by default (#1553) [Chris AtLee]
* Hash registers no longer leak into subcontexts as static registers (#1564) [Chris AtLee]
* Fix `ParseTreeVisitor` for `with` variable expressions in `Render` tag (#1596) [CP Clermont]
### Changed
* Liquid::Context#registers now always returns a Liquid::Registers object, though supports the most used Hash functions for compatibility (#1553)
+2 -3
View File
@@ -18,6 +18,7 @@ module Liquid
IDENTIFIER = /[a-zA-Z_][\w-]*\??/
SINGLE_STRING_LITERAL = /'[^\']*'/
DOUBLE_STRING_LITERAL = /"[^\"]*"/
STRING_LITERAL = Regexp.union(SINGLE_STRING_LITERAL, DOUBLE_STRING_LITERAL)
NUMBER_LITERAL = /-?\d+(\.\d+)?/
DOTDOT = /\.\./
COMPARISON_OPERATOR = /==|!=|<>|<=?|>=?|contains(?=\s)/
@@ -35,9 +36,7 @@ module Liquid
break if @ss.eos?
tok = if (t = @ss.scan(COMPARISON_OPERATOR))
[:comparison, t]
elsif (t = @ss.scan(SINGLE_STRING_LITERAL))
[:string, t]
elsif (t = @ss.scan(DOUBLE_STRING_LITERAL))
elsif (t = @ss.scan(STRING_LITERAL))
[:string, t]
elsif (t = @ss.scan(NUMBER_LITERAL))
[:number, t]
+11 -1
View File
@@ -8,7 +8,17 @@ module Liquid
if start_obj.respond_to?(:evaluate) || end_obj.respond_to?(:evaluate)
new(start_obj, end_obj)
else
start_obj.to_i..end_obj.to_i
begin
start_obj.to_i..end_obj.to_i
rescue NoMethodError
invalid_expr = start_markup unless start_obj.respond_to?(:to_i)
invalid_expr ||= end_markup unless end_obj.respond_to?(:to_i)
if invalid_expr
raise Liquid::SyntaxError, "Invalid expression type '#{invalid_expr}' in range expression"
end
raise
end
end
end
+5 -1
View File
@@ -358,7 +358,11 @@ module Liquid
# @liquid_type filter
# @liquid_category array
# @liquid_summary
# Sorts the items in an array in case-insensitive alphabetical, or numerical, order.
# Sorts the items in an array in case-insensitive alphabetical order.
# @liquid_description
# > Caution:
# > You shouldn't use the `sort_natural` filter to sort numerical values. When comparing items an array, each item is converted to a
# > string, so sorting on numerical values can lead to unexpected results.
# @liquid_syntax array | sort_natural
# @liquid_return [array[untyped]]
def sort_natural(input, property = nil)
+4
View File
@@ -14,6 +14,10 @@ module Liquid
strainer_from_cache(filters).new(context)
end
def global_filter_names
GlobalCache.filter_method_names
end
GlobalCache = Class.new(StrainerTemplate)
private
+4
View File
@@ -36,6 +36,10 @@ module Liquid
subclass.instance_variable_set(:@filter_methods, @filter_methods.dup)
end
def filter_method_names
filter_methods.map(&:to_s).to_a
end
private
def filter_methods
+6 -3
View File
@@ -19,15 +19,18 @@ module Liquid
# {% decrement variable_name %}
# @liquid_syntax_keyword variable_name The name of the variable being decremented.
class Decrement < Tag
attr_reader :variable_name
def initialize(tag_name, markup, options)
super
@variable = markup.strip
@variable_name = markup.strip
end
def render_to_output_buffer(context, output)
value = context.environments.first[@variable] ||= 0
counter_environment = context.environments.first
value = counter_environment[@variable_name] || 0
value -= 1
context.environments.first[@variable] = value
counter_environment[@variable_name] = value
output << value.to_s
output
end
+6 -3
View File
@@ -19,14 +19,17 @@ module Liquid
# {% increment variable_name %}
# @liquid_syntax_keyword variable_name The name of the variable being incremented.
class Increment < Tag
attr_reader :variable_name
def initialize(tag_name, markup, options)
super
@variable = markup.strip
@variable_name = markup.strip
end
def render_to_output_buffer(context, output)
value = context.environments.first[@variable] ||= 0
context.environments.first[@variable] = value + 1
counter_environment = context.environments.first
value = counter_environment[@variable_name] || 0
counter_environment[@variable_name] = value + 1
output << value.to_s
output
+8 -3
View File
@@ -31,7 +31,11 @@ module Liquid
disable_tags "include"
attr_reader :template_name_expr, :attributes
attr_reader :template_name_expr, :variable_name_expr, :attributes, :alias_name
def for_loop?
@is_for_loop
end
def initialize(tag_name, markup, options)
super
@@ -45,7 +49,7 @@ module Liquid
@alias_name = Regexp.last_match(6)
@variable_name_expr = variable_name ? parse_expression(variable_name) : nil
@template_name_expr = parse_expression(template_name)
@for = (with_or_for == FOR)
@is_for_loop = (with_or_for == FOR)
@attributes = {}
markup.scan(TagAttributes) do |key, value|
@@ -85,7 +89,7 @@ module Liquid
}
variable = @variable_name_expr ? context.evaluate(@variable_name_expr) : nil
if @for && variable.respond_to?(:each) && variable.respond_to?(:count)
if @is_for_loop && variable.respond_to?(:each) && variable.respond_to?(:count)
forloop = Liquid::ForloopDrop.new(template_name, variable.count, nil)
variable.each { |var| render_partial_func.call(var, forloop) }
else
@@ -99,6 +103,7 @@ module Liquid
def children
[
@node.template_name_expr,
@node.variable_name_expr,
] + @node.attributes.values
end
end
+1 -1
View File
@@ -15,7 +15,7 @@ module Liquid
# @liquid_syntax
# {% unless condition %}
# expression
# {% endif %}
# {% endunless %}
# @liquid_syntax_keyword condition The condition to evaluate.
# @liquid_syntax_keyword expression The expression to render unless the condition is met.
class Unless < If
+5 -1
View File
@@ -32,6 +32,10 @@ module Liquid
end
end
def lookup_command?(lookup_index)
@command_flags & (1 << lookup_index) != 0
end
def evaluate(context)
name = context.evaluate(@name)
object = context.find_variable(name)
@@ -55,7 +59,7 @@ module Liquid
# Some special cases. If the part wasn't in square brackets and
# no key with the same name was found we interpret following calls
# as commands and call them on the current object
elsif @command_flags & (1 << i) != 0 && object.respond_to?(key)
elsif lookup_command?(i) && object.respond_to?(key)
object = object.send(key).to_liquid
# No key was present with the desired value and it wasn't one of the directly supported
+1 -1
View File
@@ -2,5 +2,5 @@
# frozen_string_literal: true
module Liquid
VERSION = "5.4.0.alpha"
VERSION = "5.4.0"
end
+12 -21
View File
@@ -6,51 +6,42 @@ class AssignTest < Minitest::Test
include Liquid
def test_assign_with_hyphen_in_variable_name
template_source = <<-END_TEMPLATE
{% assign this-thing = 'Print this-thing' %}
{{ this-thing }}
template_source = <<~END_TEMPLATE
{% assign this-thing = 'Print this-thing' -%}
{{ this-thing -}}
END_TEMPLATE
template = Template.parse(template_source)
rendered = template.render!
assert_equal("Print this-thing", rendered.strip)
assert_template_result("Print this-thing", template_source)
end
def test_assigned_variable
assert_template_result('.foo.',
'{% assign foo = values %}.{{ foo[0] }}.',
'values' => %w(foo bar baz))
{ 'values' => %w(foo bar baz) })
assert_template_result('.bar.',
'{% assign foo = values %}.{{ foo[1] }}.',
'values' => %w(foo bar baz))
{ 'values' => %w(foo bar baz) })
end
def test_assign_with_filter
assert_template_result('.bar.',
'{% assign foo = values | split: "," %}.{{ foo[1] }}.',
'values' => "foo,bar,baz")
{ 'values' => "foo,bar,baz" })
end
def test_assign_syntax_error
assert_match_syntax_error(/assign/,
'{% assign foo not values %}.',
'values' => "foo,bar,baz")
assert_match_syntax_error(/assign/, '{% assign foo not values %}.')
end
def test_assign_uses_error_mode
with_error_mode(:strict) do
assert_raises(SyntaxError) do
Template.parse("{% assign foo = ('X' | downcase) %}")
end
end
with_error_mode(:lax) do
assert(Template.parse("{% assign foo = ('X' | downcase) %}"))
end
assert_match_syntax_error("Expected dotdot but found pipe in ",
"{% assign foo = ('X' | downcase) %}", error_mode: :strict)
assert_template_result("", "{% assign foo = ('X' | downcase) %}", error_mode: :lax)
end
def test_expression_with_whitespace_in_square_brackets
source = "{% assign r = a[ 'b' ] %}{{ r }}"
assert_template_result('result', source, 'a' => { 'b' => 'result' })
assert_template_result('result', source, { 'a' => { 'b' => 'result' } })
end
def test_assign_score_exceeding_resource_limit
+6 -10
View File
@@ -9,12 +9,6 @@ class FoobarTag < Liquid::Tag
end
end
class BlankTestFileSystem
def read_template_file(template_path)
template_path
end
end
class BlankTest < Minitest::Test
include Liquid
N = 10
@@ -95,10 +89,12 @@ class BlankTest < Minitest::Test
end
def test_include_is_blank
Liquid::Template.file_system = BlankTestFileSystem.new
assert_template_result("foobar" * (N + 1), wrap("{% include 'foobar' %}"))
assert_template_result(" foobar " * (N + 1), wrap("{% include ' foobar ' %}"))
assert_template_result(" " * (N + 1), wrap(" {% include ' ' %} "))
assert_template_result("foobar" * (N + 1), wrap("{% include 'foobar' %}"),
partials: { 'foobar' => 'foobar' })
assert_template_result(" foobar " * (N + 1), wrap("{% include ' foobar ' %}"),
partials: { ' foobar ' => ' foobar ' })
assert_template_result(" " * (N + 1), wrap(" {% include ' ' %} "),
partials: { ' ' => ' ' })
end
def test_case_is_blank
+2 -4
View File
@@ -6,10 +6,8 @@ class BlockTest < Minitest::Test
include Liquid
def test_unexpected_end_tag
exc = assert_raises(SyntaxError) do
Template.parse("{% if true %}{% endunless %}")
end
assert_equal(exc.message, "Liquid syntax error: 'endunless' is not a valid delimiter for if tags. use endif")
source = '{% if true %}{% endunless %}'
assert_match_syntax_error("Liquid syntax error (line 1): 'endunless' is not a valid delimiter for if tags. use endif", source)
end
def test_with_custom_tag
+23 -29
View File
@@ -10,44 +10,38 @@ class CaptureTest < Minitest::Test
end
def test_capture_with_hyphen_in_variable_name
template_source = <<-END_TEMPLATE
{% capture this-thing %}Print this-thing{% endcapture %}
{{ this-thing }}
template_source = <<~END_TEMPLATE
{% capture this-thing %}Print this-thing{% endcapture -%}
{{ this-thing -}}
END_TEMPLATE
template = Template.parse(template_source)
rendered = template.render!
assert_equal("Print this-thing", rendered.strip)
assert_template_result("Print this-thing", template_source)
end
def test_capture_to_variable_from_outer_scope_if_existing
template_source = <<-END_TEMPLATE
{% assign var = '' %}
{% if true %}
{% capture var %}first-block-string{% endcapture %}
{% endif %}
{% if true %}
{% capture var %}test-string{% endcapture %}
{% endif %}
{{var}}
template_source = <<~END_TEMPLATE
{% assign var = '' -%}
{% if true -%}
{% capture var %}first-block-string{% endcapture -%}
{% endif -%}
{% if true -%}
{% capture var %}test-string{% endcapture -%}
{% endif -%}
{{var-}}
END_TEMPLATE
template = Template.parse(template_source)
rendered = template.render!
assert_equal("test-string", rendered.gsub(/\s/, ''))
assert_template_result("test-string", template_source)
end
def test_assigning_from_capture
template_source = <<-END_TEMPLATE
{% assign first = '' %}
{% assign second = '' %}
{% for number in (1..3) %}
{% capture first %}{{number}}{% endcapture %}
{% assign second = first %}
{% endfor %}
{{ first }}-{{ second }}
template_source = <<~END_TEMPLATE
{% assign first = '' -%}
{% assign second = '' -%}
{% for number in (1..3) -%}
{% capture first %}{{number}}{% endcapture -%}
{% assign second = first -%}
{% endfor -%}
{{ first }}-{{ second -}}
END_TEMPLATE
template = Template.parse(template_source)
rendered = template.render!
assert_equal("3-3", rendered.gsub(/\s/, ''))
assert_template_result("3-3", template_source)
end
def test_increment_assign_score_by_bytes_not_characters
+71 -82
View File
@@ -102,7 +102,7 @@ class ContextTest < Minitest::Test
end
def test_variables_not_existing
assert_nil(@context['does_not_exist'])
assert_template_result("true", "{% if does_not_exist == nil %}true{% endif %}")
end
def test_scoping
@@ -121,22 +121,18 @@ class ContextTest < Minitest::Test
end
def test_length_query
@context['numbers'] = [1, 2, 3, 4]
assert_template_result("true", "{% if numbers.size == 4 %}true{% endif %}",
{ "numbers" => [1, 2, 3, 4] })
assert_equal(4, @context['numbers.size'])
assert_template_result("true", "{% if numbers.size == 4 %}true{% endif %}",
{ "numbers" => { 1 => 1, 2 => 2, 3 => 3, 4 => 4 } })
@context['numbers'] = { 1 => 1, 2 => 2, 3 => 3, 4 => 4 }
assert_equal(4, @context['numbers.size'])
@context['numbers'] = { 1 => 1, 2 => 2, 3 => 3, 4 => 4, 'size' => 1000 }
assert_equal(1000, @context['numbers.size'])
assert_template_result("true", "{% if numbers.size == 1000 %}true{% endif %}",
{ "numbers" => { 1 => 1, 2 => 2, 3 => 3, 4 => 4, 'size' => 1000 } })
end
def test_hyphenated_variable
@context['oh-my'] = 'godz'
assert_equal('godz', @context['oh-my'])
assert_template_result("godz", "{{ oh-my }}", { "oh-my" => 'godz' })
end
def test_add_filter
@@ -188,24 +184,24 @@ class ContextTest < Minitest::Test
end
def test_hierachical_data
@context['hash'] = { "name" => 'tobi' }
assert_equal('tobi', @context['hash.name'])
assert_equal('tobi', @context['hash["name"]'])
assigns = { 'hash' => { "name" => 'tobi' } }
assert_template_result("tobi", "{{ hash.name }}", assigns)
assert_template_result("tobi", '{{ hash["name"] }}', assigns)
end
def test_keywords
assert_equal(true, @context['true'])
assert_equal(false, @context['false'])
assert_template_result("pass", "{% if true == expect %}pass{% endif %}", { "expect" => true })
assert_template_result("pass", "{% if false == expect %}pass{% endif %}", { "expect" => false })
end
def test_digits
assert_equal(100, @context['100'])
assert_equal(100.00, @context['100.00'])
assert_template_result("pass", "{% if 100 == expect %}pass{% endif %}", { "expect" => 100 })
assert_template_result("pass", "{% if 100.00 == expect %}pass{% endif %}", { "expect" => 100.00 })
end
def test_strings
assert_equal("hello!", @context['"hello!"'])
assert_equal("hello!", @context["'hello!'"])
assert_template_result("hello!", '{{ "hello!" }}')
assert_template_result("hello!", "{{ 'hello!' }}")
end
def test_merge
@@ -217,99 +213,90 @@ class ContextTest < Minitest::Test
end
def test_array_notation
@context['test'] = [1, 2, 3, 4, 5]
assert_equal(1, @context['test[0]'])
assert_equal(2, @context['test[1]'])
assert_equal(3, @context['test[2]'])
assert_equal(4, @context['test[3]'])
assert_equal(5, @context['test[4]'])
assigns = { "test" => ["a", "b"] }
assert_template_result("a", "{{ test[0] }}", assigns)
assert_template_result("b", "{{ test[1] }}", assigns)
assert_template_result("pass", "{% if test[2] == nil %}pass{% endif %}", assigns)
end
def test_recoursive_array_notation
@context['test'] = { 'test' => [1, 2, 3, 4, 5] }
assigns = { "test" => { 'test' => [1, 2, 3, 4, 5] } }
assert_template_result("1", "{{ test.test[0] }}", assigns)
assert_equal(1, @context['test.test[0]'])
@context['test'] = [{ 'test' => 'worked' }]
assert_equal('worked', @context['test[0].test'])
assigns = { "test" => [{ 'test' => 'worked' }] }
assert_template_result("worked", "{{ test[0].test }}", assigns)
end
def test_hash_to_array_transition
@context['colors'] = {
assigns = { 'colors' => {
'Blue' => ['003366', '336699', '6699CC', '99CCFF'],
'Green' => ['003300', '336633', '669966', '99CC99'],
'Yellow' => ['CC9900', 'FFCC00', 'FFFF99', 'FFFFCC'],
'Red' => ['660000', '993333', 'CC6666', 'FF9999'],
}
} }
assert_equal('003366', @context['colors.Blue[0]'])
assert_equal('FF9999', @context['colors.Red[3]'])
assert_template_result("003366", "{{ colors.Blue[0] }}", assigns)
assert_template_result("FF9999", "{{ colors.Red[3] }}", assigns)
end
def test_try_first
@context['test'] = [1, 2, 3, 4, 5]
assigns = { 'test' => [1, 2, 3, 4, 5] }
assert_template_result("1", "{{ test.first }}", assigns)
assert_template_result("pass", "{% if test.last == 5 %}pass{% endif %}", assigns)
assert_equal(1, @context['test.first'])
assert_equal(5, @context['test.last'])
assigns = { "test" => { "test" => [1, 2, 3, 4, 5] } }
assert_template_result("1", "{{ test.test.first }}", assigns)
assert_template_result("5", "{{ test.test.last }}", assigns)
@context['test'] = { 'test' => [1, 2, 3, 4, 5] }
assert_equal(1, @context['test.test.first'])
assert_equal(5, @context['test.test.last'])
@context['test'] = [1]
assert_equal(1, @context['test.first'])
assert_equal(1, @context['test.last'])
assigns = { "test" => [1] }
assert_template_result("1", "{{ test.first }}", assigns)
assert_template_result("1", "{{ test.last }}", assigns)
end
def test_access_hashes_with_hash_notation
@context['products'] = { 'count' => 5, 'tags' => ['deepsnow', 'freestyle'] }
@context['product'] = { 'variants' => [{ 'title' => 'draft151cm' }, { 'title' => 'element151cm' }] }
assigns = { 'products' => { 'count' => 5, 'tags' => ['deepsnow', 'freestyle'] } }
assert_template_result("5", '{{ products["count"] }}', assigns)
assert_template_result("deepsnow", '{{ products["tags"][0] }}', assigns)
assert_template_result("deepsnow", '{{ products["tags"].first }}', assigns)
assert_equal(5, @context['products["count"]'])
assert_equal('deepsnow', @context['products["tags"][0]'])
assert_equal('deepsnow', @context['products["tags"].first'])
assert_equal('draft151cm', @context['product["variants"][0]["title"]'])
assert_equal('element151cm', @context['product["variants"][1]["title"]'])
assert_equal('draft151cm', @context['product["variants"][0]["title"]'])
assert_equal('element151cm', @context['product["variants"].last["title"]'])
assigns = { 'product' => { 'variants' => [{ 'title' => 'draft151cm' }, { 'title' => 'element151cm' }] } }
assert_template_result("draft151cm", '{{ product["variants"][0]["title"] }}', assigns)
assert_template_result("element151cm", '{{ product["variants"][1]["title"] }}', assigns)
assert_template_result("draft151cm", '{{ product["variants"][0]["title"] }}', assigns)
assert_template_result("element151cm", '{{ product["variants"].last["title"] }}', assigns)
end
def test_access_variable_with_hash_notation
@context['foo'] = 'baz'
@context['bar'] = 'foo'
assert_equal('baz', @context['["foo"]'])
assert_equal('baz', @context['[bar]'])
assert_template_result('baz', '{{ ["foo"] }}', { "foo" => "baz" })
assert_template_result('baz', '{{ [bar] }}', { 'foo' => 'baz', 'bar' => 'foo' })
end
def test_access_hashes_with_hash_access_variables
@context['var'] = 'tags'
@context['nested'] = { 'var' => 'tags' }
@context['products'] = { 'count' => 5, 'tags' => ['deepsnow', 'freestyle'] }
assigns = {
'var' => 'tags',
'nested' => { 'var' => 'tags' },
'products' => { 'count' => 5, 'tags' => ['deepsnow', 'freestyle'] },
}
assert_equal('deepsnow', @context['products[var].first'])
assert_equal('freestyle', @context['products[nested.var].last'])
assert_template_result('deepsnow', '{{ products[var].first }}', assigns)
assert_template_result('freestyle', '{{ products[nested.var].last }}', assigns)
end
def test_hash_notation_only_for_hash_access
@context['array'] = [1, 2, 3, 4, 5]
@context['hash'] = { 'first' => 'Hello' }
assigns = { "array" => [1, 2, 3, 4, 5] }
assert_template_result("1", "{{ array.first }}", assigns)
assert_template_result("pass", '{% if array["first"] == nil %}pass{% endif %}', assigns)
assert_equal(1, @context['array.first'])
assert_nil(@context['array["first"]'])
assert_equal('Hello', @context['hash["first"]'])
assert_template_result("Hello", '{{ hash["first"] }}', { "hash" => { "first" => "Hello" } })
end
def test_first_can_appear_in_middle_of_callchain
@context['product'] = { 'variants' => [{ 'title' => 'draft151cm' }, { 'title' => 'element151cm' }] }
assigns = { "product" => { 'variants' => [{ 'title' => 'draft151cm' }, { 'title' => 'element151cm' }] } }
assert_equal('draft151cm', @context['product.variants[0].title'])
assert_equal('element151cm', @context['product.variants[1].title'])
assert_equal('draft151cm', @context['product.variants.first.title'])
assert_equal('element151cm', @context['product.variants.last.title'])
assert_template_result('draft151cm', '{{ product.variants[0].title }}', assigns)
assert_template_result('element151cm', '{{ product.variants[1].title }}', assigns)
assert_template_result('draft151cm', '{{ product.variants.first.title }}', assigns)
assert_template_result('element151cm', '{{ product.variants.last.title }}', assigns)
end
def test_cents
@@ -351,10 +338,12 @@ class ContextTest < Minitest::Test
end
def test_ranges
@context.merge("test" => '5')
assert_equal((1..5), @context['(1..5)'])
assert_equal((1..5), @context['(1..test)'])
assert_equal((5..5), @context['(test..test)'])
assert_template_result("1..5", '{{ (1..5) }}')
assert_template_result("pass", '{% if (1..5) == expect %}pass{% endif %}', { "expect" => (1..5) })
assigns = { "test" => '5' }
assert_template_result("1..5", "{{ (1..test) }}", assigns)
assert_template_result("5..5", "{{ (test..test) }}", assigns)
end
def test_cents_through_drop_nestedly
+4 -8
View File
@@ -6,16 +6,12 @@ class DocumentTest < Minitest::Test
include Liquid
def test_unexpected_outer_tag
exc = assert_raises(SyntaxError) do
Template.parse("{% else %}")
end
assert_equal(exc.message, "Liquid syntax error: Unexpected outer 'else' tag")
source = "{% else %}"
assert_match_syntax_error("Liquid syntax error (line 1): Unexpected outer 'else' tag", source)
end
def test_unknown_tag
exc = assert_raises(SyntaxError) do
Template.parse("{% foo %}")
end
assert_equal(exc.message, "Liquid syntax error: Unknown tag 'foo'")
source = "{% foo %}"
assert_match_syntax_error("Liquid syntax error (line 1): Unknown tag 'foo'", source)
end
end
+21 -33
View File
@@ -63,9 +63,7 @@ class ErrorHandlingTest < Minitest::Test
end
def test_missing_endtag_parse_time_error
assert_raises(Liquid::SyntaxError) do
Liquid::Template.parse(' {% for a in b %} ... ')
end
assert_match_syntax_error(/: 'for' tag was never closed\z/, ' {% for a in b %} ... ')
end
def test_unrecognized_operator
@@ -84,33 +82,26 @@ class ErrorHandlingTest < Minitest::Test
end
def test_with_line_numbers_adds_numbers_to_parser_errors
err = assert_raises(SyntaxError) do
Liquid::Template.parse('
foobar
source = <<~LIQUID
foobar
{% "cat" | foobar %}
{% "cat" | foobar %}
bla
',
line_numbers: true)
end
assert_match(/Liquid syntax error \(line 4\)/, err.message)
bla
LIQUID
assert_match_syntax_error(/Liquid syntax error \(line 3\)/, source)
end
def test_with_line_numbers_adds_numbers_to_parser_errors_with_whitespace_trim
err = assert_raises(SyntaxError) do
Liquid::Template.parse('
foobar
source = <<~LIQUID
foobar
{%- "cat" | foobar -%}
{%- "cat" | foobar -%}
bla
',
line_numbers: true)
end
bla
LIQUID
assert_match(/Liquid syntax error \(line 4\)/, err.message)
assert_match_syntax_error(/Liquid syntax error \(line 3\)/, source)
end
def test_parsing_warn_with_line_numbers_adds_numbers_to_lexer_errors
@@ -145,20 +136,17 @@ class ErrorHandlingTest < Minitest::Test
end
def test_syntax_errors_in_nested_blocks_have_correct_line_number
err = assert_raises(SyntaxError) do
Liquid::Template.parse('
foobar
source = <<~LIQUID
foobar
{% if 1 != 2 %}
{% foo %}
{% endif %}
{% if 1 != 2 %}
{% foo %}
{% endif %}
bla
',
line_numbers: true)
end
bla
LIQUID
assert_equal("Liquid syntax error (line 5): Unknown tag 'foo'", err.message)
assert_match_syntax_error("Liquid syntax error (line 4): Unknown tag 'foo'", source)
end
def test_strict_error_messages
+25 -22
View File
@@ -4,43 +4,46 @@ require 'test_helper'
class ExpressionTest < Minitest::Test
def test_keyword_literals
assert_equal(true, parse_and_eval("true"))
assert_equal(true, parse_and_eval(" true "))
assert_template_result("true", "{{ true }}")
assert_expression_result(true, "true")
end
def test_string
assert_equal("single quoted", parse_and_eval("'single quoted'"))
assert_equal("double quoted", parse_and_eval('"double quoted"'))
assert_equal("spaced", parse_and_eval(" 'spaced' "))
assert_equal("spaced2", parse_and_eval(' "spaced2" '))
assert_template_result("single quoted", "{{'single quoted'}}")
assert_template_result("double quoted", '{{"double quoted"}}')
assert_template_result("spaced", "{{ 'spaced' }}")
assert_template_result("spaced2", "{{ 'spaced2' }}")
end
def test_int
assert_equal(123, parse_and_eval("123"))
assert_equal(456, parse_and_eval(" 456 "))
assert_equal(12, parse_and_eval("012"))
assert_template_result("456", "{{ 456 }}")
assert_expression_result(123, "123")
assert_expression_result(12, "012")
end
def test_float
assert_equal(1.5, parse_and_eval("1.5"))
assert_equal(2.5, parse_and_eval(" 2.5 "))
assert_template_result("2.5", "{{ 2.5 }}")
assert_expression_result(1.5, "1.5")
end
def test_range
assert_equal(1..2, parse_and_eval("(1..2)"))
assert_equal(3..4, parse_and_eval(" ( 3 .. 4 ) "))
assert_template_result("3..4", "{{ ( 3 .. 4 ) }}")
assert_expression_result(1..2, "(1..2)")
assert_match_syntax_error(
"Liquid syntax error (line 1): Invalid expression type 'false' in range expression",
"{{ (false..true) }}"
)
assert_match_syntax_error(
"Liquid syntax error (line 1): Invalid expression type '(1..2)' in range expression",
"{{ ((1..2)..3) }}"
)
end
private
def parse_and_eval(markup, **assigns)
if Liquid::Template.error_mode == :strict
p = Liquid::Parser.new(markup)
markup = p.expression
p.consume(:end_of_string)
end
expression = Liquid::Expression.parse(markup)
context = Liquid::Context.new(assigns)
context.evaluate(expression)
def assert_expression_result(expect, markup, **assigns)
liquid = "{% if expect == #{markup} %}pass{% else %}got {{ #{markup} }}{% endif %}"
assert_template_result("pass", liquid, { "expect" => expect, **assigns })
end
end
+24 -42
View File
@@ -59,84 +59,66 @@ class FiltersTest < Minitest::Test
end
def test_size
@context['var'] = 'abcd'
@context.add_filters(MoneyFilter)
assert_equal('4', Template.parse("{{var | size}}").render(@context))
assert_template_result("4", "{{var | size}}", { "var" => 'abcd' })
end
def test_join
@context['var'] = [1, 2, 3, 4]
assert_equal("1 2 3 4", Template.parse("{{var | join}}").render(@context))
assert_template_result("1 2 3 4", "{{var | join}}", { "var" => [1, 2, 3, 4] })
end
def test_sort
@context['value'] = 3
@context['numbers'] = [2, 1, 4, 3]
@context['words'] = ['expected', 'as', 'alphabetic']
@context['arrays'] = ['flower', 'are']
@context['case_sensitive'] = ['sensitive', 'Expected', 'case']
assert_equal('1 2 3 4', Template.parse("{{numbers | sort | join}}").render(@context))
assert_equal('alphabetic as expected', Template.parse("{{words | sort | join}}").render(@context))
assert_equal('3', Template.parse("{{value | sort}}").render(@context))
assert_equal('are flower', Template.parse("{{arrays | sort | join}}").render(@context))
assert_equal('Expected case sensitive', Template.parse("{{case_sensitive | sort | join}}").render(@context))
assert_template_result("1 2 3 4", "{{numbers | sort | join}}", { "numbers" => [2, 1, 4, 3] })
assert_template_result("alphabetic as expected", "{{words | sort | join}}",
{ "words" => ['expected', 'as', 'alphabetic'] })
assert_template_result("3", "{{value | sort}}", { "value" => 3 })
assert_template_result('are flower', "{{arrays | sort | join}}", { 'arrays' => ['flower', 'are'] })
assert_template_result("Expected case sensitive", "{{case_sensitive | sort | join}}",
{ "case_sensitive" => ["sensitive", "Expected", "case"] })
end
def test_sort_natural
@context['words'] = ['case', 'Assert', 'Insensitive']
@context['hashes'] = [{ 'a' => 'A' }, { 'a' => 'b' }, { 'a' => 'C' }]
@context['objects'] = [TestObject.new('A'), TestObject.new('b'), TestObject.new('C')]
# Test strings
assert_equal('Assert case Insensitive', Template.parse("{{words | sort_natural | join}}").render(@context))
assert_template_result("Assert case Insensitive", "{{words | sort_natural | join}}",
{ "words" => ["case", "Assert", "Insensitive"] })
# Test hashes
assert_equal('A b C', Template.parse("{{hashes | sort_natural: 'a' | map: 'a' | join}}").render(@context))
assert_template_result("A b C", "{{hashes | sort_natural: 'a' | map: 'a' | join}}",
{ "hashes" => [{ "a" => "A" }, { "a" => "b" }, { "a" => "C" }] })
# Test objects
@context['objects'] = [TestObject.new('A'), TestObject.new('b'), TestObject.new('C')]
assert_equal('A b C', Template.parse("{{objects | sort_natural: 'a' | map: 'a' | join}}").render(@context))
end
def test_compact
@context['words'] = ['a', nil, 'b', nil, 'c']
@context['hashes'] = [{ 'a' => 'A' }, { 'a' => nil }, { 'a' => 'C' }]
@context['objects'] = [TestObject.new('A'), TestObject.new(nil), TestObject.new('C')]
# Test strings
assert_equal('a b c', Template.parse("{{words | compact | join}}").render(@context))
assert_template_result("a b c", "{{words | compact | join}}",
{ "words" => ['a', nil, 'b', nil, 'c'] })
# Test hashes
assert_equal('A C', Template.parse("{{hashes | compact: 'a' | map: 'a' | join}}").render(@context))
assert_template_result("A C", "{{hashes | compact: 'a' | map: 'a' | join}}",
{ "hashes" => [{ "a" => "A" }, { "a" => nil }, { "a" => "C" }] })
# Test objects
@context['objects'] = [TestObject.new('A'), TestObject.new(nil), TestObject.new('C')]
assert_equal('A C', Template.parse("{{objects | compact: 'a' | map: 'a' | join}}").render(@context))
end
def test_strip_html
@context['var'] = "<b>bla blub</a>"
assert_equal("bla blub", Template.parse("{{ var | strip_html }}").render(@context))
assert_template_result("bla blub", "{{ var | strip_html }}", { "var" => "<b>bla blub</a>" })
end
def test_strip_html_ignore_comments_with_html
@context['var'] = "<!-- split and some <ul> tag --><b>bla blub</a>"
assert_equal("bla blub", Template.parse("{{ var | strip_html }}").render(@context))
assert_template_result("bla blub", "{{ var | strip_html }}",
{ "var" => "<!-- split and some <ul> tag --><b>bla blub</a>" })
end
def test_capitalize
@context['var'] = "blub"
assert_equal("Blub", Template.parse("{{ var | capitalize }}").render(@context))
assert_template_result("Blub", "{{ var | capitalize }}", { "var" => "blub" })
end
def test_nonexistent_filter_is_ignored
@context['var'] = 1000
assert_equal('1000', Template.parse("{{ var | xyzzy }}").render(@context))
assert_template_result("1000", "{{ var | xyzzy }}", { "var" => 1000 })
end
def test_filter_with_keyword_arguments
+9 -14
View File
@@ -33,31 +33,25 @@ class OutputTest < Minitest::Test
def setup
@assigns = {
'best_cars' => 'bmw',
'car' => { 'bmw' => 'good', 'gm' => 'bad' },
}
end
def test_variable
text = %( {{best_cars}} )
expected = %( bmw )
assert_equal(expected, Template.parse(text).render!(@assigns))
assert_template_result(" bmw ", " {{best_cars}} ", { "best_cars" => "bmw" })
end
def test_variable_traversing_with_two_brackets
text = %({{ site.data.menu[include.menu][include.locale] }})
assert_equal("it works!", Template.parse(text).render!(
source = "{{ site.data.menu[include.menu][include.locale] }}"
assert_template_result("it works!", source, {
"site" => { "data" => { "menu" => { "foo" => { "bar" => "it works!" } } } },
"include" => { "menu" => "foo", "locale" => "bar" }
))
"include" => { "menu" => "foo", "locale" => "bar" },
})
end
def test_variable_traversing
text = %( {{car.bmw}} {{car.gm}} {{car.bmw}} )
expected = %( good bad good )
assert_equal(expected, Template.parse(text).render!(@assigns))
source = " {{car.bmw}} {{car.gm}} {{car.bmw}} "
assert_template_result(" good bad good ", source, @assigns)
end
def test_variable_piping
@@ -110,10 +104,11 @@ class OutputTest < Minitest::Test
end
def test_multiple_pipings
assigns = { 'best_cars' => 'bmw' }
text = %( {{ best_cars | cite_funny | paragraph }} )
expected = %( <p>LOL: bmw</p> )
assert_equal(expected, Template.parse(text).render!(@assigns, filters: [FunnyFilter]))
assert_equal(expected, Template.parse(text).render!(assigns, filters: [FunnyFilter]))
end
def test_link_to
+1 -1
View File
@@ -129,6 +129,6 @@ class ParsingQuirksTest < Minitest::Test
end
def test_contains_in_id
assert_template_result(' YES ', '{% if containsallshipments == true %} YES {% endif %}', 'containsallshipments' => true)
assert_template_result(' YES ', '{% if containsallshipments == true %} YES {% endif %}', { 'containsallshipments' => true })
end
end # ParsingQuirksTest
+45 -45
View File
@@ -426,7 +426,7 @@ class StandardFiltersTest < Minitest::Test
def test_map
assert_equal([1, 2, 3, 4], @filters.map([{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }], 'a'))
assert_template_result('abc', "{{ ary | map:'foo' | map:'bar' }}",
'ary' => [{ 'foo' => { 'bar' => 'a' } }, { 'foo' => { 'bar' => 'b' } }, { 'foo' => { 'bar' => 'c' } }])
{ 'ary' => [{ 'foo' => { 'bar' => 'a' } }, { 'foo' => { 'bar' => 'b' } }, { 'foo' => { 'bar' => 'c' } }] })
end
def test_map_doesnt_call_arbitrary_stuff
@@ -436,7 +436,7 @@ class StandardFiltersTest < Minitest::Test
def test_map_calls_to_liquid
t = TestThing.new
assert_template_result("woot: 1", '{{ foo | map: "whatever" }}', "foo" => [t])
assert_template_result("woot: 1", '{{ foo | map: "whatever" }}', { "foo" => [t] })
end
def test_map_calls_context=
@@ -451,13 +451,13 @@ class StandardFiltersTest < Minitest::Test
def test_map_on_hashes
assert_template_result("4217", '{{ thing | map: "foo" | map: "bar" }}',
"thing" => { "foo" => [{ "bar" => 42 }, { "bar" => 17 }] })
{ "thing" => { "foo" => [{ "bar" => 42 }, { "bar" => 17 }] } })
end
def test_legacy_map_on_hashes_with_dynamic_key
template = "{% assign key = 'foo' %}{{ thing | map: key | map: 'bar' }}"
hash = { "foo" => { "bar" => 42 } }
assert_template_result("42", template, "thing" => hash)
assert_template_result("42", template, { "thing" => hash })
end
def test_sort_calls_to_liquid
@@ -470,7 +470,7 @@ class StandardFiltersTest < Minitest::Test
drop = TestDrop.new(value: "testfoo")
p = proc { drop }
templ = '{{ procs | map: "value" }}'
assert_template_result("testfoo", templ, "procs" => [p])
assert_template_result("testfoo", templ, { "procs" => [p] })
end
def test_map_over_drops_returning_procs
@@ -483,11 +483,11 @@ class StandardFiltersTest < Minitest::Test
},
]
templ = '{{ drops | map: "proc" }}'
assert_template_result("foobar", templ, "drops" => drops)
assert_template_result("foobar", templ, { "drops" => drops })
end
def test_map_works_on_enumerables
assert_template_result("123", '{{ foo | map: "foo" }}', "foo" => TestEnumerable.new)
assert_template_result("123", '{{ foo | map: "foo" }}', { "foo" => TestEnumerable.new })
end
def test_map_returns_empty_on_2d_input_array
@@ -514,16 +514,16 @@ class StandardFiltersTest < Minitest::Test
end
def test_sort_works_on_enumerables
assert_template_result("213", '{{ foo | sort: "bar" | map: "foo" }}', "foo" => TestEnumerable.new)
assert_template_result("213", '{{ foo | sort: "bar" | map: "foo" }}', { "foo" => TestEnumerable.new })
end
def test_first_and_last_call_to_liquid
assert_template_result('foobar', '{{ foo | first }}', 'foo' => [ThingWithToLiquid.new])
assert_template_result('foobar', '{{ foo | last }}', 'foo' => [ThingWithToLiquid.new])
assert_template_result('foobar', '{{ foo | first }}', { 'foo' => [ThingWithToLiquid.new] })
assert_template_result('foobar', '{{ foo | last }}', { 'foo' => [ThingWithToLiquid.new] })
end
def test_truncate_calls_to_liquid
assert_template_result("wo...", '{{ foo | truncate: 5 }}', "foo" => TestThing.new)
assert_template_result("wo...", '{{ foo | truncate: 5 }}', { "foo" => TestThing.new })
end
def test_date
@@ -597,42 +597,42 @@ class StandardFiltersTest < Minitest::Test
end
def test_strip
assert_template_result('ab c', "{{ source | strip }}", 'source' => " ab c ")
assert_template_result('ab c', "{{ source | strip }}", 'source' => " \tab c \n \t")
assert_template_result('ab c', "{{ source | strip }}", { 'source' => " ab c " })
assert_template_result('ab c', "{{ source | strip }}", { 'source' => " \tab c \n \t" })
end
def test_lstrip
assert_template_result('ab c ', "{{ source | lstrip }}", 'source' => " ab c ")
assert_template_result("ab c \n \t", "{{ source | lstrip }}", 'source' => " \tab c \n \t")
assert_template_result('ab c ', "{{ source | lstrip }}", { 'source' => " ab c " })
assert_template_result("ab c \n \t", "{{ source | lstrip }}", { 'source' => " \tab c \n \t" })
end
def test_rstrip
assert_template_result(" ab c", "{{ source | rstrip }}", 'source' => " ab c ")
assert_template_result(" \tab c", "{{ source | rstrip }}", 'source' => " \tab c \n \t")
assert_template_result(" ab c", "{{ source | rstrip }}", { 'source' => " ab c " })
assert_template_result(" \tab c", "{{ source | rstrip }}", { 'source' => " \tab c \n \t" })
end
def test_strip_newlines
assert_template_result('abc', "{{ source | strip_newlines }}", 'source' => "a\nb\nc")
assert_template_result('abc', "{{ source | strip_newlines }}", 'source' => "a\r\nb\nc")
assert_template_result('abc', "{{ source | strip_newlines }}", { 'source' => "a\nb\nc" })
assert_template_result('abc', "{{ source | strip_newlines }}", { 'source' => "a\r\nb\nc" })
end
def test_newlines_to_br
assert_template_result("a<br />\nb<br />\nc", "{{ source | newline_to_br }}", 'source' => "a\nb\nc")
assert_template_result("a<br />\nb<br />\nc", "{{ source | newline_to_br }}", 'source' => "a\r\nb\nc")
assert_template_result("a<br />\nb<br />\nc", "{{ source | newline_to_br }}", { 'source' => "a\nb\nc" })
assert_template_result("a<br />\nb<br />\nc", "{{ source | newline_to_br }}", { 'source' => "a\r\nb\nc" })
end
def test_plus
assert_template_result("2", "{{ 1 | plus:1 }}")
assert_template_result("2.0", "{{ '1' | plus:'1.0' }}")
assert_template_result("5", "{{ price | plus:'2' }}", 'price' => NumberLikeThing.new(3))
assert_template_result("5", "{{ price | plus:'2' }}", { 'price' => NumberLikeThing.new(3) })
end
def test_minus
assert_template_result("4", "{{ input | minus:operand }}", 'input' => 5, 'operand' => 1)
assert_template_result("4", "{{ input | minus:operand }}", { 'input' => 5, 'operand' => 1 })
assert_template_result("2.3", "{{ '4.3' | minus:'2' }}")
assert_template_result("5", "{{ price | minus:'2' }}", 'price' => NumberLikeThing.new(7))
assert_template_result("5", "{{ price | minus:'2' }}", { 'price' => NumberLikeThing.new(7) })
end
def test_abs
@@ -655,7 +655,7 @@ class StandardFiltersTest < Minitest::Test
assert_template_result("7.25", "{{ 0.0725 | times:100 }}")
assert_template_result("-7.25", '{{ "-0.0725" | times:100 }}')
assert_template_result("7.25", '{{ "-0.0725" | times: -100 }}')
assert_template_result("4", "{{ price | times:2 }}", 'price' => NumberLikeThing.new(2))
assert_template_result("4", "{{ price | times:2 }}", { 'price' => NumberLikeThing.new(2) })
end
def test_divided_by
@@ -670,7 +670,7 @@ class StandardFiltersTest < Minitest::Test
assert_template_result("4", "{{ 1 | modulo: 0 }}")
end
assert_template_result("5", "{{ price | divided_by:2 }}", 'price' => NumberLikeThing.new(10))
assert_template_result("5", "{{ price | divided_by:2 }}", { 'price' => NumberLikeThing.new(10) })
end
def test_modulo
@@ -679,39 +679,39 @@ class StandardFiltersTest < Minitest::Test
assert_template_result("4", "{{ 1 | modulo: 0 }}")
end
assert_template_result("1", "{{ price | modulo:2 }}", 'price' => NumberLikeThing.new(3))
assert_template_result("1", "{{ price | modulo:2 }}", { 'price' => NumberLikeThing.new(3) })
end
def test_round
assert_template_result("5", "{{ input | round }}", 'input' => 4.6)
assert_template_result("5", "{{ input | round }}", { 'input' => 4.6 })
assert_template_result("4", "{{ '4.3' | round }}")
assert_template_result("4.56", "{{ input | round: 2 }}", 'input' => 4.5612)
assert_template_result("4.56", "{{ input | round: 2 }}", { 'input' => 4.5612 })
assert_raises(Liquid::FloatDomainError) do
assert_template_result("4", "{{ 1.0 | divided_by: 0.0 | round }}")
end
assert_template_result("5", "{{ price | round }}", 'price' => NumberLikeThing.new(4.6))
assert_template_result("4", "{{ price | round }}", 'price' => NumberLikeThing.new(4.3))
assert_template_result("5", "{{ price | round }}", { 'price' => NumberLikeThing.new(4.6) })
assert_template_result("4", "{{ price | round }}", { 'price' => NumberLikeThing.new(4.3) })
end
def test_ceil
assert_template_result("5", "{{ input | ceil }}", 'input' => 4.6)
assert_template_result("5", "{{ input | ceil }}", { 'input' => 4.6 })
assert_template_result("5", "{{ '4.3' | ceil }}")
assert_raises(Liquid::FloatDomainError) do
assert_template_result("4", "{{ 1.0 | divided_by: 0.0 | ceil }}")
end
assert_template_result("5", "{{ price | ceil }}", 'price' => NumberLikeThing.new(4.6))
assert_template_result("5", "{{ price | ceil }}", { 'price' => NumberLikeThing.new(4.6) })
end
def test_floor
assert_template_result("4", "{{ input | floor }}", 'input' => 4.6)
assert_template_result("4", "{{ input | floor }}", { 'input' => 4.6 })
assert_template_result("4", "{{ '4.3' | floor }}")
assert_raises(Liquid::FloatDomainError) do
assert_template_result("4", "{{ 1.0 | divided_by: 0.0 | floor }}")
end
assert_template_result("5", "{{ price | floor }}", 'price' => NumberLikeThing.new(5.4))
assert_template_result("5", "{{ price | floor }}", { 'price' => NumberLikeThing.new(5.4) })
end
def test_at_most
@@ -720,9 +720,9 @@ class StandardFiltersTest < Minitest::Test
assert_template_result("5", "{{ 5 | at_most:6 }}")
assert_template_result("4.5", "{{ 4.5 | at_most:5 }}")
assert_template_result("5", "{{ width | at_most:5 }}", 'width' => NumberLikeThing.new(6))
assert_template_result("4", "{{ width | at_most:5 }}", 'width' => NumberLikeThing.new(4))
assert_template_result("4", "{{ 5 | at_most: width }}", 'width' => NumberLikeThing.new(4))
assert_template_result("5", "{{ width | at_most:5 }}", { 'width' => NumberLikeThing.new(6) })
assert_template_result("4", "{{ width | at_most:5 }}", { 'width' => NumberLikeThing.new(4) })
assert_template_result("4", "{{ 5 | at_most: width }}", { 'width' => NumberLikeThing.new(4) })
end
def test_at_least
@@ -731,9 +731,9 @@ class StandardFiltersTest < Minitest::Test
assert_template_result("6", "{{ 5 | at_least:6 }}")
assert_template_result("5", "{{ 4.5 | at_least:5 }}")
assert_template_result("6", "{{ width | at_least:5 }}", 'width' => NumberLikeThing.new(6))
assert_template_result("5", "{{ width | at_least:5 }}", 'width' => NumberLikeThing.new(4))
assert_template_result("6", "{{ 5 | at_least: width }}", 'width' => NumberLikeThing.new(6))
assert_template_result("6", "{{ width | at_least:5 }}", { 'width' => NumberLikeThing.new(6) })
assert_template_result("5", "{{ width | at_least:5 }}", { 'width' => NumberLikeThing.new(4) })
assert_template_result("6", "{{ 5 | at_least: width }}", { 'width' => NumberLikeThing.new(6) })
end
def test_append
@@ -766,8 +766,8 @@ class StandardFiltersTest < Minitest::Test
assert_equal("bar", @filters.default([], "bar"))
assert_equal("bar", @filters.default({}, "bar"))
assert_template_result('bar', "{{ false | default: 'bar' }}")
assert_template_result('bar', "{{ drop | default: 'bar' }}", 'drop' => BooleanDrop.new(false))
assert_template_result('Yay', "{{ drop | default: 'bar' }}", 'drop' => BooleanDrop.new(true))
assert_template_result('bar', "{{ drop | default: 'bar' }}", { 'drop' => BooleanDrop.new(false) })
assert_template_result('Yay', "{{ drop | default: 'bar' }}", { 'drop' => BooleanDrop.new(true) })
end
def test_default_handle_false
@@ -778,8 +778,8 @@ class StandardFiltersTest < Minitest::Test
assert_equal("bar", @filters.default([], "bar", "allow_false" => true))
assert_equal("bar", @filters.default({}, "bar", "allow_false" => true))
assert_template_result('false', "{{ false | default: 'bar', allow_false: true }}")
assert_template_result('Nay', "{{ drop | default: 'bar', allow_false: true }}", 'drop' => BooleanDrop.new(false))
assert_template_result('Yay', "{{ drop | default: 'bar', allow_false: true }}", 'drop' => BooleanDrop.new(true))
assert_template_result('Nay', "{{ drop | default: 'bar', allow_false: true }}", { 'drop' => BooleanDrop.new(false) })
assert_template_result('Yay', "{{ drop | default: 'bar', allow_false: true }}", { 'drop' => BooleanDrop.new(true) })
end
def test_cannot_access_private_methods
+1 -1
View File
@@ -6,7 +6,7 @@ class EchoTest < Minitest::Test
include Liquid
def test_echo_outputs_its_input
assert_template_result('BAR', <<~LIQUID, 'variable-name' => 'bar')
assert_template_result('BAR', <<~LIQUID, { 'variable-name' => 'bar' })
{%- echo variable-name | upcase -%}
LIQUID
end
+24 -24
View File
@@ -12,10 +12,10 @@ class ForTagTest < Minitest::Test
include Liquid
def test_for
assert_template_result(' yo yo yo yo ', '{%for item in array%} yo {%endfor%}', 'array' => [1, 2, 3, 4])
assert_template_result('yoyo', '{%for item in array%}yo{%endfor%}', 'array' => [1, 2])
assert_template_result(' yo ', '{%for item in array%} yo {%endfor%}', 'array' => [1])
assert_template_result('', '{%for item in array%}{%endfor%}', 'array' => [1, 2])
assert_template_result(' yo yo yo yo ', '{%for item in array%} yo {%endfor%}', { 'array' => [1, 2, 3, 4] })
assert_template_result('yoyo', '{%for item in array%}yo{%endfor%}', { 'array' => [1, 2] })
assert_template_result(' yo ', '{%for item in array%} yo {%endfor%}', { 'array' => [1] })
assert_template_result('', '{%for item in array%}{%endfor%}', { 'array' => [1, 2] })
expected = <<HERE
yo
@@ -30,7 +30,7 @@ HERE
yo
{%endfor%}
HERE
assert_template_result(expected, template, 'array' => [1, 2, 3])
assert_template_result(expected, template, { 'array' => [1, 2, 3] })
end
def test_for_reversed
@@ -45,30 +45,30 @@ HERE
Template.parse('{% for i in (a..2) %}{% endfor %}').render!("a" => [1, 2])
end
assert_template_result(' 0 1 2 3 ', '{% for item in (a..3) %} {{item}} {% endfor %}', "a" => "invalid integer")
assert_template_result(' 0 1 2 3 ', '{% for item in (a..3) %} {{item}} {% endfor %}', { "a" => "invalid integer" })
end
def test_for_with_variable_range
assert_template_result(' 1 2 3 ', '{%for item in (1..foobar) %} {{item}} {%endfor%}', "foobar" => 3)
assert_template_result(' 1 2 3 ', '{%for item in (1..foobar) %} {{item}} {%endfor%}', { "foobar" => 3 })
end
def test_for_with_hash_value_range
foobar = { "value" => 3 }
assert_template_result(' 1 2 3 ', '{%for item in (1..foobar.value) %} {{item}} {%endfor%}', "foobar" => foobar)
assert_template_result(' 1 2 3 ', '{%for item in (1..foobar.value) %} {{item}} {%endfor%}', { "foobar" => foobar })
end
def test_for_with_drop_value_range
foobar = ThingWithValue.new
assert_template_result(' 1 2 3 ', '{%for item in (1..foobar.value) %} {{item}} {%endfor%}', "foobar" => foobar)
assert_template_result(' 1 2 3 ', '{%for item in (1..foobar.value) %} {{item}} {%endfor%}', { "foobar" => foobar })
end
def test_for_with_variable
assert_template_result(' 1 2 3 ', '{%for item in array%} {{item}} {%endfor%}', 'array' => [1, 2, 3])
assert_template_result('123', '{%for item in array%}{{item}}{%endfor%}', 'array' => [1, 2, 3])
assert_template_result('123', '{% for item in array %}{{item}}{% endfor %}', 'array' => [1, 2, 3])
assert_template_result('abcd', '{%for item in array%}{{item}}{%endfor%}', 'array' => ['a', 'b', 'c', 'd'])
assert_template_result('a b c', '{%for item in array%}{{item}}{%endfor%}', 'array' => ['a', ' ', 'b', ' ', 'c'])
assert_template_result('abc', '{%for item in array%}{{item}}{%endfor%}', 'array' => ['a', '', 'b', '', 'c'])
assert_template_result(' 1 2 3 ', '{%for item in array%} {{item}} {%endfor%}', { 'array' => [1, 2, 3] })
assert_template_result('123', '{%for item in array%}{{item}}{%endfor%}', { 'array' => [1, 2, 3] })
assert_template_result('123', '{% for item in array %}{{item}}{% endfor %}', { 'array' => [1, 2, 3] })
assert_template_result('abcd', '{%for item in array%}{{item}}{%endfor%}', { 'array' => ['a', 'b', 'c', 'd'] })
assert_template_result('a b c', '{%for item in array%}{{item}}{%endfor%}', { 'array' => ['a', ' ', 'b', ' ', 'c'] })
assert_template_result('abc', '{%for item in array%}{{item}}{%endfor%}', { 'array' => ['a', '', 'b', '', 'c'] })
end
def test_for_helpers
@@ -92,9 +92,9 @@ HERE
end
def test_for_else
assert_template_result('+++', '{%for item in array%}+{%else%}-{%endfor%}', 'array' => [1, 2, 3])
assert_template_result('-', '{%for item in array%}+{%else%}-{%endfor%}', 'array' => [])
assert_template_result('-', '{%for item in array%}+{%else%}-{%endfor%}', 'array' => nil)
assert_template_result('+++', '{%for item in array%}+{%else%}-{%endfor%}', { 'array' => [1, 2, 3] })
assert_template_result('-', '{%for item in array%}+{%else%}-{%endfor%}', { 'array' => [] })
assert_template_result('-', '{%for item in array%}+{%else%}-{%endfor%}', { 'array' => nil })
end
def test_limiting
@@ -313,11 +313,11 @@ HERE
assert_template_result('test string',
'{%for val in string%}{{val}}{%endfor%}',
'string' => "test string")
{ 'string' => "test string" })
assert_template_result('test string',
'{%for val in string limit:1%}{{val}}{%endfor%}',
'string' => "test string")
{ 'string' => "test string" })
assert_template_result('val-string-1-1-0-1-0-true-true-test string',
'{%for val in string%}' \
@@ -330,7 +330,7 @@ HERE
'{{forloop.first}}-' \
'{{forloop.last}}-' \
'{{val}}{%endfor%}',
'string' => "test string")
{ 'string' => "test string" })
end
def test_for_parentloop_references_parent_loop
@@ -338,7 +338,7 @@ HERE
'{% for inner in outer %}{% for k in inner %}' \
'{{ forloop.parentloop.index }}.{{ forloop.index }} ' \
'{% endfor %}{% endfor %}',
'outer' => [[1, 1, 1], [1, 1, 1]])
{ 'outer' => [[1, 1, 1], [1, 1, 1]] })
end
def test_for_parentloop_nil_when_not_present
@@ -346,7 +346,7 @@ HERE
'{% for inner in outer %}' \
'{{ forloop.parentloop.index }}.{{ forloop.index }} ' \
'{% endfor %}',
'outer' => [[1, 1, 1], [1, 1, 1]])
{ 'outer' => [[1, 1, 1], [1, 1, 1]] })
end
def test_inner_for_over_empty_input
@@ -354,7 +354,7 @@ HERE
end
def test_blank_string_not_iterable
assert_template_result('', "{% for char in characters %}I WILL NOT BE OUTPUT{% endfor %}", 'characters' => '')
assert_template_result('', "{% for char in characters %}I WILL NOT BE OUTPUT{% endfor %}", { 'characters' => '' })
end
def test_bad_variable_naming_in_for_loop
+38 -38
View File
@@ -24,23 +24,23 @@ class IfElseTagTest < Minitest::Test
end
def test_if_boolean
assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => true)
assert_template_result(' YES ', '{% if var %} YES {% endif %}', { 'var' => true })
end
def test_if_or
assert_template_result(' YES ', '{% if a or b %} YES {% endif %}', 'a' => true, 'b' => true)
assert_template_result(' YES ', '{% if a or b %} YES {% endif %}', 'a' => true, 'b' => false)
assert_template_result(' YES ', '{% if a or b %} YES {% endif %}', 'a' => false, 'b' => true)
assert_template_result('', '{% if a or b %} YES {% endif %}', 'a' => false, 'b' => false)
assert_template_result(' YES ', '{% if a or b %} YES {% endif %}', { 'a' => true, 'b' => true })
assert_template_result(' YES ', '{% if a or b %} YES {% endif %}', { 'a' => true, 'b' => false })
assert_template_result(' YES ', '{% if a or b %} YES {% endif %}', { 'a' => false, 'b' => true })
assert_template_result('', '{% if a or b %} YES {% endif %}', { 'a' => false, 'b' => false })
assert_template_result(' YES ', '{% if a or b or c %} YES {% endif %}', 'a' => false, 'b' => false, 'c' => true)
assert_template_result('', '{% if a or b or c %} YES {% endif %}', 'a' => false, 'b' => false, 'c' => false)
assert_template_result(' YES ', '{% if a or b or c %} YES {% endif %}', { 'a' => false, 'b' => false, 'c' => true })
assert_template_result('', '{% if a or b or c %} YES {% endif %}', { 'a' => false, 'b' => false, 'c' => false })
end
def test_if_or_with_operators
assert_template_result(' YES ', '{% if a == true or b == true %} YES {% endif %}', 'a' => true, 'b' => true)
assert_template_result(' YES ', '{% if a == true or b == false %} YES {% endif %}', 'a' => true, 'b' => true)
assert_template_result('', '{% if a == false or b == false %} YES {% endif %}', 'a' => true, 'b' => true)
assert_template_result(' YES ', '{% if a == true or b == true %} YES {% endif %}', { 'a' => true, 'b' => true })
assert_template_result(' YES ', '{% if a == true or b == false %} YES {% endif %}', { 'a' => true, 'b' => true })
assert_template_result('', '{% if a == false or b == false %} YES {% endif %}', { 'a' => true, 'b' => true })
end
def test_comparison_of_strings_containing_and_or_or
@@ -66,40 +66,40 @@ class IfElseTagTest < Minitest::Test
end
def test_hash_miss_generates_false
assert_template_result('', '{% if foo.bar %} NO {% endif %}', 'foo' => {})
assert_template_result('', '{% if foo.bar %} NO {% endif %}', { 'foo' => {} })
end
def test_if_from_variable
assert_template_result('', '{% if var %} NO {% endif %}', 'var' => false)
assert_template_result('', '{% if var %} NO {% endif %}', 'var' => nil)
assert_template_result('', '{% if foo.bar %} NO {% endif %}', 'foo' => { 'bar' => false })
assert_template_result('', '{% if foo.bar %} NO {% endif %}', 'foo' => {})
assert_template_result('', '{% if foo.bar %} NO {% endif %}', 'foo' => nil)
assert_template_result('', '{% if foo.bar %} NO {% endif %}', 'foo' => true)
assert_template_result('', '{% if var %} NO {% endif %}', { 'var' => false })
assert_template_result('', '{% if var %} NO {% endif %}', { 'var' => nil })
assert_template_result('', '{% if foo.bar %} NO {% endif %}', { 'foo' => { 'bar' => false } })
assert_template_result('', '{% if foo.bar %} NO {% endif %}', { 'foo' => {} })
assert_template_result('', '{% if foo.bar %} NO {% endif %}', { 'foo' => nil })
assert_template_result('', '{% if foo.bar %} NO {% endif %}', { 'foo' => true })
assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => "text")
assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => true)
assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => 1)
assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => {})
assert_template_result(' YES ', '{% if var %} YES {% endif %}', 'var' => [])
assert_template_result(' YES ', '{% if var %} YES {% endif %}', { 'var' => "text" })
assert_template_result(' YES ', '{% if var %} YES {% endif %}', { 'var' => true })
assert_template_result(' YES ', '{% if var %} YES {% endif %}', { 'var' => 1 })
assert_template_result(' YES ', '{% if var %} YES {% endif %}', { 'var' => {} })
assert_template_result(' YES ', '{% if var %} YES {% endif %}', { 'var' => [] })
assert_template_result(' YES ', '{% if "foo" %} YES {% endif %}')
assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', 'foo' => { 'bar' => true })
assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', 'foo' => { 'bar' => "text" })
assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', 'foo' => { 'bar' => 1 })
assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', 'foo' => { 'bar' => {} })
assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', 'foo' => { 'bar' => [] })
assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', { 'foo' => { 'bar' => true } })
assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', { 'foo' => { 'bar' => "text" } })
assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', { 'foo' => { 'bar' => 1 } })
assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', { 'foo' => { 'bar' => {} } })
assert_template_result(' YES ', '{% if foo.bar %} YES {% endif %}', { 'foo' => { 'bar' => [] } })
assert_template_result(' YES ', '{% if var %} NO {% else %} YES {% endif %}', 'var' => false)
assert_template_result(' YES ', '{% if var %} NO {% else %} YES {% endif %}', 'var' => nil)
assert_template_result(' YES ', '{% if var %} YES {% else %} NO {% endif %}', 'var' => true)
assert_template_result(' YES ', '{% if "foo" %} YES {% else %} NO {% endif %}', 'var' => "text")
assert_template_result(' YES ', '{% if var %} NO {% else %} YES {% endif %}', { 'var' => false })
assert_template_result(' YES ', '{% if var %} NO {% else %} YES {% endif %}', { 'var' => nil })
assert_template_result(' YES ', '{% if var %} YES {% else %} NO {% endif %}', { 'var' => true })
assert_template_result(' YES ', '{% if "foo" %} YES {% else %} NO {% endif %}', { 'var' => "text" })
assert_template_result(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', 'foo' => { 'bar' => false })
assert_template_result(' YES ', '{% if foo.bar %} YES {% else %} NO {% endif %}', 'foo' => { 'bar' => true })
assert_template_result(' YES ', '{% if foo.bar %} YES {% else %} NO {% endif %}', 'foo' => { 'bar' => "text" })
assert_template_result(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', 'foo' => { 'notbar' => true })
assert_template_result(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', 'foo' => {})
assert_template_result(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', 'notfoo' => { 'bar' => true })
assert_template_result(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', { 'foo' => { 'bar' => false } })
assert_template_result(' YES ', '{% if foo.bar %} YES {% else %} NO {% endif %}', { 'foo' => { 'bar' => true } })
assert_template_result(' YES ', '{% if foo.bar %} YES {% else %} NO {% endif %}', { 'foo' => { 'bar' => "text" } })
assert_template_result(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', { 'foo' => { 'notbar' => true } })
assert_template_result(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', { 'foo' => {} })
assert_template_result(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', { 'notfoo' => { 'bar' => true } })
end
def test_nested_if
@@ -184,7 +184,7 @@ class IfElseTagTest < Minitest::Test
tests.each do |vals, expected|
a, b, c = vals
assigns = { 'a' => a, 'b' => b, 'c' => c }
assert_template_result(expected.to_s, tpl, assigns, assigns.to_s)
assert_template_result(expected.to_s, tpl, assigns, message: assigns.to_s)
end
end
end
+19 -13
View File
@@ -91,27 +91,31 @@ class IncludeTagTest < Minitest::Test
def test_include_tag_with
assert_template_result("Product: Draft 151cm ",
"{% include 'product' with products[0] %}", "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }])
"{% include 'product' with products[0] %}",
{ "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }] })
end
def test_include_tag_with_alias
assert_template_result("Product: Draft 151cm ",
"{% include 'product_alias' with products[0] as product %}", "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }])
"{% include 'product_alias' with products[0] as product %}",
{ "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }] })
end
def test_include_tag_for_alias
assert_template_result("Product: Draft 151cm Product: Element 155cm ",
"{% include 'product_alias' for products as product %}", "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }])
"{% include 'product_alias' for products as product %}",
{ "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }] })
end
def test_include_tag_with_default_name
assert_template_result("Product: Draft 151cm ",
"{% include 'product' %}", "product" => { 'title' => 'Draft 151cm' })
"{% include 'product' %}", { "product" => { 'title' => 'Draft 151cm' } })
end
def test_include_tag_for
assert_template_result("Product: Draft 151cm Product: Element 155cm ",
"{% include 'product' for products %}", "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }])
"{% include 'product' for products %}",
{ "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }] })
end
def test_include_tag_with_local_variables
@@ -126,7 +130,7 @@ class IncludeTagTest < Minitest::Test
def test_include_tag_with_multiple_local_variables_from_context
assert_template_result("Locale: test123 test321",
"{% include 'locale_variables' echo1: echo1, echo2: more_echos.echo2 %}",
'echo1' => 'test123', 'more_echos' => { "echo2" => 'test321' })
{ 'echo1' => 'test123', 'more_echos' => { "echo2" => 'test321' } })
end
def test_included_templates_assigns_variables
@@ -141,10 +145,10 @@ class IncludeTagTest < Minitest::Test
def test_nested_include_with_variable
assert_template_result("Product: Draft 151cm details ",
"{% include 'nested_product_template' with product %}", "product" => { "title" => 'Draft 151cm' })
"{% include 'nested_product_template' with product %}", { "product" => { "title" => 'Draft 151cm' } })
assert_template_result("Product: Draft 151cm details Product: Element 155cm details ",
"{% include 'nested_product_template' for products %}", "products" => [{ "title" => 'Draft 151cm' }, { "title" => 'Element 155cm' }])
"{% include 'nested_product_template' for products %}", { "products" => [{ "title" => 'Draft 151cm' }, { "title" => 'Element 155cm' }] })
end
def test_recursively_included_template_does_not_produce_endless_loop
@@ -162,11 +166,11 @@ class IncludeTagTest < Minitest::Test
end
def test_dynamically_choosen_template
assert_template_result("Test123", "{% include template %}", "template" => 'Test123')
assert_template_result("Test321", "{% include template %}", "template" => 'Test321')
assert_template_result("Test123", "{% include template %}", { "template" => 'Test123' })
assert_template_result("Test321", "{% include template %}", { "template" => 'Test321' })
assert_template_result("Product: Draft 151cm ", "{% include template for product %}",
"template" => 'product', 'product' => { 'title' => 'Draft 151cm' })
{ "template" => 'product', 'product' => { 'title' => 'Draft 151cm' } })
end
def test_include_tag_caches_second_read_of_same_partial
@@ -250,9 +254,11 @@ class IncludeTagTest < Minitest::Test
def test_including_via_variable_value
assert_template_result("from TestFileSystem", "{% assign page = 'pick_a_source' %}{% include page %}")
assert_template_result("Product: Draft 151cm ", "{% assign page = 'product' %}{% include page %}", "product" => { 'title' => 'Draft 151cm' })
assert_template_result("Product: Draft 151cm ", "{% assign page = 'product' %}{% include page %}",
{ "product" => { 'title' => 'Draft 151cm' } })
assert_template_result("Product: Draft 151cm ", "{% assign page = 'product' %}{% include page for foo %}", "foo" => { 'title' => 'Draft 151cm' })
assert_template_result("Product: Draft 151cm ", "{% assign page = 'product' %}{% include page for foo %}",
{ "foo" => { 'title' => 'Draft 151cm' } })
end
def test_including_with_strict_variables
+2 -2
View File
@@ -15,11 +15,11 @@ class IncrementTagTest < Minitest::Test
end
def test_dec
assert_template_result('9', '{%decrement port %}', 'port' => 10)
assert_template_result('9', '{%decrement port %}', { 'port' => 10 })
assert_template_result('-1 -2', '{%decrement port %} {%decrement port%}', {})
assert_template_result('1 5 2 2 5',
'{%increment port %} {%increment starboard%} ' \
'{%increment port %} {%decrement port%} ' \
'{%decrement starboard %}', 'port' => 1, 'starboard' => 5)
'{%decrement starboard %}', { 'port' => 1, 'starboard' => 5 })
end
end
+3 -3
View File
@@ -6,13 +6,13 @@ class LiquidTagTest < Minitest::Test
include Liquid
def test_liquid_tag
assert_template_result('1 2 3', <<~LIQUID, 'array' => [1, 2, 3])
assert_template_result('1 2 3', <<~LIQUID, { 'array' => [1, 2, 3] })
{%- liquid
echo array | join: " "
-%}
LIQUID
assert_template_result('1 2 3', <<~LIQUID, 'array' => [1, 2, 3])
assert_template_result('1 2 3', <<~LIQUID, { 'array' => [1, 2, 3] })
{%- liquid
for value in array
echo value
@@ -23,7 +23,7 @@ class LiquidTagTest < Minitest::Test
-%}
LIQUID
assert_template_result('4 8 12 6', <<~LIQUID, 'array' => [1, 2, 3])
assert_template_result('4 8 12 6', <<~LIQUID, { 'array' => [1, 2, 3] })
{%- liquid
for value in array
assign double_value = value | times: 2
+23 -15
View File
@@ -19,7 +19,7 @@ class RenderTagTest < Minitest::Test
def test_render_passes_named_arguments_into_inner_scope
Liquid::Template.file_system = StubFileSystem.new('product' => '{{ inner_product.title }}')
assert_template_result('My Product', '{% render "product", inner_product: outer_product %}',
'outer_product' => { 'title' => 'My Product' })
{ 'outer_product' => { 'title' => 'My Product' } })
end
def test_render_accepts_literals_as_arguments
@@ -134,14 +134,17 @@ class RenderTagTest < Minitest::Test
end
def test_includes_will_not_render_inside_nested_sibling_tags
Liquid::Template.file_system = StubFileSystem.new(
'foo' => 'bar',
'nested_render_with_sibling_include' => '{% render "test_include" %}{% include "foo" %}',
'test_include' => '{% include "foo" %}'
assert_template_result(
"Liquid error (test_include line 1): include usage is not allowed in this context" \
"Liquid error (nested_render_with_sibling_include line 1): include usage is not allowed in this context",
'{% render "nested_render_with_sibling_include" %}',
partials: {
'foo' => 'bar',
'nested_render_with_sibling_include' => '{% render "test_include" %}{% include "foo" %}',
'test_include' => '{% include "foo" %}',
},
render_errors: true
)
output = Liquid::Template.parse('{% render "nested_render_with_sibling_include" %}').render
assert_equal('Liquid error: include usage is not allowed in this contextLiquid error: include usage is not allowed in this context', output)
end
def test_render_tag_with
@@ -151,7 +154,8 @@ class RenderTagTest < Minitest::Test
)
assert_template_result("Product: Draft 151cm ",
"{% render 'product' with products[0] %}", "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }])
"{% render 'product' with products[0] %}",
{ "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }] })
end
def test_render_tag_with_alias
@@ -161,7 +165,8 @@ class RenderTagTest < Minitest::Test
)
assert_template_result("Product: Draft 151cm ",
"{% render 'product_alias' with products[0] as product %}", "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }])
"{% render 'product_alias' with products[0] as product %}",
{ "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }] })
end
def test_render_tag_for_alias
@@ -171,7 +176,8 @@ class RenderTagTest < Minitest::Test
)
assert_template_result("Product: Draft 151cm Product: Element 155cm ",
"{% render 'product_alias' for products as product %}", "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }])
"{% render 'product_alias' for products as product %}",
{ "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }] })
end
def test_render_tag_for
@@ -181,7 +187,8 @@ class RenderTagTest < Minitest::Test
)
assert_template_result("Product: Draft 151cm Product: Element 155cm ",
"{% render 'product' for products %}", "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }])
"{% render 'product' for products %}",
{ "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }] })
end
def test_render_tag_forloop
@@ -190,7 +197,8 @@ class RenderTagTest < Minitest::Test
)
assert_template_result("Product: Draft 151cm first index:1 Product: Element 155cm last index:2 ",
"{% render 'product' for products %}", "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }])
"{% render 'product' for products %}",
{ "products" => [{ 'title' => 'Draft 151cm' }, { 'title' => 'Element 155cm' }] })
end
def test_render_tag_for_drop
@@ -199,7 +207,7 @@ class RenderTagTest < Minitest::Test
)
assert_template_result("123",
"{% render 'loop' for loop as value %}", "loop" => TestEnumerable.new)
"{% render 'loop' for loop as value %}", { "loop" => TestEnumerable.new })
end
def test_render_tag_with_drop
@@ -208,6 +216,6 @@ class RenderTagTest < Minitest::Test
)
assert_template_result("TestEnumerable",
"{% render 'loop' with loop as value %}", "loop" => TestEnumerable.new)
"{% render 'loop' with loop as value %}", { "loop" => TestEnumerable.new })
end
end
+38 -39
View File
@@ -71,7 +71,7 @@ class StandardTagTest < Minitest::Test
assert_raises(SyntaxError) do
assert_template_result('content foo content foo ',
'{{ var2 }}{% capture %}{{ var }} foo {% endcapture %}{{ var2 }}{{ var2 }}',
'var' => 'content')
{ 'var' => 'content' })
end
end
@@ -120,38 +120,38 @@ class StandardTagTest < Minitest::Test
end
def test_case_on_size
assert_template_result('', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [])
assert_template_result('1', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1])
assert_template_result('2', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1, 1])
assert_template_result('', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1, 1, 1])
assert_template_result('', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1, 1, 1, 1])
assert_template_result('', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1, 1, 1, 1, 1])
assert_template_result('', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', { 'a' => [] })
assert_template_result('1', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', { 'a' => [1] })
assert_template_result('2', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', { 'a' => [1, 1] })
assert_template_result('', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', { 'a' => [1, 1, 1] })
assert_template_result('', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', { 'a' => [1, 1, 1, 1] })
assert_template_result('', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', { 'a' => [1, 1, 1, 1, 1] })
end
def test_case_on_size_with_else
assert_template_result('else',
'{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
'a' => [])
{ 'a' => [] })
assert_template_result('1',
'{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
'a' => [1])
{ 'a' => [1] })
assert_template_result('2',
'{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
'a' => [1, 1])
{ 'a' => [1, 1] })
assert_template_result('else',
'{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
'a' => [1, 1, 1])
{ 'a' => [1, 1, 1] })
assert_template_result('else',
'{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
'a' => [1, 1, 1, 1])
{ 'a' => [1, 1, 1, 1] })
assert_template_result('else',
'{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}',
'a' => [1, 1, 1, 1, 1])
{ 'a' => [1, 1, 1, 1, 1] })
end
def test_case_on_length_with_else
@@ -174,48 +174,47 @@ class StandardTagTest < Minitest::Test
def test_assign_from_case
# Example from the shopify forums
code = "{% case collection.handle %}{% when 'menswear-jackets' %}{% assign ptitle = 'menswear' %}{% when 'menswear-t-shirts' %}{% assign ptitle = 'menswear' %}{% else %}{% assign ptitle = 'womenswear' %}{% endcase %}{{ ptitle }}"
template = Liquid::Template.parse(code)
assert_equal("menswear", template.render!("collection" => { 'handle' => 'menswear-jackets' }))
assert_equal("menswear", template.render!("collection" => { 'handle' => 'menswear-t-shirts' }))
assert_equal("womenswear", template.render!("collection" => { 'handle' => 'x' }))
assert_equal("womenswear", template.render!("collection" => { 'handle' => 'y' }))
assert_equal("womenswear", template.render!("collection" => { 'handle' => 'z' }))
code = "{% case collection.handle %}{% when 'menswear-jackets' %}{% assign ptitle = 'menswear' %}{% when 'menswear-t-shirts' %}{% assign ptitle = 'menswear' %}{% else %}{% assign ptitle = 'womenswear' %}{% endcase %}{{ ptitle }}"
assert_template_result("menswear", code, { "collection" => { 'handle' => 'menswear-jackets' } })
assert_template_result("menswear", code, { "collection" => { 'handle' => 'menswear-t-shirts' } })
assert_template_result("womenswear", code, { "collection" => { 'handle' => 'x' } })
assert_template_result("womenswear", code, { "collection" => { 'handle' => 'y' } })
assert_template_result("womenswear", code, { "collection" => { 'handle' => 'z' } })
end
def test_case_when_or
code = '{% case condition %}{% when 1 or 2 or 3 %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 1)
assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 2)
assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 3)
assert_template_result(' its 4 ', code, 'condition' => 4)
assert_template_result('', code, 'condition' => 5)
assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 1 })
assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 2 })
assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 3 })
assert_template_result(' its 4 ', code, { 'condition' => 4 })
assert_template_result('', code, { 'condition' => 5 })
code = '{% case condition %}{% when 1 or "string" or null %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 1)
assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 'string')
assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => nil)
assert_template_result('', code, 'condition' => 'something else')
assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 1 })
assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 'string' })
assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => nil })
assert_template_result('', code, { 'condition' => 'something else' })
end
def test_case_when_comma
code = '{% case condition %}{% when 1, 2, 3 %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 1)
assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 2)
assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 3)
assert_template_result(' its 4 ', code, 'condition' => 4)
assert_template_result('', code, 'condition' => 5)
assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 1 })
assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 2 })
assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 3 })
assert_template_result(' its 4 ', code, { 'condition' => 4 })
assert_template_result('', code, { 'condition' => 5 })
code = '{% case condition %}{% when 1, "string", null %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 1)
assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => 'string')
assert_template_result(' its 1 or 2 or 3 ', code, 'condition' => nil)
assert_template_result('', code, 'condition' => 'something else')
assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 1 })
assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => 'string' })
assert_template_result(' its 1 or 2 or 3 ', code, { 'condition' => nil })
assert_template_result('', code, { 'condition' => 'something else' })
end
def test_case_when_comma_and_blank_body
code = '{% case condition %}{% when 1, 2 %} {% assign r = "result" %} {% endcase %}{{ r }}'
assert_template_result('result', code, 'condition' => 2)
assert_template_result('result', code, { 'condition' => 2 })
end
def test_assign
+10 -10
View File
@@ -60,22 +60,22 @@ class StatementsTest < Minitest::Test
def test_var_strings_equal
text = ' {% if var == "hello there!" %} true {% else %} false {% endif %} '
assert_template_result(' true ', text, 'var' => 'hello there!')
assert_template_result(' true ', text, { 'var' => 'hello there!' })
end
def test_var_strings_are_not_equal
text = ' {% if "hello there!" == var %} true {% else %} false {% endif %} '
assert_template_result(' true ', text, 'var' => 'hello there!')
assert_template_result(' true ', text, { 'var' => 'hello there!' })
end
def test_var_and_long_string_are_equal
text = " {% if var == 'hello there!' %} true {% else %} false {% endif %} "
assert_template_result(' true ', text, 'var' => 'hello there!')
assert_template_result(' true ', text, { 'var' => 'hello there!' })
end
def test_var_and_long_string_are_equal_backwards
text = " {% if 'hello there!' == var %} true {% else %} false {% endif %} "
assert_template_result(' true ', text, 'var' => 'hello there!')
assert_template_result(' true ', text, { 'var' => 'hello there!' })
end
# def test_is_nil
@@ -87,27 +87,27 @@ class StatementsTest < Minitest::Test
def test_is_collection_empty
text = ' {% if array == empty %} true {% else %} false {% endif %} '
assert_template_result(' true ', text, 'array' => [])
assert_template_result(' true ', text, { 'array' => [] })
end
def test_is_not_collection_empty
text = ' {% if array == empty %} true {% else %} false {% endif %} '
assert_template_result(' false ', text, 'array' => [1, 2, 3])
assert_template_result(' false ', text, { 'array' => [1, 2, 3] })
end
def test_nil
text = ' {% if var == nil %} true {% else %} false {% endif %} '
assert_template_result(' true ', text, 'var' => nil)
assert_template_result(' true ', text, { 'var' => nil })
text = ' {% if var == null %} true {% else %} false {% endif %} '
assert_template_result(' true ', text, 'var' => nil)
assert_template_result(' true ', text, { 'var' => nil })
end
def test_not_nil
text = ' {% if var != nil %} true {% else %} false {% endif %} '
assert_template_result(' true ', text, 'var' => 1)
assert_template_result(' true ', text, { 'var' => 1 })
text = ' {% if var != null %} true {% else %} false {% endif %} '
assert_template_result(' true ', text, 'var' => 1)
assert_template_result(' true ', text, { 'var' => 1 })
end
end # StatementsTest
+11 -9
View File
@@ -20,47 +20,49 @@ class TableRowTest < Minitest::Test
def test_table_row
assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 4 </td><td class=\"col2\"> 5 </td><td class=\"col3\"> 6 </td></tr>\n",
'{% tablerow n in numbers cols:3%} {{n}} {% endtablerow %}',
'numbers' => [1, 2, 3, 4, 5, 6])
{ 'numbers' => [1, 2, 3, 4, 5, 6] })
assert_template_result("<tr class=\"row1\">\n</tr>\n",
'{% tablerow n in numbers cols:3%} {{n}} {% endtablerow %}',
'numbers' => [])
{ 'numbers' => [] })
end
def test_table_row_with_different_cols
assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td><td class=\"col4\"> 4 </td><td class=\"col5\"> 5 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 6 </td></tr>\n",
'{% tablerow n in numbers cols:5%} {{n}} {% endtablerow %}',
'numbers' => [1, 2, 3, 4, 5, 6])
{ 'numbers' => [1, 2, 3, 4, 5, 6] })
end
def test_table_col_counter
assert_template_result("<tr class=\"row1\">\n<td class=\"col1\">1</td><td class=\"col2\">2</td></tr>\n<tr class=\"row2\"><td class=\"col1\">1</td><td class=\"col2\">2</td></tr>\n<tr class=\"row3\"><td class=\"col1\">1</td><td class=\"col2\">2</td></tr>\n",
'{% tablerow n in numbers cols:2%}{{tablerowloop.col}}{% endtablerow %}',
'numbers' => [1, 2, 3, 4, 5, 6])
{ 'numbers' => [1, 2, 3, 4, 5, 6] })
end
def test_quoted_fragment
assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 4 </td><td class=\"col2\"> 5 </td><td class=\"col3\"> 6 </td></tr>\n",
"{% tablerow n in collections.frontpage cols:3%} {{n}} {% endtablerow %}",
'collections' => { 'frontpage' => [1, 2, 3, 4, 5, 6] })
{ 'collections' => { 'frontpage' => [1, 2, 3, 4, 5, 6] } })
assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 4 </td><td class=\"col2\"> 5 </td><td class=\"col3\"> 6 </td></tr>\n",
"{% tablerow n in collections['frontpage'] cols:3%} {{n}} {% endtablerow %}",
'collections' => { 'frontpage' => [1, 2, 3, 4, 5, 6] })
{ 'collections' => { 'frontpage' => [1, 2, 3, 4, 5, 6] } })
end
def test_enumerable_drop
assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 4 </td><td class=\"col2\"> 5 </td><td class=\"col3\"> 6 </td></tr>\n",
'{% tablerow n in numbers cols:3%} {{n}} {% endtablerow %}',
'numbers' => ArrayDrop.new([1, 2, 3, 4, 5, 6]))
{ 'numbers' => ArrayDrop.new([1, 2, 3, 4, 5, 6]) })
end
def test_offset_and_limit
assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 4 </td><td class=\"col2\"> 5 </td><td class=\"col3\"> 6 </td></tr>\n",
'{% tablerow n in numbers cols:3 offset:1 limit:6%} {{n}} {% endtablerow %}',
'numbers' => [0, 1, 2, 3, 4, 5, 6, 7])
{ 'numbers' => [0, 1, 2, 3, 4, 5, 6, 7] })
end
def test_blank_string_not_iterable
assert_template_result("<tr class=\"row1\">\n</tr>\n", "{% tablerow char in characters cols:3 %}I WILL NOT BE OUTPUT{% endtablerow %}", 'characters' => '')
assert_template_result("<tr class=\"row1\">\n</tr>\n",
"{% tablerow char in characters cols:3 %}I WILL NOT BE OUTPUT{% endtablerow %}",
{ 'characters' => '' })
end
end
@@ -19,10 +19,10 @@ class UnlessElseTagTest < Minitest::Test
end
def test_unless_in_loop
assert_template_result('23', '{% for i in choices %}{% unless i %}{{ forloop.index }}{% endunless %}{% endfor %}', 'choices' => [1, nil, false])
assert_template_result('23', '{% for i in choices %}{% unless i %}{{ forloop.index }}{% endunless %}{% endfor %}', { 'choices' => [1, nil, false] })
end
def test_unless_else_in_loop
assert_template_result(' TRUE 2 3 ', '{% for i in choices %}{% unless i %} {{ forloop.index }} {% else %} TRUE {% endunless %}{% endfor %}', 'choices' => [1, nil, false])
assert_template_result(' TRUE 2 3 ', '{% for i in choices %}{% unless i %} {{ forloop.index }} {% else %} TRUE {% endunless %}{% endfor %}', { 'choices' => [1, nil, false] })
end
end # UnlessElseTest
+4 -6
View File
@@ -315,13 +315,11 @@ class TemplateTest < Minitest::Test
end
def test_using_range_literal_works_as_expected
t = Template.parse("{% assign foo = (x..y) %}{{ foo }}")
result = t.render('x' => 1, 'y' => 5)
assert_equal('1..5', result)
source = "{% assign foo = (x..y) %}{{ foo }}"
assert_template_result("1..5", source, { "x" => 1, "y" => 5 })
t = Template.parse("{% assign nums = (x..y) %}{% for num in nums %}{{ num }}{% endfor %}")
result = t.render('x' => 1, 'y' => 5)
assert_equal('12345', result)
source = "{% assign nums = (x..y) %}{% for num in nums %}{{ num }}{% endfor %}"
assert_template_result("12345", source, { "x" => 1, "y" => 5 })
end
def test_source_string_subclass
+3 -8
View File
@@ -530,14 +530,9 @@ class TrimModeTest < Minitest::Test
end
def test_pre_trim_blank_preceding_text
template = Liquid::Template.parse("\n{%- raw %}{% endraw %}")
assert_equal("", template.render)
template = Liquid::Template.parse("\n{%- if true %}{% endif %}")
assert_equal("", template.render)
template = Liquid::Template.parse("{{ 'B' }} \n{%- if true %}C{% endif %}")
assert_equal("BC", template.render)
assert_template_result("", "\n{%- raw %}{% endraw %}")
assert_template_result("", "\n{%- if true %}{% endif %}")
assert_template_result("BC", "{{ 'B' }} \n{%- if true %}C{% endif %}")
end
def test_bug_compatible_pre_trim
+34 -39
View File
@@ -6,81 +6,76 @@ class VariableTest < Minitest::Test
include Liquid
def test_simple_variable
template = Template.parse(%({{test}}))
assert_equal('worked', template.render!('test' => 'worked'))
assert_equal('worked wonderfully', template.render!('test' => 'worked wonderfully'))
assert_template_result('worked', "{{test}}", { 'test' => 'worked' })
assert_template_result('worked wonderfully', "{{test}}", { 'test' => 'worked wonderfully' })
end
def test_variable_render_calls_to_liquid
assert_template_result('foobar', '{{ foo }}', 'foo' => ThingWithToLiquid.new)
assert_template_result('foobar', '{{ foo }}', { 'foo' => ThingWithToLiquid.new })
end
def test_variable_lookup_calls_to_liquid_value
assert_template_result('1', '{{ foo }}', 'foo' => IntegerDrop.new('1'))
assert_template_result('2', '{{ list[foo] }}', 'foo' => IntegerDrop.new('1'), 'list' => [1, 2, 3])
assert_template_result('one', '{{ list[foo] }}', 'foo' => IntegerDrop.new('1'), 'list' => { 1 => 'one' })
assert_template_result('Yay', '{{ foo }}', 'foo' => BooleanDrop.new(true))
assert_template_result('YAY', '{{ foo | upcase }}', 'foo' => BooleanDrop.new(true))
assert_template_result('1', '{{ foo }}', { 'foo' => IntegerDrop.new('1') })
assert_template_result('2', '{{ list[foo] }}', { 'foo' => IntegerDrop.new('1'), 'list' => [1, 2, 3] })
assert_template_result('one', '{{ list[foo] }}', { 'foo' => IntegerDrop.new('1'), 'list' => { 1 => 'one' } })
assert_template_result('Yay', '{{ foo }}', { 'foo' => BooleanDrop.new(true) })
assert_template_result('YAY', '{{ foo | upcase }}', { 'foo' => BooleanDrop.new(true) })
end
def test_if_tag_calls_to_liquid_value
assert_template_result('one', '{% if foo == 1 %}one{% endif %}', 'foo' => IntegerDrop.new('1'))
assert_template_result('one', '{% if 0 < foo %}one{% endif %}', 'foo' => IntegerDrop.new('1'))
assert_template_result('one', '{% if foo > 0 %}one{% endif %}', 'foo' => IntegerDrop.new('1'))
assert_template_result('true', '{% if foo == true %}true{% endif %}', 'foo' => BooleanDrop.new(true))
assert_template_result('true', '{% if foo %}true{% endif %}', 'foo' => BooleanDrop.new(true))
assert_template_result('one', '{% if foo == 1 %}one{% endif %}', { 'foo' => IntegerDrop.new('1') })
assert_template_result('one', '{% if 0 < foo %}one{% endif %}', { 'foo' => IntegerDrop.new('1') })
assert_template_result('one', '{% if foo > 0 %}one{% endif %}', { 'foo' => IntegerDrop.new('1') })
assert_template_result('true', '{% if foo == true %}true{% endif %}', { 'foo' => BooleanDrop.new(true) })
assert_template_result('true', '{% if foo %}true{% endif %}', { 'foo' => BooleanDrop.new(true) })
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 %}true{% endif %}', { 'foo' => BooleanDrop.new(false) })
assert_template_result('', '{% if foo == true %}True{% endif %}', { 'foo' => BooleanDrop.new(false) })
end
def test_unless_tag_calls_to_liquid_value
assert_template_result('', '{% unless foo %}true{% endunless %}', 'foo' => BooleanDrop.new(true))
assert_template_result('', '{% unless foo %}true{% endunless %}', { 'foo' => BooleanDrop.new(true) })
end
def test_case_tag_calls_to_liquid_value
assert_template_result('One', '{% case foo %}{% when 1 %}One{% endcase %}', 'foo' => IntegerDrop.new('1'))
assert_template_result('One', '{% case foo %}{% when 1 %}One{% endcase %}', { 'foo' => IntegerDrop.new('1') })
end
def test_simple_with_whitespaces
template = Template.parse(%( {{ test }} ))
assert_equal(' worked ', template.render!('test' => 'worked'))
assert_equal(' worked wonderfully ', template.render!('test' => 'worked wonderfully'))
assert_template_result(" worked ", " {{ test }} ", { "test" => "worked" })
assert_template_result(" worked wonderfully ", " {{ test }} ", { "test" => "worked wonderfully" })
end
def test_expression_with_whitespace_in_square_brackets
assert_template_result('result', "{{ a[ 'b' ] }}", 'a' => { 'b' => 'result' })
assert_template_result('result', "{{ a[ [ 'b' ] ] }}", 'b' => 'c', 'a' => { 'c' => 'result' })
assert_template_result('result', "{{ a[ 'b' ] }}", { 'a' => { 'b' => 'result' } })
assert_template_result('result', "{{ a[ [ 'b' ] ] }}", { 'b' => 'c', 'a' => { 'c' => 'result' } })
end
def test_ignore_unknown
template = Template.parse(%({{ test }}))
assert_equal('', template.render!)
assert_template_result("", "{{ test }}")
end
def test_using_blank_as_variable_name
template = Template.parse("{% assign foo = blank %}{{ foo }}")
assert_equal('', template.render!)
assert_template_result("", "{% assign foo = blank %}{{ foo }}")
end
def test_using_empty_as_variable_name
template = Template.parse("{% assign foo = empty %}{{ foo }}")
assert_equal('', template.render!)
assert_template_result("", "{% assign foo = empty %}{{ foo }}")
end
def test_hash_scoping
assert_template_result('worked', "{{ test.test }}", 'test' => { 'test' => 'worked' })
assert_template_result('worked', "{{ test . test }}", 'test' => { 'test' => 'worked' })
assert_template_result('worked', "{{ test.test }}", { 'test' => { 'test' => 'worked' } })
assert_template_result('worked', "{{ test . test }}", { 'test' => { 'test' => 'worked' } })
end
def test_false_renders_as_false
assert_equal('false', Template.parse("{{ foo }}").render!('foo' => false))
assert_equal('false', Template.parse("{{ false }}").render!)
assert_template_result("false", "{{ foo }}", { 'foo' => false })
assert_template_result("false", "{{ false }}")
end
def test_nil_renders_as_empty_string
assert_equal('', Template.parse("{{ nil }}").render!)
assert_equal('cat', Template.parse("{{ nil | append: 'cat' }}").render!)
assert_template_result("", "{{ nil }}")
assert_template_result("cat", "{{ nil | append: 'cat' }}")
end
def test_preset_assigns
@@ -121,18 +116,18 @@ class VariableTest < Minitest::Test
end
def test_multiline_variable
assert_equal('worked', Template.parse("{{\ntest\n}}").render!('test' => 'worked'))
assert_template_result("worked", "{{\ntest\n}}", { "test" => "worked" })
end
def test_render_symbol
assert_template_result('bar', '{{ foo }}', 'foo' => :bar)
assert_template_result('bar', '{{ foo }}', { 'foo' => :bar })
end
def test_dynamic_find_var
assert_template_result('bar', '{{ [key] }}', 'key' => 'foo', 'foo' => 'bar')
assert_template_result('bar', '{{ [key] }}', { 'key' => 'foo', 'foo' => 'bar' })
end
def test_raw_value_variable
assert_template_result('bar', '{{ [key] }}', 'key' => 'foo', 'foo' => 'bar')
assert_template_result('bar', '{{ [key] }}', { 'key' => 'foo', 'foo' => 'bar' })
end
end
+12 -10
View File
@@ -37,19 +37,21 @@ module Minitest
module Assertions
include Liquid
def assert_template_result(expected, template, assigns = {}, message = nil)
assert_equal(expected, Template.parse(template, line_numbers: true).render!(assigns), message)
def assert_template_result(
expected, template, assigns = {},
message: nil, partials: nil, error_mode: nil, render_errors: false
)
template = Liquid::Template.parse(template, line_numbers: true, error_mode: error_mode&.to_sym)
file_system = StubFileSystem.new(partials) if partials
registers = Liquid::Registers.new(file_system: file_system)
context = Liquid::Context.build(environments: assigns, rethrow_errors: !render_errors, registers: registers)
output = template.render(context)
assert_equal(expected, output, message)
end
def assert_template_result_matches(expected, template, assigns = {}, message = nil)
return assert_template_result(expected, template, assigns, message) unless expected.is_a?(Regexp)
assert_match(expected, Template.parse(template, line_numbers: true).render!(assigns), message)
end
def assert_match_syntax_error(match, template, assigns = {})
def assert_match_syntax_error(match, template, error_mode: nil)
exception = assert_raises(Liquid::SyntaxError) do
Template.parse(template, line_numbers: true).render(assigns)
Template.parse(template, line_numbers: true, error_mode: error_mode&.to_sym).render
end
assert_match(match, exception.message)
end
+14
View File
@@ -236,6 +236,20 @@ class ParseTreeVisitorTest < Minitest::Test
)
end
def test_render_with
assert_equal(
["test"],
visit(%({% render "hai" with test %}))
)
end
def test_render_for
assert_equal(
["test"],
visit(%({% render "hai" for test %}))
)
end
def test_preserve_tree_structure
assert_equal(
[[nil, [