facebooker 0.9.5

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 (60) hide show
  1. data/CHANGELOG.txt +0 -0
  2. data/COPYING +19 -0
  3. data/History.txt +3 -0
  4. data/Manifest.txt +60 -0
  5. data/README +44 -0
  6. data/README.txt +79 -0
  7. data/Rakefile +38 -0
  8. data/TODO.txt +10 -0
  9. data/facebooker.yml.tpl +36 -0
  10. data/init.rb +52 -0
  11. data/install.rb +5 -0
  12. data/lib/facebooker.rb +63 -0
  13. data/lib/facebooker/affiliation.rb +10 -0
  14. data/lib/facebooker/album.rb +11 -0
  15. data/lib/facebooker/cookie.rb +10 -0
  16. data/lib/facebooker/data.rb +38 -0
  17. data/lib/facebooker/education_info.rb +11 -0
  18. data/lib/facebooker/event.rb +26 -0
  19. data/lib/facebooker/feed.rb +65 -0
  20. data/lib/facebooker/group.rb +35 -0
  21. data/lib/facebooker/location.rb +8 -0
  22. data/lib/facebooker/model.rb +118 -0
  23. data/lib/facebooker/notifications.rb +17 -0
  24. data/lib/facebooker/parser.rb +386 -0
  25. data/lib/facebooker/photo.rb +9 -0
  26. data/lib/facebooker/rails/controller.rb +174 -0
  27. data/lib/facebooker/rails/facebook_asset_path.rb +18 -0
  28. data/lib/facebooker/rails/facebook_form_builder.rb +112 -0
  29. data/lib/facebooker/rails/facebook_request_fix.rb +14 -0
  30. data/lib/facebooker/rails/facebook_session_handling.rb +58 -0
  31. data/lib/facebooker/rails/facebook_url_rewriting.rb +31 -0
  32. data/lib/facebooker/rails/helpers.rb +535 -0
  33. data/lib/facebooker/rails/routing.rb +49 -0
  34. data/lib/facebooker/rails/test_helpers.rb +11 -0
  35. data/lib/facebooker/rails/utilities.rb +22 -0
  36. data/lib/facebooker/server_cache.rb +24 -0
  37. data/lib/facebooker/service.rb +25 -0
  38. data/lib/facebooker/session.rb +385 -0
  39. data/lib/facebooker/tag.rb +12 -0
  40. data/lib/facebooker/user.rb +200 -0
  41. data/lib/facebooker/version.rb +9 -0
  42. data/lib/facebooker/work_info.rb +9 -0
  43. data/lib/net/http_multipart_post.rb +123 -0
  44. data/lib/tasks/facebooker.rake +16 -0
  45. data/lib/tasks/tunnel.rake +39 -0
  46. data/setup.rb +1585 -0
  47. data/test/event_test.rb +15 -0
  48. data/test/facebook_cache_test.rb +43 -0
  49. data/test/facebook_data_test.rb +50 -0
  50. data/test/facebooker_test.rb +766 -0
  51. data/test/fixtures/multipart_post_body_with_only_parameters.txt +33 -0
  52. data/test/fixtures/multipart_post_body_with_single_file.txt +38 -0
  53. data/test/fixtures/multipart_post_body_with_single_file_that_has_nil_key.txt +38 -0
  54. data/test/http_multipart_post_test.rb +54 -0
  55. data/test/model_test.rb +79 -0
  56. data/test/rails_integration_test.rb +732 -0
  57. data/test/session_test.rb +396 -0
  58. data/test/test_helper.rb +54 -0
  59. data/test/user_test.rb +101 -0
  60. metadata +130 -0
@@ -0,0 +1,15 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class EventTest< Test::Unit::TestCase
4
+ def test_attendance_will_query_for_event_when_asked_for_full_event_object
5
+ session = flexmock("a session object")
6
+ eid = 123
7
+ attendance = Facebooker::Event::Attendance.new
8
+ attendance.eid = eid
9
+ attendance.session = session
10
+ event = Facebooker::Event.new
11
+ event.eid = eid
12
+ session.should_receive(:post).once.with('facebook.events.get', :eids => [eid]).and_return([{:eid => eid}])
13
+ assert_equal(123, attendance.event.eid)
14
+ end
15
+ end
@@ -0,0 +1,43 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class FacebookCacheTest < Test::Unit::TestCase
4
+ def setup
5
+ @session = Facebooker::Session.create('apikey', 'secretkey')
6
+ end
7
+
8
+ def test_can_ask_facebook_to_store_fbml_in_a_named_reference
9
+ expect_http_posts_with_responses(example_set_ref_handle_xml)
10
+ assert(@session.server_cache.set_ref_handle('a_handle_name', '<h2>Some FBML</h2>'))
11
+ end
12
+
13
+ def test_can_ask_facebook_to_recache_content_stored_from_a_given_url
14
+ expect_http_posts_with_responses(example_refresh_ref_url_xml)
15
+ assert(@session.server_cache.refresh_ref_url('http://localhost/roflmao'))
16
+ end
17
+
18
+ def test_can_ask_facebook_to_recache_an_img
19
+ expect_http_posts_with_responses(example_refresh_img_xml)
20
+ assert(@session.server_cache.refresh_img_src('http://localhost/roflmao.jpg'))
21
+ end
22
+
23
+ private
24
+ def example_set_ref_handle_xml
25
+ <<-XML
26
+ <?xml version="1.0" encoding="UTF-8"?>
27
+ <fbml_setRefHandle_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd">1</fbml_setRefHandle_response>
28
+ XML
29
+ end
30
+
31
+ def example_refresh_ref_url_xml
32
+ <<-XML
33
+ <?xml version="1.0" encoding="UTF-8"?>
34
+ <fbml_refreshRefUrl_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd">1</fbml_refreshRefUrl_response>
35
+ XML
36
+ end
37
+ def example_refresh_img_xml
38
+ <<-XML
39
+ <?xml version="1.0" encoding="UTF-8"?>
40
+ <fbml_refreshImgSrc_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd">1</fbml_refreshImgSrc_response>
41
+ XML
42
+ end
43
+ end
@@ -0,0 +1,50 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class FacebookDataTest < Test::Unit::TestCase
4
+ def setup
5
+ @session = Facebooker::Session.create('apikey', 'secretkey')
6
+ end
7
+
8
+ def test_can_ask_facebook_to_set_a_cookies
9
+ expect_http_posts_with_responses(example_set_cookie_xml)
10
+ assert(@session.data.set_cookie(12345, 'name', 'value'))
11
+ end
12
+
13
+ def test_can_ask_facebook_to_get_cookies
14
+ expect_http_posts_with_responses(example_get_cookies_xml)
15
+ assert(@session.data.get_cookies(12345))
16
+ end
17
+
18
+ def test_can_get_cookies_for_user
19
+ mock_http = establish_session
20
+ mock_http.should_receive(:post_form).and_return(example_get_cookies_xml).once.ordered(:posts)
21
+ cookies = @session.data.get_cookies(508508326)
22
+ assert_equal 'Foo', cookies.first.name
23
+ assert_equal 'Bar', cookies.first.value
24
+ end
25
+
26
+ private
27
+ def example_set_cookie_xml
28
+ <<-XML
29
+ <?xml version="1.0" encoding="UTF-8"?>
30
+ <data_setCookie_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
31
+ xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd">1</data_setCookie_response>
32
+ XML
33
+ end
34
+
35
+ def example_get_cookies_xml
36
+ <<-XML
37
+ <?xml version="1.0" encoding="UTF-8"?>
38
+ <data_getCookie_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
39
+ xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd">
40
+ <cookies>
41
+ <uid>508508326</uid>
42
+ <name>Foo</name>
43
+ <value>Bar</value>
44
+ <expires>0</expires>
45
+ <path>/tmp/</path>
46
+ </cookies>
47
+ </data_getCookie_response>
48
+ XML
49
+ end
50
+ end
@@ -0,0 +1,766 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+ class TestFacebooker < Test::Unit::TestCase
3
+
4
+ def setup
5
+ @api_key = "95a71599e8293s66f1f0a6f4aeab3df7"
6
+ @secret_key = "3e4du8eea435d8e205a6c9b5d095bed1"
7
+ @session = Facebooker::Session.create(@api_key, @secret_key)
8
+ @desktop_session = Facebooker::Session::Desktop.create(@api_key, @secret_key)
9
+ @service = Facebooker::Service.new('http://apibase.com', '/api/path', @api_key)
10
+ @desktop_session.instance_variable_set("@service", @service)
11
+ end
12
+
13
+ def test_session_must_be_created_from_api_key_and_secret_key
14
+ assert_kind_of(Facebooker::Session, @session)
15
+ end
16
+
17
+ def test_session_can_tell_you_its_login_url
18
+ assert_not_nil(@session.login_url)
19
+ assert_equal("http://www.facebook.com/login.php?api_key=#{@api_key}&v=1.0", @session.login_url)
20
+ end
21
+
22
+ def test_desktop_session_returns_auth_toke_as_part_of_login_url
23
+ @service = flexmock(@service).should_receive(:post).at_least.once.and_return(123)
24
+ assert_kind_of(Facebooker::Session::Desktop, @desktop_session)
25
+ assert_match(/auth_token=[a-z0-9A-Z]/, @desktop_session.login_url)
26
+ end
27
+
28
+ def test_service_posts_data_to_http_location
29
+ flexmock(Net::HTTP).should_receive(:post_form).and_return(example_auth_token_xml)
30
+ assert_equal("http://www.facebook.com/login.php?api_key=#{@api_key}&v=1.0&auth_token=3e4a22bb2f5ed75114b0fc9995ea85f1", @desktop_session.login_url)
31
+ end
32
+
33
+ def test_serivce_post_file_delegates_to_post_multipart_form
34
+ # flexmock(@service).should_receive(:url).and_return('url')
35
+ # flexmock(Net::HTTP).expects(:post_multipart_form).with('url', {:method => 'facebook.auth.createToken'}).returns(example_auth_token_xml)
36
+
37
+ res = mock(:content_type => 'text/html', :code => '200', :body => '<html><body>my blog</body></html>')
38
+ Net::HTTP.stubs(:get_response).once.with(uri).returns res
39
+
40
+ @service.post_file(:method => 'facebook.auth.createToken')
41
+ end
42
+
43
+ def test_desktop_session_be_secured_and_activated_after_receiving_auth_token_and_logging_in
44
+ establish_session
45
+ assert_equal("5f34e11bfb97c762e439e6a5-8055", @session.instance_variable_get("@session_key"))
46
+ end
47
+
48
+ def test_desktop_session_uses_secret_api_key_for_hashing_until_user_authenticates
49
+ assert_equal(@secret_key, @desktop_session.secret_for_method('facebook.auth.createToken'))
50
+ establish_session(@desktop_session)
51
+ assert_equal("ohairoflamao12345", @desktop_session.secret_for_method('anyNonAuthMethodName'))
52
+ end
53
+
54
+ def test_session_can_get_current_logged_in_user_id_and_will_cache
55
+ establish_session
56
+ flexmock(Net::HTTP).should_receive(:post_form).and_return(example_get_logged_in_user_xml)
57
+ assert_equal(8055, @session.user.id)
58
+ end
59
+
60
+ def test_can_get_current_users_friends
61
+ mock_http = establish_session
62
+ mock_http.should_receive(:post_form).and_return(example_friends_xml).once.ordered(:posts)
63
+ assert_equal([222333, 1240079], @session.user.friends.map{|friend| friend.id})
64
+ end
65
+
66
+ def test_can_get_info_for_instance_of_user
67
+ populate_user_info
68
+ @session.user.first_name = "Dave"
69
+ end
70
+
71
+ def test_can_get_info_for_one_or_more_users
72
+ friends = populate_session_friends
73
+ friend = friends.detect{|f| f.id == 222333}
74
+ assert_equal('This field perpetuates the glorification of the ego. Also, it has a character limit.',
75
+ friend.about_me)
76
+ assert_equal('Facebook Developers', friend.affiliations.first.name)
77
+ assert_equal('Friendship', friend.meeting_for.first)
78
+ assert_equal('94303', friend.current_location.zip)
79
+ assert_equal('York', friend.hometown_location.city)
80
+ assert_equal('Harvard', friend.education_history.first.name)
81
+ assert(friend.education_history.first.concentrations.include?("Computer Science"))
82
+ assert_equal('Central York High School', friend.hs_info.hs1_name)
83
+ assert_equal('female', friend.meeting_sex.first)
84
+ assert_equal('I rule', friend.status.message)
85
+ end
86
+
87
+ def test_can_get_specific_info_for_one_or_more_users
88
+ friends = populate_session_friends_with_limited_fields
89
+ friend = friends.detect{|f| f.id == 222333}
90
+ assert_equal('I rule', friend.status.message)
91
+ assert_equal(nil, friend.hometown_location)
92
+ end
93
+
94
+ def test_session_can_expire_on_server_and_client_handles_appropriately
95
+ mock_http = establish_session
96
+ mock_http.should_receive(:post_form).and_return(example_session_expired_error_response).once.ordered(:posts)
97
+ assert_raises(Facebooker::Session::SessionExpired) {
98
+ @session.user.friends
99
+ }
100
+ end
101
+
102
+
103
+ def test_can_publish_story_to_users_feed
104
+ mock_http = establish_session
105
+ mock_http.should_receive(:post_form).and_return(example_publish_story_xml).once.ordered(:posts)
106
+ assert_nothing_raised {
107
+ assert(@session.user.publish_story((s = Facebooker::Feed::Story.new; s.title = 'o hai'; s.body = '4srsly'; s)))
108
+ }
109
+ end
110
+
111
+
112
+ def test_can_publish_action_to_users_feed
113
+ mock_http = establish_session
114
+ mock_http.should_receive(:post_form).and_return(example_publish_action_xml).once.ordered(:posts)
115
+ assert_nothing_raised {
116
+ assert(@session.user.publish_action((s = Facebooker::Feed::Action.new; s.title = 'o hai'; s.body = '4srsly'; s)))
117
+ }
118
+ end
119
+
120
+ def test_can_publish_templatized_action_to_users_feed
121
+ mock_http = establish_session
122
+ mock_http.should_receive(:post_form).and_return(example_publish_templatized_action_xml).once.ordered(:posts)
123
+ assert_nothing_raised {
124
+ action = Facebooker::Feed::TemplatizedAction.new
125
+ action.actor_id = '12345'
126
+ action.title_template = "{actor} did something"
127
+ assert(@session.user.publish_templatized_action(action))
128
+ }
129
+ end
130
+
131
+ def test_can_publish_templatized_action_to_users_feed_with_params_as_string
132
+ json_data="{\"move\": \"punch\"}"
133
+ action = Facebooker::Feed::TemplatizedAction.new
134
+ action.title_template = "{actor} did something "
135
+ action.title_data=json_data
136
+ assert_equal action.to_params[:title_data],json_data
137
+ end
138
+
139
+ def test_can_publish_templatized_action_to_users_feed_with_params_as_hash
140
+ json_data="{\"move\": \"punch\"}"
141
+ hash={:move=>"punch"}
142
+ hash.expects(:to_json).returns(json_data)
143
+ action = Facebooker::Feed::TemplatizedAction.new
144
+ action.title_template = "{actor} did something "
145
+ action.title_data=hash
146
+ assert_equal action.to_params[:title_data],json_data
147
+ end
148
+
149
+ def test_can_get_notifications_for_logged_in_user
150
+ mock_http = establish_session
151
+ mock_http.should_receive(:post_form).and_return(example_notifications_get_xml).once.ordered(:posts)
152
+ assert_equal("1", @session.user.notifications.messages.unread)
153
+ assert_equal("0", @session.user.notifications.pokes.unread)
154
+ assert_equal("1", @session.user.notifications.shares.unread)
155
+ end
156
+
157
+ def test_can_send_notifications
158
+ mock_http = establish_session
159
+ mock_http.should_receive(:post_form).and_return(example_notifications_send_xml).once.ordered(:posts)
160
+ assert_nothing_raised {
161
+ user_ids = [123, 321]
162
+ notification_fbml = "O HAI!!!"
163
+ optional_email_fbml = "This would be in the email. If this is not passed, facebook sends no mailz!"
164
+ assert_equal('http://www.facebook.com/send_email.php?from=211031&id=52', @session.send_notification(user_ids, notification_fbml, optional_email_fbml))
165
+ }
166
+ end
167
+
168
+ def test_can_send_emails
169
+ mock_http = establish_session
170
+ mock_http.should_receive(:post_form).and_return(example_notifications_send_email_xml).once.ordered(:posts)
171
+ assert_nothing_raised {
172
+ user_ids = [123, 321]
173
+ text = "Hi I am the text part of the email."
174
+ fbml = "Hi I am the fbml version of the <b>email</a>"
175
+ subject = "Somethign you should really pay attention to."
176
+ assert_equal('123,321', @session.send_email(user_ids, subject,text,fbml ))
177
+ }
178
+ end
179
+
180
+ def test_can_find_friends_who_have_installed_app
181
+ mock_http = establish_session
182
+ mock_http.should_receive(:post_form).and_return(example_app_users_xml).once.ordered(:posts)
183
+ assert_equal(2, @session.user.friends_with_this_app.size)
184
+ assert_equal([222333, 1240079], @session.user.friends_with_this_app.map{|f| f.id})
185
+ end
186
+
187
+ def test_when_marshaling_a_session_object_only_enough_data_to_stay_authenticated_is_stored
188
+ populate_session_friends
189
+ assert_equal(2, @session.user.friends.size)
190
+ reloaded_session = Marshal.load(Marshal.dump(@session))
191
+ %w(@session_key @uid @expires @secret_from_session @auth_token).each do |iv_name|
192
+ assert_not_nil(reloaded_session.instance_variable_get(iv_name))
193
+ end
194
+ assert_nil(reloaded_session.user.instance_variable_get("@friends"))
195
+ end
196
+
197
+ def test_sessions_can_be_infinite_or_can_expire
198
+ establish_session
199
+ assert(@session.expired?, "Session with expiry time #{@session.instance_variable_get('@expires')} occurred in the past and should be expired.")
200
+ @session.instance_variable_set("@expires", 0)
201
+ assert(@session.infinite?)
202
+ assert(!@session.expired?)
203
+ end
204
+
205
+ def test_session_can_tell_you_if_it_has_been_secured
206
+ mock = flexmock(Net::HTTP).should_receive(:post_form).and_return(example_auth_token_xml).once.ordered(:posts)
207
+ mock.should_receive(:post_form).and_return(example_get_session_xml.sub(/1173309298/, (Time.now + 60).to_i.to_s)).once.ordered(:posts)
208
+ @session.secure!
209
+ assert(@session.secured?)
210
+ end
211
+
212
+ def test_can_get_photos_by_pids
213
+ mock_http = establish_session
214
+ mock_http.should_receive(:post_form).and_return(example_get_photo_xml).once.ordered(:posts)
215
+ photos = @session.get_photos([97503428461115590, 97503428461115573])
216
+ assert_equal 2, photos.size
217
+ assert_equal "Rooftop barbecues make me act funny", photos.first.caption
218
+ end
219
+
220
+ def test_can_get_photos_by_subject_and_album
221
+ mock_http = establish_session
222
+ mock_http.should_receive(:post_form).and_return(example_get_photo_xml).once.ordered(:posts)
223
+ photos = @session.get_photos(nil, 22701786, 97503428432802022 )
224
+ assert_equal '97503428432802022', photos.first.aid
225
+ end
226
+
227
+ def test_getting_photos_requires_arguments
228
+ mock_http = establish_session
229
+ assert_raise(ArgumentError) { @session.get_photos() }
230
+ end
231
+
232
+ def test_can_get_albums_for_user
233
+ mock_http = establish_session
234
+ mock_http.should_receive(:post_form).and_return(example_user_albums_xml).once.ordered(:posts)
235
+ assert_equal('Summertime is Best', @session.user.albums.first.name)
236
+ assert_equal(2, @session.user.albums.size)
237
+ end
238
+
239
+ def test_can_get_albums_by_album_ids
240
+ mock_http = establish_session
241
+ mock_http.should_receive(:post_form).and_return(example_user_albums_xml).once.ordered(:posts)
242
+ albums = @session.get_albums([97503428432802022, 97503428432797817] )
243
+ assert_equal('Summertime is Best', albums[0].name)
244
+ assert_equal('Bonofon\'s Recital', albums[1].name)
245
+ end
246
+
247
+ def test_can_create_album
248
+ mock_http = establish_session
249
+ mock_http.should_receive(:post_form).and_return(example_new_album_xml).once.ordered(:posts)
250
+ assert_equal "My Empty Album", @session.user.create_album(:name => "My Empty Album", :location => "Limboland").name
251
+ end
252
+
253
+ def test_can_upload_photo
254
+ mock_http = establish_session
255
+ mock_http.should_receive(:post_multipart_form).and_return(example_upload_photo_xml).once.ordered(:posts)
256
+ f = Net::HTTP::MultipartPostFile.new("image.jpg", "image/jpeg", "RAW DATA")
257
+ assert_equal "Under the sunset", @session.user.upload_photo(f).caption
258
+ end
259
+
260
+ def test_can_get_photo_tags
261
+ mock_http = establish_session
262
+ mock_http.should_receive(:post_form).and_return(example_photo_tags_xml).once.ordered(:posts)
263
+ assert_instance_of Facebooker::Tag, @session.get_tags(:pids => 97503428461115571 ).first
264
+ end
265
+
266
+ # TODO: how to test that tags were created properly? Response doesn't contain much
267
+ def test_can_tag_a_user_in_a_photo
268
+ mock_http = establish_session
269
+ mock_http.should_receive(:post_form).and_return(example_add_tag_xml).once.ordered(:posts)
270
+ assert !@session.add_tags(pid = 97503428461115571, x= 30.0, y = 62.5, tag_uid = 1234567890).nil?
271
+ end
272
+
273
+ def test_can_add_multiple_tags_to_photos
274
+ end
275
+
276
+ def test_can_get_coordinates_for_photo_tags
277
+ mock_http = establish_session
278
+ mock_http.should_receive(:post_form).and_return(example_photo_tags_xml).once.ordered(:posts)
279
+ tag = @session.get_tags([97503428461115571]).first
280
+ assert_equal ['65.4248', '16.8627'], tag.coordinates
281
+ end
282
+
283
+ def test_can_get_app_profile_fbml_for_user
284
+ mock_http = establish_session
285
+ mock_http.should_receive(:post_form).and_return(example_get_fbml_xml).once.ordered(:posts)
286
+ assert_match(/My profile!/, @session.user.profile_fbml)
287
+ end
288
+
289
+ def test_can_set_app_profile_fbml_for_user
290
+ mock_http = establish_session
291
+ mock_http.should_receive(:post_form).and_return(example_set_fbml_xml).once.ordered(:posts)
292
+ assert_nothing_raised {
293
+ @session.user.profile_fbml = 'aha!'
294
+ }
295
+ end
296
+
297
+ def test_desktop_apps_cannot_request_to_get_or_set_profile_fbml_for_any_user_other_than_logged_in_user
298
+ mock_http = establish_session(@desktop_session)
299
+ mock_http.should_receive(:post_form).and_return(example_friends_xml).once.ordered(:posts)
300
+ assert_raises(Facebooker::NonSessionUser) {
301
+ @desktop_session.user.friends.first.profile_fbml
302
+ }
303
+ assert_raises(Facebooker::NonSessionUser) {
304
+ @desktop_session.user.friends.first.profile_fbml = "O rly"
305
+ }
306
+ end
307
+
308
+ private
309
+ def populate_user_info
310
+ mock_http = establish_session
311
+ mock_http.should_receive(:post_form).and_return(example_user_info_xml).once
312
+ @session.user.populate
313
+ end
314
+
315
+ def populate_user_info_with_limited_fields
316
+ mock_http = establish_session
317
+ mock_http.should_receive(:post_form).and_return(example_limited_user_info_xml).once.ordered(:posts)
318
+ @session.user.populate(:affiliations, :status, :meeting_for)
319
+ end
320
+
321
+ def populate_session_friends
322
+ mock_http = establish_session
323
+ mock_http.should_receive(:post_form).and_return(example_friends_xml).once.ordered(:posts)
324
+ mock_http.should_receive(:post_form).and_return(example_user_info_xml).once.ordered(:posts)
325
+ @session.user.friends!
326
+ end
327
+
328
+ def populate_session_friends_with_limited_fields
329
+ mock_http = establish_session
330
+ mock_http.should_receive(:post_form).and_return(example_friends_xml).once.ordered(:posts)
331
+ mock_http.should_receive(:post_form).and_return(example_limited_user_info_xml).once.ordered(:posts)
332
+ @session.user.friends!(:affiliations, :status, :meeting_for)
333
+ end
334
+
335
+ def sample_args_to_post
336
+ {:method=>"facebook.auth.createToken", :sig=>"18b3dc4f5258a63c0ad641eebd3e3930"}
337
+ end
338
+
339
+ def example_set_fbml_xml
340
+ <<-XML
341
+ <?xml version="1.0" encoding="UTF-8"?>
342
+ <profile_setFBML_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd">1</profile_setFBML_response>
343
+ XML
344
+ end
345
+
346
+ def example_get_fbml_xml
347
+ <<-XML
348
+ <?xml version="1.0" encoding="UTF-8"?>
349
+ <profile_getFBML_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd">
350
+ &lt;fb:if-is-own-profile&gt;My profile!
351
+ &lt;fb:else&gt; Not my profile!&lt;/fb:else&gt;
352
+ &lt;/fb:if-is-own-profile&gt;
353
+ </profile_getFBML_response>
354
+ XML
355
+ end
356
+
357
+ def example_notifications_send_xml
358
+ <<-XML
359
+ <?xml version="1.0" encoding="UTF-8"?>
360
+ <notifications_send_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd">http://www.facebook.com/send_email.php?from=211031&id=52</notifications_send_response>
361
+ XML
362
+ end
363
+
364
+ def example_notifications_send_email_xml
365
+ <<-XML
366
+ <?xml version="1.0" encoding="UTF-8"?>
367
+ <notifications_sendEmail_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd">123,321</notifications_sendEmail_response>
368
+ XML
369
+ end
370
+
371
+ def example_request_send_xml
372
+ <<-XML
373
+ <?xml version="1.0" encoding="UTF-8"?>
374
+ <notifications_sendRequest_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd">http://www.facebook.com/send_req.php?from=211031&id=6</notifications_sendRequest_response>
375
+ XML
376
+ end
377
+
378
+ def example_notifications_get_xml
379
+ <<-XML
380
+ <?xml version="1.0" encoding="UTF-8"?>
381
+ <notifications_get_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd" list="true">
382
+ <messages>
383
+ <unread>1</unread>
384
+ <most_recent>1170644932</most_recent>
385
+ </messages>
386
+ <pokes>
387
+ <unread>0</unread>
388
+ <most_recent>0</most_recent>
389
+ </pokes>
390
+ <shares>
391
+ <unread>1</unread>
392
+ <most_recent>1170657686</most_recent>
393
+ </shares>
394
+ <friend_requests list="true">
395
+ <uid>2231342839</uid>
396
+ <uid>2231511925</uid>
397
+ <uid>2239284527</uid>
398
+ </friend_requests>
399
+ <group_invites list="true"/>
400
+ <event_invites list="true"/>
401
+ </notifications_get_response>
402
+ XML
403
+ end
404
+
405
+ def example_publish_story_xml
406
+ <<-XML
407
+ <?xml version="1.0" encoding="UTF-8"?>
408
+ <feed_publishStoryToUser_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd">1</feed_publishStoryToUser_response>
409
+ XML
410
+ end
411
+
412
+ def example_publish_action_xml
413
+ <<-XML
414
+ <?xml version="1.0" encoding="UTF-8"?>
415
+ <feed_publishActionOfUser_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd">1</feed_publishActionOfUser_response>
416
+ XML
417
+ end
418
+
419
+ def example_publish_templatized_action_xml
420
+ <<-XML
421
+ <?xml version="1.0" encoding="UTF-8"?>
422
+ <feed_publishTemplatizedAction_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd" list="true">
423
+ <feed_publishTemplatizedAction_response_elt>1</feed_publishTemplatizedAction_response_elt>
424
+ </feed_publishTemplatizedAction_response>
425
+ XML
426
+ end
427
+
428
+ def example_user_info_xml
429
+ <<-XML
430
+ <?xml version="1.0" encoding="UTF-8"?>
431
+ <users_getInfo_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd" list="true">
432
+ <user>
433
+ <uid>222333</uid>
434
+ <about_me>This field perpetuates the glorification of the ego. Also, it has a character limit.</about_me>
435
+ <activities>Here: facebook, etc. There: Glee Club, a capella, teaching.</activities>
436
+ <affiliations list="true">
437
+ <affiliation>
438
+ <nid>50453093</nid>
439
+ <name>Facebook Developers</name>
440
+ <type>work</type>
441
+ <status/>
442
+ <year/>
443
+ </affiliation>
444
+ </affiliations>
445
+ <birthday>November 3</birthday>
446
+ <books>The Brothers K, GEB, Ken Wilber, Zen and the Art, Fitzgerald, The Emporer's New Mind, The Wonderful Story of Henry Sugar</books>
447
+ <current_location>
448
+ <city>Palo Alto</city>
449
+ <state>CA</state>
450
+ <country>United States</country>
451
+ <zip>94303</zip>
452
+ </current_location>
453
+ <education_history list="true">
454
+ <education_info>
455
+ <name>Harvard</name>
456
+ <year>2003</year>
457
+ <concentrations list="true">
458
+ <concentration>Applied Mathematics</concentration>
459
+ <concentration>Computer Science</concentration>
460
+ </concentrations>
461
+ <degree>Masters</degree>
462
+ </education_info>
463
+ </education_history>
464
+ <first_name>Dave</first_name>
465
+ <hometown_location>
466
+ <city>York</city>
467
+ <state>PA</state>
468
+ <country>United States</country>
469
+ <zip>0</zip>
470
+ </hometown_location>
471
+ <hs_info>
472
+ <hs1_name>Central York High School</hs1_name>
473
+ <hs2_name/>
474
+ <grad_year>1999</grad_year>
475
+ <hs1_id>21846</hs1_id>
476
+ <hs2_id>0</hs2_id>
477
+ </hs_info>
478
+ <is_app_user>1</is_app_user>
479
+ <has_added_app>1</has_added_app>
480
+ <interests>coffee, computers, the funny, architecture, code breaking,snowboarding, philosophy, soccer, talking to strangers</interests>
481
+ <last_name>Fetterman</last_name>
482
+ <meeting_for list="true">
483
+ <seeking>Friendship</seeking>
484
+ </meeting_for>
485
+ <meeting_sex list="true">
486
+ <sex>female</sex>
487
+ </meeting_sex>
488
+ <movies>Tommy Boy, Billy Madison, Fight Club, Dirty Work, Meet the Parents, My Blue Heaven, Office Space </movies>
489
+ <music>New Found Glory, Daft Punk, Weezer, The Crystal Method, Rage, the KLF, Green Day, Live, Coldplay, Panic at the Disco, Family Force 5</music>
490
+ <name>Dave Fetterman</name>
491
+ <notes_count>0</notes_count>
492
+ <pic>http://photos-055.facebook.com/ip007/profile3/1271/65/s8055_39735.jpg</pic>
493
+ <pic_big>http://photos-055.facebook.com/ip007/profile3/1271/65/n8055_39735.jpg</pic_big>
494
+ <pic_small>http://photos-055.facebook.com/ip007/profile3/1271/65/t8055_39735.jpg</pic_small>
495
+ <pic_square>http://photos-055.facebook.com/ip007/profile3/1271/65/q8055_39735.jpg</pic_square>
496
+ <political>Moderate</political>
497
+ <profile_update_time>1170414620</profile_update_time>
498
+ <quotes/>
499
+ <relationship_status>In a Relationship</relationship_status>
500
+ <religion/>
501
+ <sex>male</sex>
502
+ <significant_other_id xsi:nil="true"/>
503
+ <status>
504
+ <message>I rule</message>
505
+ <time>0</time>
506
+ </status>
507
+ <timezone>-8</timezone>
508
+ <tv>cf. Bob Trahan</tv>
509
+ <wall_count>121</wall_count>
510
+ <work_history list="true">
511
+ <work_info>
512
+ <location>
513
+ <city>Palo Alto</city>
514
+ <state>CA</state>
515
+ <country>United States</country>
516
+ </location>
517
+ <company_name>Facebook</company_name>
518
+ <position>Software Engineer</position>
519
+ <description>Tech Lead, Facebook Platform</description>
520
+ <start_date>2006-01</start_date>
521
+ <end_date/>
522
+ </work_info>
523
+ </work_history>
524
+ </user>
525
+ <user>
526
+ <uid>1240079</uid>
527
+ <about_me>I am here.</about_me>
528
+ <activities>Party.</activities>
529
+ </user>
530
+ </users_getInfo_response>
531
+ XML
532
+ end
533
+
534
+ def example_limited_user_info_xml
535
+ <<-XML
536
+ <?xml version="1.0" encoding="UTF-8"?>
537
+ <users_getInfo_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd" list="true">
538
+ <user>
539
+ <uid>222333</uid>
540
+ <affiliations list="true">
541
+ <affiliation>
542
+ <nid>50453093</nid>
543
+ <name>Facebook Developers</name>
544
+ <type>work</type>
545
+ <status/>
546
+ <year/>
547
+ </affiliation>
548
+ </affiliations>
549
+ <meeting_for list="true">
550
+ <seeking>Friendship</seeking>
551
+ </meeting_for>
552
+ <status>
553
+ <message>I rule</message>
554
+ <time>0</time>
555
+ </status>
556
+ </user>
557
+ <user>
558
+ <uid>1240079</uid>
559
+ <activities>Party.</activities>
560
+ </user>
561
+ </users_getInfo_response>
562
+ XML
563
+ end
564
+
565
+
566
+ def example_friends_xml
567
+ <<-XML
568
+ <?xml version="1.0" encoding="UTF-8"?>
569
+ <friends_get_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd" list="true">
570
+ <uid>222333</uid>
571
+ <uid>1240079</uid>
572
+ </friends_get_response>
573
+ XML
574
+ end
575
+
576
+ def example_get_logged_in_user_xml
577
+ <<-XML
578
+ <?xml version="1.0" encoding="UTF-8"?>
579
+ <users_getLoggedInUser_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd" list="true">1240077</users_getLoggedInUser_response>
580
+ XML
581
+ end
582
+
583
+ def example_invalid_api_key_error_response
584
+ <<-XML
585
+ <?xml version="1.0" encoding="UTF-8"?>
586
+ <error_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd">
587
+ <error_code>101</error_code>
588
+ <error_msg>Invalid API key</error_msg>
589
+ <request_args list="true">
590
+ <arg>
591
+ <key>v</key>
592
+ <value>1.0</value>
593
+ </arg>
594
+ <arg>
595
+ <key>method</key>
596
+ <value>facebook.auth.createToken</value>
597
+ </arg>
598
+ <arg>
599
+ <key>sig</key>
600
+ <value>611f5f44e55f3fe17f858a8de84a4b0a</value>
601
+ </arg>
602
+ <arg>
603
+ <key>call_id</key>
604
+ <value>1186088346.82142</value>
605
+ </arg>
606
+ </request_args>
607
+ </error_response>
608
+ XML
609
+ end
610
+
611
+ def example_session_expired_error_response
612
+ <<-XML
613
+ <?xml version="1.0" encoding="UTF-8"?>
614
+ <error_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd">
615
+ <error_code>102</error_code>
616
+ <error_msg>Session Expired</error_msg>
617
+ <request_args list="true">
618
+ <arg>
619
+ <key>v</key>
620
+ <value>1.0</value>
621
+ </arg>
622
+ <arg>
623
+ <key>method</key>
624
+ <value>facebook.auth.createToken</value>
625
+ </arg>
626
+ <arg>
627
+ <key>sig</key>
628
+ <value>611f5f44e55f3fe17f858a8de84a4b0a</value>
629
+ </arg>
630
+ <arg>
631
+ <key>call_id</key>
632
+ <value>1186088346.82142</value>
633
+ </arg>
634
+ </request_args>
635
+ </error_response>
636
+ XML
637
+ end
638
+
639
+ def example_app_users_xml
640
+ <<-XML
641
+ <?xml version="1.0" encoding="UTF-8"?>
642
+ <friends_getAppUsers_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd" list="true">
643
+ <uid>222333</uid>
644
+ <uid>1240079</uid>
645
+ </friends_getAppUsers_response>
646
+ XML
647
+ end
648
+
649
+ def example_user_albums_xml
650
+ <<-XML
651
+ <?xml version="1.0" encoding="UTF-8"?>
652
+ <photos_getAlbums_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd" list="true">
653
+ <album>
654
+ <aid>97503428432802022</aid>
655
+ <cover_pid>97503428461115574</cover_pid>
656
+ <owner>22701786</owner>
657
+ <name>Summertime is Best</name>
658
+ <created>1184120648</created>
659
+ <modified>1185465771</modified>
660
+ <description>Happenings on or around Summer '07</description>
661
+ <location>Brooklyn, New York</location>
662
+ <link>http://www.facebook.com/album.php?aid=2011366&amp;id=22701786</link>
663
+ <size>49</size>
664
+ </album>
665
+ <album>
666
+ <aid>97503428432797817</aid>
667
+ <cover_pid>97503428460977993</cover_pid>
668
+ <owner>22701786</owner>
669
+ <name>Bonofon's Recital</name>
670
+ <created>1165356279</created>
671
+ <modified>1165382364</modified>
672
+ <description>The whole Ewing fam flies out to flatland to watch the Bonofon's senior recital. That boy sure can tinkle them ivories.</description>
673
+ <location>Grinnell College, Grinnell Iowa</location>
674
+ <link>http://www.facebook.com/album.php?aid=2007161&amp;id=22701786</link>
675
+ <size>14</size>
676
+ </album>
677
+ </photos_getAlbums_response>
678
+ XML
679
+ end
680
+
681
+ def example_upload_photo_xml
682
+ <<-XML
683
+ <?xml version="1.0" encoding="UTF-8"?>
684
+ <photos_upload_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd">
685
+ <pid>940915697041656</pid>
686
+ <aid>940915667462717</aid>
687
+ <owner>219074</owner>
688
+ <src>http://ip002.facebook.com/v67/161/72/219074/s219074_31637752_5455.jpg</src>
689
+ <src_big>http://ip002.facebook.com/v67/161/72/219074/n219074_31637752_5455.jpg</src_big>
690
+ <src_small>http://ip002.facebook.com/v67/161/72/219074/t219074_31637752_5455.jpg</src_small>
691
+ <link>http://www.facebook.com/photo.php?pid=31637752&id=219074</link>
692
+ <caption>Under the sunset</caption>
693
+ </photos_upload_response>
694
+ XML
695
+ end
696
+
697
+ def example_new_album_xml
698
+ <<-XML
699
+ <?xml version="1.0" encoding="UTF-8"?>
700
+ <photos_createAlbum_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd">
701
+ <aid>34595963571485</aid>
702
+ <cover_pid>0</cover_pid>
703
+ <owner>8055</owner>
704
+ <name>My Empty Album</name>
705
+ <created>1132553109</created>
706
+ <modified>1132553363</modified>
707
+ <description>No I will not make out with you</description>
708
+ <location>York, PA</location>
709
+ <link>http://www.facebook.com/album.php?aid=2002205&id=8055</link>
710
+ <size>0</size>
711
+ </photos_createAlbum_response>
712
+ XML
713
+ end
714
+
715
+ def example_photo_tags_xml
716
+ <<-XML
717
+ <?xml version="1.0" encoding="UTF-8"?>
718
+ <photos_getTags_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd" list="true">
719
+ <photo_tag>
720
+ <pid>97503428461115571</pid>
721
+ <subject>570070524</subject>
722
+ <xcoord>65.4248</xcoord>
723
+ <ycoord>16.8627</ycoord>
724
+ </photo_tag>
725
+ </photos_getTags_response>
726
+ XML
727
+ end
728
+
729
+ def example_add_tag_xml
730
+ <<-XML
731
+ <?xml version="1.0" encoding="UTF-8"?>
732
+ <photos_addTag_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd">1</photos_addTag_response>
733
+ XML
734
+ end
735
+
736
+ def example_get_photo_xml
737
+ <<-XML
738
+ <?xml version="1.0" encoding="UTF-8"?>
739
+ <photos_get_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd" list="true">
740
+ <photo>
741
+ <pid>97503428461115590</pid>
742
+ <aid>97503428432802022</aid>
743
+ <owner>22701786</owner>
744
+ <src>http://photos-c.ak.facebook.com/photos-ak-sf2p/v77/74/112/22701786/s22701786_30324934_7816.jpg</src>
745
+ <src_big>http://photos-c.ak.facebook.com/photos-ak-sf2p/v77/74/112/22701786/n22701786_30324934_7816.jpg</src_big>
746
+ <src_small>http://photos-c.ak.facebook.com/photos-ak-sf2p/v77/74/112/22701786/t22701786_30324934_7816.jpg</src_small>
747
+ <link>http://www.facebook.com/photo.php?pid=30324934&amp;id=22701786</link>
748
+ <caption>Rooftop barbecues make me act funny</caption>
749
+ <created>1184120987</created>
750
+ </photo>
751
+ <photo>
752
+ <pid>97503428461115573</pid>
753
+ <aid>97503428432802022</aid>
754
+ <owner>22701786</owner>
755
+ <src>http://photos-b.ak.facebook.com/photos-ak-sf2p/v77/74/112/22701786/s22701786_30324917_4555.jpg</src>
756
+ <src_big>http://photos-b.ak.facebook.com/photos-ak-sf2p/v77/74/112/22701786/n22701786_30324917_4555.jpg</src_big>
757
+ <src_small>http://photos-b.ak.facebook.com/photos-ak-sf2p/v77/74/112/22701786/t22701786_30324917_4555.jpg</src_small>
758
+ <link>http://www.facebook.com/photo.php?pid=30324917&amp;id=22701786</link>
759
+ <caption/>
760
+ <created>1184120654</created>
761
+ </photo>
762
+ </photos_get_response>
763
+ XML
764
+ end
765
+
766
+ end