From 25bc833b4d40e14464a4205b4c506e0a96298fb5 Mon Sep 17 00:00:00 2001 From: Dylan Thacker-Smith Date: Tue, 10 Jan 2023 16:01:57 -0500 Subject: [PATCH] Instrument usage of bug with iteration of String with offset or 0 limit --- lib/liquid/utils.rb | 6 +++++- test/unit/tags/for_tag_unit_test.rb | 30 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/lib/liquid/utils.rb b/lib/liquid/utils.rb index 38a406ef2..4ec7d8117 100644 --- a/lib/liquid/utils.rb +++ b/lib/liquid/utils.rb @@ -16,7 +16,11 @@ def self.slice_collection_using_each(collection, from, to) # Maintains Ruby 1.8.7 String#each behaviour on 1.9 if collection.is_a?(String) - return collection.empty? ? [] : [collection] + return [] if collection.empty? + if from > 0 || to == 0 + Usage.increment("string_slice_bug") + end + return [collection] end return [] unless collection.respond_to?(:each) diff --git a/test/unit/tags/for_tag_unit_test.rb b/test/unit/tags/for_tag_unit_test.rb index 5a52c71c7..cbb68fcb0 100644 --- a/test/unit/tags/for_tag_unit_test.rb +++ b/test/unit/tags/for_tag_unit_test.rb @@ -12,4 +12,34 @@ def test_for_else_nodelist template = Liquid::Template.parse('{% for item in items %}FOR{% else %}ELSE{% endfor %}') assert_equal(['FOR', 'ELSE'], template.root.nodelist[0].nodelist.map(&:nodelist).flatten) end + + def test_for_string_slice_bug_usage + template = Liquid::Template.parse("{% for x in str, offset: 1 %}{{ x }},{% endfor %}") + assert_usage("string_slice_bug") do + assert_equal("abc,", template.render({ "str" => "abc" })) + end + end + + def test_for_string_0_limit_usage + template = Liquid::Template.parse("{% for x in str, limit: 0 %}{{ x }},{% endfor %}") + assert_usage("string_slice_bug") do + assert_equal("abc,", template.render({ "str" => "abc" })) + end + end + + def test_for_string_no_slice_usage + template = Liquid::Template.parse("{% for x in str, offset: 0, limit: 1 %}{{ x }},{% endfor %}") + assert_usage("string_slice_bug", times: 0) do + assert_equal("abc,", template.render({ "str" => "abc" })) + end + end + + private + + def assert_usage(name, times: 1, &block) + count = 0 + result = Liquid::Usage.stub(:increment, ->(n) { count += 1 if n == name }, &block) + assert_equal(times, count) + result + end end