atom-tools 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. data/COPYING +18 -0
  2. data/README +103 -0
  3. data/Rakefile +77 -0
  4. data/bin/atom-client.rb +246 -0
  5. data/bin/atom-server.rb~ +71 -0
  6. data/doc/classes/Atom/App.html +217 -0
  7. data/doc/classes/Atom/Author.html +130 -0
  8. data/doc/classes/Atom/Category.html +128 -0
  9. data/doc/classes/Atom/Collection.html +322 -0
  10. data/doc/classes/Atom/Content.html +129 -0
  11. data/doc/classes/Atom/Contributor.html +119 -0
  12. data/doc/classes/Atom/Element.html +325 -0
  13. data/doc/classes/Atom/Entry.html +365 -0
  14. data/doc/classes/Atom/Feed.html +585 -0
  15. data/doc/classes/Atom/HTTP.html +374 -0
  16. data/doc/classes/Atom/Link.html +137 -0
  17. data/doc/classes/Atom/Text.html +229 -0
  18. data/doc/classes/XHTML.html +118 -0
  19. data/doc/created.rid +1 -0
  20. data/doc/files/README.html +213 -0
  21. data/doc/files/lib/atom/app_rb.html +110 -0
  22. data/doc/files/lib/atom/collection_rb.html +110 -0
  23. data/doc/files/lib/atom/element_rb.html +109 -0
  24. data/doc/files/lib/atom/entry_rb.html +111 -0
  25. data/doc/files/lib/atom/feed_rb.html +112 -0
  26. data/doc/files/lib/atom/http_rb.html +109 -0
  27. data/doc/files/lib/atom/text_rb.html +108 -0
  28. data/doc/files/lib/atom/xml_rb.html +110 -0
  29. data/doc/files/lib/atom/yaml_rb.html +109 -0
  30. data/doc/fr_class_index.html +39 -0
  31. data/doc/fr_file_index.html +36 -0
  32. data/doc/fr_method_index.html +62 -0
  33. data/doc/index.html +24 -0
  34. data/doc/rdoc-style.css +208 -0
  35. data/lib/atom/app.rb +87 -0
  36. data/lib/atom/collection.rb +75 -0
  37. data/lib/atom/element.rb +277 -0
  38. data/lib/atom/entry.rb +135 -0
  39. data/lib/atom/feed.rb +229 -0
  40. data/lib/atom/http.rb +132 -0
  41. data/lib/atom/text.rb +163 -0
  42. data/lib/atom/xml.rb +200 -0
  43. data/lib/atom/yaml.rb +101 -0
  44. data/setup.rb +1585 -0
  45. data/test/conformance/order.rb +117 -0
  46. data/test/conformance/title.rb +108 -0
  47. data/test/conformance/updated.rb +33 -0
  48. data/test/conformance/xhtmlcontentdiv.rb +18 -0
  49. data/test/conformance/xmlnamespace.rb +54 -0
  50. data/test/runtests.rb +14 -0
  51. data/test/test_constructs.rb +91 -0
  52. data/test/test_feed.rb +128 -0
  53. data/test/test_general.rb +99 -0
  54. data/test/test_http.rb +86 -0
  55. data/test/test_protocol.rb +69 -0
  56. data/test/test_xml.rb +353 -0
  57. metadata +107 -0
@@ -0,0 +1,117 @@
1
+ require "test/unit"
2
+ require "atom/feed"
3
+
4
+ # http://www.intertwingly.net/wiki/pie/OrderConformanceTests
5
+
6
+ FEED = Atom::Feed.new("http://www.snellspace.com/public/ordertest.xml")
7
+ FEED.update!
8
+
9
+ class TestOrderConformance < Test::Unit::TestCase
10
+ def test_0
11
+ entry = FEED.entries[0]
12
+
13
+ assert_equal "tag:example.org,2006:atom/conformance/element_order/1", entry.id
14
+ assert_equal "Simple order, nothing fancy", entry.title.to_s
15
+ assert_equal "Simple ordering, nothing fancy", entry.summary.to_s
16
+ assert_equal Time.parse("2006-01-26T09:20:01Z"), entry.updated
17
+
18
+ assert_alternate_href(entry, "http://www.snellspace.com/public/alternate")
19
+ end
20
+
21
+ def test_1
22
+ entry = FEED.entries[1]
23
+
24
+ assert_equal "tag:example.org,2006:atom/conformance/element_order/2", entry.id
25
+ assert_equal "Same as the first, only mixed up a bit", entry.title.to_s
26
+ assert_equal "Same as the first, only mixed up a bit", entry.summary.to_s
27
+ assert_equal Time.parse("2006-01-26T09:20:02Z"), entry.updated
28
+
29
+ assert_alternate_href(entry, "http://www.snellspace.com/public/alternate")
30
+ end
31
+
32
+ # Multiple alt link elements, which does your reader show?
33
+ def test_2
34
+ entry = FEED.entries[2]
35
+
36
+ # both links should be available, but it's up to you to choose which one to use
37
+ assert_link_href(entry, "http://www.snellspace.com/public/alternate") { |l| l["rel"] == "alternate" and l["type"] == nil }
38
+
39
+ assert_link_href(entry, "http://www.snellspace.com/public/alternate2") { |l| l["rel"] == "alternate" and l["type"] == "text/plain" }
40
+ end
41
+
42
+ # Multiple link elements, does your feed reader show the "alternate" correctly? (also checks to see if the reader is paying attention to link rel values)
43
+ def test_3
44
+ entry = FEED.entries[3]
45
+
46
+ assert_alternate_href(entry, "http://www.snellspace.com/public/alternate")
47
+
48
+ assert_link_href(entry, "http://www.snellspace.com/public/related") { |l| l["rel"] == "related" }
49
+
50
+ assert_link_href(entry, "http://www.snellspace.com/public/foo") { |l| l["rel"] == "urn:foo" }
51
+ end
52
+
53
+ # Entry with a source first.. does your feed reader show the right title, updated, and alt link?
54
+ def test_4
55
+ entry = FEED.entries[4]
56
+
57
+ assert_equal "tag:example.org,2006:atom/conformance/element_order/5", entry.id
58
+ assert_equal "Entry with a source first", entry.title.to_s
59
+ assert_equal Time.parse("2006-01-26T09:20:05Z"), entry.updated
60
+
61
+ assert_alternate_href(entry, "http://www.snellspace.com/public/alternate")
62
+ end
63
+
64
+ # Entry with a source first.. does your feed reader show the right title, updated, and alt link?
65
+ # ^-- quoted summary is a typo, source is last
66
+ def test_5
67
+ entry = FEED.entries[5]
68
+
69
+ assert_equal "tag:example.org,2006:atom/conformance/element_order/6", entry.id
70
+ assert_equal "Entry with a source last", entry.title.to_s
71
+ assert_equal Time.parse("2006-01-26T09:20:06Z"), entry.updated
72
+
73
+ assert_alternate_href(entry, "http://www.snellspace.com/public/alternate")
74
+ end
75
+
76
+ # Entry with a source in the middle.. does your feed reader show the right id, title, updated, and alt link?
77
+ def test_6
78
+ entry = FEED.entries[6]
79
+
80
+ assert_equal "tag:example.org,2006:atom/conformance/element_order/7", entry.id
81
+ assert_equal "Entry with a source in the middle", entry.title.to_s
82
+ assert_equal Time.parse("2006-01-26T09:20:07Z"), entry.updated
83
+
84
+ assert_alternate_href(entry, "http://www.snellspace.com/public/alternate")
85
+ end
86
+
87
+ # Atom elements in an extension element
88
+ def test_7
89
+ entry = FEED.entries[7]
90
+
91
+ assert_equal "tag:example.org,2006:atom/conformance/element_order/8", entry.id
92
+ assert_equal "Atom elements in an extension element", entry.title.to_s
93
+ assert_equal Time.parse("2006-01-26T09:20:08Z"), entry.updated
94
+
95
+ assert_alternate_href(entry, "http://www.snellspace.com/public/alternate")
96
+ end
97
+
98
+ # Atom elements in an extension element
99
+ def test_8
100
+ entry = FEED.entries[8]
101
+
102
+ assert_equal "tag:example.org,2006:atom/conformance/element_order/9", entry.id
103
+ assert_equal "Atom elements in an extension element", entry.title.to_s
104
+ assert_equal Time.parse("2006-01-26T09:20:09Z"), entry.updated
105
+
106
+ assert_alternate_href(entry, "http://www.snellspace.com/public/alternate")
107
+ end
108
+
109
+ def assert_link_href(entry, href, &block)
110
+ link = entry.links.find(&block)
111
+ assert_equal href, link["href"]
112
+ end
113
+
114
+ def assert_alternate_href(entry, href)
115
+ assert_link_href(entry, href) { |l| l["rel"] == "alternate" }
116
+ end
117
+ end
@@ -0,0 +1,108 @@
1
+ require "test/unit"
2
+ require "atom/feed"
3
+
4
+ # wiki page at <http://www.intertwingly.net/wiki/pie/TitleConformanceTests>
5
+
6
+ # http://atomtests.philringnalda.com/tests/item/title/html-cdata.atom
7
+ # http://atomtests.philringnalda.com/tests/item/title/html-entity.atom
8
+ # http://atomtests.philringnalda.com/tests/item/title/html-ncr.atom
9
+ # http://atomtests.philringnalda.com/tests/item/title/text-cdata.atom
10
+ # http://atomtests.philringnalda.com/tests/item/title/text-entity.atom
11
+ # http://atomtests.philringnalda.com/tests/item/title/text-ncr.atom
12
+ # http://atomtests.philringnalda.com/tests/item/title/xhtml-entity.atom
13
+ # http://atomtests.philringnalda.com/tests/item/title/xhtml-ncr.atom
14
+
15
+ # I make no attempt to normalize the XML from entry.title.to_s
16
+ # therefore, the direct equalities I do below are unwise.
17
+ # (eg. they *could* return &lt; or &#60; and still be perfectly correct)
18
+ #
19
+ # It shouldn't be a problem unless REXML changes what it encodes.
20
+ class TestTitleConformance < Test::Unit::TestCase
21
+ def test_html_cdata
22
+ url = "http://atomtests.philringnalda.com/tests/item/title/html-cdata.atom"
23
+
24
+ feed = Atom::Feed.new(url)
25
+ feed.update!
26
+
27
+ entry = feed.entries.first
28
+ assert_equal "html", entry.title["type"]
29
+ assert_equal "&lt;title>", entry.title.html
30
+ end
31
+
32
+ def test_html_entity
33
+ url = "http://atomtests.philringnalda.com/tests/item/title/html-entity.atom"
34
+
35
+ feed = Atom::Feed.new(url)
36
+ feed.update!
37
+
38
+ entry = feed.entries.first
39
+ assert_equal "html", entry.title["type"]
40
+ assert_equal "&lt;title>", entry.title.html
41
+ end
42
+
43
+ def test_html_ncr
44
+ url = "http://atomtests.philringnalda.com/tests/item/title/html-ncr.atom"
45
+
46
+ feed = Atom::Feed.new(url)
47
+ feed.update!
48
+
49
+ entry = feed.entries.first
50
+ assert_equal "html", entry.title["type"]
51
+ assert_equal "&lt;title>", entry.title.html
52
+ end
53
+
54
+ def test_text_cdata
55
+ url = "http://atomtests.philringnalda.com/tests/item/title/text-cdata.atom"
56
+
57
+ feed = Atom::Feed.new(url)
58
+ feed.update!
59
+
60
+ entry = feed.entries.first
61
+ assert_equal "text", entry.title["type"]
62
+ assert_equal "&lt;title&gt;", entry.title.html
63
+ end
64
+
65
+ def test_text_entity
66
+ url = "http://atomtests.philringnalda.com/tests/item/title/text-entity.atom"
67
+
68
+ feed = Atom::Feed.new(url)
69
+ feed.update!
70
+
71
+ entry = feed.entries.first
72
+ assert_equal "text", entry.title["type"]
73
+ assert_equal "&lt;title&gt;", entry.title.html
74
+ end
75
+
76
+ def test_text_ncr
77
+ url = "http://atomtests.philringnalda.com/tests/item/title/text-ncr.atom"
78
+
79
+ feed = Atom::Feed.new(url)
80
+ feed.update!
81
+
82
+ entry = feed.entries.first
83
+ assert_equal "text", entry.title["type"]
84
+ assert_equal "&lt;title&gt;", entry.title.html
85
+ end
86
+
87
+ def test_xhtml_entity
88
+ url = "http://atomtests.philringnalda.com/tests/item/title/xhtml-entity.atom"
89
+
90
+ feed = Atom::Feed.new(url)
91
+ feed.update!
92
+
93
+ entry = feed.entries.first
94
+ assert_equal "xhtml", entry.title["type"]
95
+ assert_equal "&lt;title>", entry.title.html
96
+ end
97
+
98
+ def test_xhtml_ncr
99
+ url = "http://atomtests.philringnalda.com/tests/item/title/xhtml-ncr.atom"
100
+
101
+ feed = Atom::Feed.new(url)
102
+ feed.update!
103
+
104
+ entry = feed.entries.first
105
+ assert_equal "xhtml", entry.title["type"]
106
+ assert_equal "&#60;title>", entry.title.html
107
+ end
108
+ end
@@ -0,0 +1,33 @@
1
+ require "test/unit"
2
+ require "atom/feed"
3
+
4
+ # wiki page at <http://www.intertwingly.net/wiki/pie/UpdatedConformanceTests>
5
+ # test feed at <http://intertwingly.net/testcase/updated.atom>
6
+
7
+ class TestUpdatedConformance < Test::Unit::TestCase
8
+ def test_it_all
9
+ feed = Atom::Feed.new "http://intertwingly.net/testcase/updated.atom"
10
+
11
+ assert_equal [], feed.entries
12
+
13
+ # initial filling
14
+ feed.update!
15
+ assert_equal "12 of 13 miner survive mine collapse", feed.entries.first.content.to_s.strip
16
+
17
+ # this is an insignificant change,
18
+ # (ie. atom:updated_1 == atom:updated_2),
19
+ # but that's for you to handle
20
+ feed.update!
21
+ assert_equal "12 of 13 miner<b>s</b> survive mine collapse", feed.entries.first.content.to_s.strip
22
+
23
+ # now we've got a significant change
24
+ feed.update!
25
+ assert_equal "12 of 13 miners <del>survive</del> <b>killed</b> in mine collapse", feed.entries.first.content.to_s.strip
26
+
27
+ # and now the feed is gone totally
28
+ assert_raises(Atom::FeedGone) do
29
+ feed.update!
30
+ end
31
+ end
32
+ end
33
+
@@ -0,0 +1,18 @@
1
+ require "test/unit"
2
+ require "atom/feed"
3
+
4
+ class TestXHTMLContentDivConformance < Test::Unit::TestCase
5
+ def test_all
6
+ feed = Atom::Feed.new("http://www.franklinmint.fm/2006/06/divtest.atom")
7
+ feed.update!
8
+
9
+ assert_equal "<b>test</b> content", feed.entries.first.content.html
10
+
11
+ e = feed.entries.first.content.xml
12
+ assert_equal "http://www.w3.org/1999/xhtml", e.first.namespace
13
+ assert_equal "b", e.first.name
14
+ assert_equal "test", e.first.text
15
+
16
+ assert_equal " content", e.last.to_s
17
+ end
18
+ end
@@ -0,0 +1,54 @@
1
+ require "test/unit"
2
+ require "atom/feed"
3
+
4
+ class TestXMLNamespaceConformance < Test::Unit::TestCase
5
+ def test_baseline
6
+ feed = Atom::Feed.new "http://plasmasturm.org/attic/atom-tests/nondefaultnamespace-baseline.atom"
7
+ feed.update!
8
+
9
+ assert_baseline feed
10
+ end
11
+
12
+ def assert_baseline feed
13
+ assert_equal Time.parse("2006-01-18T12:26:54+01:00"), feed.updated
14
+ assert_equal "http://example.org/tests/namespace/result.html", feed.links.first["href"]
15
+
16
+ assert_equal "urn:uuid:f8195e66-863f-11da-9fcb-dd680b0526e0", feed.id
17
+
18
+ assert_equal "Aristotle Pagaltzis", feed.authors.first.name
19
+ assert_equal "pagaltzis@gmx.de", feed.authors.first.email
20
+
21
+ entry = feed.entries.first
22
+
23
+ assert_equal "urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a", entry.id
24
+
25
+ assert_equal Time.parse("2006-01-18T12:26:54+01:00"), entry.updated
26
+ assert_equal "http://example.org/tests/namespace/result.html", entry.links.first["href"]
27
+
28
+ # XXX content.html should strip namespace prefixes
29
+ e = entry.content.xml
30
+
31
+ assert_equal "http://www.w3.org/1999/xhtml", e[1].namespace
32
+ assert_equal "p", e[1].name
33
+ assert_equal "For information, see:", e[1].text
34
+ end
35
+
36
+ def test_1
37
+ feed = Atom::Feed.new "http://plasmasturm.org/attic/atom-tests/nondefaultnamespace.atom"
38
+ feed.update!
39
+
40
+ assert_baseline feed
41
+ end
42
+
43
+ def test_2
44
+ feed = Atom::Feed.new "http://plasmasturm.org/attic/atom-tests/nondefaultnamespace-xhtml.atom"
45
+ feed.update!
46
+
47
+ assert_baseline feed
48
+ end
49
+
50
+ def test_3
51
+ assert(false, "I haven't written the last test")
52
+ # XXX FINISHME
53
+ end
54
+ end
data/test/runtests.rb ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/ruby
2
+
3
+ $LOAD_PATH << File.expand_path(File.dirname(__FILE__) + "/../lib")
4
+
5
+ require "test/unit"
6
+
7
+ Dir["test_*.rb"].each do |test|
8
+ begin
9
+ require test
10
+ rescue LoadError
11
+ puts "skipping #{test} (LoadError)"
12
+ next
13
+ end
14
+ end
@@ -0,0 +1,91 @@
1
+ require "test/unit"
2
+ require "atom/entry"
3
+
4
+ class ConstructTest < Test::Unit::TestCase
5
+ def test_text_construct_text
6
+ entry = Atom::Entry.new
7
+
8
+ assert_nil(entry.title)
9
+ assert_equal("", entry.title.to_s)
10
+
11
+ entry.title = "<3"
12
+
13
+ assert_equal "text", entry.title["type"]
14
+ assert_equal "<3", entry.title.to_s
15
+ assert_equal "&lt;3", entry.title.html
16
+
17
+ assert_equal "'<3'#text", entry.title.inspect
18
+
19
+ title = entry.to_xml.root.children.first
20
+ assert_equal "<3", title.text
21
+ end
22
+
23
+ def test_text_construct_html
24
+ entry = Atom::Entry.new
25
+
26
+ =begin
27
+ entry.title = "<3"
28
+ entry.title["type"] = "html"
29
+
30
+ assert_equal "html", entry.title["type"]
31
+ assert_equal "<3", entry.title.to_s
32
+ assert_equal "&lt;3", entry.title.html
33
+
34
+ title = entry.to_xml.root.children.first
35
+ assert_equal "<3", title.text
36
+ =end
37
+
38
+ entry.title = "<p>pi &lt; 4?"
39
+ entry.title["type"] = "html"
40
+
41
+ assert_equal "<p>pi &lt; 4?", entry.title.to_s
42
+ assert_equal "<p>pi &lt; 4?", entry.title.html
43
+ end
44
+
45
+ def test_text_construct_xhtml
46
+ entry = Atom::Entry.new
47
+
48
+ entry.title = "<3"
49
+ assert_raises(RuntimeError) { entry.title["type"] = "xhtml" }
50
+
51
+ assert_raises(RuntimeError) do
52
+ entry.title["type"] = "application/xhtml+xml"
53
+ end
54
+
55
+ entry.title = REXML::Document.new("<div xmlns='http://www.w3.org/1999/xhtml'>&lt;3</div>").root
56
+ entry.title["type"] = "xhtml"
57
+
58
+ assert_equal "&lt;3", entry.title.to_s
59
+ assert_equal "&lt;3", entry.title.html
60
+
61
+ entry.title = "&lt;3"
62
+ entry.title["type"] = "xhtml"
63
+
64
+ assert_equal "&lt;3", entry.title.to_s
65
+ assert_equal "&lt;3", entry.title.html
66
+
67
+ entry.title = "<em>goodness</em> gracious"
68
+ entry.title["type"] = "xhtml"
69
+
70
+ assert_equal "<em>goodness</em> gracious", entry.title.to_s
71
+ assert_equal "<em>goodness</em> gracious", entry.title.html
72
+ end
73
+
74
+ def test_content
75
+ entry = Atom::Entry.new
76
+
77
+ entry.content = ""
78
+ entry.content["src"] = "http://example.com/example.svg"
79
+ entry.content["type"] = "image/svg+xml"
80
+
81
+ assert_equal("", entry.content.to_s)
82
+ end
83
+
84
+ require "date"
85
+ def test_date_construct
86
+ today = Date.today
87
+ time = Atom::Time.new today
88
+
89
+ assert_match(/^#{today}T00:00:00/, time.to_s)
90
+ end
91
+ end
data/test/test_feed.rb ADDED
@@ -0,0 +1,128 @@
1
+ require "test/unit"
2
+
3
+ require "atom/feed"
4
+ require "webrick"
5
+
6
+ class AtomFeedTest < Test::Unit::TestCase
7
+ def setup
8
+ @http = Atom::HTTP.new
9
+ @port = rand(1024) + 1024
10
+ @s = WEBrick::HTTPServer.new :Port => @port,
11
+ :Logger => WEBrick::Log.new($stderr, WEBrick::Log::FATAL),
12
+ :AccessLog => []
13
+
14
+ @test_feed =<<END
15
+ <?xml version="1.0" encoding="utf-8"?>
16
+ <feed xmlns="http://www.w3.org/2005/Atom">
17
+ <title>Example Feed</title>
18
+ <link href="http://example.org/"/>
19
+ <updated>2003-12-13T18:30:02Z</updated>
20
+ <author>
21
+ <name>John Doe</name>
22
+ </author>
23
+ <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
24
+
25
+ <entry>
26
+ <title>Atom-Powered Robots Run Amok</title>
27
+ <link href="http://example.org/2003/12/13/atom03"/>
28
+ <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
29
+ <updated>2003-12-13T18:30:02Z</updated>
30
+ <summary>Some text.</summary>
31
+ </entry>
32
+ </feed>
33
+ END
34
+ end
35
+
36
+ def test_merge
37
+ feed1 = Atom::Feed.new
38
+
39
+ feed1.title = "title"
40
+
41
+ feed1.subtitle = "<br>"
42
+ feed1.subtitle["type"] = "html"
43
+
44
+ a = feed1.authors.new
45
+ a.name = "test"
46
+
47
+ feed2 = Atom::Feed.new
48
+
49
+ feed = feed1.merge(feed2)
50
+
51
+ assert_equal "text", feed.title["type"]
52
+ assert_equal "title", feed.title.to_s
53
+
54
+ assert_equal "html", feed.subtitle["type"]
55
+ assert_equal "<br>", feed.subtitle.to_s
56
+
57
+ assert_equal 1, feed.authors.length
58
+ assert_equal "test", feed.authors.first.name
59
+ end
60
+
61
+ def test_update
62
+ @s.mount_proc("/") do |req,res|
63
+ res.content_type = "application/atom+xml"
64
+ res.body = @test_feed
65
+
66
+ @s.stop
67
+ end
68
+
69
+ feed = Atom::Feed.new "http://localhost:#{@port}/"
70
+
71
+ assert_equal nil, feed.title
72
+ assert_equal nil, feed.id
73
+ assert_equal [], feed.entries
74
+
75
+ one_shot
76
+
77
+ feed.update!
78
+
79
+ assert_equal "Example Feed", feed.title.to_s
80
+ assert_equal "urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6", feed.id
81
+ assert_equal 1, feed.entries.length
82
+ end
83
+
84
+ def test_conditional_get
85
+ @s.mount_proc("/") do |req,res|
86
+ assert_nil req["If-None-Match"]
87
+ assert_nil req["If-Modified-Since"]
88
+
89
+ res["Etag"] = '"xyzzy"'
90
+ res["Last-Modified"] = 'Wed, 15 Nov 1995 04:58:08 GMT'
91
+ res.content_type = "application/atom+xml"
92
+ res.body = @test_feed
93
+
94
+ @s.stop
95
+ end
96
+
97
+ feed = Atom::Feed.new "http://localhost:#{@port}/"
98
+
99
+ assert_equal 0, feed.entries.length
100
+ assert_equal nil, feed.etag
101
+ assert_equal nil, feed.last_modified
102
+
103
+ one_shot
104
+
105
+ feed.update!
106
+
107
+ assert_equal 1, feed.entries.length
108
+ assert_equal '"xyzzy"', feed.etag
109
+ assert_equal 'Wed, 15 Nov 1995 04:58:08 GMT', feed.last_modified
110
+
111
+ @s.mount_proc("/") do |req,res|
112
+ assert_equal '"xyzzy"', req["If-None-Match"]
113
+ assert_equal 'Wed, 15 Nov 1995 04:58:08 GMT', req["If-Modified-Since"]
114
+
115
+ res.status = 304
116
+ res.body = "this hasn't been modified"
117
+
118
+ @s.stop
119
+ end
120
+
121
+ one_shot
122
+ feed.update!
123
+
124
+ assert_equal 1, feed.entries.length
125
+ end
126
+
127
+ def one_shot; Thread.new { @s.start }; end
128
+ end