From 27ead517ee3e657fadef9cd9f4f876745128bddd Mon Sep 17 00:00:00 2001 From: CP Clermont Date: Tue, 10 Sep 2024 11:23:53 -0400 Subject: [PATCH 1/5] Add `end` tag support (#1823) --- lib/liquid/block.rb | 10 ++++++--- lib/liquid/block_body.rb | 2 +- lib/liquid/locales/en.yml | 3 ++- lib/liquid/tags/comment.rb | 4 ++++ lib/liquid/tags/raw.rb | 4 ++++ test/integration/block_test.rb | 24 +++++++++++++++++++++- test/integration/tags/if_else_tag_test.rb | 1 + test/integration/tags/liquid_tag_test.rb | 14 +++++++++++++ test/integration/tags/raw_tag_test.rb | 4 ++++ test/integration/tags/standard_tag_test.rb | 1 + 10 files changed, 61 insertions(+), 6 deletions(-) diff --git a/lib/liquid/block.rb b/lib/liquid/block.rb index 73d86c7bd..8a0c50e75 100644 --- a/lib/liquid/block.rb +++ b/lib/liquid/block.rb @@ -34,7 +34,7 @@ def unknown_tag(tag_name, _markup, _tokenizer) end # @api private - def self.raise_unknown_tag(tag, block_name, block_delimiter, parse_context) + def self.raise_unknown_tag(tag, block_name, block_delimiter, parse_context, supports_end_tag = true) if tag == 'else' raise SyntaxError, parse_context.locale.t( "errors.syntax.unexpected_else", @@ -42,7 +42,7 @@ def self.raise_unknown_tag(tag, block_name, block_delimiter, parse_context) ) elsif tag.start_with?('end') raise SyntaxError, parse_context.locale.t( - "errors.syntax.invalid_delimiter", + supports_end_tag ? "errors.syntax.invalid_delimiter" : "errors.syntax.invalid_delimiter_no_end", tag: tag, block_name: block_name, block_delimiter: block_delimiter, @@ -64,6 +64,10 @@ def block_delimiter @block_delimiter ||= "end#{block_name}" end + def supports_end_tag? + true + end + private # @api public @@ -81,7 +85,7 @@ def parse_body(body, tokens) body.parse(tokens, parse_context) do |end_tag_name, end_tag_params| @blank &&= body.blank? - return false if end_tag_name == block_delimiter + return false if end_tag_name == block_delimiter || (supports_end_tag? && end_tag_name == 'end') raise_tag_never_closed(block_name) unless end_tag_name # this tag is not registered with the system diff --git a/lib/liquid/block_body.rb b/lib/liquid/block_body.rb index 33a6a99f5..8d438e00b 100644 --- a/lib/liquid/block_body.rb +++ b/lib/liquid/block_body.rb @@ -68,7 +68,7 @@ def freeze # @api private def self.unknown_tag_in_liquid_tag(tag, parse_context) - Block.raise_unknown_tag(tag, 'liquid', '%}', parse_context) + Block.raise_unknown_tag(tag, 'liquid', '%}', parse_context, false) end # @api private diff --git a/lib/liquid/locales/en.yml b/lib/liquid/locales/en.yml index 7e232de42..55d65a58f 100644 --- a/lib/liquid/locales/en.yml +++ b/lib/liquid/locales/en.yml @@ -14,7 +14,8 @@ if: "Syntax Error in tag 'if' - Valid syntax: if [expression]" include: "Error in tag 'include' - Valid syntax: include '[template]' (with|for) [object|collection]" inline_comment_invalid: "Syntax error in tag '#' - Each line of comments must be prefixed by the '#' character" - invalid_delimiter: "'%{tag}' is not a valid delimiter for %{block_name} tags. use %{block_delimiter}" + invalid_delimiter: "'%{tag}' is not a valid delimiter for %{block_name} tags. use end or %{block_delimiter}" + invalid_delimiter_no_end: "'%{tag}' is not a valid delimiter for %{block_name} tags. use %{block_delimiter}" render: "Syntax error in tag 'render' - Template name must be a quoted string" table_row: "Syntax Error in 'table_row loop' - Valid syntax: table_row [item] in [collection] cols=3" tag_never_closed: "'%{block_name}' tag was never closed" diff --git a/lib/liquid/tags/comment.rb b/lib/liquid/tags/comment.rb index 9922ee0dd..eb0313410 100644 --- a/lib/liquid/tags/comment.rb +++ b/lib/liquid/tags/comment.rb @@ -22,6 +22,10 @@ def render_to_output_buffer(_context, output) def unknown_tag(_tag, _markup, _tokens) end + def supports_end_tag? + false + end + def blank? true end diff --git a/lib/liquid/tags/raw.rb b/lib/liquid/tags/raw.rb index 7f3dec9b1..ed0f81ff6 100644 --- a/lib/liquid/tags/raw.rb +++ b/lib/liquid/tags/raw.rb @@ -22,6 +22,10 @@ def initialize(tag_name, markup, parse_context) ensure_valid_markup(tag_name, markup, parse_context) end + def supports_end_tag? + false + end + def parse(tokens) @body = +'' while (token = tokens.shift) diff --git a/test/integration/block_test.rb b/test/integration/block_test.rb index 1d3c78cf6..475b96f02 100644 --- a/test/integration/block_test.rb +++ b/test/integration/block_test.rb @@ -5,9 +5,31 @@ class BlockTest < Minitest::Test include Liquid + def test_simple_end_tag + assert_template_result('you rock', '{% if true %}you rock{% end %}') + assert_template_result('you rock', '{% if true %}{% unless false %}you rock{% end %}{% end %}') + end + def test_unexpected_end_tag 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) + assert_match_syntax_error("Liquid syntax error (line 1): 'endunless' is not a valid delimiter for if tags. use end or endif", source) + end + + def test_end_closes_closest_open_tag + source = '{% if true %}{% unless true %}{% end %}{% endunless %}' + assert_match_syntax_error("Liquid syntax error (line 1): 'endunless' is not a valid delimiter for if tags. use end or endif", source) + end + + # comments are special and can't be closed by `end` + def test_unexpected_end_tag_comment + source = '{% comment %}{% end %}' + assert_match_syntax_error("Liquid syntax error (line 1): 'comment' tag was never closed", source) + end + + # raw is special and can't be closed by `end` + def test_unexpected_end_tag_raw + source = '{% raw %}{% end %}' + assert_match_syntax_error("Liquid syntax error (line 1): 'raw' tag was never closed", source) end def test_with_custom_tag diff --git a/test/integration/tags/if_else_tag_test.rb b/test/integration/tags/if_else_tag_test.rb index 3f04f2b8d..3824c300b 100644 --- a/test/integration/tags/if_else_tag_test.rb +++ b/test/integration/tags/if_else_tag_test.rb @@ -12,6 +12,7 @@ def test_if ' {% if true %} this text should go into the output {% endif %} ', ) assert_template_result(' you rock ?', '{% if false %} you suck {% endif %} {% if true %} you rock {% endif %}?') + assert_template_result(' you rock ?', '{% if false %} you suck {% endif %} {% if true %} you rock {% end %}?') end def test_literal_comparisons diff --git a/test/integration/tags/liquid_tag_test.rb b/test/integration/tags/liquid_tag_test.rb index c6694fa70..9c8e67e17 100644 --- a/test/integration/tags/liquid_tag_test.rb +++ b/test/integration/tags/liquid_tag_test.rb @@ -106,6 +106,11 @@ def test_cannot_close_blocks_created_before_a_liquid_tag 42 {%- liquid endif -%} LIQUID + assert_match_syntax_error("syntax error (line 3): 'end' is not a valid delimiter for liquid tags. use %}", <<~LIQUID) + {%- if true -%} + 42 + {%- liquid end -%} + LIQUID end def test_liquid_tag_in_raw @@ -123,6 +128,15 @@ def test_nested_liquid_tags endif -%} LIQUID + + assert_template_result('good', <<~LIQUID) + {%- liquid + liquid + if true + echo "good" + end + -%} + LIQUID end def test_nested_liquid_tags_on_same_line diff --git a/test/integration/tags/raw_tag_test.rb b/test/integration/tags/raw_tag_test.rb index 3629f39c2..f4ac484ef 100644 --- a/test/integration/tags/raw_tag_test.rb +++ b/test/integration/tags/raw_tag_test.rb @@ -10,6 +10,10 @@ def test_tag_in_raw '{% comment %} test {% endcomment %}', '{% raw %}{% comment %} test {% endcomment %}{% endraw %}', ) + assert_template_result( + '', + '{% comment %} {% if true %}{% end %} {% endcomment %}', + ) end def test_output_in_raw diff --git a/test/integration/tags/standard_tag_test.rb b/test/integration/tags/standard_tag_test.rb index 6c297d407..adf21d5e0 100644 --- a/test/integration/tags/standard_tag_test.rb +++ b/test/integration/tags/standard_tag_test.rb @@ -38,6 +38,7 @@ def test_has_a_block_which_does_nothing assert_template_result('', '{%comment%}{%blabla%}{%endcomment%}') assert_template_result('', '{% comment %}{% blabla %}{% endcomment %}') assert_template_result('', '{%comment%}{% endif %}{%endcomment%}') + assert_template_result('', '{%comment%}{% end %}{%endcomment%}') assert_template_result('', '{% comment %}{% endwhatever %}{% endcomment %}') assert_template_result('', '{% comment %}{% raw %} {{%%%%}} }} { {% endcomment %} {% comment {% endraw %} {% endcomment %}') assert_template_result('', '{% comment %}{% " %}{% endcomment %}') From 200fa0c11baebf110624ed0f24a7136d7e2f2870 Mon Sep 17 00:00:00 2001 From: Ian Ker-Seymer Date: Wed, 11 Sep 2024 11:12:39 -0400 Subject: [PATCH 2/5] Revert "Add `end` tag support (#1823)" (#1824) This reverts commit 27ead517ee3e657fadef9cd9f4f876745128bddd. --- lib/liquid/block.rb | 10 +++------ lib/liquid/block_body.rb | 2 +- lib/liquid/locales/en.yml | 3 +-- lib/liquid/tags/comment.rb | 4 ---- lib/liquid/tags/raw.rb | 4 ---- test/integration/block_test.rb | 24 +--------------------- test/integration/tags/if_else_tag_test.rb | 1 - test/integration/tags/liquid_tag_test.rb | 14 ------------- test/integration/tags/raw_tag_test.rb | 4 ---- test/integration/tags/standard_tag_test.rb | 1 - 10 files changed, 6 insertions(+), 61 deletions(-) diff --git a/lib/liquid/block.rb b/lib/liquid/block.rb index 8a0c50e75..73d86c7bd 100644 --- a/lib/liquid/block.rb +++ b/lib/liquid/block.rb @@ -34,7 +34,7 @@ def unknown_tag(tag_name, _markup, _tokenizer) end # @api private - def self.raise_unknown_tag(tag, block_name, block_delimiter, parse_context, supports_end_tag = true) + def self.raise_unknown_tag(tag, block_name, block_delimiter, parse_context) if tag == 'else' raise SyntaxError, parse_context.locale.t( "errors.syntax.unexpected_else", @@ -42,7 +42,7 @@ def self.raise_unknown_tag(tag, block_name, block_delimiter, parse_context, supp ) elsif tag.start_with?('end') raise SyntaxError, parse_context.locale.t( - supports_end_tag ? "errors.syntax.invalid_delimiter" : "errors.syntax.invalid_delimiter_no_end", + "errors.syntax.invalid_delimiter", tag: tag, block_name: block_name, block_delimiter: block_delimiter, @@ -64,10 +64,6 @@ def block_delimiter @block_delimiter ||= "end#{block_name}" end - def supports_end_tag? - true - end - private # @api public @@ -85,7 +81,7 @@ def parse_body(body, tokens) body.parse(tokens, parse_context) do |end_tag_name, end_tag_params| @blank &&= body.blank? - return false if end_tag_name == block_delimiter || (supports_end_tag? && end_tag_name == 'end') + return false if end_tag_name == block_delimiter raise_tag_never_closed(block_name) unless end_tag_name # this tag is not registered with the system diff --git a/lib/liquid/block_body.rb b/lib/liquid/block_body.rb index 8d438e00b..33a6a99f5 100644 --- a/lib/liquid/block_body.rb +++ b/lib/liquid/block_body.rb @@ -68,7 +68,7 @@ def freeze # @api private def self.unknown_tag_in_liquid_tag(tag, parse_context) - Block.raise_unknown_tag(tag, 'liquid', '%}', parse_context, false) + Block.raise_unknown_tag(tag, 'liquid', '%}', parse_context) end # @api private diff --git a/lib/liquid/locales/en.yml b/lib/liquid/locales/en.yml index 55d65a58f..7e232de42 100644 --- a/lib/liquid/locales/en.yml +++ b/lib/liquid/locales/en.yml @@ -14,8 +14,7 @@ if: "Syntax Error in tag 'if' - Valid syntax: if [expression]" include: "Error in tag 'include' - Valid syntax: include '[template]' (with|for) [object|collection]" inline_comment_invalid: "Syntax error in tag '#' - Each line of comments must be prefixed by the '#' character" - invalid_delimiter: "'%{tag}' is not a valid delimiter for %{block_name} tags. use end or %{block_delimiter}" - invalid_delimiter_no_end: "'%{tag}' is not a valid delimiter for %{block_name} tags. use %{block_delimiter}" + invalid_delimiter: "'%{tag}' is not a valid delimiter for %{block_name} tags. use %{block_delimiter}" render: "Syntax error in tag 'render' - Template name must be a quoted string" table_row: "Syntax Error in 'table_row loop' - Valid syntax: table_row [item] in [collection] cols=3" tag_never_closed: "'%{block_name}' tag was never closed" diff --git a/lib/liquid/tags/comment.rb b/lib/liquid/tags/comment.rb index eb0313410..9922ee0dd 100644 --- a/lib/liquid/tags/comment.rb +++ b/lib/liquid/tags/comment.rb @@ -22,10 +22,6 @@ def render_to_output_buffer(_context, output) def unknown_tag(_tag, _markup, _tokens) end - def supports_end_tag? - false - end - def blank? true end diff --git a/lib/liquid/tags/raw.rb b/lib/liquid/tags/raw.rb index ed0f81ff6..7f3dec9b1 100644 --- a/lib/liquid/tags/raw.rb +++ b/lib/liquid/tags/raw.rb @@ -22,10 +22,6 @@ def initialize(tag_name, markup, parse_context) ensure_valid_markup(tag_name, markup, parse_context) end - def supports_end_tag? - false - end - def parse(tokens) @body = +'' while (token = tokens.shift) diff --git a/test/integration/block_test.rb b/test/integration/block_test.rb index 475b96f02..1d3c78cf6 100644 --- a/test/integration/block_test.rb +++ b/test/integration/block_test.rb @@ -5,31 +5,9 @@ class BlockTest < Minitest::Test include Liquid - def test_simple_end_tag - assert_template_result('you rock', '{% if true %}you rock{% end %}') - assert_template_result('you rock', '{% if true %}{% unless false %}you rock{% end %}{% end %}') - end - def test_unexpected_end_tag source = '{% if true %}{% endunless %}' - assert_match_syntax_error("Liquid syntax error (line 1): 'endunless' is not a valid delimiter for if tags. use end or endif", source) - end - - def test_end_closes_closest_open_tag - source = '{% if true %}{% unless true %}{% end %}{% endunless %}' - assert_match_syntax_error("Liquid syntax error (line 1): 'endunless' is not a valid delimiter for if tags. use end or endif", source) - end - - # comments are special and can't be closed by `end` - def test_unexpected_end_tag_comment - source = '{% comment %}{% end %}' - assert_match_syntax_error("Liquid syntax error (line 1): 'comment' tag was never closed", source) - end - - # raw is special and can't be closed by `end` - def test_unexpected_end_tag_raw - source = '{% raw %}{% end %}' - assert_match_syntax_error("Liquid syntax error (line 1): 'raw' tag was never closed", source) + 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 diff --git a/test/integration/tags/if_else_tag_test.rb b/test/integration/tags/if_else_tag_test.rb index 3824c300b..3f04f2b8d 100644 --- a/test/integration/tags/if_else_tag_test.rb +++ b/test/integration/tags/if_else_tag_test.rb @@ -12,7 +12,6 @@ def test_if ' {% if true %} this text should go into the output {% endif %} ', ) assert_template_result(' you rock ?', '{% if false %} you suck {% endif %} {% if true %} you rock {% endif %}?') - assert_template_result(' you rock ?', '{% if false %} you suck {% endif %} {% if true %} you rock {% end %}?') end def test_literal_comparisons diff --git a/test/integration/tags/liquid_tag_test.rb b/test/integration/tags/liquid_tag_test.rb index 9c8e67e17..c6694fa70 100644 --- a/test/integration/tags/liquid_tag_test.rb +++ b/test/integration/tags/liquid_tag_test.rb @@ -106,11 +106,6 @@ def test_cannot_close_blocks_created_before_a_liquid_tag 42 {%- liquid endif -%} LIQUID - assert_match_syntax_error("syntax error (line 3): 'end' is not a valid delimiter for liquid tags. use %}", <<~LIQUID) - {%- if true -%} - 42 - {%- liquid end -%} - LIQUID end def test_liquid_tag_in_raw @@ -128,15 +123,6 @@ def test_nested_liquid_tags endif -%} LIQUID - - assert_template_result('good', <<~LIQUID) - {%- liquid - liquid - if true - echo "good" - end - -%} - LIQUID end def test_nested_liquid_tags_on_same_line diff --git a/test/integration/tags/raw_tag_test.rb b/test/integration/tags/raw_tag_test.rb index f4ac484ef..3629f39c2 100644 --- a/test/integration/tags/raw_tag_test.rb +++ b/test/integration/tags/raw_tag_test.rb @@ -10,10 +10,6 @@ def test_tag_in_raw '{% comment %} test {% endcomment %}', '{% raw %}{% comment %} test {% endcomment %}{% endraw %}', ) - assert_template_result( - '', - '{% comment %} {% if true %}{% end %} {% endcomment %}', - ) end def test_output_in_raw diff --git a/test/integration/tags/standard_tag_test.rb b/test/integration/tags/standard_tag_test.rb index adf21d5e0..6c297d407 100644 --- a/test/integration/tags/standard_tag_test.rb +++ b/test/integration/tags/standard_tag_test.rb @@ -38,7 +38,6 @@ def test_has_a_block_which_does_nothing assert_template_result('', '{%comment%}{%blabla%}{%endcomment%}') assert_template_result('', '{% comment %}{% blabla %}{% endcomment %}') assert_template_result('', '{%comment%}{% endif %}{%endcomment%}') - assert_template_result('', '{%comment%}{% end %}{%endcomment%}') assert_template_result('', '{% comment %}{% endwhatever %}{% endcomment %}') assert_template_result('', '{% comment %}{% raw %} {{%%%%}} }} { {% endcomment %} {% comment {% endraw %} {% endcomment %}') assert_template_result('', '{% comment %}{% " %}{% endcomment %}') From 504b1e7971fc79c269b1c8ba82b2466828a5d3c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20S=C3=B8gaard?= <9662430+andershagbard@users.noreply.github.com> Date: Sat, 11 Oct 2025 00:01:41 +0200 Subject: [PATCH 3/5] Handle boolean values in sort filter comparison Updated nil_safe_compare to treat booleans consistently during sorting. Added tests to verify correct sorting of arrays containing boolean values and nils. --- lib/liquid/standardfilters.rb | 7 +++++++ test/integration/standard_filter_test.rb | 2 ++ 2 files changed, 9 insertions(+) diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb index 661235a9d..8152685cf 100644 --- a/lib/liquid/standardfilters.rb +++ b/lib/liquid/standardfilters.rb @@ -911,6 +911,9 @@ def apply_operation(input, operand, operation) end def nil_safe_compare(a, b) + a = a ? 0 : 1 if boolean?(a) + b = b ? 0 : 1 if boolean?(b) + result = a <=> b if result @@ -932,6 +935,10 @@ def nil_safe_casecmp(a, b) end end + def boolean?(value) + value.is_a?(TrueClass) || value.is_a?(FalseClass) + end + class InputIterator include Enumerable diff --git a/test/integration/standard_filter_test.rb b/test/integration/standard_filter_test.rb index b2405f7f8..e82ab92b8 100644 --- a/test/integration/standard_filter_test.rb +++ b/test/integration/standard_filter_test.rb @@ -263,11 +263,13 @@ def test_join def test_sort assert_equal([1, 2, 3, 4], @filters.sort([4, 3, 2, 1])) assert_equal([{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }], @filters.sort([{ "a" => 4 }, { "a" => 3 }, { "a" => 1 }, { "a" => 2 }], "a")) + assert_equal([{ "a" => true }, { "a" => true }, { "a" => false }, { "a" => false }], @filters.sort([{ "a" => true }, { "a" => false }, { "a" => true }, { "a" => false }], "a")) end def test_sort_with_nils assert_equal([1, 2, 3, 4, nil], @filters.sort([nil, 4, 3, 2, 1])) assert_equal([{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }, {}], @filters.sort([{ "a" => 4 }, { "a" => 3 }, {}, { "a" => 1 }, { "a" => 2 }], "a")) + assert_equal([{ "a" => true }, { "a" => true }, { "a" => false }, { "a" => false }, {}], @filters.sort([{ "a" => true }, {}, { "a" => false }, { "a" => true }, { "a" => false }], "a")) end def test_sort_when_property_is_sometimes_missing_puts_nils_last From b31f9cfea8b0921c0e04a3ff5e09812553cb8979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20S=C3=B8gaard?= <9662430+andershagbard@users.noreply.github.com> Date: Sat, 11 Oct 2025 00:07:41 +0200 Subject: [PATCH 4/5] Remove trailing white space --- lib/liquid/standardfilters.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb index 56c20cb65..9943363e5 100644 --- a/lib/liquid/standardfilters.rb +++ b/lib/liquid/standardfilters.rb @@ -1006,8 +1006,8 @@ def apply_operation(input, operand, operation) end def nil_safe_compare(a, b) - a = a ? 0 : 1 if boolean?(a) - b = b ? 0 : 1 if boolean?(b) + a = a ? 0 : 1 if boolean?(a) + b = b ? 0 : 1 if boolean?(b) result = a <=> b From 1b35d3e47ab418de8b00807e70facf0b9d29888c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20S=C3=B8gaard?= <9662430+andershagbard@users.noreply.github.com> Date: Sat, 11 Oct 2025 11:44:41 +0200 Subject: [PATCH 5/5] Sort false values first --- lib/liquid/standardfilters.rb | 4 ++-- test/integration/standard_filter_test.rb | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb index 9943363e5..5b60e7d7a 100644 --- a/lib/liquid/standardfilters.rb +++ b/lib/liquid/standardfilters.rb @@ -1006,8 +1006,8 @@ def apply_operation(input, operand, operation) end def nil_safe_compare(a, b) - a = a ? 0 : 1 if boolean?(a) - b = b ? 0 : 1 if boolean?(b) + a = a ? 1 : 0 if boolean?(a) + b = b ? 1 : 0 if boolean?(b) result = a <=> b diff --git a/test/integration/standard_filter_test.rb b/test/integration/standard_filter_test.rb index 9ae56738a..455dacaa8 100644 --- a/test/integration/standard_filter_test.rb +++ b/test/integration/standard_filter_test.rb @@ -305,14 +305,15 @@ def to_liquid def test_sort assert_equal([1, 2, 3, 4], @filters.sort([4, 3, 2, 1])) + assert_equal([false, false, true, true], @filters.sort([true, false, true, false])) assert_equal([{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }], @filters.sort([{ "a" => 4 }, { "a" => 3 }, { "a" => 1 }, { "a" => 2 }], "a")) - assert_equal([{ "a" => true }, { "a" => true }, { "a" => false }, { "a" => false }], @filters.sort([{ "a" => true }, { "a" => false }, { "a" => true }, { "a" => false }], "a")) + assert_equal([{ "a" => false }, { "a" => false }, { "a" => true }, { "a" => true }], @filters.sort([{ "a" => true }, { "a" => false }, { "a" => true }, { "a" => false }], "a")) end def test_sort_with_nils assert_equal([1, 2, 3, 4, nil], @filters.sort([nil, 4, 3, 2, 1])) assert_equal([{ "a" => 1 }, { "a" => 2 }, { "a" => 3 }, { "a" => 4 }, {}], @filters.sort([{ "a" => 4 }, { "a" => 3 }, {}, { "a" => 1 }, { "a" => 2 }], "a")) - assert_equal([{ "a" => true }, { "a" => true }, { "a" => false }, { "a" => false }, {}], @filters.sort([{ "a" => true }, {}, { "a" => false }, { "a" => true }, { "a" => false }], "a")) + assert_equal([{ "a" => false }, { "a" => false }, { "a" => true }, { "a" => true }, {}], @filters.sort([{ "a" => true }, {}, { "a" => false }, { "a" => true }, { "a" => false }], "a")) end def test_sort_when_property_is_sometimes_missing_puts_nils_last