fleakr 0.3.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 (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