From aec5b104ce2c9c120cd4fa30fe4b01295d6d90c5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Sep 2025 17:58:40 +0000 Subject: [PATCH 1/2] Initial plan From f12b7e61242469ec0c7e205a1f38a03f5c15c9c4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Sep 2025 18:09:06 +0000 Subject: [PATCH 2/2] Fix incomplete string escaping in HTML encoder begin_line method Co-authored-by: korny <1037292+korny@users.noreply.github.com> --- lib/coderay/encoders/html.rb | 2 +- test/unit/html_escaping.rb | 80 ++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 test/unit/html_escaping.rb diff --git a/lib/coderay/encoders/html.rb b/lib/coderay/encoders/html.rb index 1b33e921..48b8696d 100644 --- a/lib/coderay/encoders/html.rb +++ b/lib/coderay/encoders/html.rb @@ -249,7 +249,7 @@ def begin_line kind if style['class="'] @out << style.sub('class="', 'class="line ') else - @out << style.sub('>', ' class="line">') + @out << style.sub(/>\s*\z/, ' class="line">') end else @out << '' diff --git a/test/unit/html_escaping.rb b/test/unit/html_escaping.rb new file mode 100644 index 00000000..7b4c8640 --- /dev/null +++ b/test/unit/html_escaping.rb @@ -0,0 +1,80 @@ +require 'test/unit' +require 'coderay' + +class HtmlEscapingTest < Test::Unit::TestCase + + def test_begin_line_with_greater_than_in_attributes + # Test that begin_line correctly handles '>' characters in HTML attributes + # This addresses issue #263: Incomplete string escaping or encoding + + encoder = CodeRay::Encoders::HTML.new + encoder.instance_variable_set(:@out, '') + encoder.instance_variable_set(:@opened, []) + encoder.instance_variable_set(:@span_for_kinds, { + # Simulate a span with '>' characters in title attribute + :test => '' + }) + + # Call begin_line which should add class="line" without breaking the title attribute + encoder.send(:begin_line, :test) + + result = encoder.instance_variable_get(:@out) + + # The result should have class="line" added to the existing class attribute + # and should NOT have corrupted the title attribute + assert_equal '', result + assert result.include?('title="value > other"'), "Title attribute should remain intact" + assert result.include?('class="line keyword"'), "Class should be properly updated" + end + + def test_begin_line_without_existing_class + # Test begin_line when the span doesn't have a class attribute + + encoder = CodeRay::Encoders::HTML.new + encoder.instance_variable_set(:@out, '') + encoder.instance_variable_set(:@opened, []) + encoder.instance_variable_set(:@span_for_kinds, { + # Span with '>' in attribute but no class + :test => '' + }) + + encoder.send(:begin_line, :test) + result = encoder.instance_variable_get(:@out) + + # Should add class="line" at the end, preserving all existing attributes + assert_equal '', result + assert result.include?('title="a > b > c"'), "Title attribute should remain intact" + assert result.include?('data-info="x > y"'), "Data attribute should remain intact" + assert result.include?('class="line"'), "Line class should be added" + end + + def test_begin_line_normal_case + # Test the normal case without special characters + + encoder = CodeRay::Encoders::HTML.new + encoder.instance_variable_set(:@out, '') + encoder.instance_variable_set(:@opened, []) + encoder.instance_variable_set(:@span_for_kinds, { + :test => '' + }) + + encoder.send(:begin_line, :test) + result = encoder.instance_variable_get(:@out) + + assert_equal '', result + end + + def test_begin_line_no_style + # Test when there's no predefined style for the kind + + encoder = CodeRay::Encoders::HTML.new + encoder.instance_variable_set(:@out, '') + encoder.instance_variable_set(:@opened, []) + encoder.instance_variable_set(:@span_for_kinds, {}) + + encoder.send(:begin_line, :unknown_kind) + result = encoder.instance_variable_get(:@out) + + assert_equal '', result + end +end \ No newline at end of file