Skip to content

Commit f12b7e6

Browse files
Copilotkorny
andcommitted
Fix incomplete string escaping in HTML encoder begin_line method
Co-authored-by: korny <1037292+korny@users.noreply.github.com>
1 parent aec5b10 commit f12b7e6

File tree

2 files changed

+81
-1
lines changed

2 files changed

+81
-1
lines changed

lib/coderay/encoders/html.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ def begin_line kind
249249
if style['class="']
250250
@out << style.sub('class="', 'class="line ')
251251
else
252-
@out << style.sub('>', ' class="line">')
252+
@out << style.sub(/>\s*\z/, ' class="line">')
253253
end
254254
else
255255
@out << '<span class="line">'

test/unit/html_escaping.rb

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
require 'test/unit'
2+
require 'coderay'
3+
4+
class HtmlEscapingTest < Test::Unit::TestCase
5+
6+
def test_begin_line_with_greater_than_in_attributes
7+
# Test that begin_line correctly handles '>' characters in HTML attributes
8+
# This addresses issue #263: Incomplete string escaping or encoding
9+
10+
encoder = CodeRay::Encoders::HTML.new
11+
encoder.instance_variable_set(:@out, '')
12+
encoder.instance_variable_set(:@opened, [])
13+
encoder.instance_variable_set(:@span_for_kinds, {
14+
# Simulate a span with '>' characters in title attribute
15+
:test => '<span title="value > other" class="keyword">'
16+
})
17+
18+
# Call begin_line which should add class="line" without breaking the title attribute
19+
encoder.send(:begin_line, :test)
20+
21+
result = encoder.instance_variable_get(:@out)
22+
23+
# The result should have class="line" added to the existing class attribute
24+
# and should NOT have corrupted the title attribute
25+
assert_equal '<span title="value > other" class="line keyword">', result
26+
assert result.include?('title="value > other"'), "Title attribute should remain intact"
27+
assert result.include?('class="line keyword"'), "Class should be properly updated"
28+
end
29+
30+
def test_begin_line_without_existing_class
31+
# Test begin_line when the span doesn't have a class attribute
32+
33+
encoder = CodeRay::Encoders::HTML.new
34+
encoder.instance_variable_set(:@out, '')
35+
encoder.instance_variable_set(:@opened, [])
36+
encoder.instance_variable_set(:@span_for_kinds, {
37+
# Span with '>' in attribute but no class
38+
:test => '<span title="a > b > c" data-info="x > y">'
39+
})
40+
41+
encoder.send(:begin_line, :test)
42+
result = encoder.instance_variable_get(:@out)
43+
44+
# Should add class="line" at the end, preserving all existing attributes
45+
assert_equal '<span title="a > b > c" data-info="x > y" class="line">', result
46+
assert result.include?('title="a > b > c"'), "Title attribute should remain intact"
47+
assert result.include?('data-info="x > y"'), "Data attribute should remain intact"
48+
assert result.include?('class="line"'), "Line class should be added"
49+
end
50+
51+
def test_begin_line_normal_case
52+
# Test the normal case without special characters
53+
54+
encoder = CodeRay::Encoders::HTML.new
55+
encoder.instance_variable_set(:@out, '')
56+
encoder.instance_variable_set(:@opened, [])
57+
encoder.instance_variable_set(:@span_for_kinds, {
58+
:test => '<span class="keyword">'
59+
})
60+
61+
encoder.send(:begin_line, :test)
62+
result = encoder.instance_variable_get(:@out)
63+
64+
assert_equal '<span class="line keyword">', result
65+
end
66+
67+
def test_begin_line_no_style
68+
# Test when there's no predefined style for the kind
69+
70+
encoder = CodeRay::Encoders::HTML.new
71+
encoder.instance_variable_set(:@out, '')
72+
encoder.instance_variable_set(:@opened, [])
73+
encoder.instance_variable_set(:@span_for_kinds, {})
74+
75+
encoder.send(:begin_line, :unknown_kind)
76+
result = encoder.instance_variable_get(:@out)
77+
78+
assert_equal '<span class="line">', result
79+
end
80+
end

0 commit comments

Comments
 (0)