1require "cgi"
2require "rexml/document"
3
4require "rss-testcase"
5
6require "rss/2.0"
7require "rss/itunes"
8
9module RSS
10  class TestITunes < TestCase
11    def test_author
12      assert_itunes_author(%w(channel)) do |content, xmlns|
13        make_rss20(make_channel20(content), xmlns)
14      end
15
16      assert_itunes_author(%w(items last)) do |content, xmlns|
17        make_rss20(make_channel20(make_item20(content)), xmlns)
18      end
19    end
20
21    def test_block
22      assert_itunes_block(%w(items last)) do |content, xmlns|
23        make_rss20(make_channel20(make_item20(content)), xmlns)
24      end
25    end
26
27    def test_category
28      assert_itunes_category(%w(channel)) do |content, xmlns|
29        make_rss20(make_channel20(content), xmlns)
30      end
31    end
32
33    def test_image
34      assert_itunes_image(%w(channel)) do |content, xmlns|
35        make_rss20(make_channel20(content), xmlns)
36      end
37    end
38
39    def test_duration
40      assert_itunes_duration(%w(items last)) do |content, xmlns|
41        make_rss20(make_channel20(make_item20(content)), xmlns)
42      end
43    end
44
45    def test_explicit
46      assert_itunes_explicit(%w(channel)) do |content, xmlns|
47        make_rss20(make_channel20(content), xmlns)
48      end
49
50      assert_itunes_explicit(%w(items last)) do |content, xmlns|
51        make_rss20(make_channel20(make_item20(content)), xmlns)
52      end
53    end
54
55    def test_keywords
56      assert_itunes_keywords(%w(channel)) do |content, xmlns|
57        make_rss20(make_channel20(content), xmlns)
58      end
59
60      assert_itunes_keywords(%w(items last)) do |content, xmlns|
61        make_rss20(make_channel20(make_item20(content)), xmlns)
62      end
63    end
64
65    def test_new_feed_url
66      assert_itunes_new_feed_url(%w(channel)) do |content, xmlns|
67        make_rss20(make_channel20(content), xmlns)
68      end
69    end
70
71    def test_owner
72      assert_itunes_owner(%w(channel)) do |content, xmlns|
73        make_rss20(make_channel20(content), xmlns)
74      end
75    end
76
77    def test_subtitle
78      assert_itunes_subtitle(%w(channel)) do |content, xmlns|
79        make_rss20(make_channel20(content), xmlns)
80      end
81
82      assert_itunes_subtitle(%w(items last)) do |content, xmlns|
83        make_rss20(make_channel20(make_item20(content)), xmlns)
84      end
85    end
86
87    def test_summary
88      assert_itunes_summary(%w(channel)) do |content, xmlns|
89        make_rss20(make_channel20(content), xmlns)
90      end
91
92      assert_itunes_summary(%w(items last)) do |content, xmlns|
93        make_rss20(make_channel20(make_item20(content)), xmlns)
94      end
95    end
96
97    private
98    def itunes_rss20_parse(content, &maker)
99      xmlns = {"itunes" => "http://www.itunes.com/dtds/podcast-1.0.dtd"}
100      rss20_xml = maker.call(content, xmlns)
101      ::RSS::Parser.parse(rss20_xml)
102    end
103
104    def assert_itunes_author(readers, &rss20_maker)
105      _wrap_assertion do
106        author = "John Lennon"
107        rss20 = itunes_rss20_parse(tag("itunes:author", author), &rss20_maker)
108        target = chain_reader(rss20, readers)
109        assert_equal(author, target.itunes_author)
110      end
111    end
112
113    def _assert_itunes_block(value, boolean_value, readers, &rss20_maker)
114      rss20 = itunes_rss20_parse(tag("itunes:block", value), &rss20_maker)
115      target = chain_reader(rss20, readers)
116      assert_equal(value, target.itunes_block)
117      assert_equal(boolean_value, target.itunes_block?)
118    end
119
120    def assert_itunes_block(readers, &rss20_maker)
121      _wrap_assertion do
122        _assert_itunes_block("yes", true, readers, &rss20_maker)
123        _assert_itunes_block("Yes", true, readers, &rss20_maker)
124        _assert_itunes_block("no", false, readers, &rss20_maker)
125        _assert_itunes_block("", false, readers, &rss20_maker)
126      end
127    end
128
129    def _assert_itunes_category(categories, readers, &rss20_maker)
130      cats = categories.collect do |category|
131        if category.is_a?(Array)
132          category, sub_category = category
133          tag("itunes:category",
134              tag("itunes:category", nil, {"text" => sub_category}),
135              {"text" => category})
136        else
137          tag("itunes:category", nil, {"text" => category})
138        end
139      end.join
140      rss20 = itunes_rss20_parse(cats, &rss20_maker)
141      target = chain_reader(rss20, readers)
142      actual_categories = target.itunes_categories.collect do |category|
143        cat = category.text
144        if category.itunes_categories.empty?
145          cat
146        else
147          [cat, *category.itunes_categories.collect {|c| c.text}]
148        end
149      end
150      assert_equal(categories, actual_categories)
151    end
152
153    def assert_itunes_category(readers, &rss20_maker)
154      _wrap_assertion do
155        _assert_itunes_category(["Audio Blogs"], readers, &rss20_maker)
156        _assert_itunes_category([["Arts & Entertainment", "Games"]],
157                                readers, &rss20_maker)
158        _assert_itunes_category([["Arts & Entertainment", "Games"],
159                                 ["Technology", "Computers"],
160                                 "Audio Blogs"],
161                                readers, &rss20_maker)
162      end
163    end
164
165    def assert_itunes_image(readers, &rss20_maker)
166      _wrap_assertion do
167        url = "http://example.com/podcasts/everything/AllAboutEverything.jpg"
168        content = tag("itunes:image", nil, {"href" => url})
169        rss20 = itunes_rss20_parse(content, &rss20_maker)
170        target = chain_reader(rss20, readers)
171        assert_not_nil(target.itunes_image)
172        assert_equal(url, target.itunes_image.href)
173
174        assert_missing_attribute("image", "href") do
175          content = tag("itunes:image")
176          itunes_rss20_parse(content, &rss20_maker)
177        end
178      end
179    end
180
181    def _assert_itunes_duration(hour, minute, second, value,
182                                readers, &rss20_maker)
183      content = tag("itunes:duration", value)
184      rss20 = itunes_rss20_parse(content, &rss20_maker)
185      duration = chain_reader(rss20, readers).itunes_duration
186      assert_equal(value, duration.content)
187      assert_equal(hour, duration.hour)
188      assert_equal(minute, duration.minute)
189      assert_equal(second, duration.second)
190    end
191
192    def _assert_itunes_duration_not_available_value(value, &rss20_maker)
193      assert_not_available_value("duration", value) do
194        content = tag("itunes:duration", value)
195        itunes_rss20_parse(content, &rss20_maker)
196      end
197    end
198
199    def assert_itunes_duration(readers, &rss20_maker)
200      _wrap_assertion do
201        _assert_itunes_duration(7, 14, 5, "07:14:05", readers, &rss20_maker)
202        _assert_itunes_duration(7, 14, 5, "7:14:05", readers, &rss20_maker)
203        _assert_itunes_duration(0, 4, 55, "04:55", readers, &rss20_maker)
204        _assert_itunes_duration(0, 4, 5, "4:05", readers, &rss20_maker)
205
206        _assert_itunes_duration_not_available_value("5", &rss20_maker)
207        _assert_itunes_duration_not_available_value("09:07:14:05", &rss20_maker)
208        _assert_itunes_duration_not_available_value("10:5", &rss20_maker)
209        _assert_itunes_duration_not_available_value("10:03:5", &rss20_maker)
210        _assert_itunes_duration_not_available_value("10:3:05", &rss20_maker)
211
212        _assert_itunes_duration_not_available_value("xx:xx:xx", &rss20_maker)
213      end
214    end
215
216    def _assert_itunes_explicit(explicit, value, readers, &rss20_maker)
217      content = tag("itunes:explicit", value)
218      rss20 = itunes_rss20_parse(content, &rss20_maker)
219      target = chain_reader(rss20, readers)
220      assert_equal(value, target.itunes_explicit)
221      assert_equal(explicit, target.itunes_explicit?)
222    end
223
224    def assert_itunes_explicit(readers, &rss20_maker)
225      _wrap_assertion do
226        _assert_itunes_explicit(true, "yes", readers, &rss20_maker)
227        _assert_itunes_explicit(false, "clean", readers, &rss20_maker)
228        _assert_itunes_explicit(nil, "no", readers, &rss20_maker)
229      end
230    end
231
232    def _assert_itunes_keywords(keywords, value, readers, &rss20_maker)
233      content = tag("itunes:keywords", value)
234      rss20 = itunes_rss20_parse(content, &rss20_maker)
235      target = chain_reader(rss20, readers)
236      assert_equal(keywords, target.itunes_keywords)
237    end
238
239    def assert_itunes_keywords(readers, &rss20_maker)
240      _wrap_assertion do
241        _assert_itunes_keywords(["salt"], "salt", readers, &rss20_maker)
242        _assert_itunes_keywords(["salt"], " salt ", readers, &rss20_maker)
243        _assert_itunes_keywords(["salt", "pepper", "shaker", "exciting"],
244                                "salt, pepper, shaker, exciting",
245                                readers, &rss20_maker)
246        _assert_itunes_keywords(["metric", "socket", "wrenches", "toolsalt"],
247                                "metric, socket, wrenches, toolsalt",
248                                readers, &rss20_maker)
249        _assert_itunes_keywords(["olitics", "red", "blue", "state"],
250                                "olitics, red, blue, state",
251                                readers, &rss20_maker)
252      end
253    end
254
255    def assert_itunes_new_feed_url(readers, &rss20_maker)
256      _wrap_assertion do
257        url = "http://newlocation.com/example.rss"
258        content = tag("itunes:new-feed-url", url)
259        rss20 = itunes_rss20_parse(content, &rss20_maker)
260        target = chain_reader(rss20, readers)
261        assert_equal(url, target.itunes_new_feed_url)
262      end
263    end
264
265    def _assert_itunes_owner(name, email, readers, &rss20_maker)
266      content = tag("itunes:owner",
267                    tag("itunes:name", name) + tag("itunes:email", email))
268      rss20 = itunes_rss20_parse(content, &rss20_maker)
269      owner = chain_reader(rss20, readers).itunes_owner
270      assert_equal(name, owner.itunes_name)
271      assert_equal(email, owner.itunes_email)
272    end
273
274    def assert_itunes_owner(readers, &rss20_maker)
275      _wrap_assertion do
276        _assert_itunes_owner("John Doe", "john.doe@example.com",
277                             readers, &rss20_maker)
278
279        assert_missing_tag("name", "owner")  do
280          content = tag("itunes:owner")
281          itunes_rss20_parse(content, &rss20_maker)
282        end
283
284        assert_missing_tag("name", "owner")  do
285          content = tag("itunes:owner",
286                        tag("itunes:email", "john.doe@example.com"))
287          itunes_rss20_parse(content, &rss20_maker)
288        end
289
290        assert_missing_tag("email", "owner")  do
291          content = tag("itunes:owner", tag("itunes:name", "John Doe"))
292          itunes_rss20_parse(content, &rss20_maker)
293        end
294      end
295    end
296
297    def _assert_itunes_subtitle(value, readers, &rss20_maker)
298      content = tag("itunes:subtitle", value)
299      rss20 = itunes_rss20_parse(content, &rss20_maker)
300      target = chain_reader(rss20, readers)
301      assert_equal(value, target.itunes_subtitle)
302    end
303
304    def assert_itunes_subtitle(readers, &rss20_maker)
305      _wrap_assertion do
306        _assert_itunes_subtitle("A show about everything", readers, &rss20_maker)
307        _assert_itunes_subtitle("A short primer on table spices",
308                                readers, &rss20_maker)
309        _assert_itunes_subtitle("Comparing socket wrenches is fun!",
310                                readers, &rss20_maker)
311        _assert_itunes_subtitle("Red + Blue != Purple", readers, &rss20_maker)
312      end
313    end
314
315    def _assert_itunes_summary(value, readers, &rss20_maker)
316      content = tag("itunes:summary", value)
317      rss20 = itunes_rss20_parse(content, &rss20_maker)
318      target = chain_reader(rss20, readers)
319      assert_equal(value, target.itunes_summary)
320    end
321
322    def assert_itunes_summary(readers, &rss20_maker)
323      _wrap_assertion do
324        _assert_itunes_summary("All About Everything is a show about " +
325                               "everything. Each week we dive into any " +
326                               "subject known to man and talk about it as " +
327                               "much as we can. Look for our Podcast in " +
328                               "the iTunes Music Store",
329                               readers, &rss20_maker)
330        _assert_itunes_summary("This week we talk about salt and pepper " +
331                               "shakers, comparing and contrasting pour " +
332                               "rates, construction materials, and overall " +
333                               "aesthetics. Come and join the party!",
334                               readers, &rss20_maker)
335        _assert_itunes_summary("This week we talk about metric vs. old " +
336                               "english socket wrenches. Which one is " +
337                               "better? Do you really need both? Get all " +
338                               "of your answers here.",
339                               readers, &rss20_maker)
340        _assert_itunes_summary("This week we talk about surviving in a " +
341                               "Red state if you're a Blue person. Or " +
342                               "vice versa.",
343                               readers, &rss20_maker)
344      end
345    end
346  end
347end
348