fleakr 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/README.rdoc +149 -0
  2. data/Rakefile +40 -0
  3. data/lib/fleakr/api/request.rb +58 -0
  4. data/lib/fleakr/api/response.rb +35 -0
  5. data/lib/fleakr/objects/contact.rb +31 -0
  6. data/lib/fleakr/objects/error.rb +22 -0
  7. data/lib/fleakr/objects/group.rb +26 -0
  8. data/lib/fleakr/objects/image.rb +51 -0
  9. data/lib/fleakr/objects/photo.rb +55 -0
  10. data/lib/fleakr/objects/search.rb +33 -0
  11. data/lib/fleakr/objects/set.rb +45 -0
  12. data/lib/fleakr/objects/user.rb +106 -0
  13. data/lib/fleakr/support/attribute.rb +28 -0
  14. data/lib/fleakr/support/object.rb +88 -0
  15. data/lib/fleakr/version.rb +13 -0
  16. data/lib/fleakr.rb +74 -0
  17. data/test/fixtures/contacts.getPublicList.xml +7 -0
  18. data/test/fixtures/groups.pools.getPhotos.xml +7 -0
  19. data/test/fixtures/people.findByEmail.xml +6 -0
  20. data/test/fixtures/people.findByUsername.xml +6 -0
  21. data/test/fixtures/people.getInfo.xml +18 -0
  22. data/test/fixtures/people.getPublicGroups.xml +7 -0
  23. data/test/fixtures/people.getPublicPhotos.xml +7 -0
  24. data/test/fixtures/photos.getSizes.xml +10 -0
  25. data/test/fixtures/photos.search.xml +7 -0
  26. data/test/fixtures/photosets.getList.xml +13 -0
  27. data/test/fixtures/photosets.getPhotos.xml +7 -0
  28. data/test/test_helper.rb +123 -0
  29. data/test/unit/fleakr/api/request_test.rb +93 -0
  30. data/test/unit/fleakr/api/response_test.rb +49 -0
  31. data/test/unit/fleakr/objects/contact_test.rb +58 -0
  32. data/test/unit/fleakr/objects/error_test.rb +21 -0
  33. data/test/unit/fleakr/objects/group_test.rb +31 -0
  34. data/test/unit/fleakr/objects/image_test.rb +76 -0
  35. data/test/unit/fleakr/objects/photo_test.rb +101 -0
  36. data/test/unit/fleakr/objects/search_test.rb +74 -0
  37. data/test/unit/fleakr/objects/set_test.rb +71 -0
  38. data/test/unit/fleakr/objects/user_test.rb +104 -0
  39. data/test/unit/fleakr/support/attribute_test.rb +68 -0
  40. data/test/unit/fleakr/support/object_test.rb +95 -0
  41. data/test/unit/fleakr_test.rb +44 -0
  42. metadata +123 -0
@@ -0,0 +1,88 @@
1
+ module Fleakr
2
+ module Support # :nodoc:all
3
+ module Object
4
+
5
+ module ClassMethods
6
+
7
+ def attributes
8
+ @attributes ||= []
9
+ end
10
+
11
+ def flickr_attribute(name, options = {})
12
+ self.attributes << Attribute.new(name, options)
13
+ class_eval "attr_accessor :#{name}"
14
+ end
15
+
16
+ def has_many(*attributes)
17
+ options = attributes.extract_options!
18
+ class_name = self.name
19
+
20
+ attributes.each do |attribute|
21
+ target = "Fleakr::Objects::#{attribute.to_s.classify}"
22
+ finder_attribute = options[:using].nil? ? "#{class_name.demodulize.underscore}_id": options[:using]
23
+ class_eval <<-CODE
24
+ def #{attribute}
25
+ @#{attribute} ||= #{target}.send("find_all_by_#{finder_attribute}".to_sym, self.id)
26
+ end
27
+ CODE
28
+ end
29
+ end
30
+
31
+ def find_all(condition, options)
32
+ attribute = options[:using].nil? ? condition.to_s.sub(/^by_/, '') : options[:using]
33
+ target_class = options[:class_name].nil? ? self.name : "Fleakr::Objects::#{options[:class_name]}"
34
+
35
+ class_eval <<-CODE
36
+ def self.find_all_#{condition}(value)
37
+ response = Fleakr::Api::Request.with_response!('#{options[:call]}', :#{attribute} => value)
38
+ (response.body/'rsp/#{options[:path]}').map {|e| #{target_class}.new(e) }
39
+ end
40
+ CODE
41
+ end
42
+
43
+ def find_one(condition, options)
44
+ attribute = options[:using].nil? ? condition.to_s.sub(/^by_/, '') : options[:using]
45
+
46
+ class_eval <<-CODE
47
+ def self.find_#{condition}(value)
48
+ response = Fleakr::Api::Request.with_response!('#{options[:call]}', :#{attribute} => value)
49
+ #{self.name}.new(response.body)
50
+ end
51
+ CODE
52
+ end
53
+
54
+ def scoped_search
55
+ key = "#{self.name.demodulize.underscore.downcase}_id".to_sym
56
+
57
+ class_eval <<-CODE
58
+ def search(search_text)
59
+ Fleakr::Objects::Search.new(:text => search_text, :#{key} => self.id).results
60
+ end
61
+ CODE
62
+ end
63
+
64
+ end
65
+
66
+ module InstanceMethods
67
+
68
+ def initialize(document = nil)
69
+ self.populate_from(document) unless document.nil?
70
+ end
71
+
72
+ def populate_from(document)
73
+ self.class.attributes.each do |attribute|
74
+ value = attribute.value_from(document)
75
+ self.send("#{attribute.name}=".to_sym, value) unless value.nil?
76
+ end
77
+ end
78
+
79
+ end
80
+
81
+ def self.included(other)
82
+ other.send(:extend, Fleakr::Support::Object::ClassMethods)
83
+ other.send(:include, Fleakr::Support::Object::InstanceMethods)
84
+ end
85
+
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,13 @@
1
+ module Fleakr
2
+ module Version # :nodoc:
3
+
4
+ MAJOR = 0
5
+ MINOR = 3
6
+ TINY = 0
7
+
8
+ def self.to_s
9
+ [MAJOR, MINOR, TINY].join('.')
10
+ end
11
+
12
+ end
13
+ end
data/lib/fleakr.rb ADDED
@@ -0,0 +1,74 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+
3
+ require 'uri'
4
+ require 'cgi'
5
+ require 'net/http'
6
+ require 'rubygems'
7
+ require 'hpricot'
8
+ require 'activesupport'
9
+
10
+ %w(support api objects).each do |path|
11
+ full_path = File.expand_path(File.dirname(__FILE__)) + "/fleakr/#{path}"
12
+ Dir["#{full_path}/*.rb"].each {|f| require f }
13
+ end
14
+
15
+ # = Fleakr: A teeny tiny gem to interface with Flickr
16
+ #
17
+ # Getting started is easy, just make sure you have a valid API key from Flickr and you can
18
+ # then start making any non-authenticated request to pull back data for yours and others'
19
+ # photostreams, sets, contacts, groups, etc...
20
+ #
21
+ # For now, all activity originates from a single user which you can find by username or
22
+ # email address.
23
+ #
24
+ # Example:
25
+ #
26
+ # require 'rubygems'
27
+ # require 'fleakr'
28
+ #
29
+ # # Our API key is ABC123 (http://www.flickr.com/services/api/keys/apply/)
30
+ # Fleakr.api_key = 'ABC123'
31
+ # user = Fleakr.user('bees')
32
+ # user = Fleakr.user('user@host.com')
33
+ # # Grab a list of sets
34
+ # user.sets
35
+ # # Grab a list of the user's public groups
36
+ # user.groups
37
+ #
38
+ # To see what other associations and attributes are available, see the Fleakr::Objects::User class
39
+ #
40
+ module Fleakr
41
+
42
+ mattr_accessor :api_key
43
+
44
+ # Find a user based on some unique user data. This method will try to find
45
+ # the user based on username and will fall back to email if that fails. Example:
46
+ #
47
+ # Fleakr.api_key = 'ABC123'
48
+ # Fleakr.user('the decapitator') # => #<Fleakr::Objects::User:0x692648 @username="the decapitator", @id="21775151@N06">
49
+ # Fleakr.user('user@host.com') # => #<Fleakr::Objects::User:0x11f484c @username="bckspcr", @id="84481630@N00">
50
+ #
51
+ def self.user(user_data)
52
+ begin
53
+ Objects::User.find_by_username(user_data)
54
+ rescue Api::Request::ApiError
55
+ Objects::User.find_by_email(user_data)
56
+ end
57
+ end
58
+
59
+ # Search all photos on the Flickr site. By default, this searches based on text, but you can pass
60
+ # different search parameters (passed as hash keys):
61
+ #
62
+ # [tags] The list of tags to search on (either as an array or comma-separated)
63
+ # [user_id] Scope the search to this user
64
+ # [group_id] Scope the search to this group
65
+ #
66
+ # If you're interested in User- and Group-scoped searches, you may want to use User#search and Group#search
67
+ # instead.
68
+ #
69
+ def self.search(params)
70
+ params = {:text => params} unless params.is_a?(Hash)
71
+ Objects::Search.new(params).results
72
+ end
73
+
74
+ end
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <rsp stat="ok">
3
+ <contacts page="1" pages="1" per_page="1000" perpage="1000" total="17">
4
+ <contact nsid="9302864@N42" username="blinky" iconserver="2263" iconfarm="3" ignored="0" />
5
+ <contact nsid="63204625@N20" username="inky" iconserver="53" iconfarm="1" ignored="0" />
6
+ </contacts>
7
+ </rsp>
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <rsp stat="ok">
3
+ <photos page="1" pages="796" perpage="100" total="79509">
4
+ <photo id="3101830908" owner="64008250@N00" secret="e85e249e72" server="3042" farm="4" title="Canal Gate" ispublic="1" isfriend="0" isfamily="0" ownername="oakraidr" dateadded="1229049777" />
5
+ <photo id="3100780049" owner="98821864@N00" secret="f46fbe211b" server="3274" farm="4" title="2alarm" ispublic="1" isfriend="0" isfamily="0" ownername="LooknFeel" dateadded="1229042651" />
6
+ </photos>
7
+ </rsp>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <rsp stat="ok">
3
+ <user id="31066442@N69" nsid="31066442@N69">
4
+ <username>frootpantz</username>
5
+ </user>
6
+ </rsp>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <rsp stat="ok">
3
+ <user id="31066442@N69" nsid="31066442@N69">
4
+ <username>frootpantz</username>
5
+ </user>
6
+ </rsp>
@@ -0,0 +1,18 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <rsp stat="ok">
3
+ <person id="31066442@N69" nsid="31066442@N69" isadmin="0" ispro="1" iconserver="30" iconfarm="1">
4
+ <username>frootpantz</username>
5
+ <realname>Sir Froot Pantz</realname>
6
+ <mbox_sha1sum>e52ed1e5b91c763694995460e9796fc2adc02019</mbox_sha1sum>
7
+ <location />
8
+ <photosurl>http://www.flickr.com/photos/frootpantz/</photosurl>
9
+ <profileurl>http://www.flickr.com/people/frootpantz/</profileurl>
10
+ <mobileurl>http://m.flickr.com/photostream.gne?id=34225</mobileurl>
11
+ <photos>
12
+ <firstdatetaken>2006-10-11 08:19:57</firstdatetaken>
13
+ <firstdate>1160612247</firstdate>
14
+ <count>3907</count>
15
+ <views>9002</views>
16
+ </photos>
17
+ </person>
18
+ </rsp>
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <rsp stat="ok">
3
+ <groups>
4
+ <group nsid="13378274@N00" name="Group #1" admin="0" eighteenplus="0" />
5
+ <group nsid="52242140489@N01" name="Group #2" admin="0" eighteenplus="0" />
6
+ </groups>
7
+ </rsp>
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <rsp stat="ok">
3
+ <photos page="1" pages="1" perpage="100" total="76">
4
+ <photo id="2924549350" owner="21775151@N06" secret="cbc1804258" server="3250" farm="4" title="Photo #1" ispublic="1" isfriend="0" isfamily="0" />
5
+ <photo id="2923697303" owner="21775151@N06" secret="649aa95f29" server="3208" farm="4" title="Photo #2" ispublic="1" isfriend="0" isfamily="0" />
6
+ </photos>
7
+ </rsp>
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <rsp stat="ok">
3
+ <sizes canblog="0" canprint="0" candownload="1">
4
+ <size label="Square" width="75" height="75" source="http://farm4.static.flickr.com/3093/2409912100_71e14ed08a_s.jpg" url="http://www.flickr.com/photos/the_decapitator/2409912100/sizes/sq/" media="photo" />
5
+ <size label="Thumbnail" width="100" height="67" source="http://farm4.static.flickr.com/3093/2409912100_71e14ed08a_t.jpg" url="http://www.flickr.com/photos/the_decapitator/2409912100/sizes/t/" media="photo" />
6
+ <size label="Small" width="240" height="160" source="http://farm4.static.flickr.com/3093/2409912100_71e14ed08a_m.jpg" url="http://www.flickr.com/photos/the_decapitator/2409912100/sizes/s/" media="photo" />
7
+ <size label="Medium" width="500" height="334" source="http://farm4.static.flickr.com/3093/2409912100_71e14ed08a.jpg" url="http://www.flickr.com/photos/the_decapitator/2409912100/sizes/m/" media="photo" />
8
+ <size label="Original" width="700" height="467" source="http://farm4.static.flickr.com/3093/2409912100_3305c4a108_o.jpg" url="http://www.flickr.com/photos/the_decapitator/2409912100/sizes/o/" media="photo" />
9
+ </sizes>
10
+ </rsp>
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <rsp stat="ok">
3
+ <photos page="1" pages="385" perpage="100" total="38424">
4
+ <photo id="3076020861" owner="31987693@N05" secret="b956549c07" server="3278" farm="4" title="Mona and Lisa" ispublic="1" isfriend="0" isfamily="0" />
5
+ <photo id="3075386827" owner="9377349@N05" secret="4e40291b2d" server="3151" farm="4" title="IMG_0055 1.JPG" ispublic="1" isfriend="0" isfamily="0" />
6
+ </photos>
7
+ </rsp>
@@ -0,0 +1,13 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <rsp stat="ok">
3
+ <photosets>
4
+ <photoset videos="0" primary="3044180117" farm="4" photos="138" id="72157609490909659" server="3012" secret="01cd1a741d">
5
+ <title>Second Set</title>
6
+ <description>This is the second set.</description>
7
+ </photoset>
8
+ <photoset videos="0" primary="2988511085" farm="4" photos="139" id="72157608538140671" server="3241" secret="a7b90926ba">
9
+ <title>First Set</title>
10
+ <description>This is the first set.</description>
11
+ </photoset>
12
+ </photosets>
13
+ </rsp>
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <rsp stat="ok">
3
+ <photoset id="72157609490909659" primary="3044180117" owner="31066442@N69" ownername="frootpantz" page="1" per_page="500" perpage="500" pages="1" total="138">
4
+ <photo id="3044163577" secret="fa27e5a824" server="3153" farm="4" title="Photo #1" isprimary="0" />
5
+ <photo id="3045001128" secret="a8c0e51b39" server="3204" farm="4" title="Photo #2" isprimary="0" />
6
+ </photoset>
7
+ </rsp>
@@ -0,0 +1,123 @@
1
+ $:.reject! { |e| e.include? 'TextMate' }
2
+
3
+ require 'rubygems'
4
+ require 'matchy'
5
+ require 'context'
6
+ require 'mocha'
7
+
8
+ require File.dirname(__FILE__) + '/../lib/fleakr'
9
+
10
+ class Test::Unit::TestCase
11
+
12
+ def self.should_have_a_value_for(attribute_test)
13
+ it "should have a value for :#{attribute_test.keys.first}" do
14
+ @object.send(attribute_test.keys.first).should == attribute_test.values.first
15
+ end
16
+ end
17
+
18
+ def self.should_search_by(key)
19
+ it "should be able to perform a scoped search by :#{key}" do
20
+ photos = [stub()]
21
+ search = stub(:results => photos)
22
+
23
+ klass = self.class.name.sub(/Test$/, '').constantize
24
+
25
+ instance = klass.new
26
+ instance.stubs(:id).with().returns('1')
27
+
28
+ Fleakr::Objects::Search.expects(:new).with(:text => 'foo', key => '1').returns(search)
29
+
30
+ instance.search('foo').should == photos
31
+ end
32
+ end
33
+
34
+ def self.should_have_many(*attributes)
35
+ class_name = self.name.demodulize.sub(/Test$/, '')
36
+ this_klass = "Fleakr::Objects::#{class_name}".constantize
37
+
38
+ options = attributes.extract_options!
39
+ finder_attribute = options[:using].nil? ? "#{class_name.downcase}_id" : options[:using]
40
+
41
+ attributes.each do |attribute|
42
+ target_klass = "Fleakr::Objects::#{attribute.to_s.singularize.classify}".constantize
43
+ it "should be able to retrieve the #{class_name.downcase}'s #{attribute}" do
44
+ results = [stub()]
45
+ object = this_klass.new
46
+ object.stubs(:id).with().returns('1')
47
+
48
+ target_klass.expects("find_all_by_#{finder_attribute}".to_sym).with('1').returns(results)
49
+ object.send(attribute).should == results
50
+ end
51
+
52
+ it "should memoize the results for the #{class_name.downcase}'s #{attribute}" do
53
+ object = this_klass.new
54
+
55
+ target_klass.expects("find_all_by_#{finder_attribute}".to_sym).once.returns([])
56
+ 2.times { object.send(attribute) }
57
+ end
58
+
59
+ end
60
+ end
61
+
62
+ def self.should_find_one(thing, options)
63
+ class_name = thing.to_s.singularize.camelcase
64
+ klass = "Fleakr::Objects::#{class_name}".constantize
65
+ object_type = class_name.downcase
66
+
67
+ options[:with] = options[:by] if options[:with].nil?
68
+
69
+ it "should be able to find a #{thing} by #{options[:by]}" do
70
+ condition_value = '1'
71
+ stub = stub()
72
+ response = mock_request_cycle :for => options[:call], :with => {options[:with] => condition_value}
73
+
74
+ klass.expects(:new).with(response.body).returns(stub)
75
+ klass.send("find_by_#{options[:by]}".to_sym, condition_value).should == stub
76
+ end
77
+ end
78
+
79
+ def self.should_find_all(thing, options)
80
+ class_name = thing.to_s.singularize.camelcase
81
+ klass = "Fleakr::Objects::#{class_name}".constantize
82
+ object_type = class_name.downcase
83
+
84
+ it "should be able to find all #{thing} by #{options[:by]}" do
85
+ condition_value = '1'
86
+ response = mock_request_cycle :for => options[:call], :with => {options[:by] => condition_value}
87
+
88
+ stubs = []
89
+ elements = (response.body/options[:path]).map
90
+
91
+
92
+ elements.each do |element|
93
+ stub = stub()
94
+ stubs << stub
95
+
96
+ klass.expects(:new).with(element).returns(stub)
97
+ end
98
+
99
+ klass.send("find_all_by_#{options[:by]}".to_sym, condition_value).should == stubs
100
+ end
101
+
102
+ end
103
+
104
+ def read_fixture(method_call)
105
+ fixture_path = File.dirname(__FILE__) + '/fixtures'
106
+ File.read("#{fixture_path}/#{method_call}.xml")
107
+ end
108
+
109
+ def mock_request_cycle(options)
110
+ response = stub(:body => Hpricot.XML(read_fixture(options[:for])))
111
+ Fleakr::Api::Request.expects(:with_response!).with(options[:for], options[:with]).returns(response)
112
+
113
+ response
114
+ end
115
+
116
+ def create_temp_directory
117
+ tmp_dir = File.dirname(__FILE__) + '/tmp'
118
+ FileUtils.mkdir(tmp_dir)
119
+
120
+ tmp_dir
121
+ end
122
+
123
+ end
@@ -0,0 +1,93 @@
1
+ require File.dirname(__FILE__) + '/../../../test_helper'
2
+
3
+ module Fleakr::Api
4
+ class RequestTest < Test::Unit::TestCase
5
+
6
+ describe "A Request instance" do
7
+
8
+ context "with an API key" do
9
+
10
+ before do
11
+ @api_key = 'f00b4r'
12
+ Fleakr.stubs(:api_key).with().returns(@api_key)
13
+ end
14
+
15
+ it "should know the full query parameters" do
16
+ request = Request.new('flickr.people.findByUsername', :username => 'foobar')
17
+
18
+ expected = [
19
+ "api_key=#{@api_key}",
20
+ "method=flickr.people.findByUsername",
21
+ "username=foobar"
22
+ ]
23
+
24
+ request.query_parameters.split('&').sort.should == expected
25
+ end
26
+
27
+ it "should escape the keys and values in the parameter list" do
28
+ request = Request.new('flickr.people.findByUsername', :username => 'the decapitator')
29
+ request.query_parameters.split('&').include?("username=#{CGI.escape('the decapitator')}").should be(true)
30
+ end
31
+
32
+ it "should translate a shorthand API call" do
33
+ request = Request.new('people.findByUsername')
34
+ request.query_parameters.split('&').include?('method=flickr.people.findByUsername').should be(true)
35
+ end
36
+
37
+ it "should know the endpoint with full parameters" do
38
+ query_parameters = 'foo=bar'
39
+
40
+ request = Request.new('people.getInfo')
41
+ request.stubs(:query_parameters).with().returns(query_parameters)
42
+
43
+ uri_mock = mock() {|m| m.expects(:query=).with(query_parameters)}
44
+
45
+ URI.expects(:parse).with("http://api.flickr.com/services/rest/").returns(uri_mock)
46
+
47
+ request.endpoint_uri.should == uri_mock
48
+ end
49
+
50
+ it "should be able to make a request" do
51
+ endpoint_uri = stub()
52
+
53
+ request = Request.new('flickr.people.findByUsername')
54
+
55
+ request.stubs(:endpoint_uri).with().returns(endpoint_uri)
56
+ Net::HTTP.expects(:get).with(endpoint_uri).returns('<xml>')
57
+
58
+ request.send
59
+ end
60
+
61
+ it "should create a response from the request" do
62
+ response_xml = '<xml>'
63
+ response_stub = stub()
64
+
65
+ request = Request.new('flickr.people.findByUsername')
66
+
67
+ Net::HTTP.stubs(:get).returns(response_xml)
68
+ Response.expects(:new).with(response_xml).returns(response_stub)
69
+
70
+ request.send.should == response_stub
71
+ end
72
+
73
+ it "should be able to make a full request and response cycle" do
74
+ response = stub(:error? => false)
75
+ Response.expects(:new).with(kind_of(String)).returns(response)
76
+
77
+ Request.with_response!('flickr.people.findByUsername', :username => 'foobar').should == response
78
+ end
79
+
80
+ it "should raise an exception when the full request / response cycle has errors" do
81
+ response = stub(:error? => true, :error => stub(:code => '1', :message => 'User not found'))
82
+ Response.stubs(:new).with(kind_of(String)).returns(response)
83
+
84
+ lambda do
85
+ Request.with_response!('flickr.people.findByUsername', :username => 'foobar')
86
+ end.should raise_error(Fleakr::Api::Request::ApiError)
87
+ end
88
+
89
+ end
90
+
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,49 @@
1
+ require File.dirname(__FILE__) + '/../../../test_helper'
2
+
3
+ module Fleakr::Api
4
+ class ResponseTest < Test::Unit::TestCase
5
+
6
+ describe "An instance of Response" do
7
+
8
+ it "should provide the response body as an Hpricot element" do
9
+ response_xml = '<xml>'
10
+ hpricot_stub = stub()
11
+
12
+ Hpricot.expects(:XML).with(response_xml).returns(hpricot_stub)
13
+
14
+ response = Response.new(response_xml)
15
+ response.body.should == hpricot_stub
16
+ end
17
+
18
+ it "should memoize the Hpricot document" do
19
+ response = Response.new('<xml>')
20
+
21
+ Hpricot.expects(:XML).with(kind_of(String)).once.returns(stub())
22
+
23
+ 2.times { response.body }
24
+ end
25
+
26
+ it "should know if there are errors in the response" do
27
+ response_xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<rsp stat=\"fail\">\n\t<err code=\"1\" msg=\"User not found\" />\n</rsp>\n"
28
+ response = Response.new(response_xml)
29
+
30
+ response.error?.should be(true)
31
+ end
32
+
33
+ it "should not have an error if there are no errors in the XML" do
34
+ response = Response.new(read_fixture('people.findByUsername'))
35
+ response.error.should be(nil)
36
+ end
37
+
38
+ it "should have an error if there is an error in the response" do
39
+ response_xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<rsp stat=\"fail\">\n\t<err code=\"1\" msg=\"User not found\" />\n</rsp>\n"
40
+ response = Response.new(response_xml)
41
+
42
+ response.error.code.should == '1'
43
+ response.error.message.should == 'User not found'
44
+ end
45
+
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,58 @@
1
+ require File.dirname(__FILE__) + '/../../../test_helper'
2
+
3
+ module Fleakr::Objects
4
+ class ContactTest < Test::Unit::TestCase
5
+
6
+ describe "The Contact class" do
7
+
8
+ should "return a list of users for a specified user's contacts" do
9
+ user_1, user_2 = [stub(), stub()]
10
+ contact_1, contact_2 = [stub(:to_user => user_1), stub(:to_user => user_2)]
11
+
12
+ response = mock_request_cycle :for => 'contacts.getPublicList', :with => {:user_id => '1'}
13
+
14
+ contact_1_doc, contact_2_doc = (response.body/'rsp/contacts/contact').map
15
+
16
+ Contact.stubs(:new).with(contact_1_doc).returns(contact_1)
17
+ Contact.stubs(:new).with(contact_2_doc).returns(contact_2)
18
+
19
+ Contact.find_all_by_user_id('1').should == [user_1, user_2]
20
+ end
21
+
22
+ end
23
+
24
+ describe "An instance of the Contact class" do
25
+ context "when populating from an XML document" do
26
+ before do
27
+ @object = Contact.new(Hpricot.XML(read_fixture('contacts.getPublicList')).at('contacts/contact'))
28
+ end
29
+
30
+ should_have_a_value_for :id => '9302864@N42'
31
+ should_have_a_value_for :username => 'blinky'
32
+ should_have_a_value_for :icon_server => '2263'
33
+ should_have_a_value_for :icon_farm => '3'
34
+
35
+ end
36
+
37
+ context "in general" do
38
+
39
+ should "be able to convert to a user" do
40
+ contact = Contact.new
41
+ user = mock()
42
+
43
+ User.stubs(:new).returns(user)
44
+
45
+ [:id, :username, :icon_server, :icon_farm].each do |method|
46
+ contact.stubs(method).with().returns(method.to_s)
47
+ user.expects("#{method}=".to_sym).with(method.to_s)
48
+ end
49
+
50
+ contact.to_user.should == user
51
+ end
52
+
53
+ end
54
+
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,21 @@
1
+ require File.dirname(__FILE__) + '/../../../test_helper'
2
+
3
+ module Fleakr::Objects
4
+ class ErrorTest < Test::Unit::TestCase
5
+
6
+ describe "An instance of the Error class" do
7
+
8
+ it "should have a code and a message" do
9
+ response_xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<rsp stat=\"fail\">\n\t<err code=\"1\" msg=\"User not found\" />\n</rsp>\n"
10
+
11
+ error = Error.new(Hpricot.XML(response_xml))
12
+
13
+ error.code.should == '1'
14
+ error.message.should == 'User not found'
15
+ end
16
+
17
+ end
18
+
19
+
20
+ end
21
+ end
@@ -0,0 +1,31 @@
1
+ require File.dirname(__FILE__) + '/../../../test_helper'
2
+
3
+ module Fleakr::Objects
4
+ class GroupTest < Test::Unit::TestCase
5
+
6
+ should_have_many :photos
7
+
8
+ should_search_by :group_id
9
+
10
+ describe "The Group class" do
11
+
12
+ should_find_all :groups, :by => :user_id, :call => 'people.getPublicGroups', :path => 'rsp/groups/group'
13
+
14
+ end
15
+
16
+ describe "An instance of the Group class" do
17
+ context "when initializing from an Hpricot document" do
18
+
19
+ before do
20
+ doc = Hpricot.XML(read_fixture('people.getPublicGroups')).at('rsp/groups/group')
21
+ @object = Group.new(doc)
22
+ end
23
+
24
+ should_have_a_value_for :id => '13378274@N00'
25
+ should_have_a_value_for :name => 'Group #1'
26
+
27
+ end
28
+ end
29
+
30
+ end
31
+ end