1require "rexml/document"
2
3require "rss-testcase"
4
5require "rss/maker"
6require "rss/1.0"
7require "rss/2.0"
8require "rss/content"
9require "rss/dublincore"
10require "rss/syndication"
11require "rss/trackback"
12
13module RSS
14  class TestToS < TestCase
15    def setup
16      @image_url = "http://example.com/foo.png"
17      @textinput_link = "http://example.com/search.cgi"
18      @item_links = [
19        "http://example.com/1",
20        "http://example.com/2",
21      ]
22
23      setup_xml_declaration_info
24      setup_xml_stylesheet_infos
25      setup_channel_info
26      setup_item_infos
27      setup_image_info
28      setup_textinput_info
29
30      setup_dublin_core_info
31      setup_syndication_info
32      setup_content_info
33      setup_trackback_info
34    end
35
36    def test_to_s_10
37      rss = RSS::Maker.make("1.0") do |maker|
38        setup_full(maker)
39      end
40
41      assert_xml_declaration(@version, @encoding, @standalone, rss)
42      assert_xml_stylesheets(@xs_infos, rss.xml_stylesheets)
43      assert_channel10(@channel_info, rss.channel)
44      assert_items10(@item_infos, rss.items)
45      rss.items.each do |item|
46        assert_trackback(@trackback_info, item)
47      end
48      assert_image10(@image_info, rss.image)
49      assert_textinput10(@textinput_info, rss.textinput)
50
51      rss = RSS::Parser.parse(rss.to_s)
52
53      assert_xml_declaration(@version, @encoding, @standalone, rss)
54      assert_xml_stylesheets(@xs_infos, rss.xml_stylesheets)
55      assert_channel10(@channel_info, rss.channel)
56      assert_items10(@item_infos, rss.items)
57      assert_image10(@image_info, rss.image)
58      assert_textinput10(@textinput_info, rss.textinput)
59    end
60
61    def test_to_s_09
62      rss = RSS::Maker.make("0.91") do |maker|
63        setup_full(maker)
64      end
65
66      assert_xml_declaration(@version, @encoding, @standalone, rss)
67      assert_xml_stylesheets(@xs_infos, rss.xml_stylesheets)
68      assert_channel09(@channel_info, rss.channel)
69      assert_items09(@item_infos, rss.items)
70      assert_image09(@image_info, rss.image)
71      assert_textinput09(@textinput_info, rss.textinput)
72
73      rss = RSS::Parser.parse(rss.to_s)
74
75      assert_xml_declaration(@version, @encoding, @standalone, rss)
76      assert_xml_stylesheets(@xs_infos, rss.xml_stylesheets)
77      assert_channel09(@channel_info, rss.channel)
78      assert_items09(@item_infos, rss.items)
79      assert_image09(@image_info, rss.image)
80      assert_textinput09(@textinput_info, rss.textinput)
81    end
82
83    def test_to_s_20
84      rss = RSS::Maker.make("2.0") do |maker|
85        setup_full(maker)
86      end
87
88      assert_xml_declaration(@version, @encoding, @standalone, rss)
89      assert_xml_stylesheets(@xs_infos, rss.xml_stylesheets)
90      assert_channel20(@channel_info, rss.channel)
91      assert_items20(@item_infos, rss.items)
92      assert_image20(@image_info, rss.image)
93      assert_textinput20(@textinput_info, rss.textinput)
94
95      rss = RSS::Parser.parse(rss.to_s)
96
97      assert_xml_declaration(@version, @encoding, @standalone, rss)
98      assert_xml_stylesheets(@xs_infos, rss.xml_stylesheets)
99      assert_channel20(@channel_info, rss.channel)
100      assert_items20(@item_infos, rss.items)
101      assert_image20(@image_info, rss.image)
102      assert_textinput20(@textinput_info, rss.textinput)
103    end
104
105    private
106    def setup_xml_declaration_info
107      @version = "1.0"
108      @encoding = "UTF-8"
109      @standalone = false
110    end
111
112    def setup_xml_stylesheet_infos
113      @xs_infos = [
114        {
115          "href" => "XXX.xsl",
116          "type" => "text/xsl",
117          "title" => "XXX",
118          "media" => "print",
119          "alternate" => "no",
120        },
121        {
122          "href" => "YYY.css",
123          "type" => "text/css",
124          "title" => "YYY",
125          "media" => "all",
126          "alternate" => "no",
127        },
128      ]
129    end
130
131    def setup_channel_info
132      @channel_info = {
133        "about" => "http://example.com/index.rdf",
134        "title" => "Sample RSS",
135        "link" => "http://example.com/",
136        "description" => "Sample\n\n\n\n\nSite",
137        "language" => "en",
138        "copyright" => "FDL",
139        "managingEditor" => "foo@example.com",
140        "webMaster" => "webmaster@example.com",
141        "rating" => '(PICS-1.1 "http://www.rsac.org/ratingsv01.html" l gen true comment "RSACi North America Server" for "http://www.rsac.org" on "1996.04.16T08:15-0500" r (n 0 s 0 v 0 l 0))',
142        "docs" => "http://backend.userland.com/rss091",
143        "skipDays" => [
144          "Monday",
145          "Friday",
146        ],
147        "skipHours" => [
148          "12",
149          "23",
150        ],
151        "date" => Time.now,
152        "lastBuildDate" => Time.now - 3600,
153        "generator" => "RSS Maker",
154        "ttl" => "60",
155        "cloud" => {
156          "domain" => "rpc.sys.com",
157          "port" => "80",
158          "path" => "/RPC2",
159          "registerProcedure" => "myCloud.rssPleaseNotify",
160          "protocol" => "xml-rpc",
161        },
162        "category" => {
163          "domain" => "http://example.com/misc/",
164          "content" => "misc",
165        },
166
167        "image" => {
168          "resource" => @image_url,
169        },
170
171        "textinput" => {
172          "resource" => @textinput_link,
173        },
174
175        "items" => @item_links.collect{|link| {"resource" => link}},
176      }
177    end
178
179    def setup_item_infos
180      @item_infos = [
181        {
182          "title" => "Sample item1",
183          "link" => @item_links[0],
184          "description" => "Sample description1",
185          "date" => Time.now - 3600,
186          "author" => "foo@example.com",
187          "comments" => "http://example.com/1/comments",
188          "guid" => {
189            "isPermaLink" => "true",
190            "content" => "http://example.com/1",
191          },
192          "enclosure" => {
193            "url" => "http://example.com/1.mp3",
194            "length" => "100",
195            "type" => "audio/mpeg",
196          },
197          "source" => {
198            "url" => "http:/example.com/",
199            "content" => "Sample site",
200          },
201          "category" => {
202            "domain" => "http://example.com/misc/",
203            "content" => "misc",
204          },
205        },
206
207        {
208          "title" => "Sample item2",
209          "link" => @item_links[1],
210          "description" => "Sample description2",
211          "date" => Time.now - 7200,
212          "author" => "foo@example.com",
213          "comments" => "http://example.com/2/comments",
214          "guid" => {
215            "isPermaLink" => "false",
216            "content" => "http://example.com/2",
217          },
218          "enclosure" => {
219            "url" => "http://example.com/2.mp3",
220            "length" => "200",
221            "type" => "audio/mpeg",
222          },
223          "source" => {
224            "url" => "http:/example.com/",
225            "content" => "Sample site",
226          },
227          "category" => {
228            "domain" => "http://example.com/misc/",
229            "content" => "misc",
230          },
231        },
232      ]
233    end
234
235    def setup_image_info
236      @image_info = {
237        "title" => "Sample image",
238        "url" => @image_url,
239        "width" => "88",
240        "height" => "31",
241        "description" => "Sample",
242      }
243    end
244
245    def setup_textinput_info
246      @textinput_info = {
247        "title" => "Sample textinput",
248        "description" => "Search",
249        "name" => "key",
250        "link" => @textinput_link,
251      }
252    end
253
254    def setup_dublin_core_info
255      @dc_info = {
256        "title" => "DC title",
257        "description" => "DC desc",
258        "creator" => "DC creator",
259        "subject" => "DC subject",
260        "publisher" => "DC publisher",
261        "contributor" => "DC contributor",
262        "type" => "DC type",
263        "format" => "DC format",
264        "identifier" => "DC identifier",
265        "source" => "DC source",
266        "language" => "ja",
267        "relation" => "DC relation",
268        "coverage" => "DC coverage",
269        "rights" => "DC rights",
270        "date" => Time.now - 60,
271      }
272    end
273
274    def setup_syndication_info
275      @sy_info = {
276        "updatePeriod" => "hourly",
277        "updateFrequency" => "2",
278        "updateBase" => Time.now - 3600,
279      }
280    end
281
282    def setup_content_info
283      @content_info = {
284        "encoded" => "<p>p</p>",
285      }
286    end
287
288    def setup_trackback_info
289      @trackback_info = {
290        "ping" => "http://example.com/tb.cgi?tb_id=XXX",
291        "abouts" => [
292          "http://example.net/tb.cgi?tb_id=YYY",
293          "http://example.org/tb.cgi?tb_id=ZZZ",
294        ]
295      }
296    end
297
298
299    def setup_full(maker)
300      setup_xml_declaration(maker)
301      setup_xml_stylesheets(maker)
302      setup_channel(maker)
303      setup_image(maker)
304      setup_items(maker)
305      setup_textinput(maker)
306    end
307
308    def setup_xml_declaration(maker)
309      %w(version encoding standalone).each do |name|
310        maker.__send__("#{name}=", instance_eval("@#{name}"))
311      end
312    end
313
314    def setup_xml_stylesheets(maker)
315      @xs_infos.each do |info|
316        xs = maker.xml_stylesheets.new_xml_stylesheet
317        info.each do |name, value|
318          xs.__send__("#{name}=", value)
319        end
320      end
321    end
322
323    def setup_channel(maker)
324      channel = maker.channel
325      info = @channel_info
326
327      %w(about title link description language copyright
328         managingEditor webMaster rating docs date
329         lastBuildDate generator ttl).each do |name|
330        channel.__send__("#{name}=", info[name])
331      end
332
333      skipDays = channel.skipDays
334      info["skipDays"].each do |day|
335        new_day = skipDays.new_day
336        new_day.content = day
337      end
338
339      skipHours = channel.skipHours
340      info["skipHours"].each do |hour|
341        new_hour = skipHours.new_hour
342        new_hour.content = hour
343      end
344
345      cloud = channel.cloud
346      %w(domain port path registerProcedure protocol).each do |name|
347        cloud.__send__("#{name}=", info["cloud"][name])
348      end
349
350      category = channel.categories.new_category
351      %w(domain content).each do |name|
352        category.__send__("#{name}=", info["category"][name])
353      end
354    end
355
356    def setup_image(maker)
357      image = maker.image
358      info = @image_info
359
360      %w(title url width height description).each do |name|
361        image.__send__("#{name}=", info[name])
362      end
363    end
364
365    def setup_items(maker)
366      items = maker.items
367
368      @item_infos.each do |info|
369        item = items.new_item
370        %w(title link description date author comments).each do |name|
371          item.__send__("#{name}=", info[name])
372        end
373
374        guid = item.guid
375        %w(isPermaLink content).each do |name|
376          guid.__send__("#{name}=", info["guid"][name])
377        end
378
379        enclosure = item.enclosure
380        %w(url length type).each do |name|
381          enclosure.__send__("#{name}=", info["enclosure"][name])
382        end
383
384        source = item.source
385        %w(url content).each do |name|
386          source.__send__("#{name}=", info["source"][name])
387        end
388
389        category = item.categories.new_category
390        %w(domain content).each do |name|
391          category.__send__("#{name}=", info["category"][name])
392        end
393
394        setup_trackback(item)
395      end
396    end
397
398    def setup_textinput(maker)
399      textinput = maker.textinput
400      info = @textinput_info
401
402      %w(title description name link).each do |name|
403        textinput.__send__("#{name}=", info[name])
404      end
405    end
406
407    def setup_content(target)
408      prefix = "content"
409      %w(encoded).each do |name|
410        target.__send__("#{prefix}_#{name}=", @content_info[name])
411      end
412    end
413
414    def setup_dublin_core(target)
415      prefix = "dc"
416      %w(title description creator subject publisher
417        contributor type format identifier source language
418        relation coverage rights).each do |name|
419        target.__send__("#{prefix}_#{name}=", @dc_info[name])
420      end
421    end
422
423    def setup_syndicate(target)
424      prefix = "sy"
425      %w(updatePeriod updateFrequency updateBase).each do |name|
426        target.__send__("#{prefix}_#{name}=", @sy_info[name])
427      end
428    end
429
430    def setup_trackback(target)
431      target.trackback_ping = @trackback_info["ping"]
432      @trackback_info["abouts"].each do |about|
433        new_about = target.trackback_abouts.new_about
434        new_about.value = about
435      end
436    end
437
438
439    def assert_channel10(attrs, channel)
440      _wrap_assertion do
441        n_attrs = normalized_attrs(attrs)
442
443        names = %w(about title link description)
444        assert_attributes(attrs, names, channel)
445
446        %w(image items textinput).each do |name|
447          value = n_attrs[name]
448          if value
449            target = channel.__send__(name)
450            __send__("assert_channel10_#{name}", value, target)
451          end
452        end
453      end
454    end
455
456    def assert_channel10_image(attrs, image)
457      _wrap_assertion do
458        assert_attributes(attrs, %w(resource), image)
459      end
460    end
461
462    def assert_channel10_textinput(attrs, textinput)
463      _wrap_assertion do
464        assert_attributes(attrs, %w(resource), textinput)
465      end
466    end
467
468    def assert_channel10_items(attrs, items)
469      _wrap_assertion do
470        assert_equal(items.resources, items.Seq.lis.collect {|x| x.resource})
471        items.Seq.lis.each_with_index do |li, i|
472          assert_attributes(attrs[i], %w(resource), li)
473        end
474      end
475    end
476
477    def assert_image10(attrs, image)
478      _wrap_assertion do
479        names = %w(about title url link)
480        assert_attributes(attrs, names, image)
481      end
482    end
483
484    def assert_items10(attrs, items)
485      _wrap_assertion do
486        names = %w(about title link description)
487        items.each_with_index do |item, i|
488          assert_attributes(attrs[i], names, item)
489        end
490      end
491    end
492
493    def assert_textinput10(attrs, textinput)
494      _wrap_assertion do
495        names = %w(about title description name link)
496        assert_attributes(attrs, names, textinput)
497      end
498    end
499
500
501    def assert_channel09(attrs, channel)
502      _wrap_assertion do
503        n_attrs = normalized_attrs(attrs)
504
505        names = %w(title description link language rating
506                   copyright pubDate lastBuildDate docs
507                   managingEditor webMaster)
508        assert_attributes(attrs, names, channel)
509
510        %w(skipHours skipDays).each do |name|
511          value = n_attrs[name]
512          if value
513            target = channel.__send__(name)
514            __send__("assert_channel09_#{name}", value, target)
515          end
516        end
517      end
518    end
519
520    def assert_channel09_skipDays(contents, skipDays)
521      _wrap_assertion do
522        days = skipDays.days
523        contents.each_with_index do |content, i|
524          assert_equal(content, days[i].content)
525        end
526      end
527    end
528
529    def assert_channel09_skipHours(contents, skipHours)
530      _wrap_assertion do
531        hours = skipHours.hours
532        contents.each_with_index do |content, i|
533          assert_equal(content.to_i, hours[i].content)
534        end
535      end
536    end
537
538    def assert_image09(attrs, image)
539      _wrap_assertion do
540        names = %w(url link title description)
541        names << ["width", :integer]
542        names << ["height", :integer]
543        assert_attributes(attrs, names, image)
544      end
545    end
546
547    def assert_items09(attrs, items)
548      _wrap_assertion do
549        names = %w(title link description)
550        items.each_with_index do |item, i|
551          assert_attributes(attrs[i], names, item)
552        end
553      end
554    end
555
556    def assert_textinput09(attrs, textinput)
557      _wrap_assertion do
558        names = %w(title description name link)
559        assert_attributes(attrs, names, textinput)
560      end
561    end
562
563
564    def assert_channel20(attrs, channel)
565      _wrap_assertion do
566        n_attrs = normalized_attrs(attrs)
567
568        names = %w(title link description language copyright
569                   managingEditor webMaster pubDate
570                   lastBuildDate generator docs rating)
571        names << ["ttl", :integer]
572        assert_attributes(attrs, names, channel)
573
574        %w(cloud categories skipHours skipDays).each do |name|
575          value = n_attrs[name]
576          if value
577            target = channel.__send__(name)
578            __send__("assert_channel20_#{name}", value, target)
579          end
580        end
581      end
582    end
583
584    def assert_channel20_skipDays(contents, skipDays)
585      assert_channel09_skipDays(contents, skipDays)
586    end
587
588    def assert_channel20_skipHours(contents, skipHours)
589      assert_channel09_skipHours(contents, skipHours)
590    end
591
592    def assert_channel20_cloud(attrs, cloud)
593      _wrap_assertion do
594        names = %w(domain path registerProcedure protocol)
595        names << ["port", :integer]
596        assert_attributes(attrs, names, cloud)
597      end
598    end
599
600    def assert_channel20_categories(attrs, categories)
601      _wrap_assertion do
602        names = %w(domain content)
603        categories.each_with_index do |category, i|
604          assert_attributes(attrs[i], names, category)
605        end
606      end
607    end
608
609    def assert_image20(attrs, image)
610      _wrap_assertion do
611        names = %w(url link title description)
612        names << ["width", :integer]
613        names << ["height", :integer]
614        assert_attributes(attrs, names, image)
615      end
616    end
617
618    def assert_items20(attrs, items)
619      _wrap_assertion do
620        names = %w(about title link description)
621        items.each_with_index do |item, i|
622          assert_attributes(attrs[i], names, item)
623
624          n_attrs = normalized_attrs(attrs[i])
625
626          %w(source enclosure categories guid).each do |name|
627            value = n_attrs[name]
628            if value
629              target = item.__send__(name)
630              __send__("assert_items20_#{name}", value, target)
631            end
632          end
633        end
634      end
635    end
636
637    def assert_items20_source(attrs, source)
638      _wrap_assertion do
639        assert_attributes(attrs, %w(url content), source)
640      end
641    end
642
643    def assert_items20_enclosure(attrs, enclosure)
644      _wrap_assertion do
645        names = ["url", ["length", :integer], "type"]
646        assert_attributes(attrs, names, enclosure)
647      end
648    end
649
650    def assert_items20_categories(attrs, categories)
651      _wrap_assertion do
652        assert_channel20_categories(attrs, categories)
653      end
654    end
655
656    def assert_items20_guid(attrs, guid)
657      _wrap_assertion do
658        names = [["isPermaLink", :boolean], ["content"]]
659        assert_attributes(attrs, names, guid)
660      end
661    end
662
663    def assert_textinput20(attrs, textinput)
664      _wrap_assertion do
665        names = %w(title description name link)
666        assert_attributes(attrs, names, textinput)
667      end
668    end
669  end
670end
671