thehack-atom-tools 2.0.3
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.
- data/COPYING +18 -0
- data/README +65 -0
- data/Rakefile +87 -0
- data/bin/atom-cp +159 -0
- data/bin/atom-grep +78 -0
- data/bin/atom-post +72 -0
- data/bin/atom-purge +82 -0
- data/lib/atom/cache.rb +178 -0
- data/lib/atom/collection.rb +125 -0
- data/lib/atom/element.rb +640 -0
- data/lib/atom/entry.rb +134 -0
- data/lib/atom/feed.rb +223 -0
- data/lib/atom/http.rb +417 -0
- data/lib/atom/service.rb +106 -0
- data/lib/atom/text.rb +231 -0
- data/lib/atom/tools.rb +163 -0
- data/setup.rb +1585 -0
- data/test/conformance/order.rb +118 -0
- data/test/conformance/title.rb +108 -0
- data/test/conformance/updated.rb +34 -0
- data/test/conformance/xhtmlcontentdiv.rb +18 -0
- data/test/conformance/xmlnamespace.rb +54 -0
- data/test/runtests.rb +14 -0
- data/test/test_constructs.rb +161 -0
- data/test/test_feed.rb +134 -0
- data/test/test_general.rb +72 -0
- data/test/test_http.rb +323 -0
- data/test/test_protocol.rb +168 -0
- data/test/test_xml.rb +445 -0
- metadata +83 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
require "test/unit"
|
|
2
|
+
|
|
3
|
+
require "atom/service"
|
|
4
|
+
|
|
5
|
+
class FakeHTTP
|
|
6
|
+
Response = Struct.new(:body, :code, :content_type)
|
|
7
|
+
|
|
8
|
+
def initialize table
|
|
9
|
+
@table = table
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def get url, headers = {}
|
|
13
|
+
res = Response.new
|
|
14
|
+
|
|
15
|
+
data = @table[url.to_s]
|
|
16
|
+
|
|
17
|
+
res.body = data[1]
|
|
18
|
+
res.code = 200.to_s
|
|
19
|
+
res.content_type = data[0]
|
|
20
|
+
|
|
21
|
+
def res.validate_content_type valid; valid.member? content_type; end
|
|
22
|
+
|
|
23
|
+
res
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
class AtomProtocolTest < Test::Unit::TestCase
|
|
28
|
+
def test_introspection
|
|
29
|
+
doc = <<END
|
|
30
|
+
<service xmlns="http://www.w3.org/2007/app"
|
|
31
|
+
xmlns:atom="http://www.w3.org/2005/Atom">
|
|
32
|
+
<workspace>
|
|
33
|
+
<atom:title>My Blog</atom:title>
|
|
34
|
+
<collection href="http://example.org/myblog/entries">
|
|
35
|
+
<atom:title>Entries</atom:title>
|
|
36
|
+
</collection>
|
|
37
|
+
<collection href="http://example.org/myblog/fotes">
|
|
38
|
+
<atom:title>Photos</atom:title>
|
|
39
|
+
<accept>image/*</accept>
|
|
40
|
+
</collection>
|
|
41
|
+
</workspace>
|
|
42
|
+
</service>
|
|
43
|
+
END
|
|
44
|
+
|
|
45
|
+
service = Atom::Service.parse doc
|
|
46
|
+
|
|
47
|
+
ws = service.workspaces.first
|
|
48
|
+
assert_equal "My Blog", ws.title.to_s
|
|
49
|
+
|
|
50
|
+
coll = ws.collections.first
|
|
51
|
+
assert_equal "http://example.org/myblog/entries", coll.href
|
|
52
|
+
assert_equal "Entries", coll.title.to_s
|
|
53
|
+
assert_equal ["application/atom+xml;type=entry"], coll.accepts
|
|
54
|
+
|
|
55
|
+
coll = ws.collections.last
|
|
56
|
+
assert_equal "http://example.org/myblog/fotes", coll.href
|
|
57
|
+
assert_equal "Photos", coll.title.to_s
|
|
58
|
+
assert_equal ["image/*"], coll.accepts
|
|
59
|
+
|
|
60
|
+
http = service.instance_variable_get(:@http)
|
|
61
|
+
assert_instance_of Atom::HTTP, http
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def test_write_introspection
|
|
65
|
+
service = Atom::Service.new
|
|
66
|
+
|
|
67
|
+
ws = service.workspaces.new
|
|
68
|
+
|
|
69
|
+
ws.title = "Workspace 1"
|
|
70
|
+
|
|
71
|
+
coll = Atom::Collection.new "http://example.org/entries"
|
|
72
|
+
coll.title = "Entries"
|
|
73
|
+
ws.collections << coll
|
|
74
|
+
|
|
75
|
+
coll = Atom::Collection.new "http://example.org/audio"
|
|
76
|
+
coll.title = "Audio"
|
|
77
|
+
coll.accepts = ["audio/*"]
|
|
78
|
+
ws.collections << coll
|
|
79
|
+
|
|
80
|
+
nses = { "app" => Atom::PP_NS, "atom" => Atom::NS }
|
|
81
|
+
|
|
82
|
+
doc = REXML::Document.new(service.to_s)
|
|
83
|
+
|
|
84
|
+
assert_equal "http://www.w3.org/2007/app", doc.root.namespace
|
|
85
|
+
|
|
86
|
+
ws = REXML::XPath.first( doc.root,
|
|
87
|
+
"/app:service/app:workspace",
|
|
88
|
+
nses )
|
|
89
|
+
|
|
90
|
+
title = REXML::XPath.first( ws, "./atom:title", nses)
|
|
91
|
+
|
|
92
|
+
assert_equal "Workspace 1", title.text
|
|
93
|
+
assert_equal "http://www.w3.org/2005/Atom", title.namespace
|
|
94
|
+
|
|
95
|
+
colls = REXML::XPath.match( ws, "./app:collection", nses)
|
|
96
|
+
assert_equal(2, colls.length)
|
|
97
|
+
|
|
98
|
+
entries = colls.first
|
|
99
|
+
|
|
100
|
+
assert_equal "http://example.org/entries", entries.attributes["href"]
|
|
101
|
+
|
|
102
|
+
title = REXML::XPath.first(entries, "./atom:title", nses)
|
|
103
|
+
assert_equal "Entries", title.text
|
|
104
|
+
|
|
105
|
+
accepts = REXML::XPath.first(entries, "./app:accept", nses)
|
|
106
|
+
assert_nil accepts
|
|
107
|
+
|
|
108
|
+
audio = colls.last
|
|
109
|
+
|
|
110
|
+
assert_equal "http://example.org/audio", audio.attributes["href"]
|
|
111
|
+
|
|
112
|
+
title = REXML::XPath.first(audio, "./atom:title", nses)
|
|
113
|
+
assert_equal "Audio", title.text
|
|
114
|
+
|
|
115
|
+
accepts = REXML::XPath.first(audio, "./app:accept", nses)
|
|
116
|
+
assert_equal "audio/*", accepts.text
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def test_dont_specify_http_object
|
|
120
|
+
collection = Atom::Collection.new("http://necronomicorp.com/testatom?atom")
|
|
121
|
+
|
|
122
|
+
assert_instance_of Atom::HTTP, collection.instance_variable_get("@http")
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def test_autodiscover_service_link
|
|
126
|
+
http = FakeHTTP.new \
|
|
127
|
+
'http://example.org/' => [ 'text/html', '<html><link rel="service" href="svc">' ],
|
|
128
|
+
'http://example.org/xhtml' => [ 'text/html', '<html><head><link rel="service" href="svc"/></head></html>' ],
|
|
129
|
+
'http://example.org/svc' => [ 'application/atomsvc+xml', '<service xmlns="http://www.w3.org/2007/app"/>' ]
|
|
130
|
+
|
|
131
|
+
svc = Atom::Service.discover 'http://example.org/', http
|
|
132
|
+
assert_instance_of Atom::Service, svc
|
|
133
|
+
|
|
134
|
+
svc = Atom::Service.discover 'http://example.org/xhtml', http
|
|
135
|
+
assert_instance_of Atom::Service, svc
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def test_autodiscover_rsd
|
|
139
|
+
http = FakeHTTP.new \
|
|
140
|
+
'http://example.org/' => [ 'text/html', '<html><link rel="EditURI" href="rsd">' ],
|
|
141
|
+
'http://example.org/svc' => [ 'application/atomsvc+xml', '<service xmlns="http://www.w3.org/2007/app"/>' ],
|
|
142
|
+
'http://example.org/rsd' => [ 'text/xml', '<rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd"><service><apis><api name="Atom" apiLink="svc" /></apis></service></rsd>' ]
|
|
143
|
+
|
|
144
|
+
svc = Atom::Service.discover 'http://example.org/', http
|
|
145
|
+
assert_instance_of Atom::Service, svc
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def test_autodiscover_conneg
|
|
149
|
+
http = FakeHTTP.new \
|
|
150
|
+
'http://example.org/svc' => [ 'application/atomsvc+xml', '<service xmlns="http://www.w3.org/2007/app"/>' ]
|
|
151
|
+
|
|
152
|
+
svc = Atom::Service.discover 'http://example.org/svc', http
|
|
153
|
+
assert_instance_of Atom::Service, svc
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def test_cant_autodiscover
|
|
157
|
+
http = FakeHTTP.new 'http://example.org/h' => [ 'text/html', '<html>' ],
|
|
158
|
+
'http://example.org/t' => [ 'text/plain', 'no joy.' ]
|
|
159
|
+
|
|
160
|
+
assert_raises Atom::AutodiscoveryFailure do
|
|
161
|
+
Atom::Service.discover 'http://example.org/h', http
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
assert_raises Atom::AutodiscoveryFailure do
|
|
165
|
+
Atom::Service.discover 'http://example.org/t', http
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
data/test/test_xml.rb
ADDED
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
$:.unshift 'lib/', File.dirname(__FILE__) + '/../lib'
|
|
2
|
+
require "test/unit"
|
|
3
|
+
require "atom/service"
|
|
4
|
+
|
|
5
|
+
class AtomTest < Test::Unit::TestCase
|
|
6
|
+
def test_text_type_text
|
|
7
|
+
entry = get_entry
|
|
8
|
+
|
|
9
|
+
entry.title = "Let's talk about <html>"
|
|
10
|
+
assert_equal("text", entry.title["type"])
|
|
11
|
+
|
|
12
|
+
assert_match('<', entry.title.xml.to_s)
|
|
13
|
+
|
|
14
|
+
xml = entry.to_xml
|
|
15
|
+
|
|
16
|
+
b = Atom::Entry.parse(xml).to_s
|
|
17
|
+
|
|
18
|
+
base_check xml
|
|
19
|
+
|
|
20
|
+
assert_equal("Let's talk about <html>", xml.elements["title"].text)
|
|
21
|
+
|
|
22
|
+
assert_match('<', entry.to_s)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def test_text_type_html
|
|
26
|
+
entry = get_entry
|
|
27
|
+
|
|
28
|
+
entry.title = "Atom-drunk pirates<br>run amok!"
|
|
29
|
+
entry.title["type"] = "html"
|
|
30
|
+
|
|
31
|
+
xml = get_elements entry
|
|
32
|
+
|
|
33
|
+
assert_equal("Atom-drunk pirates<br>run amok!", xml.elements["title"].text)
|
|
34
|
+
assert_equal("html", xml.elements["title"].attributes["type"])
|
|
35
|
+
|
|
36
|
+
assert_match('<', entry.to_s)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def test_text_type_xhtml
|
|
40
|
+
entry = get_entry
|
|
41
|
+
|
|
42
|
+
entry.title = "Atom-drunk pirates <em>run amok</em>!"
|
|
43
|
+
entry.title["type"] = "xhtml"
|
|
44
|
+
|
|
45
|
+
xml = get_elements entry
|
|
46
|
+
|
|
47
|
+
assert_equal(XHTML::NS, xml.elements["title/div"].namespace)
|
|
48
|
+
assert_equal("run amok", xml.elements["title/div/em"].text)
|
|
49
|
+
|
|
50
|
+
assert_match('<em>', entry.to_s)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def test_html_text_with_entities
|
|
54
|
+
entry = get_entry
|
|
55
|
+
|
|
56
|
+
entry.title = "Atoms discovered to be smaller than 1μm"
|
|
57
|
+
entry.title["type"] = "html"
|
|
58
|
+
|
|
59
|
+
assert_match(/&mu;/, entry.to_s)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def test_author
|
|
63
|
+
entry = get_entry
|
|
64
|
+
a = entry.authors.new
|
|
65
|
+
|
|
66
|
+
a.name= "Brendan Taylor"
|
|
67
|
+
a.uri = "http://necronomicorp.com/blog/"
|
|
68
|
+
|
|
69
|
+
xml = get_elements entry
|
|
70
|
+
|
|
71
|
+
assert_equal("http://necronomicorp.com/blog/", xml.elements["author/uri"].text)
|
|
72
|
+
assert_equal("Brendan Taylor", xml.elements["author/name"].text)
|
|
73
|
+
assert_nil(xml.elements["author/email"])
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def test_tags
|
|
77
|
+
entry = get_entry
|
|
78
|
+
entry.tag_with "test tags"
|
|
79
|
+
|
|
80
|
+
xml = get_elements entry
|
|
81
|
+
|
|
82
|
+
assert_has_category(xml, "test")
|
|
83
|
+
assert_has_category(xml, "tags")
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def test_updated
|
|
87
|
+
entry = get_entry
|
|
88
|
+
entry.updated = "1970-01-01"
|
|
89
|
+
entry.content = "blah"
|
|
90
|
+
|
|
91
|
+
assert entry.updated.is_a?(Time)
|
|
92
|
+
|
|
93
|
+
xml = entry.to_xml
|
|
94
|
+
|
|
95
|
+
b = Atom::Entry.parse(xml).to_s
|
|
96
|
+
|
|
97
|
+
base_check xml
|
|
98
|
+
|
|
99
|
+
assert_match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/, xml.elements["updated"].text, "atom:updated isn't in xsd:datetime format")
|
|
100
|
+
|
|
101
|
+
entry.updated!
|
|
102
|
+
|
|
103
|
+
assert((Time.parse("1970-01-01") < entry.updated), "<updated/> is not updated")
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def test_edited
|
|
107
|
+
entry = get_entry
|
|
108
|
+
|
|
109
|
+
assert_nil entry.edited
|
|
110
|
+
|
|
111
|
+
entry.edited = "1990-04-07"
|
|
112
|
+
assert entry.edited.is_a?(Time)
|
|
113
|
+
|
|
114
|
+
xml = get_elements entry
|
|
115
|
+
assert_equal(Atom::PP_NS, xml.elements["app:edited"].namespace)
|
|
116
|
+
assert_match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/, xml.elements["app:edited"].text,
|
|
117
|
+
"atom:edited isn't in xsd:datetime format")
|
|
118
|
+
|
|
119
|
+
entry.edited!
|
|
120
|
+
assert((Time.parse("1990-04-07") < entry.edited), "<edited/> is not updated")
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def test_out_of_line
|
|
124
|
+
entry = get_entry
|
|
125
|
+
|
|
126
|
+
entry.content = "this shouldn't appear"
|
|
127
|
+
entry.content["src"] = 'http://example.org/test.png'
|
|
128
|
+
entry.content["type"] = "image/png"
|
|
129
|
+
|
|
130
|
+
xml = get_elements(entry)
|
|
131
|
+
|
|
132
|
+
assert_nil xml.elements["content"].text
|
|
133
|
+
assert_equal("http://example.org/test.png", xml.elements["content"].attributes["src"])
|
|
134
|
+
assert_equal("image/png", xml.elements["content"].attributes["type"])
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def test_extensions
|
|
138
|
+
entry = get_entry
|
|
139
|
+
|
|
140
|
+
assert(entry.extensions.empty?)
|
|
141
|
+
|
|
142
|
+
element = REXML::Element.new("test")
|
|
143
|
+
element.add_namespace "http://purl.org/"
|
|
144
|
+
|
|
145
|
+
entry.extensions << element
|
|
146
|
+
|
|
147
|
+
assert entry.extensions.member?(element)
|
|
148
|
+
|
|
149
|
+
xml = get_elements entry
|
|
150
|
+
|
|
151
|
+
assert_equal(REXML::Element, xml.elements["test"].class)
|
|
152
|
+
assert_equal("http://purl.org/", xml.elements["test"].namespace)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def test_roundtrip_extension
|
|
156
|
+
entry = Atom::Entry.parse("<entry xmlns='http://www.w3.org/2005/Atom' xmlns:nil='http://necronomicorp.com/nil'><nil:ext/></entry>")
|
|
157
|
+
|
|
158
|
+
assert_match(/xmlns:nil='http:\/\/necronomicorp.com\/nil'/, entry.to_s)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def test_app_control
|
|
162
|
+
entry = get_entry
|
|
163
|
+
|
|
164
|
+
assert !entry.draft
|
|
165
|
+
|
|
166
|
+
assert_nil get_elements(entry).elements["control"]
|
|
167
|
+
|
|
168
|
+
entry.draft = true
|
|
169
|
+
|
|
170
|
+
xml = get_elements entry
|
|
171
|
+
|
|
172
|
+
assert_equal Atom::PP_NS, xml.elements["app:control"].namespace
|
|
173
|
+
assert_equal Atom::PP_NS, xml.elements["app:control/app:draft"].namespace
|
|
174
|
+
assert_equal "yes", xml.elements["app:control/app:draft"].text
|
|
175
|
+
|
|
176
|
+
entry2 = Atom::Entry.parse xml
|
|
177
|
+
|
|
178
|
+
assert entry.draft
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def test_extensive_entry_parsing
|
|
182
|
+
str = '<entry xmlns="http://www.w3.org/2005/Atom">
|
|
183
|
+
<title>Atom draft-07 snapshot</title>
|
|
184
|
+
<link rel="alternate" type="text/html"
|
|
185
|
+
href="http://example.org/2005/04/02/atom"/>
|
|
186
|
+
<link rel="enclosure" type="audio/mpeg" length="1337"
|
|
187
|
+
href="http://example.org/audio/ph34r_my_podcast.mp3"/>
|
|
188
|
+
<id>tag:example.org,2003:3.2397</id>
|
|
189
|
+
<updated>2005-07-31T12:29:29Z</updated>
|
|
190
|
+
<published>2003-12-13T08:29:29-04:00</published>
|
|
191
|
+
<author>
|
|
192
|
+
<name>Mark Pilgrim</name>
|
|
193
|
+
<uri>http://example.org/</uri>
|
|
194
|
+
<email>f8dy@example.com</email>
|
|
195
|
+
</author>
|
|
196
|
+
<contributor>
|
|
197
|
+
<name>Sam Ruby</name>
|
|
198
|
+
</contributor>
|
|
199
|
+
<contributor>
|
|
200
|
+
<name>Joe Gregorio</name>
|
|
201
|
+
</contributor>
|
|
202
|
+
<content type="xhtml" xml:lang="en"
|
|
203
|
+
xml:base="http://diveintomark.org/">
|
|
204
|
+
<div xmlns="http://www.w3.org/1999/xhtml">
|
|
205
|
+
<p><i>[Update: The Atom draft is finished.]</i></p>
|
|
206
|
+
</div>
|
|
207
|
+
</content>
|
|
208
|
+
</entry>'
|
|
209
|
+
|
|
210
|
+
entry = Atom::Entry.parse(str)
|
|
211
|
+
|
|
212
|
+
assert_equal("Atom draft-07 snapshot", entry.title.to_s)
|
|
213
|
+
assert_equal("tag:example.org,2003:3.2397", entry.id)
|
|
214
|
+
|
|
215
|
+
assert_equal(Time.parse("2005-07-31T12:29:29Z"), entry.updated)
|
|
216
|
+
assert_equal(Time.parse("2003-12-13T08:29:29-04:00"), entry.published)
|
|
217
|
+
|
|
218
|
+
assert_equal(2, entry.links.length)
|
|
219
|
+
assert_equal("alternate", entry.links.first["rel"])
|
|
220
|
+
assert_equal("text/html", entry.links.first["type"])
|
|
221
|
+
assert_equal("http://example.org/2005/04/02/atom", entry.links.first["href"])
|
|
222
|
+
|
|
223
|
+
assert_equal("enclosure", entry.links.last["rel"])
|
|
224
|
+
assert_equal("audio/mpeg", entry.links.last["type"])
|
|
225
|
+
assert_equal("1337", entry.links.last["length"])
|
|
226
|
+
assert_equal("http://example.org/audio/ph34r_my_podcast.mp3", entry.links.last["href"])
|
|
227
|
+
|
|
228
|
+
assert_equal(1, entry.authors.length)
|
|
229
|
+
assert_equal("Mark Pilgrim", entry.authors.first.name)
|
|
230
|
+
assert_equal("http://example.org/", entry.authors.first.uri)
|
|
231
|
+
assert_equal("f8dy@example.com", entry.authors.first.email)
|
|
232
|
+
|
|
233
|
+
assert_equal(2, entry.contributors.length)
|
|
234
|
+
assert_equal("Sam Ruby", entry.contributors.first.name)
|
|
235
|
+
assert_equal("Joe Gregorio", entry.contributors.last.name)
|
|
236
|
+
|
|
237
|
+
assert_equal("xhtml", entry.content["type"])
|
|
238
|
+
|
|
239
|
+
assert_match("<p><i>[Update: The Atom draft is finished.]</i></p>",
|
|
240
|
+
entry.content.to_s)
|
|
241
|
+
|
|
242
|
+
assert_equal("http://diveintomark.org/", entry.content.base)
|
|
243
|
+
# XXX unimplemented
|
|
244
|
+
# assert_equal("en", entry.content.lang)
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def test_extensive_feed_parsing
|
|
248
|
+
feed = <<END
|
|
249
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
250
|
+
<feed xmlns="http://www.w3.org/2005/Atom">
|
|
251
|
+
<title type="text">dive into mark</title>
|
|
252
|
+
<subtitle type="html">
|
|
253
|
+
A <em>lot</em> of effort
|
|
254
|
+
went into making this effortless
|
|
255
|
+
</subtitle>
|
|
256
|
+
<updated>2005-07-31T12:29:29Z</updated>
|
|
257
|
+
<id>tag:example.org,2003:3</id>
|
|
258
|
+
<link rel="alternate" type="text/html"
|
|
259
|
+
hreflang="en" href="http://example.org/"/>
|
|
260
|
+
<link rel="self" type="application/atom+xml"
|
|
261
|
+
href="http://example.org/feed.atom"/>
|
|
262
|
+
<rights>Copyright (c) 2003, Mark Pilgrim</rights>
|
|
263
|
+
<generator uri="http://www.example.com/" version="1.0">
|
|
264
|
+
Example Toolkit
|
|
265
|
+
</generator>
|
|
266
|
+
<entry>
|
|
267
|
+
<title>Atom draft-07 snapshot</title>
|
|
268
|
+
<author>
|
|
269
|
+
<name>Mark Pilgrim</name>
|
|
270
|
+
<uri>http://example.org/</uri>
|
|
271
|
+
<email>f8dy@example.com</email>
|
|
272
|
+
</author>
|
|
273
|
+
<link rel="alternate" type="text/html"
|
|
274
|
+
href="http://example.org/2005/04/02/atom"/>
|
|
275
|
+
<id>tag:example.org,2003:3.2397</id>
|
|
276
|
+
<updated>2005-07-31T12:29:29Z</updated>
|
|
277
|
+
</entry>
|
|
278
|
+
</feed>
|
|
279
|
+
END
|
|
280
|
+
|
|
281
|
+
feed = Atom::Feed.parse(feed)
|
|
282
|
+
|
|
283
|
+
assert_equal("", feed.base)
|
|
284
|
+
|
|
285
|
+
assert_equal("text", feed.title["type"])
|
|
286
|
+
assert_equal("dive into mark", feed.title.to_s)
|
|
287
|
+
|
|
288
|
+
assert_equal("html", feed.subtitle["type"])
|
|
289
|
+
assert_equal("\n A <em>lot</em> of effort\n went into making this effortless\n ", feed.subtitle.to_s)
|
|
290
|
+
|
|
291
|
+
assert_equal(Time.parse("2005-07-31T12:29:29Z"), feed.updated)
|
|
292
|
+
assert_equal("tag:example.org,2003:3", feed.id)
|
|
293
|
+
|
|
294
|
+
assert_equal([], feed.authors)
|
|
295
|
+
|
|
296
|
+
alt = feed.links.find { |l| l["rel"] == "alternate" }
|
|
297
|
+
assert_equal("alternate", alt["rel"])
|
|
298
|
+
assert_equal("text/html", alt["type"])
|
|
299
|
+
assert_equal("en", alt["hreflang"])
|
|
300
|
+
assert_equal("http://example.org/", alt["href"])
|
|
301
|
+
|
|
302
|
+
assert_equal("text", feed.rights["type"])
|
|
303
|
+
assert_equal("Copyright (c) 2003, Mark Pilgrim", feed.rights.to_s)
|
|
304
|
+
|
|
305
|
+
assert_equal("\n Example Toolkit\n ", feed.generator)
|
|
306
|
+
# XXX unimplemented
|
|
307
|
+
# assert_equal("http://www.example.com/", feed.generator["uri"])
|
|
308
|
+
# assert_equal("1.0", feed.generator["version"])
|
|
309
|
+
|
|
310
|
+
assert_equal(1, feed.entries.length)
|
|
311
|
+
assert_equal "Atom draft-07 snapshot", feed.entries.first.title.to_s
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
def test_parse_html_content
|
|
315
|
+
xml = <<END
|
|
316
|
+
<entry xmlns="http://www.w3.org/2005/Atom">
|
|
317
|
+
<summary type="html">
|
|
318
|
+
<p>...&amp; as a result of this, I submit that <var>pi</var> &lt; 4
|
|
319
|
+
</summary>
|
|
320
|
+
</entry>
|
|
321
|
+
END
|
|
322
|
+
|
|
323
|
+
entry = Atom::Entry.parse(xml)
|
|
324
|
+
|
|
325
|
+
assert_equal "html", entry.summary["type"]
|
|
326
|
+
assert_equal "<p>...& as a result of this, I submit that <var>pi</var> < 4", entry.summary.html.strip
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
def test_parse_goofy_entries
|
|
330
|
+
xml = <<END
|
|
331
|
+
<entry xmlns="http://www.w3.org/2005/Atom">
|
|
332
|
+
<content type="html"></content>
|
|
333
|
+
</entry>
|
|
334
|
+
END
|
|
335
|
+
|
|
336
|
+
entry = Atom::Entry.parse(xml)
|
|
337
|
+
|
|
338
|
+
assert_equal("", entry.content.to_s)
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
def test_parse_outofline_content
|
|
342
|
+
xml = <<END
|
|
343
|
+
<entry xmlns="http://www.w3.org/2005/Atom">
|
|
344
|
+
<content src="http://necronomicorp.com/nil">
|
|
345
|
+
src means empty content.
|
|
346
|
+
</content>
|
|
347
|
+
</entry>
|
|
348
|
+
END
|
|
349
|
+
|
|
350
|
+
entry = Atom::Entry.parse xml
|
|
351
|
+
|
|
352
|
+
assert_equal "http://necronomicorp.com/nil", entry.content["src"]
|
|
353
|
+
assert_equal "", entry.content.to_s
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
def test_serialize_base
|
|
357
|
+
entry = Atom::Entry.new
|
|
358
|
+
|
|
359
|
+
entry.base = "http://necronomicorp.com/nil"
|
|
360
|
+
|
|
361
|
+
base = get_elements(entry).root.attributes["xml:base"]
|
|
362
|
+
assert_equal "http://necronomicorp.com/nil", base
|
|
363
|
+
|
|
364
|
+
entry.base = URI.parse("http://necronomicorp.com/nil")
|
|
365
|
+
|
|
366
|
+
base = get_elements(entry).root.attributes["xml:base"]
|
|
367
|
+
assert_equal "http://necronomicorp.com/nil", base
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
def test_relative_base
|
|
371
|
+
base_url = "http://www.tbray.org/ongoing/ongoing.atom"
|
|
372
|
+
doc = "<entry xmlns='http://www.w3.org/2005/Atom' xml:base='When/200x/2006/10/11/'/>"
|
|
373
|
+
|
|
374
|
+
entry = Atom::Entry.parse(doc, base_url)
|
|
375
|
+
assert_equal("http://www.tbray.org/ongoing/When/200x/2006/10/11/", entry.base)
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
def test_relative_src
|
|
379
|
+
base_url = "http://example.org/foo/"
|
|
380
|
+
doc = "<entry xmlns='http://www.w3.org/2005/Atom'><content src='./bar'/></entry>"
|
|
381
|
+
|
|
382
|
+
entry = Atom::Entry.parse(doc, base_url)
|
|
383
|
+
assert_equal("http://example.org/foo/bar", entry.content['src'])
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
def test_edit_url
|
|
387
|
+
doc = <<END
|
|
388
|
+
<entry xmlns="http://www.w3.org/2005/Atom"><link rel="edit"/></entry>
|
|
389
|
+
END
|
|
390
|
+
entry = Atom::Entry.parse(doc)
|
|
391
|
+
|
|
392
|
+
assert_nil(entry.edit_url)
|
|
393
|
+
|
|
394
|
+
doc = <<END
|
|
395
|
+
<entry xmlns="http://www.w3.org/2005/Atom"><link rel="edit"/></entry>
|
|
396
|
+
END
|
|
397
|
+
|
|
398
|
+
entry = Atom::Entry.parse(doc)
|
|
399
|
+
|
|
400
|
+
assert_nil(entry.edit_url)
|
|
401
|
+
|
|
402
|
+
doc = <<END
|
|
403
|
+
<entry xmlns="http://www.w3.org/2005/Atom">
|
|
404
|
+
<link rel="edit" href="http://necronomicorp.com/nil"/>
|
|
405
|
+
</entry>
|
|
406
|
+
END
|
|
407
|
+
|
|
408
|
+
entry = Atom::Entry.parse(doc)
|
|
409
|
+
|
|
410
|
+
assert_equal("http://necronomicorp.com/nil", entry.edit_url)
|
|
411
|
+
|
|
412
|
+
entry.edit_url = "http://necronomicorp.com/foo"
|
|
413
|
+
assert_equal "http://necronomicorp.com/foo", entry.edit_url
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
def assert_has_category xml, term
|
|
417
|
+
assert_not_nil(REXML::XPath.match(xml, "/entry/category[@term = #{term}]"))
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
def assert_has_content_type xml, type
|
|
421
|
+
assert_equal(type, xml.elements["content"].attributes["type"])
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
def get_entry
|
|
425
|
+
Atom::Entry.new
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
# round-trips it to make sure things stay the same
|
|
429
|
+
def get_elements entry
|
|
430
|
+
xml = entry.to_xml
|
|
431
|
+
|
|
432
|
+
b = Atom::Entry.parse(xml)
|
|
433
|
+
|
|
434
|
+
assert_equal(xml.to_s, b.to_s)
|
|
435
|
+
|
|
436
|
+
base_check xml
|
|
437
|
+
|
|
438
|
+
xml
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
def base_check xml
|
|
442
|
+
assert_equal("entry", xml.root.name)
|
|
443
|
+
assert_equal("http://www.w3.org/2005/Atom", xml.root.namespace)
|
|
444
|
+
end
|
|
445
|
+
end
|