simple-rss 1.3.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,56 @@
1
+ require_relative "../test_helper"
2
+ require "timeout"
3
+
4
+ class EmptyTagTest < Test::Unit::TestCase
5
+ def setup
6
+ @rss20 = SimpleRSS.parse(open(File.dirname(__FILE__) + "/../data/rss20.xml"))
7
+ end
8
+
9
+ def test_empty_item_tag_does_not_hang
10
+ # Reproduces issue #16: 100% cpu and hanging process on blank item tag
11
+ # Adding an empty tag should not cause regex catastrophic backtracking
12
+ original_tags = SimpleRSS.item_tags.dup
13
+
14
+ begin
15
+ SimpleRSS.item_tags << :""
16
+
17
+ # This should complete quickly, not hang
18
+ Timeout.timeout(5) do
19
+ rss = SimpleRSS.parse(open(File.dirname(__FILE__) + "/../data/rss20.xml"))
20
+ assert_not_nil rss.items
21
+ end
22
+ ensure
23
+ SimpleRSS.item_tags.replace(original_tags)
24
+ end
25
+ end
26
+
27
+ def test_blank_item_tag_does_not_hang
28
+ original_tags = SimpleRSS.item_tags.dup
29
+
30
+ begin
31
+ SimpleRSS.item_tags << :" "
32
+
33
+ Timeout.timeout(5) do
34
+ rss = SimpleRSS.parse(open(File.dirname(__FILE__) + "/../data/rss20.xml"))
35
+ assert_not_nil rss.items
36
+ end
37
+ ensure
38
+ SimpleRSS.item_tags.replace(original_tags)
39
+ end
40
+ end
41
+
42
+ def test_empty_feed_tag_does_not_hang
43
+ original_tags = SimpleRSS.feed_tags.dup
44
+
45
+ begin
46
+ SimpleRSS.feed_tags << :""
47
+
48
+ Timeout.timeout(5) do
49
+ rss = SimpleRSS.parse(open(File.dirname(__FILE__) + "/../data/rss20.xml"))
50
+ assert_not_nil rss.channel
51
+ end
52
+ ensure
53
+ SimpleRSS.feed_tags.replace(original_tags)
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,87 @@
1
+ require_relative "../test_helper"
2
+
3
+ class EncodingTest < Test::Unit::TestCase
4
+ def test_strings_are_utf8_encoded
5
+ rss = SimpleRSS.parse(open(File.dirname(__FILE__) + "/../data/rss20.xml"))
6
+
7
+ assert_equal Encoding::UTF_8, rss.title.encoding
8
+ assert_equal Encoding::UTF_8, rss.link.encoding
9
+ assert_equal Encoding::UTF_8, rss.description.encoding
10
+ end
11
+
12
+ def test_strings_without_percent_are_utf8_encoded
13
+ # Issue #28: strings without '%' were returning ASCII-8BIT
14
+ rss = SimpleRSS.parse(open(File.dirname(__FILE__) + "/../data/rss20.xml"))
15
+
16
+ rss.items.each do |item|
17
+ assert_equal Encoding::UTF_8, item.title.encoding, "Item title should be UTF-8"
18
+ assert_equal Encoding::UTF_8, item.link.encoding, "Item link should be UTF-8"
19
+ end
20
+ end
21
+
22
+ def test_utf8_content_preserved
23
+ rss = SimpleRSS.parse(open(File.dirname(__FILE__) + "/../data/rss20_utf8.xml"))
24
+
25
+ assert_equal Encoding::UTF_8, rss.title.encoding
26
+ # Verify UTF-8 characters are preserved
27
+ assert(rss.items.any? { |item| item.title && item.title.encoding == Encoding::UTF_8 })
28
+ end
29
+
30
+ def test_ascii_8bit_source_normalized_to_utf8
31
+ # Issue #28: when source is ASCII-8BIT, output should still be UTF-8
32
+ xml = <<~XML.b # .b forces ASCII-8BIT encoding
33
+ <?xml version="1.0"?>
34
+ <rss version="2.0">
35
+ <channel>
36
+ <title>Test Feed</title>
37
+ <link>http://example.com</link>
38
+ <description>A test feed</description>
39
+ <item>
40
+ <title>Test Item</title>
41
+ <link>http://example.com/item</link>
42
+ </item>
43
+ </channel>
44
+ </rss>
45
+ XML
46
+
47
+ assert_equal Encoding::ASCII_8BIT, xml.encoding, "Source should be ASCII-8BIT"
48
+
49
+ rss = SimpleRSS.parse(xml)
50
+
51
+ assert_equal Encoding::UTF_8, rss.title.encoding, "Title should be UTF-8"
52
+ assert_equal Encoding::UTF_8, rss.link.encoding, "Link should be UTF-8"
53
+ assert_equal Encoding::UTF_8, rss.items.first.title.encoding, "Item title should be UTF-8"
54
+ end
55
+
56
+ def test_consistent_encoding_with_and_without_percent
57
+ # Issue #28: CGI.unescape returns UTF-8, but without '%' we got ASCII-8BIT
58
+ xml_with_percent = <<~XML.b
59
+ <?xml version="1.0"?>
60
+ <rss version="2.0">
61
+ <channel>
62
+ <title>Test%20Feed</title>
63
+ <link>http://example.com</link>
64
+ <description>Test</description>
65
+ </channel>
66
+ </rss>
67
+ XML
68
+
69
+ xml_without_percent = <<~XML.b
70
+ <?xml version="1.0"?>
71
+ <rss version="2.0">
72
+ <channel>
73
+ <title>Test Feed</title>
74
+ <link>http://example.com</link>
75
+ <description>Test</description>
76
+ </channel>
77
+ </rss>
78
+ XML
79
+
80
+ rss_with = SimpleRSS.parse(xml_with_percent)
81
+ rss_without = SimpleRSS.parse(xml_without_percent)
82
+
83
+ assert_equal rss_with.title.encoding, rss_without.title.encoding,
84
+ "Encoding should be consistent regardless of '%' in content"
85
+ assert_equal Encoding::UTF_8, rss_without.title.encoding
86
+ end
87
+ end
@@ -0,0 +1,26 @@
1
+ require "test_helper"
2
+
3
+ class FeedAttributesTest < Test::Unit::TestCase
4
+ def setup
5
+ # Add feed attribute tags before parsing
6
+ SimpleRSS.feed_tags << :"channel#custom:version"
7
+ SimpleRSS.feed_tags << :"feed#app:id"
8
+
9
+ @rss20 = SimpleRSS.parse open(File.dirname(__FILE__) + "/../data/rss20_with_channel_attrs.xml")
10
+ @atom = SimpleRSS.parse open(File.dirname(__FILE__) + "/../data/atom_with_feed_attrs.xml")
11
+ end
12
+
13
+ def teardown
14
+ # Clean up added tags
15
+ SimpleRSS.feed_tags.delete(:"channel#custom:version")
16
+ SimpleRSS.feed_tags.delete(:"feed#app:id")
17
+ end
18
+
19
+ def test_rss20_channel_attribute
20
+ assert_equal "2.0", @rss20.channel_custom_version
21
+ end
22
+
23
+ def test_atom_feed_attribute
24
+ assert_equal "12345", @atom.feed_app_id
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ require "test_helper"
2
+
3
+ class ItemAttributesTest < Test::Unit::TestCase
4
+ def setup
5
+ # Add item/entry attribute tags before parsing
6
+ SimpleRSS.item_tags << :"entry#custom:id"
7
+ SimpleRSS.item_tags << :"item#data-id"
8
+
9
+ @atom = SimpleRSS.parse open(File.dirname(__FILE__) + "/../data/atom_with_entry_attrs.xml")
10
+ @rss20 = SimpleRSS.parse open(File.dirname(__FILE__) + "/../data/rss20_with_item_attrs.xml")
11
+ end
12
+
13
+ def teardown
14
+ # Clean up added tags
15
+ SimpleRSS.item_tags.delete(:"entry#custom:id")
16
+ SimpleRSS.item_tags.delete(:"item#data-id")
17
+ end
18
+
19
+ def test_atom_entry_attribute
20
+ assert_equal "12345", @atom.entries.first[:entry_custom_id]
21
+ end
22
+
23
+ def test_rss20_item_attribute
24
+ assert_equal "67890", @rss20.items.first[:"item_data-id"]
25
+ end
26
+ end
@@ -0,0 +1,13 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <feed xmlns="http://www.w3.org/2005/Atom" xmlns:custom="http://example.org/custom">
3
+ <title type="text">Test Feed</title>
4
+ <updated>2005-07-31T12:29:29Z</updated>
5
+ <id>tag:example.org,2003:3</id>
6
+ <link rel="alternate" type="text/html" href="http://example.org/"/>
7
+ <entry custom:id="12345">
8
+ <title>Test Entry</title>
9
+ <link rel="alternate" type="text/html" href="http://example.org/entry/1"/>
10
+ <id>tag:example.org,2003:3.2397</id>
11
+ <updated>2005-07-31T12:29:29Z</updated>
12
+ </entry>
13
+ </feed>
@@ -0,0 +1,13 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <feed xmlns="http://www.w3.org/2005/Atom" xmlns:app="http://example.org/app" app:id="12345">
3
+ <title type="text">Test Feed</title>
4
+ <updated>2005-07-31T12:29:29Z</updated>
5
+ <id>tag:example.org,2003:3</id>
6
+ <link rel="alternate" type="text/html" href="http://example.org/"/>
7
+ <entry>
8
+ <title>Test Entry</title>
9
+ <link rel="alternate" type="text/html" href="http://example.org/entry/1"/>
10
+ <id>tag:example.org,2003:3.2397</id>
11
+ <updated>2005-07-31T12:29:29Z</updated>
12
+ </entry>
13
+ </feed>