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.
- checksums.yaml +4 -4
- data/LICENSE +79 -7
- data/README.markdown +1 -1
- data/Rakefile +134 -136
- data/lib/simple-rss.rb +273 -154
- data/simple-rss.gemspec +4 -5
- data/test/base/array_tags_test.rb +37 -0
- data/test/base/base_test.rb +76 -77
- data/test/base/empty_tag_test.rb +56 -0
- data/test/base/encoding_test.rb +87 -0
- data/test/base/feed_attributes_test.rb +26 -0
- data/test/base/item_attributes_test.rb +26 -0
- data/test/data/atom_with_entry_attrs.xml +13 -0
- data/test/data/atom_with_feed_attrs.xml +13 -0
- data/test/data/media_rss.xml +465 -0
- data/test/data/rss20_utf8.xml +61 -0
- data/test/data/rss20_with_channel_attrs.xml +13 -0
- data/test/data/rss20_with_item_attrs.xml +13 -0
- data/test/test_helper.rb +10 -3
- metadata +14 -8
- data/install.rb +0 -40
|
@@ -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>
|