Changesets can be listed by changeset number.
The Git repository is here.
- Revision:
- 15
- Log:
Attempt to update Typo to a Typo SVN HEAD release from around the
time the prototype installation was set up on the RISC OS Open Limited
web site. Timestamps place this at 04-Jul so a revision from 05-Jul or
earlier was pulled and copied over the 2.6.0 tarball stable code.
- Author:
- adh
- Date:
- Sat Jul 22 23:27:35 +0100 2006
- Size:
- 10482 Bytes
1 | require File.dirname(__FILE__) + '/../test_helper' |
2 | require 'xml_controller' |
3 | require 'dns_mock' |
4 | |
5 | # This test now has optional support for validating the generated RSS feeds. |
6 | # Since Ruby doesn't have a RSS/Atom validator, I'm using the Python source |
7 | # for http://feedvalidator.org and calling it via 'system'. |
8 | # |
9 | # To install the validator, download the source from |
10 | # http://sourceforge.net/cvs/?group_id=99943 |
11 | # Then copy src/feedvalidator and src/rdflib into a Python lib directory. |
12 | # Finally, copy src/demo.py into your path as 'feedvalidator', make it executable, |
13 | # and change the first line to something like '#!/usr/bin/python'. |
14 | |
15 | if($validator_installed == nil) |
16 | $validator_installed = false |
17 | begin |
18 | IO.popen("feedvalidator 2> /dev/null","r") do |pipe| |
19 | if (pipe.read =~ %r{Validating http://www.intertwingly.net/blog/index.}) |
20 | puts "Using locally installed Python feed validator" |
21 | $validator_installed = true |
22 | end |
23 | end |
24 | rescue |
25 | nil |
26 | end |
27 | end |
28 | |
29 | # Re-raise errors caught by the controller. |
30 | class XmlController; def rescue_action(e) raise e end; end |
31 | |
32 | class XmlControllerTest < Test::Unit::TestCase |
33 | fixtures :contents, :categories, :articles_categories, :tags, |
34 | :articles_tags, :users, :blogs, :resources |
35 | |
36 | def setup |
37 | @controller = XmlController.new |
38 | @request, @response = ActionController::TestRequest.new, ActionController::TestResponse.new |
39 | |
40 | Article.create!(:title => "News from the future!", |
41 | :body => "The future is cool!", |
42 | :keywords => "future", |
43 | :created_at => Time.now + 12.minutes) |
44 | end |
45 | |
46 | def assert_feedvalidator(rss, todo=nil) |
47 | return unless $validator_installed |
48 | |
49 | begin |
50 | file = Tempfile.new('typo-feed-test') |
51 | filename = file.path |
52 | file.write(rss) |
53 | file.close |
54 | |
55 | messages = '' |
56 | |
57 | IO.popen("feedvalidator file://#{filename}") do |pipe| |
58 | messages = pipe.read |
59 | end |
60 | |
61 | okay, messages = parse_validator_messages(messages) |
62 | |
63 | if todo && ! ENV['RUN_TODO_TESTS'] |
64 | assert !okay, messages + "\nTest unexpectedly passed!\nFeed text:\n"+rss |
65 | else |
66 | assert okay, messages + "\nFeed text:\n"+rss |
67 | end |
68 | end |
69 | end |
70 | |
71 | def parse_validator_messages(message) |
72 | messages=message.split(/\n/).reject do |m| |
73 | m =~ /Feeds should not be served with the "text\/plain" media type/ || |
74 | m =~ /Self reference doesn't match document location/ |
75 | end |
76 | |
77 | if(messages.size > 1) |
78 | [false, messages.join("\n")] |
79 | else |
80 | [true, ""] |
81 | end |
82 | end |
83 | |
84 | def test_feed_rss20 |
85 | get :feed, :format => 'rss20', :type => 'feed' |
86 | assert_response :success |
87 | assert_xml @response.body |
88 | assert_feedvalidator @response.body, :todo |
89 | |
90 | assert_rss20(6) |
91 | end |
92 | |
93 | def test_feed_rss20_comments |
94 | get :feed, :format => 'rss20', :type => 'comments' |
95 | assert_response :success |
96 | assert_xml @response.body |
97 | assert_feedvalidator @response.body |
98 | |
99 | assert_rss20(3) |
100 | end |
101 | |
102 | def test_feed_rss20_trackbacks |
103 | get :feed, :format => 'rss20', :type => 'trackbacks' |
104 | assert_response :success |
105 | assert_xml @response.body |
106 | assert_feedvalidator @response.body |
107 | |
108 | assert_rss20(2) |
109 | end |
110 | |
111 | def test_feed_rss20_article |
112 | get :feed, :format => 'rss20', :type => 'article', :id => 1 |
113 | assert_response :success |
114 | assert_xml @response.body |
115 | assert_feedvalidator @response.body, :todo |
116 | |
117 | assert_rss20(2) |
118 | end |
119 | |
120 | def test_feed_rss20_category |
121 | get :feed, :format => 'rss20', :type => 'category', :id => 'personal' |
122 | assert_response :success |
123 | assert_xml @response.body |
124 | assert_feedvalidator @response.body, :todo |
125 | |
126 | assert_rss20(3) |
127 | end |
128 | |
129 | def test_feed_rss20_tag |
130 | get :feed, :format => 'rss20', :type => 'tag', :id => 'foo' |
131 | assert_response :success |
132 | assert_xml @response.body |
133 | assert_feedvalidator @response.body, :todo |
134 | |
135 | assert_rss20(2) |
136 | end |
137 | |
138 | def test_feed_atom10_feed |
139 | get :feed, :format => 'atom10', :type => 'feed' |
140 | |
141 | assert_response :success |
142 | assert_xml @response.body |
143 | assert_feedvalidator @response.body |
144 | |
145 | assert_equal(assigns(:items).sort { |a, b| b.created_at <=> a.created_at }, |
146 | assigns(:items)) |
147 | |
148 | assert_atom10(6) |
149 | end |
150 | |
151 | def test_feed_atom10_comments |
152 | get :feed, :format => 'atom10', :type => 'comments' |
153 | assert_response :success |
154 | assert_xml @response.body |
155 | assert_feedvalidator @response.body |
156 | |
157 | assert_equal(assigns(:items).sort { |a, b| b.created_at <=> a.created_at }, |
158 | assigns(:items)) |
159 | |
160 | assert_atom10(3) |
161 | |
162 | assert_xpath('//title[@type="html"]') |
163 | end |
164 | |
165 | def test_feed_atom10_trackbacks |
166 | get :feed, :format => 'atom10', :type => 'trackbacks' |
167 | assert_response :success |
168 | assert_xml @response.body |
169 | assert_feedvalidator @response.body |
170 | |
171 | assert_equal(assigns(:items).sort { |a, b| b.created_at <=> a.created_at }, |
172 | assigns(:items)) |
173 | |
174 | assert_atom10(2) |
175 | |
176 | assert_xpath('//title[@type="html"]') |
177 | assert_xpath('//summary', "Trackback entry has no summaries") |
178 | end |
179 | |
180 | def test_feed_atom10_article |
181 | get :feed, :format => 'atom10', :type => 'article', :id => 1 |
182 | assert_response :success |
183 | assert_xml @response.body |
184 | assert_feedvalidator @response.body |
185 | |
186 | assert_equal(assigns(:items).sort { |a, b| b.created_at <=> a.created_at }, |
187 | assigns(:items)) |
188 | |
189 | assert_atom10(2) |
190 | end |
191 | |
192 | def test_feed_atom10_category |
193 | get :feed, :format => 'atom10', :type => 'category', :id => 'personal' |
194 | assert_response :success |
195 | assert_xml @response.body |
196 | assert_feedvalidator @response.body |
197 | |
198 | assert_equal(assigns(:items).sort { |a, b| b.created_at <=> a.created_at }, |
199 | assigns(:items)) |
200 | |
201 | assert_atom10(3) |
202 | end |
203 | |
204 | def test_feed_atom10_tag |
205 | get :feed, :format => 'atom10', :type => 'tag', :id => 'foo' |
206 | assert_response :success |
207 | assert_xml @response.body |
208 | assert_feedvalidator @response.body |
209 | |
210 | assert_equal(assigns(:items).sort { |a, b| b.created_at <=> a.created_at }, |
211 | assigns(:items)) |
212 | |
213 | assert_atom10(2) |
214 | end |
215 | |
216 | def test_articlerss |
217 | get :articlerss, :id => 1 |
218 | assert_response :redirect |
219 | end |
220 | |
221 | def test_commentrss |
222 | get :commentrss, :id => 1 |
223 | assert_response :redirect |
224 | end |
225 | |
226 | def test_trackbackrss |
227 | get :trackbackrss, :id => 1 |
228 | assert_response :redirect |
229 | end |
230 | |
231 | def test_bad_format |
232 | get :feed, :format => 'atom04', :type => 'feed' |
233 | assert_response :missing |
234 | end |
235 | |
236 | def test_bad_type |
237 | get :feed, :format => 'rss20', :type => 'foobar' |
238 | assert_response :missing |
239 | end |
240 | |
241 | def test_pubdate_conformance |
242 | get :feed, :format => 'rss20', :type => 'feed' |
243 | assert_response :success |
244 | xml = REXML::Document.new(@response.body) |
245 | assert_equal contents(:article2).created_at.rfc822, REXML::XPath.match(xml, '/rss/channel/item[title="Article 2!"]/pubDate').first.text |
246 | end |
247 | |
248 | def test_rsd |
249 | get :rsd, :id => 1 |
250 | assert_response :success |
251 | assert_nothing_raised do |
252 | assert REXML::Document.new(@response.body) |
253 | end |
254 | end |
255 | |
256 | def test_extended_rss20 |
257 | set_extended_on_rss true |
258 | get :feed, :format => 'rss20', :type => 'feed' |
259 | assert_response :success |
260 | assert_match /extended content/, @response.body |
261 | |
262 | set_extended_on_rss false |
263 | get :feed, :format => 'rss20', :type => 'feed' |
264 | assert_response :success |
265 | assert_no_match /extended content/, @response.body |
266 | end |
267 | |
268 | def test_atom03 |
269 | get :feed, :format => 'atom03', :type => 'feed' |
270 | assert_response :redirect |
271 | assert_redirected_to :format => 'atom' |
272 | end |
273 | |
274 | def test_extended_atom10 |
275 | set_extended_on_rss true |
276 | get :feed, :format => 'atom10', :type => 'feed' |
277 | assert_response :success |
278 | assert_match /extended content/, @response.body |
279 | assert_not_equal 0, get_xpath(%{//summary]}).size, "Extended feed has no summaries" |
280 | assert_not_equal 0, get_xpath(%{//content]}).size, "Extended feed has no content" |
281 | |
282 | set_extended_on_rss false |
283 | get :feed, :format => 'atom10', :type => 'feed' |
284 | assert_response :success |
285 | assert_no_match /extended content/, @response.body |
286 | assert_not_equal 0, get_xpath(%{//summary]}).size, "Non-Extended feed has no summaries" |
287 | assert_equal 0, get_xpath(%{//content]}).size, "Non-extended feed has content" |
288 | end |
289 | |
290 | def test_xml_atom10 |
291 | get :feed, :format => 'atom10', :type => 'feed' |
292 | assert_response :success |
293 | |
294 | # titles are escaped html |
295 | assert_xpath('//entry/title[text()="Associations aren\'t :dependent =&gt; true anymore" and @type="html"]') |
296 | |
297 | # categories are well formed |
298 | assert_match /this & that/, @response.body |
299 | end |
300 | |
301 | def test_enclosure_rss20 |
302 | get :feed, :format => 'rss20', :type => 'feed' |
303 | assert_response :success |
304 | |
305 | # There's an enclosure in there somewhere |
306 | assert_xpath('/rss/channel/item/enclosure') |
307 | |
308 | # There's an enclosure attached to the node with the title "Article 1!" |
309 | assert_xpath('/rss/channel/item[title="Article 1!"]/enclosure') |
310 | assert_xpath('/rss/channel/item[title="Article 2!"]/enclosure') |
311 | |
312 | # Article 3 exists, but has no enclosure |
313 | assert_xpath('/rss/channel/item[title="Article 3!"]') |
314 | assert_not_xpath('/rss/channel/item[title="Article 3!"]/enclosure') |
315 | end |
316 | |
317 | def test_enclosure_atom10 |
318 | get :feed, :format => 'atom10', :type => 'feed' |
319 | assert_response :success |
320 | |
321 | # There's an enclosure in there somewhere |
322 | assert_xpath('/feed/entry/link[@rel="enclosure"]') |
323 | |
324 | # There's an enclosure attached to "Article 1!" with a length |
325 | assert_xpath('/feed/entry[title="Article 1!"]/link[@rel="enclosure" and @length]') |
326 | |
327 | # There's an enclosure attached to "Article 2!" with no length |
328 | assert_xpath('/feed/entry[title="Article 2!"]/link[@rel="enclosure" and not(@length)]') |
329 | |
330 | # Article 3 exists, but has no enclosure |
331 | assert_xpath('/feed/entry[title="Article 3!"]') |
332 | assert_not_xpath('/feed/entry[title="Article 3!"]/link[@rel="enclosure"]') |
333 | end |
334 | |
335 | def test_itunes |
336 | get :itunes |
337 | assert_response :success |
338 | assert_xml @response.body |
339 | assert_feedvalidator @response.body, :todo |
340 | end |
341 | |
342 | def assert_rss20(items) |
343 | assert_equal 1, get_xpath(%{/rss[@version="2.0"]/channel[count(child::item)=#{items}]}).size, "RSS 2.0 feed has wrong number of channel/item nodes" |
344 | end |
345 | |
346 | def assert_atom10(entries) |
347 | assert_equal 1, get_xpath(%{/feed[@xmlns="http://www.w3.org/2005/Atom" and count(child::entry)=#{entries}]}).size, "Atom 1.0 feed has wrong number of feed/entry nodes" |
348 | end |
349 | |
350 | def set_extended_on_rss(value) |
351 | this_blog.show_extended_on_rss = value |
352 | end |
353 | end |