1require "erb"
2
3require "test/unit"
4require 'rss-assertions'
5
6require "rss"
7
8module RSS
9  class TestCase < Test::Unit::TestCase
10    include ERB::Util
11
12    include RSS
13    include Assertions
14
15    XMLDECL_VERSION = "1.0"
16    XMLDECL_ENCODING = "UTF-8"
17    XMLDECL_STANDALONE = "no"
18
19    RDF_ABOUT = "http://www.xml.com/xml/news.rss"
20    RDF_RESOURCE = "http://xml.com/universal/images/xml_tiny.gif"
21    TITLE_VALUE = "XML.com"
22    LINK_VALUE = "http://xml.com/pub"
23    URL_VALUE = "http://xml.com/universal/images/xml_tiny.gif"
24    NAME_VALUE = "hogehoge"
25    LANGUAGE_VALUE = "ja"
26    DESCRIPTION_VALUE = "
27    XML.com features a rich mix of information and services
28    for the XML community.
29    "
30    RESOURCES = [
31      "http://xml.com/pub/2000/08/09/xslt/xslt.html",
32      "http://xml.com/pub/2000/08/09/rdfdb/index.html",
33    ]
34
35    CLOUD_DOMAIN = "data.ourfavoritesongs.com"
36    CLOUD_PORT = "80"
37    CLOUD_PATH = "/RPC2"
38    CLOUD_REGISTER_PROCEDURE = "ourFavoriteSongs.rssPleaseNotify"
39    CLOUD_PROTOCOL = "xml-rpc"
40
41    ENCLOSURE_URL = "http://www.scripting.com/mp3s/weatherReportSuite.mp3"
42    ENCLOSURE_LENGTH = "12216320"
43    ENCLOSURE_TYPE = "audio/mpeg"
44
45    CATEGORY_DOMAIN = "http://www.superopendirectory.com/"
46
47    FEED_TITLE = "dive into mark"
48    FEED_UPDATED = "2003-12-13T18:30:02Z"
49    FEED_AUTHOR_NAME = "John Doe"
50    FEED_ID = "urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6"
51
52    ENTRY_TITLE = "Atom-Powered Robots Run Amok"
53    ENTRY_LINK = "http://example.org/2003/12/13/atom03"
54    ENTRY_ID = "urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a"
55    ENTRY_UPDATED = "2003-12-13T18:30:02Z"
56    ENTRY_SUMMARY = "Some text."
57
58    t = Time.iso8601("2000-01-01T12:00:05+00:00")
59    class << t
60      alias_method(:to_s, :iso8601)
61    end
62
63    DC_ELEMENTS = {
64      :title => "hoge",
65      :description =>
66        " XML is placing increasingly heavy loads on
67          the existing technical infrastructure of the Internet.",
68      :creator => "Rael Dornfest (mailto:rael@oreilly.com)",
69      :subject => "XML",
70      :publisher => "The O'Reilly Network",
71      :contributor => "hogehoge",
72      :type => "fugafuga",
73      :format => "hohoho",
74      :identifier => "fufufu",
75      :source => "barbar",
76      :language => "ja",
77      :relation => "cococo",
78      :rights => "Copyright (c) 2000 O'Reilly &amp; Associates, Inc.",
79      :date => t,
80    }
81
82    DC_NODES = DC_ELEMENTS.collect do |name, value|
83      "<#{DC_PREFIX}:#{name}>#{value}</#{DC_PREFIX}:#{name}>"
84    end.join("\n")
85
86    def default_test
87      # This class isn't tested
88    end
89
90    private
91    def make_xmldecl(v=XMLDECL_VERSION, e=XMLDECL_ENCODING, s=XMLDECL_STANDALONE)
92      rv = "<?xml version='#{v}'"
93      rv << " encoding='#{e}'" if e
94      rv << " standalone='#{s}'" if s
95      rv << "?>"
96      rv
97    end
98
99    def make_RDF(content=nil, xmlns=[])
100      <<-EORSS
101#{make_xmldecl}
102<rdf:RDF xmlns="#{URI}" xmlns:rdf="#{RDF::URI}"
103#{xmlns.collect {|pre, uri| "xmlns:#{pre}='#{uri}'"}.join(' ')}>
104#{block_given? ? yield : content}
105</rdf:RDF>
106EORSS
107    end
108
109    def make_channel(content=nil)
110      <<-EOC
111<channel rdf:about="#{RDF_ABOUT}">
112  <title>#{TITLE_VALUE}</title>
113  <link>#{LINK_VALUE}</link>
114  <description>#{DESCRIPTION_VALUE}</description>
115
116  <image rdf:resource="#{RDF_RESOURCE}" />
117
118  <items>
119    <rdf:Seq>
120#{RESOURCES.collect do |res| '<rdf:li resource="' + res + '" />' end.join("\n")}
121    </rdf:Seq>
122  </items>
123
124  <textinput rdf:resource="#{RDF_RESOURCE}" />
125
126#{block_given? ? yield : content}
127</channel>
128EOC
129    end
130
131    def make_image(content=nil)
132      <<-EOI
133<image rdf:about="#{RDF_ABOUT}">
134  <title>#{TITLE_VALUE}</title>
135  <url>#{URL_VALUE}</url>
136  <link>#{LINK_VALUE}</link>
137#{block_given? ? yield : content}
138</image>
139EOI
140    end
141
142    def make_item(content=nil)
143      <<-EOI
144<item rdf:about="#{RDF_ABOUT}">
145  <title>#{TITLE_VALUE}</title>
146  <link>#{LINK_VALUE}</link>
147  <description>#{DESCRIPTION_VALUE}</description>
148#{block_given? ? yield : content}
149</item>
150EOI
151    end
152
153    def make_textinput(content=nil)
154      <<-EOT
155<textinput rdf:about="#{RDF_ABOUT}">
156  <title>#{TITLE_VALUE}</title>
157  <description>#{DESCRIPTION_VALUE}</description>
158  <name>#{NAME_VALUE}</name>
159  <link>#{LINK_VALUE}</link>
160#{block_given? ? yield : content}
161</textinput>
162EOT
163    end
164
165    def make_sample_RDF
166      make_RDF(<<-EOR)
167#{make_channel}
168#{make_image}
169#{make_item}
170#{make_textinput}
171EOR
172    end
173
174    def make_rss20(content=nil, xmlns=[])
175      <<-EORSS
176#{make_xmldecl}
177<rss version="2.0"
178#{xmlns.collect {|pre, uri| "xmlns:#{pre}='#{uri}'"}.join(' ')}>
179#{block_given? ? yield : content}
180</rss>
181EORSS
182    end
183
184    def make_sample_items20
185      RESOURCES.collect do |res|
186        elems = ["<link>#{res}</link>"]
187        elems << "<title>title of #{res}</title>"
188        elems = elems.join("\n")
189        "<item>\n#{elems}\n</item>"
190      end.join("\n")
191    end
192
193    def make_channel20(content=nil)
194      <<-EOC
195<channel>
196  <title>#{TITLE_VALUE}</title>
197  <link>#{LINK_VALUE}</link>
198  <description>#{DESCRIPTION_VALUE}</description>
199  <language>#{LANGUAGE_VALUE}</language>
200
201  <image>
202    <url>#{RDF_RESOURCE}</url>
203    <title>#{TITLE_VALUE}</title>
204    <link>#{LINK_VALUE}</link>
205  </image>
206
207#{make_sample_items20}
208
209  <textInput>
210    <title>#{TITLE_VALUE}</title>
211    <description>#{DESCRIPTION_VALUE}</description>
212    <name>#{NAME_VALUE}</name>
213    <link>#{RDF_RESOURCE}</link>
214  </textInput>
215
216#{block_given? ? yield : content}
217</channel>
218EOC
219    end
220
221    def make_item20(content=nil)
222      <<-EOI
223<item>
224  <title>#{TITLE_VALUE}</title>
225  <link>#{LINK_VALUE}</link>
226  <description>#{DESCRIPTION_VALUE}</description>
227#{block_given? ? yield : content}
228</item>
229EOI
230    end
231
232    def make_cloud20
233      <<-EOC
234<cloud
235  domain="#{CLOUD_DOMAIN}"
236  port="#{CLOUD_PORT}"
237  path="#{CLOUD_PATH}"
238  registerProcedure="#{CLOUD_REGISTER_PROCEDURE}"
239  protocol="#{CLOUD_PROTOCOL}" />
240EOC
241    end
242
243    def make_sample_rss20
244      make_rss20(<<-EOR)
245#{make_channel20}
246EOR
247    end
248
249    def make_feed_without_entry(content=nil, xmlns=[])
250      <<-EOA
251<feed xmlns="#{Atom::URI}"
252#{xmlns.collect {|pre, uri| "xmlns:#{pre}='#{uri}'"}.join(' ')}>
253  <id>#{FEED_ID}</id>
254  <title>#{FEED_TITLE}</title>
255  <updated>#{FEED_UPDATED}</updated>
256  <author>
257    <name>#{FEED_AUTHOR_NAME}</name>
258  </author>
259#{block_given? ? yield : content}
260</feed>
261EOA
262    end
263
264    def make_entry(content=nil)
265      <<-EOA
266  <entry>
267    <title>#{ENTRY_TITLE}</title>
268    <id>#{ENTRY_ID}</id>
269    <updated>#{ENTRY_UPDATED}</updated>
270#{block_given? ? yield : content}
271  </entry>
272EOA
273    end
274
275    def make_feed_with_open_entry(content=nil, xmlns=[], &block)
276      make_feed_without_entry(<<-EOA, xmlns)
277#{make_entry(content, &block)}
278EOA
279    end
280
281    def make_feed_with_open_entry_source(content=nil, xmlns=[])
282      make_feed_with_open_entry(<<-EOA, xmlns)
283  <source>
284#{block_given? ? yield : content}
285  </source>
286EOA
287    end
288
289    def make_feed(content=nil, xmlns=[])
290      make_feed_without_entry(<<-EOA, xmlns)
291  <entry>
292    <title>#{ENTRY_TITLE}</title>
293    <link href="#{ENTRY_LINK}"/>
294    <id>#{ENTRY_ID}</id>
295    <updated>#{ENTRY_UPDATED}</updated>
296    <summary>#{ENTRY_SUMMARY}</summary>
297  </entry>
298#{block_given? ? yield : content}
299EOA
300    end
301
302    def make_entry_document(content=nil, xmlns=[])
303      <<-EOA
304<entry xmlns="#{Atom::URI}"
305#{xmlns.collect {|pre, uri| "xmlns:#{pre}='#{uri}'"}.join(' ')}>
306  <id>#{ENTRY_ID}</id>
307  <title>#{ENTRY_TITLE}</title>
308  <updated>#{ENTRY_UPDATED}</updated>
309  <author>
310    <name>#{FEED_AUTHOR_NAME}</name>
311  </author>
312#{block_given? ? yield : content}
313</entry>
314EOA
315    end
316
317    def make_entry_document_with_open_source(content=nil, xmlns=[])
318      make_entry_document(<<-EOA, xmlns)
319  <source>
320#{block_given? ? yield : content}
321  </source>
322EOA
323    end
324
325    def make_element(elem_name, attrs, contents)
326      attrs_str = attrs.collect do |name, value|
327        "#{h name}='#{h value}'"
328      end.join(" ")
329      attrs_str = " #{attrs_str}" unless attrs_str.empty?
330
331      if contents.is_a?(String)
332        contents_str = h(contents)
333      else
334        contents_str = contents.collect do |name, value|
335          "#{Element::INDENT}<#{h name}>#{h value}</#{h name}>"
336        end.join("\n")
337        contents_str = "\n#{contents_str}\n"
338      end
339
340      "<#{h elem_name}#{attrs_str}>#{contents_str}</#{h elem_name}>"
341    end
342
343    def xmlns_container(xmlns_decls, content)
344      attributes = xmlns_decls.collect do |prefix, uri|
345        "xmlns:#{h prefix}=\"#{h uri}\""
346      end.join(" ")
347      "<dummy #{attributes}>#{content}</dummy>"
348    end
349
350    private
351    def setup_rss10(rdf)
352      assert_equal("", rdf.to_s)
353
354      channel = RDF::Channel.new
355      assert_equal("", channel.to_s)
356      channel.about = "http://example.com/index.rdf"
357      channel.title = "title"
358      channel.link = "http://example.com/"
359      channel.description = "description"
360      assert_equal("", channel.to_s)
361
362      item_title = "item title"
363      item_link = "http://example.com/item"
364      channel.items = RDF::Channel::Items.new
365      channel.items.Seq.lis << RDF::Channel::Items::Seq::Li.new(item_link)
366      assert_not_equal("", channel.to_s)
367
368      rdf.channel = channel
369      assert_equal("", rdf.to_s)
370
371      item = RDF::Item.new
372      item.title = item_title
373      item.link = item_link
374      item.about = item_link
375      rdf.items << item
376      assert_not_equal("", rdf.to_s)
377    end
378
379    def setup_rss20(rss)
380      assert_equal("", rss.to_s)
381
382      channel = Rss::Channel.new
383      assert_equal("", channel.to_s)
384      channel.title = "title"
385      channel.link = "http://example.com/"
386      channel.description = "description"
387      assert_not_equal("", channel.to_s)
388
389      rss.channel = channel
390      assert_not_equal("", rss.to_s)
391    end
392
393    def setup_dummy_channel(maker)
394      about = "http://hoge.com"
395      title = "fugafuga"
396      link = "http://hoge.com/feed.xml"
397      description = "fugafugafugafuga"
398      language = "ja"
399
400      maker.channel.about = about
401      maker.channel.title = title
402      maker.channel.link = link
403      maker.channel.description = description
404      maker.channel.language = language
405    end
406
407    def setup_dummy_channel_atom(maker)
408      updated = Time.now
409      author = "Foo"
410
411      setup_dummy_channel(maker)
412      maker.channel.links.first.rel = "self"
413      maker.channel.links.first.type = "application/atom+xml"
414      maker.channel.updated = updated
415      maker.channel.author = author
416    end
417
418    def setup_dummy_image(maker)
419      title = "fugafuga"
420      link = "http://hoge.com"
421      url = "http://hoge.com/hoge.png"
422
423      maker.channel.link = link if maker.channel.link.nil?
424
425      maker.image.title = title
426      maker.image.url = url
427    end
428
429    def setup_dummy_textinput(maker)
430      title = "fugafuga"
431      description = "text hoge fuga"
432      name = "hoge"
433      link = "http://hoge.com/search.cgi"
434
435      maker.textinput.title = title
436      maker.textinput.description = description
437      maker.textinput.name = name
438      maker.textinput.link = link
439    end
440
441    def setup_dummy_item(maker)
442      title = "TITLE"
443      link = "http://hoge.com/"
444
445      item = maker.items.new_item
446      item.title = title
447      item.link = link
448    end
449
450    def setup_dummy_item_atom(maker)
451      setup_dummy_item(maker)
452
453      item = maker.items.first
454      item.id = "http://example.net/xxx"
455      item.updated = Time.now
456    end
457
458    def setup_taxo_topic(target, topics)
459      topics.each do |topic|
460        taxo_topic = target.taxo_topics.new_taxo_topic
461        topic.each do |name, value|
462          case name
463          when :link
464            taxo_topic.taxo_link = value
465          when :topics
466            value.each do |t|
467              taxo_topic.taxo_topics << t
468            end
469          else
470            dc_elems = taxo_topic.__send__("dc_#{name}s")
471            dc_elem = dc_elems.__send__("new_#{name}")
472            dc_elem.value = value
473          end
474        end
475      end
476    end
477  end
478end
479