# Copyright (c) 2008 The Kaphan Foundation # # Possession of a copy of this file grants no permission or license # to use, modify, or create derivate works. # Please contact info@peerworks.org for further information. # require File.dirname(__FILE__) + '/spec_helper.rb' require 'net/http' require 'time' shared_examples_for 'simple_single_entry.atom attributes' do it "should parse title" do @feed.title.should == 'Example Feed' end it "should parse updated" do @feed.updated.should == Time.parse('2003-12-13T18:30:02Z') end it "should parse id" do @feed.id.should == 'urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6' end it "should have an entries array" do @feed.entries.should be_an_instance_of(Array) end it "should have one element in the entries array" do @feed.entries.size.should == 1 end it "should have an alternate" do @feed.alternate.should_not be_nil end it "should have an Atom::Link as the alternate" do @feed.alternate.should be_an_instance_of(Atom::Link) end it "should have the correct href in the alternate" do @feed.alternate.href.should == 'http://example.org/' end it "should have 1 author" do @feed.should have(1).authors end it "should have 'John Doe' as the author's name" do @feed.authors.first.name.should == "John Doe" end it "should parse title" do @entry.title.should == 'Atom-Powered Robots Run Amok' end it "should have an alternate" do @entry.alternate.should_not be_nil end it "should have an Atom::Link as the alternate" do @entry.alternate.should be_an_instance_of(Atom::Link) end it "should have the correct href on the alternate" do @entry.alternate.href.should == 'http://example.org/2003/12/13/atom03' end it "should parse id" do @entry.id.should == 'urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a' end it "should parse updated" do @entry.updated.should == Time.parse('2003-12-13T18:30:02Z') end it "should parse summary" do @entry.summary.should == 'Some text.' end it "should parse content" do @entry.content.should == 'This is html.' end it "should parse content type" do @entry.content.type.should == 'html' end end describe Atom do describe "Atom::Feed.load_feed" do it "should accept an IO" do lambda { Atom::Feed.load_feed(File.open('spec/fixtures/simple_single_entry.atom')) }.should_not raise_error end it "should raise ArgumentError with something other than IO or URI" do lambda { Atom::Feed.load_feed(nil) }.should raise_error(ArgumentError) end it "should accept a String" do Atom::Feed.load_feed(File.read('spec/fixtures/simple_single_entry.atom')).should be_an_instance_of(Atom::Feed) end it "should accept a URI" do uri = URI.parse('http://example.com/feed.atom') response = Net::HTTPSuccess.new(nil, nil, nil) response.stub!(:body).and_return(File.read('spec/fixtures/simple_single_entry.atom')) mock_http_get(uri, response) Atom::Feed.load_feed(uri).should be_an_instance_of(Atom::Feed) end it "should accept a URI with query parameters" do uri = URI.parse('http://example.com/feed.atom?page=2') response = Net::HTTPSuccess.new(nil, nil, nil) response.stub!(:body).and_return(File.read('spec/fixtures/simple_single_entry.atom')) mock_http_get(uri, response) Atom::Feed.load_feed(uri).should be_an_instance_of(Atom::Feed) end it "should raise ArgumentError with non-http uri" do uri = URI.parse('file:/tmp') lambda { Atom::Feed.load_feed(uri) }.should raise_error(ArgumentError) end it "should return an Atom::Feed" do feed = Atom::Feed.load_feed(File.open('spec/fixtures/simple_single_entry.atom')) feed.should be_an_instance_of(Atom::Feed) end it "should not raise an error with a String and basic-auth credentials" do lambda { Atom::Feed.load_feed(File.read('spec/fixtures/simple_single_entry.atom'), :user => 'user', :pass => 'pass') }.should_not raise_error end it "should not raise an error with a URI with basic-auth credentials" do uri = URI.parse('http://example.com/feed.atom') response = Net::HTTPSuccess.new(nil, nil, nil) response.stub!(:body).and_return(File.read('spec/fixtures/simple_single_entry.atom')) mock_http_get(uri, response, 'user', 'pass') lambda { Atom::Feed.load_feed(uri, :user => 'user', :pass => 'pass') }.should_not raise_error end it "should pass basic-auth credentials on the request" do end end describe 'Atom::Entry.load_entry' do it "should accept an IO" do Atom::Entry.load_entry(File.open('spec/fixtures/entry.atom')).should be_an_instance_of(Atom::Entry) end it "should accept a URI" do uri = URI.parse('http://example.org/entry.atom') response = Net::HTTPSuccess.new(nil, nil, nil) response.stub!(:body).and_return(File.read('spec/fixtures/entry.atom')) mock_http_get(uri, response) Atom::Entry.load_entry(uri).should be_an_instance_of(Atom::Entry) end it "should accept a String" do Atom::Entry.load_entry(File.read('spec/fixtures/entry.atom')).should be_an_instance_of(Atom::Entry) end it "should raise ArgumentError with something other than IO, String or URI" do lambda { Atom::Entry.load_entry(nil) }.should raise_error(ArgumentError) end it "should raise ArgumentError with non-http uri" do lambda { Atom::Entry.load_entry(URI.parse('file:/tmp')) }.should raise_error(ArgumentError) end end describe 'SimpleSingleFeed' do before(:all) do @feed = Atom::Feed.load_feed(File.open('spec/fixtures/simple_single_entry.atom')) @entry = @feed.entries.first end it_should_behave_like "simple_single_entry.atom attributes" end describe 'ComplexFeed' do before(:all) do @feed = Atom::Feed.load_feed(File.open('spec/fixtures/complex_single_entry.atom')) end describe Atom::Feed do it "should have a title" do @feed.title.should == 'dive into mark' end it "should have type on the title" do @feed.title.type.should == 'text' end it "should have a subtitle" do @feed.subtitle.should == 'A lot of effort went into making this effortless' end it "should have a type for the subtitle" do @feed.subtitle.type.should == 'html' end it "should have an updated date" do @feed.updated.should == Time.parse('2005-07-31T12:29:29Z') end it "should have an id" do @feed.id.should == 'tag:example.org,2003:3' end it "should have 2 links" do @feed.should have(2).links end it "should have an alternate link" do @feed.alternate.should_not be_nil end it "should have the right url for the alternate" do @feed.alternate.to_s.should == 'http://example.org/' end it "should have a self link" do @feed.self.should_not be_nil end it "should have the right url for self" do @feed.self.to_s.should == 'http://example.org/feed.atom' end it "should have rights" do @feed.rights.should == 'Copyright (c) 2003, Mark Pilgrim' end it "should have a generator" do @feed.generator.should_not be_nil end it "should have a generator uri" do @feed.generator.uri.should == 'http://www.example.com/' end it "should have a generator version" do @feed.generator.version.should == '1.0' end it "should have a generator name" do @feed.generator.name.should == 'Example Toolkit' end it "should have an entry" do @feed.should have(1).entries end it "should have a category" do @feed.should have(1).categories end end describe Atom::Entry do before(:each) do @entry = @feed.entries.first end it "should have a title" do @entry.title.should == 'Atom draft-07 snapshot' end it "should have an id" do @entry.id.should == 'tag:example.org,2003:3.2397' end it "should have an updated date" do @entry.updated.should == Time.parse('2005-07-31T12:29:29Z') end it "should have a published date" do @entry.published.should == Time.parse('2003-12-13T08:29:29-04:00') end it "should have an author" do @entry.should have(1).authors end it "should have two links" do @entry.should have(2).links end it "should have one alternate link" do @entry.should have(1).alternates end it "should have one enclosure link" do @entry.should have(1).enclosures end it "should have 2 contributors" do @entry.should have(2).contributors end it "should have names for the contributors" do @entry.contributors[0].name.should == 'Sam Ruby' @entry.contributors[1].name.should == 'Joe Gregorio' end it "should have content" do @entry.content.should_not be_nil end it "should have 2 categories" do @entry.should have(2).categories end end describe Atom::Category do describe 'atom category' do before(:each) do @category = @feed.entries.first.categories.first end it "should have a term" do @category.term.should == "atom" end it "should have a scheme" do @category.scheme.should == "http://example.org" end it "should have a label" do @category.label.should == "Atom" end end describe 'draft category' do before(:each) do @category = @feed.entries.first.categories.last end it "should have a term" do @category.term.should == "drafts" end it "should have a scheme" do @category.scheme.should == "http://example2.org" end it "should have a label" do @category.label.should == "Drafts" end end end describe Atom::Link do describe 'alternate link' do before(:each) do @entry = @feed.entries.first @link = @entry.alternate end it "should have text/html type" do @link.type.should == 'text/html' end it "should have alternate rel" do @link.rel.should == 'alternate' end it "should have href 'http://example.org/2005/04/02/atom'" do @link.href.should == 'http://example.org/2005/04/02/atom' end it "should have 'http://example.org/2005/04/02/atom' string representation" do @link.to_s.should == 'http://example.org/2005/04/02/atom' end end describe 'enclosure link' do before(:each) do @entry = @feed.entries.first @link = @entry.enclosures.first end it "should have audio/mpeg type" do @link.type.should == 'audio/mpeg' end it "should have enclosure rel" do @link.rel.should == 'enclosure' end it "should have length 1337" do @link.length.should == 1337 end it "should have href 'http://example.org/audio/ph34r_my_podcast.mp3'" do @link.href.should == 'http://example.org/audio/ph34r_my_podcast.mp3' end it "should have 'http://example.org/audio/ph34r_my_podcast.mp3' string representation" do @link.to_s.should == 'http://example.org/audio/ph34r_my_podcast.mp3' end end end describe Atom::Person do before(:each) do @entry = @feed.entries.first @person = @entry.authors.first end it "should have a name" do @person.name.should == 'Mark Pilgrim' end it "should have a uri" do @person.uri.should == 'http://example.org/' end it "should have an email address" do @person.email.should == 'f8dy@example.com' end end describe Atom::Content do before(:each) do @entry = @feed.entries.first @content = @entry.content end it "should have 'xhtml' type" do @content.type.should == 'xhtml' end it "should have 'en' language" do @content.xml_lang.should == 'en' end it "should have the content as the string representation" do @content.should == '

[Update: The Atom draft is finished.]

' end end end describe 'ConformanceTests' do describe 'nondefaultnamespace.atom' do before(:all) do @feed = Atom::Feed.load_feed(File.open('spec/conformance/nondefaultnamespace.atom')) end it "should have a title" do @feed.title.should == 'Non-default namespace test' end it "should have 1 entry" do @feed.should have(1).entries end describe Atom::Entry do before(:all) do @entry = @feed.entries.first end it "should have a title" do @entry.title.should == 'If you can read the content of this entry, your aggregator works fine.' end it "should have content" do @entry.content.should_not be_nil end it "should have 'xhtml' for the type of the content" do @entry.content.type.should == 'xhtml' end it "should strip the outer div of the content" do @entry.content.should_not match(/div/) end it "should keep inner xhtml of content" do @entry.content.should == '

For information, see:

' + '' end end end describe 'unknown-namespace.atom' do before(:all) do @feed = Atom::Feed.load_feed(File.open('spec/conformance/unknown-namespace.atom')) @entry = @feed.entries.first @content = @entry.content end it "should have content" do @content.should_not be_nil end it "should strip surrounding div" do @content.should_not match(/div/) end it "should keep inner lists" do @content.should match(/ true) do |entry| entry_count += 1 end entry_count.should == 3 end it "should not paginate through each entry when paginate not true" do entry_count = 0 @feed.each_entry do |entry| entry_count += 1 end entry_count.should == 1 end it "should only paginate up to since" do response1 = Net::HTTPSuccess.new(nil, nil, nil) response1.stub!(:body).and_return(File.read('spec/paging/middle_paged_feed.atom')) mock_http_get(URI.parse('http://example.org/index.atom?page=2'), response1) entry_count = 0 @feed.each_entry(:paginate => true, :since => Time.parse('2003-11-19T18:30:02Z')) do |entry| entry_count += 1 end entry_count.should == 1 end end describe "entry_with_simple_extensions.atom" do before(:each) do @feed = Atom::Feed.load_feed(File.open('spec/fixtures/entry_with_simple_extensions.atom')) @entry = @feed.entries.first end it "should load simple extension for feed" do @feed["http://example.org/example", 'simple1'].should == ['Simple1 Value'] end it "should load empty simple extension for feed" do @feed["http://example.org/example", 'simple-empty'].should == [''] end it "should load simple extension 1 for entry" do @entry["http://example.org/example", 'simple1'].should == ['Simple1 Entry Value'] end it "should load simple extension 2 for entry" do @entry["http://example.org/example", 'simple2'].should == ['Simple2', 'Simple2a'] end it "should find a simple extension in another namespace" do @entry["http://example2.org/example2", 'simple1'].should == ['Simple Entry Value (NS2)'] end it "should load simple extension attribute on a category" do @entry.categories.first["http://example.org/example", "attribute"].first.should == "extension" end it "should write a simple extension attribute as an attribute" do @entry.categories.first.to_xml(true)['ns1:attribute'].should == 'extension' end it "should read an extension with the same local name as an Atom element" do @feed['http://example.org/example', 'title'].should == ['Extension Title'] end it_should_behave_like 'simple_single_entry.atom attributes' it "should load simple extension 3 xml for entry" do @entry["http://example.org/example3", 'simple3'].should == ['Simple Entry Value (NS2)'] end end describe 'writing simple extensions' do it "should recode and re-read a simple extension element" do entry = Atom::Entry.new do |entry| entry.id = 'urn:test' entry.title = 'Simple Ext. Test' entry.updated = Time.now entry['http://example.org', 'title'] << 'Example title' end entry2 = Atom::Entry.load_entry(entry.to_xml) entry2['http://example.org', 'title'].should == ['Example title'] end end end describe Atom::Link do before(:each) do @href = 'http://example.org/next' @link = Atom::Link.new(:rel => 'next', :href => @href) end it "should fetch feed for fetch_next" do Atom::Feed.should_receive(:load_feed).with(URI.parse(@href), an_instance_of(Hash)) @link.fetch end it "should fetch content when response is not xml" do Atom::Feed.should_receive(:load_feed).and_raise(Atom::LoadError) response = Net::HTTPSuccess.new(nil, nil, nil) response.stub!(:body).and_return('some text.') Net::HTTP.should_receive(:get_response).with(URI.parse(@href)).and_return(response) @link.fetch.should == 'some text.' end end describe Atom::Entry do before(:all) do @entry = Atom::Entry.load_entry(File.read('spec/fixtures/entry.atom')) end it "should be == to itself" do @entry.should == Atom::Entry.load_entry(File.read('spec/fixtures/entry.atom')) end it "should be != if something changes" do @other = Atom::Entry.load_entry(File.read('spec/fixtures/entry.atom')) @other.title = 'foo' @entry.should_not == @other end it "should be != if content changes" do @other = Atom::Entry.load_entry(File.read('spec/fixtures/entry.atom')) @other.content.type = 'html' @entry.should_not == @other end it "should output itself" do other = Atom::Entry.load_entry(@entry.to_xml) @entry.should == other end it "should properly escape titles" do @entry.title = "Breaking Space" other = Atom::Entry.load_entry(@entry.to_xml) @entry.should == other end it "should raise error when to_xml'ing non-utf8 content" do lambda { puts(Atom::Entry.new do |entry| entry.title = "My entry" entry.id = "urn:entry:1" entry.content = Atom::Content::Html.new("this is not \227 utf8") end.to_xml) }.should raise_error(Atom::SerializationError) end end describe 'Atom::Feed initializer' do it "should create an empty Feed" do lambda { Atom::Feed.new }.should_not raise_error end it "should yield to a block" do lambda do Atom::Feed.new do |f| f.should be_an_instance_of(Atom::Feed) throw :yielded end end.should throw_symbol(:yielded) end end describe 'Atom::Entry initializer' do it "should create an empty feed" do lambda { Atom::Entry.new }.should_not raise_error end it "should yield to a block" do lambda do Atom::Entry.new do |f| f.should be_an_instance_of(Atom::Entry) throw :yielded end end.should throw_symbol(:yielded) end end describe Atom::Content::Html do it "should escape ampersands in entities" do Atom::Content::Html.new(" ").to_xml.to_s.should == "&nbsp;" end end describe 'Atom::Category initializer' do it "should create a empty category" do lambda { Atom::Category.new }.should_not raise_error end it "should create from a hash" do category = Atom::Category.new(:term => 'term', :scheme => 'scheme', :label => 'label') category.term.should == 'term' category.scheme.should == 'scheme' category.label.should == 'label' end it "should create from a block" do category = Atom::Category.new do |cat| cat.term = 'term' end category.term.should == 'term' end end describe Atom::Source do it "should create an empty source" do lambda { Atom::Source.new }.should_not raise_error end it "should create from a hash" do source = Atom::Source.new(:title => 'title', :id => 'sourceid') source.title.should == 'title' source.id.should == 'sourceid' end it "should create from a block" do source = Atom::Source.new do |source| source.title = 'title' source.id = 'sourceid' end source.title.should == 'title' source.id.should == 'sourceid' end end describe Atom::Generator do it "should create an empty generator" do lambda { Atom::Generator.new }.should_not raise_error end it "should create from a hash" do source = Atom::Generator.new(:name => 'generator', :uri => 'http://generator') source.name.should == 'generator' source.uri.should == 'http://generator' end it "should create from a block" do source = Atom::Generator.new do |source| source.name = 'generator' source.uri = 'http://generator' end source.name.should == 'generator' source.uri.should == 'http://generator' end end end