1require 'erb'
2
3module RSS
4  module Assertions
5    def _wrap_assertion
6      yield
7    end
8
9    def assert_parse(rss, assert_method, *args)
10      __send__("assert_#{assert_method}", *args) do
11        ::RSS::Parser.parse(rss)
12      end
13      __send__("assert_#{assert_method}", *args) do
14        ::RSS::Parser.parse(rss, false).validate
15      end
16    end
17
18    def assert_ns(prefix, uri)
19      _wrap_assertion do
20        begin
21          yield
22          flunk("Not raise NSError")
23        rescue ::RSS::NSError => e
24          assert_equal(prefix, e.prefix)
25          assert_equal(uri, e.uri)
26        end
27      end
28    end
29
30    def assert_missing_tag(tag, parent)
31      _wrap_assertion do
32        begin
33          yield
34          flunk("Not raise MissingTagError")
35        rescue ::RSS::MissingTagError => e
36          assert_equal(tag, e.tag)
37          assert_equal(parent, e.parent)
38        end
39      end
40    end
41
42    def assert_too_much_tag(tag, parent)
43      _wrap_assertion do
44        begin
45          yield
46          flunk("Not raise TooMuchTagError")
47        rescue ::RSS::TooMuchTagError => e
48          assert_equal(tag, e.tag)
49          assert_equal(parent, e.parent)
50        end
51      end
52    end
53
54    def assert_missing_attribute(tag, attrname)
55      _wrap_assertion do
56        begin
57          yield
58          flunk("Not raise MissingAttributeError")
59        rescue ::RSS::MissingAttributeError => e
60          assert_equal(tag, e.tag)
61          assert_equal(attrname, e.attribute)
62        end
63      end
64    end
65
66    def assert_not_expected_tag(tag, uri, parent)
67      _wrap_assertion do
68        begin
69          yield
70          flunk("Not raise NotExpectedTagError")
71        rescue ::RSS::NotExpectedTagError => e
72          assert_equal(tag, e.tag)
73          assert_equal(uri, e.uri)
74          assert_equal(parent, e.parent)
75        end
76      end
77    end
78
79    def assert_not_available_value(tag, value, attribute=nil)
80      _wrap_assertion do
81        begin
82          yield
83          flunk("Not raise NotAvailableValueError")
84        rescue ::RSS::NotAvailableValueError => e
85          assert_equal(tag, e.tag)
86          assert_equal(value, e.value)
87          assert_equal(attribute, e.attribute)
88        end
89      end
90    end
91
92    def assert_not_set_error(name, variables)
93      _wrap_assertion do
94        begin
95          yield
96          flunk("Not raise NotSetError")
97        rescue ::RSS::NotSetError => e
98          assert_equal(name, e.name)
99          assert_kind_of(Array, variables)
100          assert_equal(variables.sort, e.variables.sort)
101        end
102      end
103    end
104
105    def assert_xml_declaration(version, encoding, standalone, rss)
106      _wrap_assertion do
107        assert_equal(version, rss.version)
108        assert_equal(encoding, rss.encoding)
109        assert_equal(standalone, rss.standalone)
110      end
111    end
112
113    def assert_xml_stylesheet_attrs(attrs, xsl)
114      _wrap_assertion do
115        n_attrs = normalized_attrs(attrs)
116        ::RSS::XMLStyleSheet::ATTRIBUTES.each do |name|
117          assert_equal(n_attrs[name], xsl.__send__(name))
118        end
119      end
120    end
121
122    def assert_xml_stylesheet(target, attrs, xsl)
123      _wrap_assertion do
124        if attrs.has_key?(:href)
125          if !attrs.has_key?(:type) and attrs.has_key?(:guess_type)
126            attrs[:type] = attrs[:guess_type]
127          end
128          assert_equal("xml-stylesheet", target)
129          assert_xml_stylesheet_attrs(attrs, xsl)
130        else
131          assert_nil(target)
132          assert_equal("", xsl.to_s)
133        end
134      end
135    end
136
137    def assert_xml_stylesheet_pis(attrs_ary, rss=nil)
138      _wrap_assertion do
139        if rss.nil?
140          rss = ::RSS::RDF.new
141          setup_rss10(rss)
142        end
143        xss_strs = []
144        attrs_ary.each do |attrs|
145          xss = ::RSS::XMLStyleSheet.new(attrs)
146          xss_strs.push(xss.to_s)
147          rss.xml_stylesheets.push(xss)
148        end
149        pi_str = rss.to_s.gsub(/<\?xml .*\n/, "").gsub(/\s*<[^\?].*\z/m, "")
150        assert_equal(xss_strs.join("\n"), pi_str)
151      end
152    end
153
154    def assert_xml_stylesheets(attrs, xss)
155      _wrap_assertion do
156        xss.each_with_index do |xs, i|
157          assert_xml_stylesheet_attrs(attrs[i], xs)
158        end
159      end
160    end
161
162
163    def assert_atom_person(tag_name, generator)
164      _wrap_assertion do
165        name = "Mark Pilgrim"
166        uri = "http://example.org/"
167        email = "f8dy@example.com"
168
169        assert_parse(generator.call(<<-EOA), :missing_tag, "name", tag_name)
170  <#{tag_name}/>
171EOA
172
173        assert_parse(generator.call(<<-EOA), :missing_tag, "name", tag_name)
174  <#{tag_name}>
175    <uri>#{uri}</uri>
176    <email>#{email}</email>
177  </#{tag_name}>
178EOA
179
180        assert_parse(generator.call(<<-EOA), :nothing_raised)
181  <#{tag_name}>
182    <name>#{name}</name>
183  </#{tag_name}>
184EOA
185
186        feed = RSS::Parser.parse(generator.call(<<-EOA))
187  <#{tag_name}>
188    <name>#{name}</name>
189    <uri>#{uri}</uri>
190    <email>#{email}</email>
191  </#{tag_name}>
192EOA
193
194        person = yield(feed)
195        assert_not_nil(person)
196        assert_equal(name, person.name.content)
197        assert_equal(uri, person.uri.content)
198        assert_equal(email, person.email.content)
199      end
200    end
201
202    def assert_atom_category(generator)
203      _wrap_assertion do
204        term = "Music"
205        scheme = "http://xmlns.com/wordnet/1.6/"
206        label = "music"
207
208        missing_args = [:missing_attribute, "category", "term"]
209        assert_parse(generator.call(<<-EOA), *missing_args)
210  <category/>
211EOA
212
213        assert_parse(generator.call(<<-EOA), *missing_args)
214  <category scheme="#{scheme}" label="#{label}"/>
215EOA
216
217        assert_parse(generator.call(<<-EOA), :nothing_raised)
218  <category term="#{term}"/>
219EOA
220
221      feed = RSS::Parser.parse(generator.call(<<-EOA))
222  <category term="#{term}" scheme="#{scheme}" label="#{label}"/>
223EOA
224
225        category = yield(feed)
226        assert_not_nil(category)
227        assert_equal(term, category.term)
228        assert_equal(scheme, category.scheme)
229        assert_equal(label, category.label)
230      end
231    end
232
233    def assert_atom_link(generator)
234      _wrap_assertion do
235        href = "http://example.org/feed.atom"
236        rel = "self"
237        type = "application/atom+xml"
238        hreflang = "en"
239        title = "Atom"
240        length = "1024"
241
242        assert_parse(generator.call(<<-EOA), :missing_attribute, "link", "href")
243  <link/>
244EOA
245
246        assert_parse(generator.call(<<-EOA), :missing_attribute, "link", "href")
247  <link rel="#{rel}" type="#{type}" hreflang="#{hreflang}"
248        title="#{title}" length="#{length}"/>
249EOA
250
251        assert_parse(generator.call(<<-EOA), :nothing_raised)
252  <link href="#{href}"/>
253EOA
254
255        feed = RSS::Parser.parse(generator.call(<<-EOA))
256  <link href="#{href}" rel="#{rel}" type="#{type}" hreflang="#{hreflang}"
257        title="#{title}" length="#{length}"/>
258EOA
259
260        link = yield(feed)
261        assert_not_nil(link)
262        assert_equal(href, link.href)
263        assert_equal(rel, link.rel)
264        assert_equal(type, link.type)
265        assert_equal(hreflang, link.hreflang)
266        assert_equal(title, link.title)
267        assert_equal(length, link.length)
268
269
270        href = "http://example.org/index.html.ja"
271        parent = link.parent.tag_name
272        return if parent == "source"
273
274        optional_attributes = %w(hreflang="ja" type="text/html")
275        0.upto(optional_attributes.size) do |i|
276          combination(optional_attributes, i).each do |attributes|
277            attrs = attributes.join(" ")
278            assert_parse(generator.call(<<-EOA), :too_much_tag, "link", parent)
279  <link rel="alternate" #{attrs} href="#{href}"/>
280  <link rel="alternate" #{attrs} href="#{href}"/>
281EOA
282          end
283        end
284      end
285    end
286
287    def assert_atom_generator(generator)
288      _wrap_assertion do
289        uri = "http://www.example.com/"
290        version = "1.0"
291        content = "Example Toolkit"
292
293        assert_parse(generator.call(<<-EOA), :nothing_raised)
294  <generator/>
295EOA
296
297        assert_parse(generator.call(<<-EOA), :nothing_raised)
298  <generator uri="#{uri}" version="#{version}"/>
299EOA
300
301        feed = RSS::Parser.parse(generator.call(<<-EOA))
302  <generator uri="#{uri}" version="#{version}">#{content}</generator>
303EOA
304
305        gen = yield(feed)
306        assert_not_nil(gen)
307        assert_equal(uri, gen.uri)
308        assert_equal(version, gen.version)
309        assert_equal(content, gen.content)
310      end
311    end
312
313    def assert_atom_icon(generator)
314      _wrap_assertion do
315        content = "http://www.example.com/example.png"
316
317        assert_parse(generator.call(<<-EOA), :nothing_raised)
318  <icon/>
319EOA
320
321        feed = RSS::Parser.parse(generator.call(<<-EOA))
322  <icon>#{content}</icon>
323EOA
324
325        icon = yield(feed)
326        assert_not_nil(icon)
327        assert_equal(content, icon.content)
328      end
329    end
330
331    def assert_atom_text_construct(tag_name, generator)
332      _wrap_assertion do
333        [nil, "text", "html"].each do |type|
334          attr = ""
335          attr = " type=\"#{type}\""if type
336          assert_parse(generator.call(<<-EOA), :nothing_raised)
337  <#{tag_name}#{attr}/>
338EOA
339        end
340
341        assert_parse(generator.call(<<-EOA), :missing_tag, "div", tag_name)
342  <#{tag_name} type="xhtml"/>
343EOA
344
345        args = ["x", Atom::URI, tag_name]
346        assert_parse(generator.call(<<-EOA), :not_expected_tag, *args)
347  <#{tag_name} type="xhtml"><x/></#{tag_name}>
348EOA
349
350        invalid_value = "invalid"
351        args = ["type", invalid_value]
352        assert_parse(generator.call(<<-EOA), :not_available_value, *args)
353  <#{tag_name} type="#{invalid_value}"/>
354EOA
355
356        [
357         [nil, "A lot of effort went into making this effortless"],
358         ["text", "A lot of effort went into making this effortless"],
359         ["html", "A <em>lot</em> of effort went into making this effortless"],
360        ].each do |type, content|
361          attr = ""
362          attr = " type=\"#{type}\"" if type
363          feed = RSS::Parser.parse(generator.call(<<-EOA))
364  <#{tag_name}#{attr}>#{h content}</#{tag_name}>
365EOA
366
367          element = yield(feed)
368          assert_not_nil(element)
369          assert_equal(type, element.type)
370          assert_equal(content, element.content)
371        end
372
373        [false, true].each do |with_space|
374          xhtml_uri = "http://www.w3.org/1999/xhtml"
375          xhtml_content = "<div xmlns=\"#{xhtml_uri}\">abc</div>"
376          xhtml_element = RSS::XML::Element.new("div", nil, xhtml_uri,
377                                                {"xmlns" => xhtml_uri},
378                                                ["abc"])
379          content = xhtml_content
380          content = "  #{content}  " if with_space
381          feed = RSS::Parser.parse(generator.call(<<-EOA))
382  <#{tag_name} type="xhtml">#{content}</#{tag_name}>
383EOA
384
385          element = yield(feed)
386          assert_not_nil(element)
387          assert_equal("xhtml", element.type)
388          assert_equal(xhtml_content, element.content)
389          assert_equal(xhtml_element, element.xhtml)
390        end
391      end
392    end
393
394    def assert_atom_date_construct(tag_name, generator)
395      _wrap_assertion do
396        args = [tag_name, ""]
397        assert_parse(generator.call(<<-EOR), :not_available_value, *args)
398  <#{tag_name}/>
399EOR
400
401        [
402         ["xxx", false],
403         ["2007", false],
404         ["2007/02/09", true],
405        ].each do |invalid_value, can_parse|
406          assert_not_available_value(tag_name, invalid_value) do
407            RSS::Parser.parse(generator.call(<<-EOR))
408  <#{tag_name}>#{invalid_value}</#{tag_name}>
409EOR
410          end
411
412          feed = RSS::Parser.parse(generator.call(<<-EOR), false)
413  <#{tag_name}>#{invalid_value}</#{tag_name}>
414EOR
415          value = yield(feed).content
416          if can_parse
417            assert_equal(Time.parse(invalid_value), value)
418          else
419            assert_nil(value)
420          end
421        end
422
423        [
424         "2003-12-13T18:30:02Z",
425         "2003-12-13T18:30:02.25Z",
426         "2003-12-13T18:30:02+01:00",
427         "2003-12-13T18:30:02.25+01:00",
428        ].each do |valid_value|
429          assert_parse(generator.call(<<-EOR), :nothing_raised)
430  <#{tag_name}>#{valid_value}</#{tag_name}>
431EOR
432
433          feed = RSS::Parser.parse(generator.call(<<-EOR))
434  <#{tag_name}>#{valid_value}</#{tag_name}>
435EOR
436          assert_equal(Time.parse(valid_value), yield(feed).content)
437        end
438      end
439    end
440
441    def assert_atom_logo(generator)
442      _wrap_assertion do
443        content = "http://www.example.com/example.png"
444
445        assert_parse(generator.call(<<-EOA), :nothing_raised)
446  <logo/>
447EOA
448
449        feed = RSS::Parser.parse(generator.call(<<-EOA))
450  <logo>#{content}</logo>
451EOA
452
453        logo = yield(feed)
454        assert_not_nil(logo)
455        assert_equal(content, logo.content)
456      end
457    end
458
459    def assert_atom_content(generator, &getter)
460      _wrap_assertion do
461        assert_atom_content_inline_text(generator, &getter)
462        assert_atom_content_inline_xhtml(generator, &getter)
463        assert_atom_content_inline_other(generator, &getter)
464        assert_atom_content_out_of_line(generator, &getter)
465      end
466    end
467
468    def assert_atom_content_inline_text(generator)
469      _wrap_assertion do
470        [nil, "text", "html"].each do |type|
471          content = "<content"
472          content << " type='#{type}'" if type
473
474          suffix = "/>"
475          assert_parse(generator.call(content + suffix), :nothing_raised)
476          suffix = ">xxx</content>"
477          assert_parse(generator.call(content + suffix), :nothing_raised)
478        end
479
480        [
481         ["text", "sample content"],
482         ["text/plain", "sample content"],
483         ["html", "<em>sample</em> content"]
484        ].each do |type, content_content|
485          feed = RSS::Parser.parse(generator.call(<<-EOA))
486  <content type="#{type}">#{h content_content}</content>
487EOA
488          content = yield(feed)
489          assert_equal(type, content.type)
490          if %w(text html).include?(type)
491            assert(content.inline_text?)
492          else
493            assert(!content.inline_text?)
494          end
495          if type == "html"
496            assert(content.inline_html?)
497          else
498            assert(!content.inline_html?)
499          end
500          assert(!content.inline_xhtml?)
501          if type == "text/plain"
502            assert(content.inline_other?)
503            assert(content.inline_other_text?)
504          else
505            assert(!content.inline_other?)
506            assert(!content.inline_other_text?)
507          end
508          assert(!content.inline_other_xml?)
509          assert(!content.inline_other_base64?)
510          assert(!content.out_of_line?)
511          assert(!content.have_xml_content?)
512          assert_equal(content_content, content.content)
513        end
514      end
515    end
516
517    def assert_atom_content_inline_xhtml(generator)
518      _wrap_assertion do
519        args = ["div", "content"]
520        assert_parse(generator.call(<<-EOA), :missing_tag, *args)
521  <content type="xhtml"/>
522EOA
523
524        args = ["x", Atom::URI, "content"]
525        assert_parse(generator.call(<<-EOA), :not_expected_tag, *args)
526  <content type="xhtml"><x/></content>
527EOA
528
529        xhtml_uri = "http://www.w3.org/1999/xhtml"
530        xhtml_content = "<div xmlns=\"#{xhtml_uri}\">abc</div>"
531        xhtml_element = RSS::XML::Element.new("div", nil, xhtml_uri,
532                                              {"xmlns" => xhtml_uri},
533                                              ["abc"])
534        feed = RSS::Parser.parse(generator.call(<<-EOA))
535  <content type="xhtml">#{xhtml_content}</content>
536EOA
537
538        content = yield(feed)
539        assert_not_nil(content)
540        assert_equal("xhtml", content.type)
541        assert(!content.inline_text?)
542        assert(!content.inline_html?)
543        assert(content.inline_xhtml?)
544        assert(!content.inline_other?)
545        assert(!content.inline_other_text?)
546        assert(!content.inline_other_xml?)
547        assert(!content.inline_other_base64?)
548        assert(!content.out_of_line?)
549        assert(content.have_xml_content?)
550        assert_equal(xhtml_content, content.content)
551        assert_equal(xhtml_element, content.xhtml)
552      end
553    end
554
555    def assert_atom_content_inline_other(generator, &getter)
556      _wrap_assertion do
557        assert_atom_content_inline_other_text(generator, &getter)
558        assert_atom_content_inline_other_xml(generator, &getter)
559      end
560    end
561
562    def assert_atom_content_inline_other_text(generator)
563      _wrap_assertion do
564        type = "image/png"
565        assert_parse(generator.call(<<-EOA), :nothing_raised)
566  <content type="#{type}"/>
567EOA
568
569        png_file = File.join(File.dirname(__FILE__), "dot.png")
570        png = File.open(png_file, "rb") do |file|
571          file.read.force_encoding("binary")
572        end
573        base64_content = [png].pack("m").delete("\n")
574
575        [false, true].each do |with_space|
576          xml_content = base64_content
577          xml_content = "  #{base64_content}" if with_space
578          feed = RSS::Parser.parse(generator.call(<<-EOA))
579  <content type="#{type}">#{xml_content}</content>
580EOA
581
582          content = yield(feed)
583          assert_not_nil(content)
584          assert_equal(type, content.type)
585          assert(!content.inline_text?)
586          assert(!content.inline_html?)
587          assert(!content.inline_xhtml?)
588          assert(content.inline_other?)
589          assert(!content.inline_other_text?)
590          assert(!content.inline_other_xml?)
591          assert(content.inline_other_base64?)
592          assert(!content.out_of_line?)
593          assert(!content.have_xml_content?)
594          assert_equal(png, content.content)
595
596          xml = REXML::Document.new(content.to_s).root
597          assert_rexml_element([], {"type" => type}, base64_content, xml)
598        end
599      end
600    end
601
602    def assert_atom_content_inline_other_xml(generator)
603      _wrap_assertion do
604        type = "image/svg+xml"
605
606        assert_parse(generator.call(<<-EOA), :nothing_raised)
607  <content type="#{type}"/>
608EOA
609
610        svg_uri = "http://www.w3.org/2000/svg"
611        svg_width = "50pt"
612        svg_height = "20pt"
613        svg_version = "1.0"
614        text_x = "15"
615        text_y = "15"
616        text = "text"
617        svg_content = <<-EOS
618<svg
619   xmlns="#{svg_uri}"
620   width="#{svg_width}"
621   height="#{svg_height}"
622   version="#{svg_version}"
623><text x="#{text_x}" y="#{text_y}">#{text}</text
624></svg>
625EOS
626
627        text_element = RSS::XML::Element.new("text", nil, svg_uri,
628                                             {
629                                               "x" => text_x,
630                                               "y" => text_y,
631                                             },
632                                             [text])
633        svg_element = RSS::XML::Element.new("svg", nil, svg_uri,
634                                            {
635                                              "xmlns" => svg_uri,
636                                              "width" => svg_width,
637                                              "height" => svg_height,
638                                              "version" => svg_version,
639                                            },
640                                            [text_element])
641        feed = RSS::Parser.parse(generator.call(<<-EOA))
642  <content type="#{type}">#{svg_content}</content>
643EOA
644
645        content = yield(feed)
646        assert_not_nil(content)
647        assert_equal(type, content.type)
648        assert(!content.inline_text?)
649        assert(!content.inline_html?)
650        assert(!content.inline_xhtml?)
651        assert(content.inline_other?)
652        assert(!content.inline_other_text?)
653        assert(content.inline_other_xml?)
654        assert(!content.inline_other_base64?)
655        assert(!content.out_of_line?)
656        assert(content.have_xml_content?)
657        assert_equal(REXML::Document.new(svg_content).to_s.chomp,
658                     REXML::Document.new(content.content).to_s.chomp)
659        assert_equal(svg_element, content.xml)
660        assert_nil(content.xhtml)
661      end
662    end
663
664    def assert_atom_content_out_of_line(generator)
665      _wrap_assertion do
666        text_type = "text/plain"
667        text_src = "http://example.com/README.txt"
668
669        missing_args = [:missing_attribute, "content", "type"]
670        # RSS Parser raises error even if this is "should" not "must".
671        assert_parse(generator.call(<<-EOA), *missing_args)
672  <content src="#{text_src}"/>
673EOA
674
675        content_content = "xxx"
676        not_available_value_args = [:not_available_value,
677                                    "content", content_content]
678        assert_parse(generator.call(<<-EOA), *not_available_value_args)
679  <content type="#{text_type}" src="#{text_src}">#{content_content}</content>
680EOA
681
682        feed = RSS::Parser.parse(generator.call(<<-EOA))
683  <content type="#{text_type}" src="#{text_src}"/>
684EOA
685        content = yield(feed)
686        assert_not_nil(content)
687        assert_equal(text_type, content.type)
688        assert_equal(text_src, content.src)
689        assert(!content.inline_text?)
690        assert(!content.inline_html?)
691        assert(!content.inline_xhtml?)
692        assert(!content.inline_other?)
693        assert(!content.inline_other_text?)
694        assert(!content.inline_other_xml?)
695        assert(!content.inline_other_base64?)
696        assert(content.out_of_line?)
697        assert(!content.have_xml_content?)
698        assert_nil(content.xml)
699        assert_nil(content.xhtml)
700        assert_equal("", content.content)
701      end
702    end
703
704    def assert_atom_source(generator, &getter)
705      _wrap_assertion do
706        assert_atom_source_author(generator, &getter)
707        assert_atom_source_category(generator, &getter)
708        assert_atom_source_contributor(generator, &getter)
709        assert_atom_source_generator(generator, &getter)
710        assert_atom_source_icon(generator, &getter)
711        assert_atom_source_id(generator, &getter)
712        assert_atom_source_link(generator, &getter)
713        assert_atom_source_logo(generator, &getter)
714        assert_atom_source_rights(generator, &getter)
715        assert_atom_source_subtitle(generator, &getter)
716        assert_atom_source_title(generator, &getter)
717        assert_atom_source_updated(generator, &getter)
718      end
719    end
720
721    def assert_atom_source_author(generator)
722      assert_atom_person("author", generator) do |feed|
723        source = yield(feed)
724        assert_equal(1, source.authors.size)
725        source.author
726      end
727    end
728
729    def assert_atom_source_category(generator)
730      assert_atom_category(generator) do |feed|
731        source = yield(feed)
732        assert_equal(1, source.categories.size)
733        source.category
734      end
735    end
736
737    def assert_atom_source_contributor(generator)
738      assert_atom_person("contributor", generator) do |feed|
739        source = yield(feed)
740        assert_equal(1, source.contributors.size)
741        source.contributor
742      end
743    end
744
745    def assert_atom_source_generator(generator)
746      assert_atom_generator(generator) do |feed|
747        yield(feed).generator
748      end
749    end
750
751    def assert_atom_source_icon(generator)
752      assert_atom_icon(generator) do |feed|
753        yield(feed).icon
754      end
755    end
756
757    def assert_atom_source_id(generator)
758      id_content = "urn:uuid:a2fb588b-5674-4898-b420-265a734fea69"
759      id = "<id>#{id_content}</id>"
760      feed = RSS::Parser.parse(generator.call(id))
761      assert_equal(id_content, yield(feed).id.content)
762    end
763
764    def assert_atom_source_link(generator)
765      assert_atom_link(generator) do |feed|
766        source = yield(feed)
767        assert_equal(1, source.links.size)
768        source.link
769      end
770    end
771
772    def assert_atom_source_logo(generator)
773      assert_atom_logo(generator) do |feed|
774        yield(feed).logo
775      end
776    end
777
778    def assert_atom_source_rights(generator)
779      assert_atom_text_construct("rights", generator) do |feed|
780        yield(feed).rights
781      end
782    end
783
784    def assert_atom_source_subtitle(generator)
785      assert_atom_text_construct("subtitle", generator) do |feed|
786        yield(feed).subtitle
787      end
788    end
789
790    def assert_atom_source_title(generator)
791      assert_atom_text_construct("title", generator) do |feed|
792        yield(feed).title
793      end
794    end
795
796    def assert_atom_source_updated(generator)
797      assert_atom_date_construct("updated", generator) do |feed|
798        yield(feed).updated
799      end
800    end
801
802    def assert_dublin_core(elems, target)
803      _wrap_assertion do
804        elems.each do |name, value|
805          assert_equal(value, target.__send__("dc_#{name}"))
806        end
807      end
808    end
809
810    def assert_multiple_dublin_core(elems, target)
811      _wrap_assertion do
812        elems.each do |name, values, plural|
813          plural ||= "#{name}s"
814          actual = target.__send__("dc_#{plural}").collect{|x| x.value}
815          assert_equal(values, actual)
816        end
817      end
818    end
819
820    def assert_syndication(elems, target)
821      _wrap_assertion do
822        elems.each do |name, value|
823          meth = "sy_#{name}"
824          value = value.to_i if meth == "sy_updateFrequency"
825          assert_equal(value, target.__send__(meth ))
826        end
827      end
828    end
829
830    def assert_content(elems, target)
831      _wrap_assertion do
832        elems.each do |name, value|
833          assert_equal(value, target.__send__("content_#{name}"))
834        end
835      end
836    end
837
838    def assert_trackback(attrs, target)
839      _wrap_assertion do
840        n_attrs = normalized_attrs(attrs)
841        if n_attrs["ping"]
842          assert_equal(n_attrs["ping"], target.trackback_ping)
843        end
844        if n_attrs["abouts"]
845          n_attrs["abouts"].each_with_index do |about, i|
846            assert_equal(about, target.trackback_abouts[i].value)
847          end
848        end
849      end
850    end
851
852    def assert_taxo_topic(topics, target)
853      _wrap_assertion do
854        topics.each_with_index do |topic, i|
855          taxo_topic = target.taxo_topics[i]
856          topic.each do |name, value|
857            case name
858            when :link
859              assert_equal(value, taxo_topic.about)
860              assert_equal(value, taxo_topic.taxo_link)
861            when :topics
862              assert_equal(value, taxo_topic.taxo_topics.resources)
863            else
864              assert_equal(value, taxo_topic.__send__("dc_#{name}"))
865            end
866          end
867        end
868      end
869    end
870
871
872    def assert_attributes(attrs, names, target)
873      _wrap_assertion do
874        n_attrs = normalized_attrs(attrs)
875        names.each do |info|
876          if info.is_a?(String)
877            name = info
878            type = nil
879          else
880            name, type = info
881          end
882          value = n_attrs[name]
883          if value.is_a?(Time)
884            actual = target.__send__(name)
885            assert_instance_of(Time, actual)
886            assert_equal(value.to_i, actual.to_i)
887          elsif value
888            case type
889            when :integer
890              value = value.to_i
891            when :boolean
892              value = value == "true" if value.is_a?(String)
893            end
894            assert_equal(value, target.__send__(name))
895          end
896        end
897      end
898    end
899
900    def assert_rexml_element(children, attrs, text, element, text_type=nil)
901      _wrap_assertion do
902        if children
903          children_info = element.elements.collect {|e| [e.namespace, e.name]}
904          assert_equal(children.collect {|uri, name| [uri, name]}.sort,
905                       children_info.sort)
906        end
907        if attrs
908          assert_equal(attrs.collect {|k, v| [k, v]}.sort,
909                       element.attributes.collect {|k, v| [k, v]}.sort)
910        end
911        case text_type
912        when :time
913          assert_not_nil(element.text)
914          assert_equal(Time.parse(text).to_s, Time.parse(element.text).to_s)
915        else
916          assert_equal(text, element.text)
917        end
918      end
919    end
920
921    def _assert_maker_atom_persons(feed_type, maker_readers, feed_readers)
922      _wrap_assertion do
923        persons = []
924        feed = RSS::Maker.make("atom:#{feed_type}") do |maker|
925          yield maker
926          targets = chain_reader(maker, maker_readers)
927          targets.each do |target|
928            person = {
929              :name => target.name,
930              :uri => target.uri,
931              :email => target.email,
932            }
933            persons << person if person[:name]
934          end
935        end
936
937        actual_persons = chain_reader(feed, feed_readers) || []
938        actual_persons = actual_persons.collect do |person|
939          {
940            :name => person.name ? person.name.content : nil,
941            :uri => person.uri ? person.uri.content : nil,
942            :email => person.email ? person.email.content : nil,
943          }
944        end
945        assert_equal(persons, actual_persons)
946      end
947    end
948
949    def assert_maker_atom_persons(feed_type, maker_readers, feed_readers,
950                                  not_set_error_name=nil,
951                                  parent_not_set_error_name=nil,
952                                  parent_not_set_variable=nil)
953      _wrap_assertion do
954        not_set_error_name ||= "maker.#{maker_readers.join('.')}"
955
956        args = [feed_type, maker_readers, feed_readers]
957        if parent_not_set_error_name or parent_not_set_variable
958          assert_not_set_error(parent_not_set_error_name,
959                               parent_not_set_variable) do
960            _assert_maker_atom_persons(*args) do |maker|
961              yield maker
962            end
963          end
964        else
965          _assert_maker_atom_persons(*args) do |maker|
966            yield maker
967          end
968        end
969
970        assert_not_set_error(not_set_error_name, %w(name)) do
971          _assert_maker_atom_persons(feed_type, maker_readers,
972                                     feed_readers) do |maker|
973            yield maker
974            targets = chain_reader(maker, maker_readers)
975            targets.new_child
976          end
977        end
978
979        assert_not_set_error(not_set_error_name, %w(name)) do
980          _assert_maker_atom_persons(feed_type, maker_readers,
981                                     feed_readers) do |maker|
982            yield maker
983            targets = chain_reader(maker, maker_readers)
984            target = targets.new_child
985            target.uri = "http://example.com/~me/"
986          end
987        end
988
989        assert_not_set_error(not_set_error_name, %w(name)) do
990          _assert_maker_atom_persons(feed_type, maker_readers,
991                                     feed_readers) do |maker|
992            yield maker
993            targets = chain_reader(maker, maker_readers)
994            target = targets.new_child
995            target.email = "me@example.com"
996          end
997        end
998
999        assert_not_set_error(not_set_error_name, %w(name)) do
1000          _assert_maker_atom_persons(feed_type, maker_readers,
1001                                     feed_readers) do |maker|
1002            yield maker
1003            targets = chain_reader(maker, maker_readers)
1004            target = targets.new_child
1005            target.uri = "http://example.com/~me/"
1006            target.email = "me@example.com"
1007          end
1008        end
1009
1010        _assert_maker_atom_persons(feed_type, maker_readers,
1011                                   feed_readers) do |maker|
1012          yield maker
1013          targets = chain_reader(maker, maker_readers)
1014          target = targets.new_child
1015          target.name = "me"
1016        end
1017
1018        _assert_maker_atom_persons(feed_type, maker_readers,
1019                                   feed_readers) do |maker|
1020          yield maker
1021          targets = chain_reader(maker, maker_readers)
1022          target = targets.new_child
1023          target.name = "me"
1024          target.uri = "http://example.com/~me/"
1025        end
1026
1027        _assert_maker_atom_persons(feed_type, maker_readers,
1028                                   feed_readers) do |maker|
1029          yield maker
1030          targets = chain_reader(maker, maker_readers)
1031          target = targets.new_child
1032          target.name = "me"
1033          target.email = "me@example.com"
1034        end
1035
1036        _assert_maker_atom_persons(feed_type, maker_readers,
1037                                   feed_readers) do |maker|
1038          yield maker
1039          targets = chain_reader(maker, maker_readers)
1040          target = targets.new_child
1041          target.name = "me"
1042          target.uri = "http://example.com/~me/"
1043          target.email = "me@example.com"
1044        end
1045
1046        _assert_maker_atom_persons(feed_type, maker_readers,
1047                                   feed_readers) do |maker|
1048          yield maker
1049          targets = chain_reader(maker, maker_readers)
1050
1051          target = targets.new_child
1052          target.name = "me"
1053          target.uri = "http://example.com/~me/"
1054          target.email = "me@example.com"
1055
1056          target = targets.new_child
1057          target.name = "you"
1058          target.uri = "http://example.com/~you/"
1059          target.email = "you@example.com"
1060        end
1061
1062        assert_not_set_error(not_set_error_name, %w(name)) do
1063          _assert_maker_atom_persons(feed_type, maker_readers,
1064                                     feed_readers) do |maker|
1065            yield maker
1066            targets = chain_reader(maker, maker_readers)
1067
1068            target = targets.new_child
1069            target.name = "me"
1070            target.uri = "http://example.com/~me/"
1071            target.email = "me@example.com"
1072
1073            target = targets.new_child
1074          end
1075        end
1076      end
1077    end
1078
1079    def _assert_maker_atom_text_construct(feed_type, maker_readers,
1080                                          feed_readers, &block)
1081      maker_extractor = Proc.new do |target|
1082        text = {
1083          :type => target.type,
1084          :content => target.content,
1085          :xml_content => target.xml_content,
1086        }
1087        if text[:type] == "xhtml"
1088          if text[:xml_content]
1089            xml_content = text[:xml_content]
1090            xhtml_uri = "http://www.w3.org/1999/xhtml"
1091            unless xml_content.is_a?(RSS::XML::Element) and
1092                ["div", xhtml_uri] == [xml_content.name, xml_content.uri]
1093              children = xml_content
1094              children = [children] unless children.is_a?(Array)
1095              xml_content = RSS::XML::Element.new("div", nil, xhtml_uri,
1096                                                  {"xmlns" => xhtml_uri},
1097                                                  children)
1098              text[:xml_content] = xml_content
1099            end
1100            text
1101          else
1102            nil
1103          end
1104        else
1105          text[:content] ? text : nil
1106        end
1107      end
1108      feed_extractor = Proc.new do |target|
1109        {
1110          :type => target.type,
1111          :content => target.content,
1112          :xml_content => target.xhtml,
1113        }
1114      end
1115      _assert_maker_atom_element(feed_type, maker_readers, feed_readers,
1116                                 maker_extractor, feed_extractor,
1117                                 &block)
1118    end
1119
1120    def assert_maker_atom_text_construct(feed_type, maker_readers, feed_readers,
1121                                         parent_not_set_error_name=nil,
1122                                         parent_not_set_variable=nil,
1123                                         not_set_error_name=nil)
1124      _wrap_assertion do
1125        not_set_error_name ||= "maker.#{maker_readers.join('.')}"
1126
1127        args = [feed_type, maker_readers, feed_readers]
1128        if parent_not_set_error_name or parent_not_set_variable
1129          assert_not_set_error(parent_not_set_error_name,
1130                               parent_not_set_variable) do
1131            _assert_maker_atom_text_construct(*args) do |maker|
1132              yield maker
1133            end
1134          end
1135        else
1136          _assert_maker_atom_text_construct(*args) do |maker|
1137            yield maker
1138          end
1139        end
1140
1141        assert_not_set_error(not_set_error_name, %w(content)) do
1142          _assert_maker_atom_text_construct(*args) do |maker|
1143            yield maker
1144            target = chain_reader(maker, maker_readers) {|x| x}
1145            target.type = "text"
1146          end
1147        end
1148
1149        assert_not_set_error(not_set_error_name, %w(content)) do
1150          _assert_maker_atom_text_construct(*args) do |maker|
1151            yield maker
1152            target = chain_reader(maker, maker_readers) {|x| x}
1153            target.type = "html"
1154          end
1155        end
1156
1157        assert_not_set_error(not_set_error_name, %w(xml_content)) do
1158          _assert_maker_atom_text_construct(*args) do |maker|
1159            yield maker
1160            target = chain_reader(maker, maker_readers) {|x| x}
1161            target.type = "xhtml"
1162          end
1163        end
1164
1165        assert_not_set_error(not_set_error_name, %w(xml_content)) do
1166          _assert_maker_atom_text_construct(*args) do |maker|
1167            yield maker
1168            target = chain_reader(maker, maker_readers) {|x| x}
1169            target.type = "xhtml"
1170            target.content = "Content"
1171          end
1172        end
1173
1174        _assert_maker_atom_text_construct(*args) do |maker|
1175          yield maker
1176          target = chain_reader(maker, maker_readers) {|x| x}
1177          target.type = "text"
1178          target.content = "Content"
1179        end
1180
1181        _assert_maker_atom_text_construct(*args) do |maker|
1182          yield maker
1183          target = chain_reader(maker, maker_readers) {|x| x}
1184          target.type = "html"
1185          target.content = "<em>Content</em>"
1186        end
1187
1188        _assert_maker_atom_text_construct(*args) do |maker|
1189          yield maker
1190          target = chain_reader(maker, maker_readers) {|x| x}
1191          target.type = "xhtml"
1192          target.xml_content = "text only"
1193        end
1194
1195        _assert_maker_atom_text_construct(*args) do |maker|
1196          yield maker
1197          target = chain_reader(maker, maker_readers) {|x| x}
1198          target.type = "xhtml"
1199          target.xml_content = RSS::XML::Element.new("unknown")
1200        end
1201      end
1202    end
1203
1204    def _assert_maker_atom_date_construct(feed_type, maker_readers,
1205                                          feed_readers, &block)
1206      maker_extractor = Proc.new do |target|
1207        date = {
1208          :content => target,
1209        }
1210        date[:content] ? date : nil
1211      end
1212      feed_extractor = Proc.new do |target|
1213        {
1214          :content => target.content,
1215        }
1216      end
1217      _assert_maker_atom_element(feed_type, maker_readers, feed_readers,
1218                                 maker_extractor, feed_extractor,
1219                                 &block)
1220    end
1221
1222    def assert_maker_atom_date_construct(feed_type, maker_readers, feed_readers,
1223                                         parent_not_set_error_name=nil,
1224                                         parent_not_set_variable=nil)
1225      _wrap_assertion do
1226        args = [feed_type, maker_readers, feed_readers]
1227        if parent_not_set_error_name or parent_not_set_variable
1228          assert_not_set_error(parent_not_set_error_name,
1229                               parent_not_set_variable) do
1230            _assert_maker_atom_date_construct(*args) do |maker|
1231              yield maker
1232            end
1233          end
1234        else
1235          _assert_maker_atom_date_construct(*args) do |maker|
1236            yield maker
1237          end
1238        end
1239
1240        maker_readers = maker_readers.dup
1241        writer = "#{maker_readers.pop}="
1242        _assert_maker_atom_date_construct(*args) do |maker|
1243          yield maker
1244          target = chain_reader(maker, maker_readers)
1245          target.__send__(writer, Time.now)
1246        end
1247      end
1248    end
1249
1250    def _assert_maker_atom_element(feed_type, maker_readers, feed_readers,
1251                                   maker_extractor, feed_extractor)
1252      _wrap_assertion do
1253        element = nil
1254        feed = RSS::Maker.make("atom:#{feed_type}") do |maker|
1255          yield maker
1256          target = chain_reader(maker, maker_readers) {|x| x}
1257          element = maker_extractor.call(target)
1258        end
1259
1260        target = chain_reader(feed, feed_readers)
1261        if target
1262          actual_element = feed_extractor.call(target)
1263        else
1264          actual_element = nil
1265        end
1266        assert_equal(element, actual_element)
1267      end
1268    end
1269
1270    def _assert_maker_atom_elements(feed_type, maker_readers, feed_readers,
1271                                    maker_extractor, feed_extractor,
1272                                    invalid_feed_checker=nil)
1273      _wrap_assertion do
1274        elements = []
1275        invalid_feed_exception = nil
1276        feed = nil
1277        begin
1278          feed = RSS::Maker.make("atom:#{feed_type}") do |maker|
1279            yield maker
1280            targets = chain_reader(maker, maker_readers)
1281            targets.each do |target|
1282              element = maker_extractor.call(target)
1283              elements << element if element
1284            end
1285            if invalid_feed_checker
1286              invalid_feed_exception = invalid_feed_checker.call(targets)
1287            end
1288          end
1289        rescue RSS::Error
1290          if invalid_feed_exception.is_a?(RSS::TooMuchTagError)
1291            assert_too_much_tag(invalid_feed_exception.tag,
1292                                invalid_feed_exception.parent) do
1293              raise
1294            end
1295          else
1296            raise
1297          end
1298        end
1299
1300        if invalid_feed_exception.nil?
1301          actual_elements = chain_reader(feed, feed_readers) || []
1302          actual_elements = actual_elements.collect do |target|
1303            feed_extractor.call(target)
1304          end
1305          assert_equal(elements, actual_elements)
1306        end
1307      end
1308    end
1309
1310    def assert_maker_atom_element(feed_type, maker_readers, feed_readers,
1311                                  setup_target, optional_variables,
1312                                  required_variable, assert_method_name,
1313                                  not_set_error_name=nil,
1314                                  *additional_args)
1315      _wrap_assertion do
1316        not_set_error_name ||= "maker.#{maker_readers.join('.')}"
1317
1318        0.upto(optional_variables.size) do |i|
1319          combination(optional_variables, i).each do |names|
1320            have = {}
1321            names.each do |name|
1322              have[name.intern] = true
1323            end
1324            have_required_variable_too =
1325              have.merge({required_variable.intern => true})
1326
1327            assert_not_set_error(not_set_error_name, [required_variable]) do
1328              __send__(assert_method_name, feed_type, maker_readers,
1329                       feed_readers, *additional_args) do |maker|
1330                yield maker
1331                target = chain_reader(maker, maker_readers) {|x| x}
1332                setup_target.call(target, have)
1333              end
1334            end
1335
1336            __send__(assert_method_name, feed_type, maker_readers, feed_readers,
1337                     *additional_args) do |maker|
1338              yield maker
1339              target = chain_reader(maker, maker_readers) {|x| x}
1340              setup_target.call(target, have_required_variable_too)
1341            end
1342          end
1343        end
1344      end
1345    end
1346
1347    def assert_maker_atom_elements(feed_type, maker_readers, feed_readers,
1348                                   setup_target, optional_variables,
1349                                   required_variable, assert_method_name,
1350                                   not_set_error_name=nil,
1351                                   *additional_args)
1352      _wrap_assertion do
1353        not_set_error_name ||= "maker.#{maker_readers.join('.')}"
1354
1355        0.upto(optional_variables.size) do |i|
1356          combination(optional_variables, i).each do |names|
1357            have = {}
1358            names.each do |name|
1359              have[name.intern] = true
1360            end
1361            have_required_variable_too =
1362              have.merge({required_variable.intern => true})
1363
1364            assert_not_set_error(not_set_error_name, [required_variable]) do
1365              __send__(assert_method_name, feed_type, maker_readers,
1366                       feed_readers, *additional_args) do |maker|
1367                yield maker
1368                targets = chain_reader(maker, maker_readers)
1369                setup_target.call(targets, have)
1370              end
1371            end
1372
1373            __send__(assert_method_name, feed_type, maker_readers, feed_readers,
1374                     *additional_args) do |maker|
1375              yield maker
1376              targets = chain_reader(maker, maker_readers)
1377              setup_target.call(targets, have_required_variable_too)
1378            end
1379
1380            __send__(assert_method_name, feed_type, maker_readers, feed_readers,
1381                     *additional_args) do |maker|
1382              yield maker
1383              targets = chain_reader(maker, maker_readers)
1384              setup_target.call(targets, have_required_variable_too)
1385              setup_target.call(targets, have_required_variable_too)
1386            end
1387
1388            assert_not_set_error(not_set_error_name, [required_variable]) do
1389            __send__(assert_method_name, feed_type, maker_readers, feed_readers,
1390                     *additional_args) do |maker|
1391                yield maker
1392                targets = chain_reader(maker, maker_readers)
1393                setup_target.call(targets, have_required_variable_too)
1394                setup_target.call(targets, have)
1395              end
1396            end
1397          end
1398        end
1399      end
1400    end
1401
1402    def _assert_maker_atom_categories(feed_type, maker_readers,
1403                                      feed_readers, &block)
1404      maker_extractor = Proc.new do |target|
1405        category = {
1406          :term => target.term,
1407          :scheme => target.scheme,
1408          :label => target.label,
1409        }
1410        category[:term] ? category : nil
1411      end
1412      feed_extractor = Proc.new do |target|
1413        {
1414          :term => target.term,
1415          :scheme => target.scheme,
1416          :label => target.label,
1417        }
1418      end
1419      _assert_maker_atom_elements(feed_type, maker_readers, feed_readers,
1420                                  maker_extractor, feed_extractor, &block)
1421    end
1422
1423    def assert_maker_atom_categories(feed_type, maker_readers, feed_readers,
1424                                     not_set_error_name=nil, &block)
1425      _wrap_assertion do
1426        _assert_maker_atom_categories(feed_type, maker_readers,
1427                                      feed_readers) do |maker|
1428          yield maker
1429        end
1430
1431        setup_target = Proc.new do |targets, have|
1432          target = targets.new_child
1433          target.term = "music" if have[:term]
1434          target.scheme = "http://example.com/category/music" if have[:scheme]
1435          target.label = "Music" if have[:label]
1436        end
1437
1438        optional_variables = %w(scheme label)
1439
1440        assert_maker_atom_elements(feed_type, maker_readers, feed_readers,
1441                                   setup_target, optional_variables,
1442                                   "term", :_assert_maker_atom_categories,
1443                                   not_set_error_name, &block)
1444      end
1445    end
1446
1447    def _assert_maker_atom_generator(feed_type, maker_readers,
1448                                     feed_readers, &block)
1449      maker_extractor = Proc.new do |target|
1450        generator = {
1451          :uri => target.uri,
1452          :version => target.version,
1453          :content => target.content,
1454        }
1455        generator[:content] ? generator : nil
1456      end
1457      feed_extractor = Proc.new do |target|
1458        {
1459          :uri => target.uri,
1460          :version => target.version,
1461          :content => target.content,
1462        }
1463      end
1464      _assert_maker_atom_element(feed_type, maker_readers, feed_readers,
1465                                 maker_extractor, feed_extractor,
1466                                 &block)
1467    end
1468
1469    def assert_maker_atom_generator(feed_type, maker_readers, feed_readers,
1470                                    not_set_error_name=nil, &block)
1471      _wrap_assertion do
1472        not_set_error_name ||= "maker.#{maker_readers.join('.')}"
1473
1474        _assert_maker_atom_generator(feed_type, maker_readers,
1475                                     feed_readers) do |maker|
1476          yield maker
1477        end
1478
1479        setup_target = Proc.new do |target, have|
1480          target.content = "RSS Maker" if have[:content]
1481          target.uri = "http://example.com/rss/maker" if have[:uri]
1482          target.version = "0.0.1" if have[:version]
1483        end
1484
1485        optional_variables = %w(uri version)
1486
1487        assert_maker_atom_element(feed_type, maker_readers, feed_readers,
1488                                  setup_target, optional_variables,
1489                                  "content", :_assert_maker_atom_generator,
1490                                  not_set_error_name, &block)
1491      end
1492    end
1493
1494    def _assert_maker_atom_icon(feed_type, maker_readers, feed_readers,
1495                                accessor_base, &block)
1496      maker_extractor = Proc.new do |target|
1497        icon = {
1498          :content => target.__send__(accessor_base),
1499        }
1500        icon[:content] ? icon : nil
1501      end
1502      feed_extractor = Proc.new do |target|
1503        {
1504          :content => target.content,
1505        }
1506      end
1507      _assert_maker_atom_element(feed_type, maker_readers, feed_readers,
1508                                 maker_extractor, feed_extractor,
1509                                 &block)
1510    end
1511
1512    def assert_maker_atom_icon(feed_type, maker_readers, feed_readers,
1513                               accessor_base=nil, not_set_error_name=nil)
1514      _wrap_assertion do
1515        accessor_base ||= "url"
1516        not_set_error_name ||= "maker.#{maker_readers.join('.')}"
1517
1518        _assert_maker_atom_icon(feed_type, maker_readers, feed_readers,
1519                                accessor_base) do |maker|
1520          yield maker
1521        end
1522
1523        _assert_maker_atom_icon(feed_type, maker_readers, feed_readers,
1524                                accessor_base) do |maker|
1525          yield maker
1526          target = chain_reader(maker, maker_readers)
1527          target.__send__("#{accessor_base}=", "http://example.com/icon.png")
1528        end
1529      end
1530    end
1531
1532    def _assert_maker_atom_links(feed_type, maker_readers, feed_readers,
1533                                 allow_duplication=false, &block)
1534      maker_extractor = Proc.new do |target|
1535        link = {
1536          :href => target.href,
1537          :rel => target.rel,
1538          :type => target.type,
1539          :hreflang => target.hreflang,
1540          :title => target.title,
1541          :length => target.length,
1542        }
1543        link[:href] ? link : nil
1544      end
1545      feed_extractor = Proc.new do |target|
1546        {
1547          :href => target.href,
1548          :rel => target.rel,
1549          :type => target.type,
1550          :hreflang => target.hreflang,
1551          :title => target.title,
1552          :length => target.length,
1553        }
1554      end
1555
1556      if feed_readers.first == "entries"
1557        parent = "entry"
1558      else
1559        parent = feed_type
1560      end
1561      invalid_feed_checker = Proc.new do |targets|
1562        infos = {}
1563        invalid_exception = nil
1564        targets.each do |target|
1565          key = [target.hreflang, target.type]
1566          if infos.has_key?(key)
1567            invalid_exception = RSS::TooMuchTagError.new("link", parent)
1568            break
1569          end
1570          infos[key] = true if target.rel.nil? or target.rel == "alternate"
1571        end
1572        invalid_exception
1573      end
1574      invalid_feed_checker = nil if allow_duplication
1575      _assert_maker_atom_elements(feed_type, maker_readers, feed_readers,
1576                                  maker_extractor, feed_extractor,
1577                                  invalid_feed_checker,
1578                                  &block)
1579    end
1580
1581    def assert_maker_atom_links(feed_type, maker_readers, feed_readers,
1582                                not_set_error_name=nil, allow_duplication=false,
1583                                &block)
1584      _wrap_assertion do
1585        _assert_maker_atom_links(feed_type, maker_readers,
1586                                 feed_readers) do |maker|
1587          yield maker
1588        end
1589
1590        langs = %(ja en fr zh po)
1591        setup_target = Proc.new do |targets, have|
1592          target = targets.new_child
1593          lang = langs[targets.size % langs.size]
1594          target.href = "http://example.com/index.html.#{lang}" if have[:href]
1595          target.rel = "alternate" if have[:rel]
1596          target.type = "text/xhtml" if have[:type]
1597          target.hreflang = lang if have[:hreflang]
1598          target.title = "FrontPage(#{lang})" if have[:title]
1599          target.length = 1024 if have[:length]
1600        end
1601
1602        optional_variables = %w(rel type hreflang title length)
1603
1604        assert_maker_atom_elements(feed_type, maker_readers, feed_readers,
1605                                   setup_target, optional_variables,
1606                                   "href", :_assert_maker_atom_links,
1607                                   not_set_error_name, allow_duplication,
1608                                   &block)
1609      end
1610    end
1611
1612    def _assert_maker_atom_logo(feed_type, maker_readers, feed_readers,
1613                                accessor_base, &block)
1614      maker_extractor = Proc.new do |target|
1615        logo = {
1616          :uri => target.__send__(accessor_base),
1617        }
1618        logo[:uri] ? logo : nil
1619      end
1620      feed_extractor = Proc.new do |target|
1621        {
1622          :uri => target.content,
1623        }
1624      end
1625      _assert_maker_atom_element(feed_type, maker_readers, feed_readers,
1626                                 maker_extractor, feed_extractor,
1627                                 &block)
1628    end
1629
1630    def assert_maker_atom_logo(feed_type, maker_readers, feed_readers,
1631                               accessor_base=nil, not_set_error_name=nil)
1632      _wrap_assertion do
1633        accessor_base ||= "uri"
1634        not_set_error_name ||= "maker.#{maker_readers.join('.')}"
1635
1636        _assert_maker_atom_logo(feed_type, maker_readers, feed_readers,
1637                                accessor_base) do |maker|
1638          yield maker
1639        end
1640
1641        _assert_maker_atom_logo(feed_type, maker_readers, feed_readers,
1642                                accessor_base) do |maker|
1643          yield maker
1644          target = chain_reader(maker, maker_readers)
1645          target.__send__("#{accessor_base}=", "http://example.com/logo.png")
1646        end
1647      end
1648    end
1649
1650    def _assert_maker_atom_id(feed_type, maker_readers, feed_readers, &block)
1651      maker_extractor = Proc.new do |target|
1652        id = {
1653          :uri => target.id,
1654        }
1655        id[:uri] ? id : nil
1656      end
1657      feed_extractor = Proc.new do |target|
1658        if target.id
1659          {
1660            :uri => target.id.content,
1661          }
1662        else
1663          nil
1664        end
1665      end
1666      _assert_maker_atom_element(feed_type, maker_readers, feed_readers,
1667                                 maker_extractor, feed_extractor,
1668                                 &block)
1669    end
1670
1671    def assert_maker_atom_id(feed_type, maker_readers, feed_readers,
1672                             not_set_error_name=nil)
1673      _wrap_assertion do
1674        not_set_error_name ||= "maker.#{maker_readers.join('.')}"
1675
1676        args = [feed_type, maker_readers, feed_readers]
1677        _assert_maker_atom_id(*args) do |maker|
1678          yield maker
1679        end
1680
1681        _assert_maker_atom_id(*args) do |maker|
1682          yield maker
1683          target = chain_reader(maker, maker_readers)
1684          target.id = "http://example.com/id/1"
1685        end
1686      end
1687    end
1688
1689    def _assert_maker_atom_content(feed_type, maker_readers,
1690                                   feed_readers, &block)
1691      maker_extractor = Proc.new do |target|
1692        content = {
1693          :type => target.type,
1694          :src => target.src,
1695          :content => target.content,
1696          :xml => target.xml,
1697          :inline_text => target.inline_text?,
1698          :inline_html => target.inline_html?,
1699          :inline_xhtml => target.inline_xhtml?,
1700          :inline_other => target.inline_other?,
1701          :inline_other_text => target.inline_other_text?,
1702          :inline_other_xml => target.inline_other_xml?,
1703          :inline_other_base64 => target.inline_other_base64?,
1704          :out_of_line => target.out_of_line?,
1705        }
1706        content[:src] = nil if content[:src] and content[:content]
1707        if content[:type] or content[:content]
1708          content
1709        else
1710          nil
1711        end
1712      end
1713      feed_extractor = Proc.new do |target|
1714        {
1715          :type => target.type,
1716          :src => target.src,
1717          :content => target.content,
1718          :xml => target.xml,
1719          :inline_text => target.inline_text?,
1720          :inline_html => target.inline_html?,
1721          :inline_xhtml => target.inline_xhtml?,
1722          :inline_other => target.inline_other?,
1723          :inline_other_text => target.inline_other_text?,
1724          :inline_other_xml => target.inline_other_xml?,
1725          :inline_other_base64 => target.inline_other_base64?,
1726          :out_of_line => target.out_of_line?,
1727        }
1728      end
1729      _assert_maker_atom_element(feed_type, maker_readers, feed_readers,
1730                                 maker_extractor, feed_extractor,
1731                                 &block)
1732    end
1733
1734    def assert_maker_atom_content(feed_type, maker_readers, feed_readers,
1735                                  not_set_error_name=nil, &block)
1736      _wrap_assertion do
1737        not_set_error_name ||= "maker.#{maker_readers.join('.')}"
1738        args = [feed_type, maker_readers, feed_readers, not_set_error_name]
1739        assert_maker_atom_content_inline_text(*args, &block)
1740        assert_maker_atom_content_inline_xhtml(*args, &block)
1741        assert_maker_atom_content_inline_other(*args, &block)
1742        assert_maker_atom_content_out_of_line(*args, &block)
1743      end
1744    end
1745
1746    def assert_maker_atom_content_inline_text(feed_type, maker_readers,
1747                                              feed_readers, not_set_error_name)
1748      _wrap_assertion do
1749        args = [feed_type, maker_readers, feed_readers]
1750        _assert_maker_atom_content(*args) do |maker|
1751          yield maker
1752        end
1753
1754        assert_not_set_error(not_set_error_name, %w(content)) do
1755          RSS::Maker.make("atom:#{feed_type}") do |maker|
1756            yield maker
1757            target = chain_reader(maker, maker_readers)
1758            target.type = "text"
1759          end
1760        end
1761
1762        assert_not_set_error(not_set_error_name, %w(content)) do
1763          RSS::Maker.make("atom:#{feed_type}") do |maker|
1764            yield maker
1765            target = chain_reader(maker, maker_readers)
1766            target.type = "html"
1767          end
1768        end
1769
1770        _assert_maker_atom_content(*args) do |maker|
1771          yield maker
1772          target = chain_reader(maker, maker_readers)
1773          target.content = ""
1774        end
1775
1776        _assert_maker_atom_content(*args) do |maker|
1777          yield maker
1778          target = chain_reader(maker, maker_readers)
1779          target.type = "text"
1780          target.content = "example content"
1781        end
1782
1783        _assert_maker_atom_content(*args) do |maker|
1784          yield maker
1785          target = chain_reader(maker, maker_readers)
1786          target.type = "html"
1787          target.content = "<em>text</em>"
1788        end
1789      end
1790    end
1791
1792    def assert_maker_atom_content_inline_xhtml(feed_type, maker_readers,
1793                                               feed_readers, not_set_error_name)
1794      _wrap_assertion do
1795        args = [feed_type, maker_readers, feed_readers]
1796        assert_not_set_error(not_set_error_name, %w(xml_content)) do
1797          RSS::Maker.make("atom:#{feed_type}") do |maker|
1798            yield maker
1799            target = chain_reader(maker, maker_readers)
1800            target.type = "xhtml"
1801          end
1802        end
1803
1804        assert_not_set_error(not_set_error_name, %w(xml_content)) do
1805          RSS::Maker.make("atom:#{feed_type}") do |maker|
1806            yield maker
1807            target = chain_reader(maker, maker_readers)
1808            target.type = "xhtml"
1809            target.content = "dummy"
1810          end
1811        end
1812
1813        _assert_maker_atom_content(*args) do |maker|
1814          yield maker
1815          target = chain_reader(maker, maker_readers)
1816          target.type = "xhtml"
1817          target.xml_content = "text"
1818        end
1819
1820        _assert_maker_atom_content(*args) do |maker|
1821          yield maker
1822          target = chain_reader(maker, maker_readers)
1823          target.type = "xhtml"
1824          target.xml = "text"
1825        end
1826
1827        _assert_maker_atom_content(*args) do |maker|
1828          yield maker
1829          target = chain_reader(maker, maker_readers)
1830          target.type = "xhtml"
1831          target.xml_content =
1832            RSS::XML::Element.new("em", nil, nil, {}, ["text"])
1833        end
1834
1835        _assert_maker_atom_content(*args) do |maker|
1836          yield maker
1837          target = chain_reader(maker, maker_readers)
1838          target.type = "xhtml"
1839          target.xml = RSS::XML::Element.new("em", nil, nil, {}, ["text"])
1840        end
1841
1842
1843        xhtml_uri = "http://www.w3.org/1999/xhtml"
1844        em = RSS::XML::Element.new("em", nil, nil, {}, ["text"])
1845        em_with_xhtml_uri =
1846          RSS::XML::Element.new("em", nil, xhtml_uri, {}, ["text"])
1847        feed = RSS::Maker.make("atom:#{feed_type}") do |maker|
1848          yield maker
1849          target = chain_reader(maker, maker_readers)
1850          target.type = "xhtml"
1851          target.xml = em
1852        end
1853        assert_equal(RSS::XML::Element.new("div", nil, xhtml_uri,
1854                                           {"xmlns" => xhtml_uri},
1855                                           [em_with_xhtml_uri]),
1856                     chain_reader(feed, feed_readers).xml)
1857
1858        div = RSS::XML::Element.new("div", nil, xhtml_uri,
1859                                    {"xmlns" => xhtml_uri,
1860                                     "class" => "sample"},
1861                                    ["text"])
1862        feed = RSS::Maker.make("atom:#{feed_type}") do |maker|
1863          yield maker
1864          target = chain_reader(maker, maker_readers)
1865          target.type = "xhtml"
1866          target.xml = div
1867        end
1868        assert_equal(div, chain_reader(feed, feed_readers).xml)
1869      end
1870    end
1871
1872    def assert_maker_atom_content_inline_other(*args, &block)
1873      _wrap_assertion do
1874        assert_maker_atom_content_inline_other_xml(*args, &block)
1875        assert_maker_atom_content_inline_other_text(*args, &block)
1876        assert_maker_atom_content_inline_other_base64(*args, &block)
1877      end
1878    end
1879
1880    def assert_maker_atom_content_inline_other_xml(feed_type, maker_readers,
1881                                                   feed_readers,
1882                                                   not_set_error_name)
1883      _wrap_assertion do
1884        args = [feed_type, maker_readers, feed_readers]
1885        assert_not_set_error(not_set_error_name, %w(xml_content)) do
1886          RSS::Maker.make("atom:#{feed_type}") do |maker|
1887            yield maker
1888            target = chain_reader(maker, maker_readers)
1889            target.type = "application/xml"
1890          end
1891        end
1892
1893        assert_not_set_error(not_set_error_name, %w(xml_content)) do
1894          RSS::Maker.make("atom:#{feed_type}") do |maker|
1895            yield maker
1896            target = chain_reader(maker, maker_readers)
1897            target.type = "svg/image+xml"
1898          end
1899        end
1900
1901        svg_uri = "http://www.w3.org/2000/svg"
1902        rect = RSS::XML::Element.new("rect", nil, svg_uri,
1903                                     {"x" => "0.5cm",
1904                                      "y" => "0.5cm",
1905                                      "width" => "2cm",
1906                                      "height" => "1cm"})
1907        svg = RSS::XML::Element.new("svg", nil, svg_uri,
1908                                    {"xmlns" => svg_uri,
1909                                     "version" => "1.1",
1910                                     "width" => "5cm",
1911                                     "height" => "4cm"},
1912                                    [rect])
1913        _assert_maker_atom_content(*args) do |maker|
1914          yield maker
1915          target = chain_reader(maker, maker_readers)
1916          target.type = "image/svg+xml"
1917          target.xml = svg
1918        end
1919
1920        feed = RSS::Maker.make("atom:#{feed_type}") do |maker|
1921          yield maker
1922          target = chain_reader(maker, maker_readers)
1923          target.type = "image/svg+xml"
1924          target.xml = svg
1925        end
1926        assert_equal(svg, chain_reader(feed, feed_readers).xml)
1927      end
1928    end
1929
1930    def assert_maker_atom_content_inline_other_text(feed_type, maker_readers,
1931                                                    feed_readers,
1932                                                    not_set_error_name)
1933      _wrap_assertion do
1934        args = [feed_type, maker_readers, feed_readers]
1935        assert_not_set_error(not_set_error_name, %w(content)) do
1936          RSS::Maker.make("atom:#{feed_type}") do |maker|
1937            yield maker
1938            target = chain_reader(maker, maker_readers)
1939            target.type = "text/plain"
1940          end
1941        end
1942
1943        _assert_maker_atom_content(*args) do |maker|
1944          yield maker
1945          target = chain_reader(maker, maker_readers)
1946          target.type = "text/plain"
1947          target.content = "text"
1948        end
1949      end
1950    end
1951
1952    def assert_maker_atom_content_inline_other_base64(feed_type, maker_readers,
1953                                                      feed_readers,
1954                                                      not_set_error_name)
1955      _wrap_assertion do
1956        args = [feed_type, maker_readers, feed_readers]
1957        content = "\211PNG\r\n\032\n"
1958        _assert_maker_atom_content(*args) do |maker|
1959          yield maker
1960          target = chain_reader(maker, maker_readers)
1961          target.type = "image/png"
1962          target.content = content
1963        end
1964
1965        _assert_maker_atom_content(*args) do |maker|
1966          yield maker
1967          target = chain_reader(maker, maker_readers)
1968          target.type = "image/png"
1969          target.src = "http://example.com/logo.png"
1970          target.content = content
1971        end
1972
1973        feed = RSS::Maker.make("atom:#{feed_type}") do |maker|
1974          yield maker
1975          target = chain_reader(maker, maker_readers)
1976          target.type = "image/png"
1977          target.src = "http://example.com/logo.png"
1978          target.content = content
1979        end
1980        target = chain_reader(feed, feed_readers)
1981        assert_nil(target.src)
1982        assert_equal(content, target.content)
1983      end
1984    end
1985
1986    def assert_maker_atom_content_out_of_line(feed_type, maker_readers,
1987                                              feed_readers, not_set_error_name)
1988      _wrap_assertion do
1989        args = [feed_type, maker_readers, feed_readers]
1990        assert_not_set_error(not_set_error_name, %w(content)) do
1991          RSS::Maker.make("atom:#{feed_type}") do |maker|
1992            yield maker
1993            target = chain_reader(maker, maker_readers)
1994            target.type = "image/png"
1995          end
1996        end
1997
1998        assert_not_set_error(not_set_error_name, %w(type)) do
1999          RSS::Maker.make("atom:#{feed_type}") do |maker|
2000            yield maker
2001            target = chain_reader(maker, maker_readers)
2002            target.src = "http://example.com/logo.png"
2003          end
2004        end
2005
2006        _assert_maker_atom_content(*args) do |maker|
2007          yield maker
2008          target = chain_reader(maker, maker_readers)
2009          target.type = "image/png"
2010          target.src = "http://example.com/logo.png"
2011        end
2012
2013        _assert_maker_atom_content(*args) do |maker|
2014          yield maker
2015          target = chain_reader(maker, maker_readers)
2016          target.type = "image/png"
2017          target.content = "\211PNG\r\n\032\n"
2018        end
2019
2020        _assert_maker_atom_content(*args) do |maker|
2021          yield maker
2022          target = chain_reader(maker, maker_readers)
2023          target.type = "application/xml"
2024          target.src = "http://example.com/sample.xml"
2025        end
2026
2027
2028        _assert_maker_atom_content(*args) do |maker|
2029          yield maker
2030          target = chain_reader(maker, maker_readers)
2031          target.type = "text/plain"
2032          target.src = "http://example.com/README.txt"
2033        end
2034      end
2035    end
2036
2037    def assert_slash_elements(expected, target)
2038      assert_equal(expected,
2039                   {
2040                     "section" => target.slash_section,
2041                     "department" => target.slash_department,
2042                     "comments" => target.slash_comments,
2043                     "hit_parades" => target.slash_hit_parades,
2044                   })
2045      assert_equal(expected["hit_parades"].join(","),
2046                   target.slash_hit_parade)
2047    end
2048
2049    def chain_reader(target, readers, &block)
2050      readers.inject(target) do |result, reader|
2051        return nil if result.nil?
2052        result.__send__(reader, &block)
2053      end
2054    end
2055
2056    def normalized_attrs(attrs)
2057      n_attrs = {}
2058      attrs.each do |name, value|
2059        n_attrs[name.to_s] = value
2060      end
2061      n_attrs
2062    end
2063
2064    def combination(elements, n)
2065      if n <= 0 or elements.size < n
2066        []
2067      elsif n == 1
2068        elements.collect {|element| [element]}
2069      else
2070        first, *rest = elements
2071        combination(rest, n - 1).collect do |sub_elements|
2072          [first, *sub_elements]
2073        end + combination(rest, n)
2074      end
2075    end
2076
2077    def tag(name, content=nil, attributes={})
2078      attributes = attributes.collect do |key, value|
2079        "#{ERB::Util.h(key)}=\"#{ERB::Util.h(value)}\""
2080      end.join(" ")
2081      begin_tag = "<#{name}"
2082      begin_tag << " #{attributes}" unless attributes.empty?
2083      if content
2084        "#{begin_tag}>#{content}</#{name}>\n"
2085      else
2086        "#{begin_tag}/>\n"
2087      end
2088    end
2089  end
2090end
2091