casademora-flickr 1.0.6

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 (7) hide show
  1. data/History.txt +54 -0
  2. data/LICENSE +20 -0
  3. data/README.txt +73 -0
  4. data/TODO +6 -0
  5. data/lib/flickr.rb +707 -0
  6. data/test/test_flickr.rb +1089 -0
  7. metadata +66 -0
@@ -0,0 +1,1089 @@
1
+ #require 'rubygems'
2
+ require 'flickr'
3
+ require 'test/unit'
4
+ #require 'mocha'
5
+
6
+ class TestFlickr < Test::Unit::TestCase
7
+
8
+ def test_get_list_of_photos_from_specified_photoset
9
+ flickr = Flickr.new('5a3f78d9a0f34169777dbb3ff266ba06')
10
+ testPhotoset = flickr.photoset('72157611041801782')
11
+
12
+ assert_not_nil testPhotoset.getPhotos
13
+ end
14
+
15
+ # Flickr client tests
16
+ #
17
+ # instantiation tests
18
+ def test_should_instantiate_new_flickr_client
19
+ Flickr.any_instance.stubs(:login)
20
+ flickr = Flickr.new('some_api_key', 'email@test.com', 'some_password', 'some_shared_secret')
21
+
22
+ assert_equal 'some_api_key', flickr.api_key
23
+ assert_equal 'some_shared_secret', flickr.instance_variable_get(:@shared_secret)
24
+ end
25
+
26
+ def test_should_try_to_login_using_old_api_if_email_and_password_passed
27
+ Flickr.any_instance.expects(:login).with('email@test.com', 'some_password') # checks email and password have been set
28
+ flickr = Flickr.new('some_api_key', 'email@test.com', 'some_password', 'some_shared_secret')
29
+ end
30
+
31
+ def test_should_instantiate_new_flickr_client_on_new_api
32
+ flickr = Flickr.new('api_key' => 'some_api_key', 'email' => 'email@test.com', 'password' => 'some_password', 'shared_secret' => 'some_shared_secret', 'foo' => 'bar')
33
+
34
+ assert_equal 'some_api_key', flickr.api_key
35
+ assert_equal 'some_shared_secret', flickr.instance_variable_get(:@shared_secret)
36
+ assert_nil flickr.instance_variable_get(:@foo) # should ignore other params
37
+ end
38
+
39
+ def test_should_not_try_to_login_using_old_api_when_instantiate_new_flickr_client_on_new_api
40
+ Flickr.any_instance.expects(:login).never # doesn't bother trying to login with new api -- it'll fail in any case
41
+ flickr = Flickr.new('api_key' => 'some_api_key', 'email' => 'email@test.com', 'password' => 'some_password', 'shared_secret' => 'some_shared_secret', 'foo' => 'bar')
42
+ end
43
+
44
+ # signature_from method tests
45
+ def test_should_return_signature_from_given_params
46
+ assert_equal Digest::MD5.hexdigest('shared_secret_codea_param1234xb_param5678yc_param97531t'),
47
+ authenticated_flickr_client.send(:signature_from, {:b_param => '5678y', 'c_param' => '97531t', :a_param => '1234x', :d_param => nil})
48
+ end
49
+
50
+ def test_should_return_nil_for_signature_when_no_shared_secret
51
+ assert_nil flickr_client.send(:signature_from, {:b_param => '5678y', :c_param => '97531t', :a_param => '1234x'})
52
+ end
53
+
54
+ # request_url method tests
55
+ def test_should_get_signature_for_params_when_building_url
56
+ f = authenticated_flickr_client
57
+ f.expects(:signature_from).with( 'method' => 'flickr.someMethod',
58
+ 'api_key' => 'some_api_key',
59
+ 'foo' => 'value which/needs&escaping',
60
+ 'auth_token' => 'some_auth_token').returns("foo123bar456")
61
+
62
+ url = f.send(:request_url, 'someMethod', 'foo' => 'value which/needs&escaping')
63
+ end
64
+
65
+ def test_should_build_url_from_params_with_signature
66
+ f = authenticated_flickr_client
67
+ f.stubs(:signature_from).returns("foo123bar456")
68
+
69
+ url = f.send(:request_url, 'someMethod', 'foo' => 'value which/needs&escaping')
70
+ [ "#{Flickr::HOST_URL}#{Flickr::API_PATH}",
71
+ 'api_key=some_api_key',
72
+ 'method=flickr.someMethod',
73
+ 'foo=value+which%2Fneeds%26escaping',
74
+ 'auth_token=some_auth_token',
75
+ 'api_sig=foo123bar456'].each do |kv_pair|
76
+ assert_match Regexp.new(Regexp.escape(kv_pair)), url
77
+ end
78
+ end
79
+
80
+ def test_should_build_url_from_params_when_signature_returns_nil
81
+ flickr = flickr_client
82
+ flickr.stubs(:signature_from)
83
+ assert_equal "#{Flickr::HOST_URL}#{Flickr::API_PATH}/?api_key=some_api_key&method=flickr.someMethod", flickr.send(:request_url, 'someMethod')
84
+ assert_equal "#{Flickr::HOST_URL}#{Flickr::API_PATH}/?api_key=some_api_key&method=flickr.someMethod&foo=bar", flickr.send(:request_url, 'someMethod', 'foo' => 'bar', 'foobar' => nil)
85
+ assert_equal "#{Flickr::HOST_URL}#{Flickr::API_PATH}/?api_key=some_api_key&method=flickr.someMethod&foo=101", flickr.send(:request_url, 'someMethod', 'foo' => 101)
86
+ assert_equal "#{Flickr::HOST_URL}#{Flickr::API_PATH}/?api_key=some_api_key&method=flickr.someMethod&foo=value+which%2Fneeds%26escaping", flickr.send(:request_url, 'someMethod', 'foo' => 'value which/needs&escaping')
87
+ end
88
+
89
+ # method_missing tests
90
+ def test_should_generate_flickr_method_from_unkown_method_on_flickr_client
91
+ f = flickr_client
92
+ f.expects(:request).with('some.unknown.methodForFlickr', {})
93
+ f.some_unknown_methodForFlickr
94
+ end
95
+
96
+ # request method tests
97
+ def test_should_make_successful_request
98
+ f = flickr_client
99
+ f.expects(:http_get).with('some.url').returns(successful_xml_response)
100
+ f.expects(:request_url).with('some_method', 'foo' => 'bar').returns("some.url")
101
+
102
+ f.send(:request, 'some_method', 'foo' => 'bar') # request is protected
103
+ end
104
+
105
+ def test_should_raise_exception_on_unsuccessful_request
106
+ f = flickr_client
107
+ f.expects(:http_get).returns(unsuccessful_xml_response)
108
+
109
+ assert_raise(RuntimeError) { f.send(:request, 'some_method', 'foo' => 'bar') }
110
+ end
111
+
112
+ def test_should_parse_returned_xml_in_successful_request
113
+ f = flickr_client
114
+ f.stubs(:http_get).returns(successful_xml_response)
115
+ expected_response = { "contacts" => { "perpage" => "1000",
116
+ "contact" => [{ "nsid"=>"12037949629@N01",
117
+ "username"=>"Eric",
118
+ "ignored"=>"1",
119
+ "family"=>"0",
120
+ "friend"=>"1",
121
+ "realname"=>"Eric Costello",
122
+ "iconserver"=>"1"},
123
+ { "nsid"=>"12037949631@N01",
124
+ "username"=>"neb",
125
+ "ignored"=>"0",
126
+ "family"=>"0",
127
+ "friend"=>"0",
128
+ "realname"=>"Ben Cerveny",
129
+ "iconserver"=>"1"}],
130
+ "total" => "2",
131
+ "pages"=> "1",
132
+ "page"=>"1" },
133
+ "stat"=>"ok" }
134
+
135
+ assert_equal expected_response, f.send(:request, 'some_method', 'foo' => 'bar')
136
+ end
137
+
138
+ # photos_request tests
139
+ def test_should_pass_photos_request_params_to_request
140
+ f = flickr_client
141
+ f.expects(:request).with('flickr.method', :one => 1, :two => "2").returns(dummy_photos_response)
142
+ f.photos_request( 'flickr.method', :one => 1, :two => "2")
143
+ end
144
+
145
+ def test_should_instantiate_recent_photos_with_id_and_all_params_returned_by_flickr
146
+ f = flickr_client
147
+ f.expects(:request).returns(dummy_photos_response)
148
+ Flickr::Photo.expects(:new).with("foo123",
149
+ "some_api_key", { "key1" => "value1",
150
+ "key2" => "value2"})
151
+ Flickr::Photo.expects(:new).with("bar456",
152
+ "some_api_key", { "key3" => "value3"})
153
+ photos = f.photos_request('some_method')
154
+ end
155
+
156
+ def test_should_parse_photos_response_into_flickr_photo_collection
157
+ f = flickr_client
158
+ f.expects(:request).returns(dummy_photos_response)
159
+ assert_kind_of Flickr::PhotoCollection, f.photos_request('some_method')
160
+ end
161
+
162
+ def test_should_store_pagination_info_in_photo_collection
163
+ f = flickr_client
164
+ f.expects(:request).returns(dummy_photos_response)
165
+ photos = f.photos_request('some_method')
166
+
167
+ assert_equal "3", photos.page
168
+ assert_equal "5", photos.pages
169
+ assert_equal "10", photos.perpage
170
+ assert_equal "42", photos.total
171
+ end
172
+
173
+ def test_should_return_collection_of_photos
174
+ f = flickr_client
175
+ f.expects(:request).returns(dummy_photos_response)
176
+ photos = f.photos_request('some_method')
177
+ assert_equal 2, photos.size
178
+ assert_kind_of Flickr::Photo, photos.first
179
+ assert_equal "foo123", photos.first.id
180
+ end
181
+
182
+ def test_should_work_with_single_result
183
+ f = flickr_client
184
+ f.expects(:request).returns(dummy_single_photo_response)
185
+ photos = f.photos_request('some_method')
186
+ assert_equal 1, photos.size
187
+ assert_kind_of Flickr::Photo, photos.first
188
+ assert_equal "foo123", photos.first.id
189
+ end
190
+
191
+ def test_should_work_with_empty_result
192
+ f = flickr_client
193
+ f.expects(:request).returns(dummy_zero_photo_response)
194
+ photos = f.photos_request('some_method')
195
+ assert_equal [], photos
196
+ end
197
+
198
+ def test_should_generate_login_url
199
+ f = flickr_client
200
+ f.expects(:signature_from).with('api_key' => 'some_api_key', 'perms' => 'write').returns('validsignature')
201
+ assert_equal 'http://flickr.com/services/auth/?api_key=some_api_key&perms=write&api_sig=validsignature', f.login_url('write')
202
+ end
203
+
204
+ def test_should_get_token_from_frob
205
+ f = flickr_client
206
+ f.expects(:request).with('auth.getToken',:frob => 'some_frob').returns({'auth' => {'token' => 'some_auth_token', 'user' => {}}})
207
+
208
+ auth_token = f.get_token_from('some_frob')
209
+ assert_equal 'some_auth_token', auth_token
210
+ end
211
+
212
+ def test_should_store_auth_token_in_client
213
+ f = flickr_client
214
+ f.expects(:request).returns({'auth' => {'token' => 'some_auth_token','user' => {}}})
215
+ f.get_token_from('some_frob')
216
+ assert_equal 'some_auth_token', f.auth_token
217
+ end
218
+
219
+ def test_should_store_authenticated_user_details_in_client
220
+ f = flickr_client
221
+ f.expects(:request).returns({ 'auth' => { 'token' => 'some_auth_token',
222
+ 'user' => { 'nsid' => 'foo123',
223
+ 'username' => 'some_user', 'fullname' => 'Some User'}}})
224
+ f.get_token_from('some_frob')
225
+ assert_kind_of Flickr::User, user = f.user
226
+ assert_equal 'foo123', user.id
227
+ assert_equal 'some_user', user.username
228
+ assert_equal 'Some User', user.name
229
+ assert_equal f, user.client
230
+ end
231
+
232
+ # photos method tests
233
+ def test_should_get_recent_photos_if_no_params_for_photos
234
+ f = flickr_client
235
+ f.expects(:photos_search)
236
+ f.photos
237
+ end
238
+
239
+ # photos_search method tests
240
+ def test_should_search_photos
241
+ f = authenticated_flickr_client
242
+ f.expects(:request).with('photos.search', anything).returns(dummy_photos_response)
243
+ photos = f.photos_search
244
+ assert_kind_of Flickr::Photo, photos.first
245
+ end
246
+
247
+ # users method tests
248
+ def test_should_find_user_from_email
249
+ f = flickr_client
250
+ f.expects(:request).with('people.findByEmail', anything).returns(dummy_user_response)
251
+ assert_kind_of Flickr::User, user = f.users("email@test.com")
252
+ assert_equal "12037949632@N01", user.id
253
+ assert_equal "Stewart", user.username
254
+ end
255
+
256
+ def test_should_find_user_from_username_if_fails_to_get_from_email
257
+ f = flickr_client
258
+ f.expects(:request).with('people.findByEmail', anything).raises
259
+ f.expects(:request).with('people.findByUsername', anything).returns(dummy_user_response)
260
+ assert_kind_of Flickr::User, f.users("email@test.com")
261
+ end
262
+
263
+ def test_should_pass_on_flickr_client_when_finding_user
264
+ f = flickr_client
265
+ f.stubs(:request).returns(dummy_user_response)
266
+ user = f.users("email@test.com")
267
+ assert_equal f, user.client
268
+ end
269
+
270
+ # groups method tests
271
+ def test_should_search_for_given_group
272
+ f = flickr_client
273
+ f.expects(:request).with("groups.search", {"text" => "foo"}).returns(dummy_groups_response)
274
+ f.groups("foo")
275
+ end
276
+
277
+ def test_should_search_for_given_group_with_additional_params
278
+ f = flickr_client
279
+ f.expects(:request).with("groups.search", {"text" => "foo", "per_page" => "1"}).returns(dummy_groups_response)
280
+ f.groups("foo", "per_page" => "1")
281
+ end
282
+
283
+ def test_should_instantiate_groups_from_search_response
284
+ f = flickr_client
285
+ f.stubs(:request).returns(dummy_groups_response)
286
+ assert_kind_of Array, groups = f.groups("foo")
287
+ assert_kind_of Flickr::Group, group = groups.first
288
+ assert_equal "group1", group.id
289
+ assert_equal "Group One", group.name
290
+ assert_equal "0", group.eighteenplus
291
+ assert_equal f, group.client
292
+ end
293
+
294
+ def test_should_instantiate_groups_from_search_response_with_single_group_returned
295
+ f = flickr_client
296
+ f.stubs(:request).returns(dummy_single_group_response)
297
+ assert_kind_of Array, groups = f.groups("foo")
298
+ assert_equal 1, groups.size
299
+ assert_equal "group1", groups.first.id
300
+ end
301
+
302
+ # ##### DIRECT MODE
303
+ #
304
+ # def test_test_echo
305
+ # assert_equal @f.test_echo['stat'], 'ok'
306
+ # end
307
+ # def test_test_login
308
+ # assert_equal @f.test_login['stat'], 'ok'
309
+ # end
310
+ #
311
+ #
312
+ # ##### BASICS
313
+ #
314
+ # def test_login
315
+ # assert_equal @username, @f.user.getInfo.username
316
+ # end
317
+ #
318
+ # def test_find_by_url
319
+ # assert_equal @group_id, @f.find_by_url(@group_url).getInfo.id # find group by URL
320
+ # assert_equal @user_id, @f.find_by_url(@user_url).getInfo.id # find user by URL
321
+ # end
322
+ #
323
+ # def test_licenses
324
+ # assert_kind_of Array, @f.licenses # find all licenses
325
+ # end
326
+ #
327
+
328
+ #
329
+ # Flickr#photos tests
330
+ #
331
+
332
+
333
+ # ##### Flickr::User tests
334
+ #
335
+ def test_should_instantiate_user
336
+ user = new_user
337
+ assert_equal 'foo123', user.id
338
+ assert_equal 'some_user', user.username
339
+ assert_equal 'bar', user.instance_variable_get(:@foo) # should collect all other params up and store as instance variables
340
+ end
341
+
342
+ def test_should_instantiate_new_user_with_old_api
343
+ Flickr.any_instance.stubs(:login) # stub logging in
344
+ user = Flickr::User.new('foo123',
345
+ 'some_user',
346
+ 'email@test.com', # email irrelevant since Flickr API no longer supports authentication in this way
347
+ 'password', # password irrelevant since Flickr API no longer supports authentication in this way
348
+ 'bar456')
349
+ assert_equal 'foo123', user.id
350
+ assert_equal 'some_user', user.username
351
+ assert_equal 'email@test.com', user.instance_variable_get(:@email)
352
+ assert_equal 'password', user.instance_variable_get(:@password)
353
+ assert_equal 'bar456', user.client.api_key
354
+ end
355
+
356
+ def test_should_instantiate_new_client_when_instantiating_user_if_no_client_passed_in_params
357
+ f = flickr_client
358
+ Flickr.expects(:new).returns(f)
359
+ user = new_user( 'api_key' => 'an_api_key' )
360
+ assert_equal f, user.client
361
+ end
362
+
363
+ def test_should_not_instantiate_new_client_when_instantiating_user_if_client_passed_in_params
364
+ f = flickr_client
365
+ Flickr.expects(:new).never
366
+ user = new_user( 'client' => f )
367
+ assert_equal f, user.client
368
+ end
369
+
370
+ def test_should_not_instantiate_client_if_no_api_key_passed
371
+ Flickr.expects(:new).never
372
+ user = new_user
373
+ assert_nil user.client
374
+ end
375
+
376
+ def test_should_build_url_for_users_profile_page_using_user_id
377
+ Flickr.any_instance.expects(:http_get).never
378
+ assert_equal "http://www.flickr.com/people/foo123/", new_user.url
379
+ end
380
+
381
+ def test_should_build_url_for_users_photos_page_using_user_id
382
+ Flickr.any_instance.expects(:http_get).never
383
+ assert_equal "http://www.flickr.com/photos/foo123/", new_user.photos_url
384
+ end
385
+
386
+ def test_should_get_pretty_url_for_users_profile_page
387
+ f = flickr_client
388
+ f.expects(:urls_getUserProfile).returns({"user" => {"nsid" => "bar456", "url" => "http://www.flickr.com/people/killer_bob/"}})
389
+
390
+ assert_equal "http://www.flickr.com/people/killer_bob/", new_user( 'client' => f ).pretty_url
391
+ end
392
+
393
+ def test_should_cache_pretty_url_for_users_profile_page
394
+ f = flickr_client
395
+ user = new_user( 'client' => f )
396
+ f.expects(:urls_getUserProfile).returns({"user" => {"nsid" => "bar456", "url" => "http://www.flickr.com/people/killer_bob/"}}) # expects only one call
397
+
398
+ user.pretty_url
399
+ user.pretty_url
400
+ end
401
+
402
+ def test_should_get_users_public_groups
403
+ f = flickr_client
404
+ f.expects(:request).with("people.getPublicGroups", anything).returns(dummy_groups_response)
405
+ new_user( 'client' => f ).groups
406
+ end
407
+
408
+ def test_should_instantiate_users_public_groups
409
+ f = flickr_client
410
+ f.stubs(:request).returns(dummy_groups_response)
411
+ user = new_user( 'client' => f )
412
+
413
+ groups = user.groups
414
+ assert_equal 2, groups.size
415
+ assert_kind_of Flickr::Group, group = groups.first
416
+ assert_equal "group1", group.id
417
+ assert_equal "Group One", group.name
418
+ assert_equal "0", group.eighteenplus
419
+ assert_equal f, group.client
420
+ end
421
+
422
+ def test_should_instantiate_users_public_groups_when_only_one_returned
423
+ f = flickr_client
424
+ f.stubs(:request).returns(dummy_single_group_response)
425
+ user = new_user( 'client' => f )
426
+ groups = user.groups
427
+ assert_equal 1, groups.size
428
+ end
429
+ # def test_getInfo
430
+ # @u.getInfo
431
+ # assert_equal @username, @u.username
432
+ # end
433
+ #
434
+ # def test_groups
435
+ # assert_kind_of Flickr::Group, @u.groups.first # public groups
436
+ # end
437
+ #
438
+ #
439
+ # def test_contacts
440
+ # assert_kind_of Flickr::User, @u.contacts.first # public contacts
441
+ # end
442
+ #
443
+ # def test_favorites
444
+ # assert_kind_of Flickr::Photo, @u.favorites.first # public favorites
445
+ # end
446
+ #
447
+ # def test_photosets
448
+ # assert_kind_of Flickr::Photoset, @u.photosets.first # public photosets
449
+ # end
450
+ #
451
+ # def test_tags
452
+ # assert_kind_of Array, @u.tags # tags
453
+ # end
454
+ #
455
+ # def test_contactsPhotos
456
+ # assert_kind_of Flickr::Photo, @u.contactsPhotos.first # contacts' favorites
457
+ # end
458
+
459
+ # User#photos tests
460
+
461
+ def test_should_get_users_public_photos
462
+ client = mock
463
+ client.expects(:photos_request).with('people.getPublicPhotos', {'user_id' => 'some_id'}).returns([new_photo, new_photo])
464
+ Flickr.expects(:new).at_least_once.returns(client)
465
+
466
+ user = Flickr::User.new("some_id", "some_user", nil, nil, "some_api_key")
467
+
468
+ photos = user.photos
469
+ assert_equal 2, photos.size
470
+ assert_kind_of Flickr::Photo, photos.first
471
+ end
472
+
473
+ def test_should_instantiate_favorite_photos_with_id_and_all_params_returned_by_query
474
+ client = mock
475
+ client.expects(:photos_request).with('favorites.getPublicList', {'user_id' => 'some_id'})
476
+ Flickr.expects(:new).at_least_once.returns(client)
477
+ user = Flickr::User.new("some_id", "some_user", nil, nil, "some_api_key")
478
+ user.favorites
479
+ end
480
+
481
+ def test_should_instantiate_contacts_photos_with_id_and_all_params_returned_by_query
482
+ client = mock
483
+ client.expects(:photos_request).with('photos.getContactsPublicPhotos', {'user_id' => 'some_id'})
484
+ Flickr.expects(:new).at_least_once.returns(client)
485
+ user = Flickr::User.new('some_id', "some_user", nil, nil, "some_api_key")
486
+ user.contactsPhotos
487
+ end
488
+
489
+ # ##### Flickr::Photo tests
490
+
491
+ def test_should_initialize_photo_from_id
492
+ photo = Flickr::Photo.new("foo123")
493
+ assert_equal "foo123", photo.id
494
+ end
495
+
496
+ def test_should_save_extra_params_as_instance_variables
497
+ photo = Flickr::Photo.new('foo123', 'some_api_key', { 'key1' => 'value1', 'key2' => 'value2'})
498
+ assert_equal 'value1', photo.instance_variable_get(:@key1)
499
+ assert_equal 'value2', photo.instance_variable_get(:@key2)
500
+ end
501
+
502
+ def test_should_be_able_to_access_instance_variables_through_hash_like_interface
503
+ photo = Flickr::Photo.new
504
+ photo.instance_variable_set(:@key1, 'value1')
505
+ assert_equal 'value1', photo['key1']
506
+ assert_equal 'value1', photo[:key1]
507
+ assert_nil photo[:key2]
508
+ assert_nil photo['key2']
509
+ end
510
+
511
+ def test_should_get_and_store_other_info_for_photo
512
+ Flickr.any_instance.stubs(:http_get).returns(photo_info_xml_response)
513
+ photo = Flickr::Photo.new('foo123', 'some_api_key')
514
+
515
+ assert_equal "1964 120 amazon estate", photo.title # calling #title method triggers getting of info
516
+ assert_equal "1964 120 amazon estate", photo.instance_variable_get(:@title)
517
+ assert_equal "3142", photo.instance_variable_get(:@server)
518
+ assert_equal "ae75bd3111", photo.instance_variable_get(:@secret)
519
+ assert_equal "4", photo.instance_variable_get(:@farm)
520
+ assert_equal "1204145093", photo.instance_variable_get(:@dateuploaded)
521
+ assert_equal "photo", photo.instance_variable_get(:@media)
522
+ assert_equal "0", photo.instance_variable_get(:@isfavorite)
523
+ assert_equal "0", photo.instance_variable_get(:@license)
524
+ assert_equal "0", photo.instance_variable_get(:@rotation)
525
+ assert_equal "1964 Volvo 120 amazon estate spotted in derbyshire.", photo.instance_variable_get(:@description)
526
+ assert_equal( { "w" => "50",
527
+ "x" => "10",
528
+ "y" => "10",
529
+ "authorname" => "Bees",
530
+ "author" => "12037949754@N01",
531
+ "id" => "313",
532
+ "content" => "foo",
533
+ "h" => "50" }, photo.instance_variable_get(:@notes))
534
+ assert_equal "http://www.flickr.com/photos/rootes_arrow/2296968304/", photo.instance_variable_get(:@url)
535
+ assert_equal [ { "id" => "9377979-2296968304-2228", "author" => "9383319@N05", "raw" => "volvo", "machine_tag" => "0", "content" => "volvo" },
536
+ { "id" => "9377979-2296968304-2229", "author" => "9383319@N06", "raw" => "amazon", "machine_tag" => "0", "content" => "amazon"
537
+ } ], photo.instance_variable_get(:@tags)
538
+ assert_equal "1", photo.instance_variable_get(:@comments)
539
+ assert_kind_of Flickr::User, owner = photo.instance_variable_get(:@owner)
540
+ assert_equal "Rootes_arrow_1725", owner.username
541
+ end
542
+
543
+ def test_should_get_and_other_info_for_photo_when_some_attributes_missing
544
+ Flickr.any_instance.stubs(:http_get).returns(sparse_photo_info_xml_response)
545
+ photo = Flickr::Photo.new('foo123', 'some_api_key')
546
+
547
+ assert_equal "1964 120 amazon estate", photo.title # calling #title method triggers getting of info
548
+ assert_equal "1964 120 amazon estate", photo.instance_variable_get(:@title)
549
+ assert_equal( {}, photo.instance_variable_get(:@description))
550
+ assert_nil photo.instance_variable_get(:@notes)
551
+ assert_nil photo.instance_variable_get(:@tags)
552
+ assert_equal "1", photo.instance_variable_get(:@comments)
553
+ end
554
+
555
+ def test_should_not_get_info_more_than_once
556
+ Flickr.any_instance.expects(:http_get).returns(photo_info_xml_response) # expects only one call
557
+ photo = Flickr::Photo.new('foo123', 'some_api_key')
558
+
559
+ photo.description # calling #description method triggers getting of info
560
+ photo.instance_variable_set(:@description, nil) # set description to nil
561
+ photo.description # call #description method again
562
+ end
563
+
564
+ #
565
+ # owner tests
566
+ def test_should_return_owner_when_flickr_user
567
+ user = Flickr::User.new
568
+ photo = new_photo("owner" => user)
569
+
570
+ assert_equal user, photo.owner
571
+ end
572
+
573
+ def test_should_get_info_on_owner_if_not_known
574
+ photo = new_photo("owner" => nil)
575
+ # stubbing private methods causes problems so we mock client method, which is what Photo#getInfo users to make API call
576
+ Flickr.any_instance.expects(:photos_getInfo).returns('photo' => { 'owner'=>{'nsid'=>'abc123', 'username'=>'SomeUserName', 'realname'=>"", 'location'=>''},
577
+ 'notes' => {}, 'tags' => {}, 'urls' => {'url' => {'content' => 'http://prettyurl'}}})
578
+
579
+ owner = photo.owner
580
+ assert_kind_of Flickr::User, owner
581
+ assert_equal 'abc123', owner.id
582
+ assert_equal 'SomeUserName', owner.username
583
+ end
584
+
585
+ def test_should_instantiate_flickr_user_from_owner_id_if_we_have_it
586
+ photo = Flickr::Photo.new
587
+ photo.instance_variable_set(:@owner, "some_user_id")
588
+ Flickr.any_instance.expects(:photos_getInfo).never
589
+
590
+ user = photo.owner
591
+ assert_kind_of Flickr::User, user
592
+ assert_equal "some_user_id", user.id
593
+ end
594
+
595
+ def test_should_cache_owner_when_instantiated
596
+ user = Flickr::User.new
597
+ photo = Flickr::Photo.new
598
+ photo.instance_variable_set(:@owner, "some_user_id")
599
+ Flickr::User.expects(:new).returns(user)
600
+
601
+ photo.owner
602
+ photo.owner # call twice but mock expects only one call
603
+ end
604
+
605
+ #
606
+ # image_source_uri_from_self tests
607
+ def test_should_build_image_source_uri_from_self
608
+ assert_equal "http://farm1.static.flickr.com/2/1418878_1e92283336.jpg",
609
+ new_photo.send(:image_source_uri_from_self) # no size specified
610
+ end
611
+
612
+ def test_should_build_image_source_uri_from_self_for_given_size
613
+ assert_equal "http://farm1.static.flickr.com/2/1418878_1e92283336_m.jpg",
614
+ new_photo.send(:image_source_uri_from_self, "Small") # size specified
615
+ end
616
+
617
+ def test_should_build_image_source_uri_from_self_for_default_size_when_explicitly_asked_for
618
+ assert_equal "http://farm1.static.flickr.com/2/1418878_1e92283336.jpg",
619
+ new_photo.send(:image_source_uri_from_self, "Medium") # medium size specified -- the default
620
+ end
621
+
622
+ def test_should_build_image_source_uri_from_self_for_default_size_when_unknown_size_asked_for
623
+ assert_equal "http://farm1.static.flickr.com/2/1418878_1e92283336.jpg",
624
+ new_photo.send(:image_source_uri_from_self, "Dummy") # bad size specified
625
+ end
626
+
627
+ def test_should_return_nil_for_image_source_uri_if_no_attributes
628
+ assert_nil Flickr::Photo.new.send(:image_source_uri_from_self)
629
+ end
630
+
631
+ def test_should_return_nil_for_image_source_uri_if_missing_required_attributes
632
+ assert_nil Flickr::Photo.new("1418878", nil, "farm" => "1").send(:image_source_uri_from_self)
633
+ end
634
+
635
+ def test_image_source_uri_from_self_should_normalize_size
636
+ photo = new_photo
637
+ assert_equal photo.send(:image_source_uri_from_self, 'Large'),
638
+ photo.send(:image_source_uri_from_self, :large)
639
+ end
640
+
641
+ def test_uri_for_photo_from_self_should_normalize_size
642
+ photo = new_photo
643
+ assert_equal photo.send(:uri_for_photo_from_self, 'Large'),
644
+ photo.send(:uri_for_photo_from_self, :large)
645
+ end
646
+
647
+ def test_should_get_source_uri_by_building_from_self_if_possible
648
+ photo = Flickr::Photo.new
649
+ photo.expects(:image_source_uri_from_self).with('Medium').returns(true) # return any non-false-evaluating value so that sizes method isn't called
650
+ photo.source
651
+ end
652
+
653
+ def test_should_get_source_uri_by_building_from_self_if_possible_requesting_source_for_given_size
654
+ photo = Flickr::Photo.new
655
+ photo.expects(:image_source_uri_from_self).with('Large').returns(true) # return any non-false-evaluating value so that sizes method isn't called
656
+ photo.source('Large')
657
+ end
658
+
659
+ def test_should_get_source_uri_by_calling_sizes_method_if_no_luck_building_uri
660
+ photo = Flickr::Photo.new
661
+ photo.stubs(:image_source_uri_from_self) # ...and hence returns nil
662
+ photo.expects(:sizes).with('Medium').returns({})
663
+ photo.source
664
+ end
665
+
666
+ def test_should_build_uri_for_photo_from_self
667
+ assert_equal "http://www.flickr.com/photos/abc123/1418878", new_photo.send(:uri_for_photo_from_self)
668
+ end
669
+
670
+ def test_should_build_uri_for_photo_from_self_when_owner_is_a_string
671
+ assert_equal "http://www.flickr.com/photos/789user321/1418878", new_photo('owner' => "789user321").send(:uri_for_photo_from_self)
672
+ end
673
+
674
+ def test_should_build_uri_for_photo_from_self_for_given_size
675
+ assert_equal "http://www.flickr.com/photos/abc123/1418878/sizes/s/", new_photo.send(:uri_for_photo_from_self, "Small")
676
+ end
677
+
678
+ def test_should_build_uri_for_photo_from_self_with_unknown_size
679
+ assert_equal "http://www.flickr.com/photos/abc123/1418878", new_photo.send(:uri_for_photo_from_self, "Dummy")
680
+ end
681
+
682
+ def test_should_return_nil_for_uri_for_photo_when_no_user_id
683
+ assert_nil Flickr::Photo.new("1418878", nil).send(:uri_for_photo_from_self)
684
+ end
685
+
686
+ def test_should_return_nil_for_uri_for_photo_when_no_photo_id
687
+ assert_nil Flickr::Photo.new.send(:uri_for_photo_from_self)
688
+ end
689
+
690
+ def test_should_get_uri_for_photo_flickr_page
691
+ photo = new_photo
692
+ assert_equal "http://www.flickr.com/photos/abc123/1418878", photo.url
693
+ end
694
+
695
+ def test_should_return_main_page_for_photo_flickr_page_when_medium_size_requested_as_per_previous_version
696
+ assert_equal "http://www.flickr.com/photos/abc123/1418878", new_photo.url('Medium')
697
+ end
698
+
699
+ def test_should_call_size_url_if_url_given_a_size
700
+ photo = new_photo
701
+ photo.expects(:size_url).with('Large')
702
+ photo.url('Large')
703
+ end
704
+
705
+ def test_should_get_flickr_page_uri_by_building_from_self_if_possible_requesting_source_for_given_size
706
+ photo = new_photo
707
+ photo.expects(:uri_for_photo_from_self).with('Large').returns(true) # return any non-false-evaluating value so that sizes method isn't called
708
+ photo.size_url('Large')
709
+ end
710
+
711
+ def test_should_get_flickr_page_uri_by_calling_sizes_method_if_no_luck_building_uri
712
+ photo = new_photo
713
+ photo.stubs(:uri_for_photo_from_self) # ...and hence returns nil
714
+ photo.expects(:sizes).with('Large').returns({})
715
+ photo.size_url('Large')
716
+ end
717
+
718
+ def test_should_allow_size_to_be_lowercase_or_symbol
719
+ photo = new_photo
720
+ assert_equal photo.normalize_size('Small'), 'Small'
721
+ assert_equal photo.normalize_size('small'), 'Small'
722
+ assert_equal photo.normalize_size(:small), 'Small'
723
+ assert_equal photo.normalize_size(:Small), 'Small'
724
+ assert_equal photo.normalize_size('smAlL'), 'Small'
725
+
726
+ assert_equal photo.normalize_size(""), ""
727
+ assert_nil photo.normalize_size(nil)
728
+ end
729
+
730
+ def test_size_url_should_normalize_size
731
+ photo = new_photo
732
+ assert_equal photo.size_url('Large'), photo.size_url(:large)
733
+ end
734
+
735
+ def test_url_should_normalize_size
736
+ photo = new_photo
737
+ assert_equal photo.url('Medium'), photo.url(:medium)
738
+ assert_equal photo.url('Small'), photo.url('small')
739
+ end
740
+
741
+ def test_source_should_normalize_size
742
+ photo = new_photo
743
+ assert_equal photo.source('Large'), photo.source(:large)
744
+ end
745
+
746
+ def test_sizes_should_normalize_size
747
+ sizes = {'sizes' => {'size' => [{'label' => 'Small'}, {'label' => 'Large'}]}}
748
+ photo = new_photo
749
+ photo.client.expects(:photos_getSizes).at_least_once.returns(sizes)
750
+ assert_equal photo.sizes('Large'), photo.sizes(:large)
751
+ end
752
+
753
+ # Photo#context tests
754
+ def test_should_call_photos_getContext_to_get_context_photos
755
+ Flickr.any_instance.expects(:photos_getContext).returns({'prevphoto' => {}, 'nextphoto' => {}})
756
+ new_photo.context
757
+ end
758
+
759
+ def test_should_instantiate_context_photos_with_id_and_all_params_returned_by_query
760
+ photo = new_photo
761
+ Flickr.any_instance.expects(:photos_getContext).returns({ 'prevphoto' => {'id' => '123', 'key_1' => 'value_1' },
762
+ 'nextphoto' => {'id' => '456', 'key_2' => 'value_2'}})
763
+ Flickr::Photo.expects(:new).with("123", "foo123", { "key_1" => "value_1"})
764
+ Flickr::Photo.expects(:new).with("456", "foo123", { "key_2" => "value_2"})
765
+
766
+ photo.context
767
+ end
768
+
769
+ def test_should_not_instantiate_context_photos_with_id_of_0
770
+ photo = new_photo
771
+ Flickr.any_instance.expects(:photos_getContext).returns({ 'prevphoto' => {'id' => '123', 'key_1' => 'value_1' },
772
+ 'nextphoto' => {'id' => '0', 'key_2' => 'value_2'}})
773
+ Flickr::Photo.expects(:new).with("123", anything, anything)
774
+ Flickr::Photo.expects(:new).with("0", anything, anything).never
775
+
776
+ photo.context
777
+ end
778
+
779
+ # ##### Flickr::Group tests
780
+ #
781
+ def test_should_instantiate_group_from_id
782
+ group = Flickr::Group.new("group1")
783
+ assert_equal "group1", group.id
784
+ end
785
+
786
+ # tests old api for instantiating groups
787
+ def test_should_instantiate_group_from_id_and_api_key
788
+ f = flickr_client
789
+ Flickr.expects(:new).with("some_api_key").returns(f)
790
+ group = Flickr::Group.new("group1", "some_api_key")
791
+ assert_equal f, group.client
792
+ end
793
+
794
+ # new api for instantiating groups
795
+ def test_should_instantiate_group_from_params_hash
796
+ group = Flickr::Group.new("id" => "group1", "name" => "Group One", "eighteenplus" => "1", "foo" => "bar")
797
+ assert_equal "group1", group.id
798
+ assert_equal "Group One", group.name
799
+ assert_equal "1", group.eighteenplus
800
+ assert_equal "bar", group.instance_variable_get(:@foo)
801
+ end
802
+
803
+ def test_should_use_flickr_client_passed_in_params_hash_when_instantiating_group
804
+ f = flickr_client
805
+ Flickr.expects(:new).never
806
+ group = Flickr::Group.new("id" => "group1", "name" => "Group One", "client" => f)
807
+ assert_equal f, group.client
808
+ end
809
+
810
+ def test_should_provide_id_name_eighteenplus_description_members_online_privacy_reader_methods_for_group
811
+ g = Flickr::Group.new
812
+ %w(id name eighteenplus description members online privacy).each do |m|
813
+ g.instance_variable_set("@#{m}", "foo_#{m}")
814
+ assert_equal "foo_#{m}", g.send(m)
815
+ end
816
+ end
817
+
818
+ # def test_should_initialize_photo_from_id
819
+ # photo = Flickr::Photo.new("foo123")
820
+ # assert_equal "foo123", photo.id
821
+ # end
822
+ #
823
+ # def test_should_save_extra_params_as_instance_variables
824
+ # photo = Flickr::Photo.new('foo123', 'some_api_key', { 'key1' => 'value1', 'key2' => 'value2'})
825
+ # assert_equal 'value1', photo.instance_variable_get(:@key1)
826
+ # assert_equal 'value2', photo.instance_variable_get(:@key2)
827
+ # end
828
+ #
829
+ # def test_should_be_able_to_access_instance_variables_through_hash_like_interface
830
+ # photo = Flickr::Photo.new
831
+ # photo.instance_variable_set(:@key1, 'value1')
832
+ # assert_equal 'value1', photo['key1']
833
+ # assert_equal 'value1', photo[:key1]
834
+ # assert_nil photo[:key2]
835
+ # assert_nil photo['key2']
836
+ # end
837
+
838
+ # ##### PHOTOSETS
839
+ #
840
+ # #def setup
841
+ # # super
842
+ # # @photoset = @f.photosets_create('title'=>@title, 'primary_photo_id'=>@photo_id)
843
+ # # @photoset_id = @photoset['photoset']['id']
844
+ # #end
845
+ # #def teardown
846
+ # # @f.photosets_delete('photoset_id'=>@photoset_id)
847
+ # #end
848
+ #
849
+ # def test_photosets_editMeta
850
+ # assert_equal @f.photosets_editMeta('photoset_id'=>@photoset_id, 'title'=>@title)['stat'], 'ok'
851
+ # end
852
+ #
853
+ # def test_photosets_editPhotos
854
+ # assert_equal @f.photosets_editPhotos('photoset_id'=>@photoset_id, 'primary_photo_id'=>@photo_id, 'photo_ids'=>@photo_id)['stat'], 'ok'
855
+ # end
856
+ #
857
+ # def test_photosets_getContext
858
+ # assert_equal @f.photosets_getContext('photoset_id'=>@photoset_id, 'photo_id'=>@photo_id)['stat'], 'ok'
859
+ # end
860
+ #
861
+ # def test_photosets_getContext
862
+ # assert_equal @f.photosets_getContext('photoset_id'=>@photoset_id, 'photo_id'=>@photo_id)['stat'], 'ok'
863
+ # end
864
+ #
865
+ # def test_photosets_getInfo
866
+ # assert_equal @f.photosets_getInfo('photoset_id'=>@photoset_id)['stat'], 'ok'
867
+ # end
868
+ #
869
+ # def test_photosets_getList
870
+ # assert_equal @f.photosets_getList['stat'], 'ok'
871
+ # end
872
+ #
873
+ # def test_photosets_getPhotos
874
+ # assert_equal @f.photosets_getPhotos('photoset_id'=>@photoset_id)['stat'], 'ok'
875
+ # end
876
+ #
877
+ # def test_photosets_orderSets
878
+ # assert_equal @f.photosets_orderSets('photoset_ids'=>@photoset_id)['stat'], 'ok'
879
+ # end
880
+
881
+ def test_related_tags
882
+ f = flickr_client
883
+ tags_response = {
884
+ "tags" => {
885
+ "tag" => [ "zoo", "animal" ],
886
+ "source" => "monkey",
887
+ },
888
+ "stat" => "ok",
889
+ }
890
+ f.expects(:tags_getRelated).with('tag' => 'monkey').returns(tags_response)
891
+ assert_equal f.related_tags('monkey'), %w(zoo animal)
892
+ end
893
+
894
+ # ##### Flickr::PhotoCollection tests
895
+ #
896
+ def test_should_subclass_array_as_photo_collection
897
+ assert_equal Array, Flickr::PhotoCollection.superclass
898
+ end
899
+
900
+ def test_should_make_page_a_reader_method
901
+ assert_equal "3", dummy_photo_collection.page
902
+ end
903
+
904
+ def test_should_make_pages_a_reader_method
905
+ assert_equal "5", dummy_photo_collection.pages
906
+ end
907
+
908
+ def test_should_make_perpage_a_reader_method
909
+ assert_equal "10", dummy_photo_collection.perpage
910
+ end
911
+
912
+ def test_should_make_total_a_reader_method
913
+ assert_equal "42", dummy_photo_collection.total
914
+ end
915
+
916
+ def test_should_instantiate_photo_collection_from_photos_hash
917
+ pc = Flickr::PhotoCollection.new(dummy_photos_response)
918
+ assert_kind_of Flickr::PhotoCollection, pc
919
+ assert_equal 2, pc.size
920
+ assert_kind_of Flickr::Photo, pc.first
921
+ assert_equal "foo123", pc.first["id"]
922
+ end
923
+
924
+ def test_should_instantiate_photo_collection_using_given_api_key
925
+ photo = Flickr::PhotoCollection.new(dummy_photos_response, "some_api_key").first
926
+ assert_equal "some_api_key", photo.instance_variable_get(:@api_key)
927
+ end
928
+
929
+ private
930
+ def flickr_client
931
+ Flickr.new("some_api_key")
932
+ end
933
+
934
+ def authenticated_flickr_client
935
+ f = Flickr.new('api_key' => 'some_api_key', 'shared_secret' => 'shared_secret_code')
936
+ f.instance_variable_set(:@auth_token, 'some_auth_token')
937
+ f
938
+ end
939
+
940
+ def new_user(options={})
941
+ Flickr::User.new({ 'id' => 'foo123',
942
+ 'username' => 'some_user',
943
+ 'name' => 'Some User',
944
+ 'foo' => 'bar',
945
+ 'auth_token' => 'foobar789'}.merge(options))
946
+
947
+ end
948
+ def new_photo(options={})
949
+ Flickr::Photo.new("1418878",
950
+ "foo123",
951
+ { "farm" => "1",
952
+ "server" => "2",
953
+ "secret" => "1e92283336",
954
+ "owner" => Flickr::User.new("abc123", "some_user", nil, nil, "some_api_key") }.merge(options))
955
+ end
956
+
957
+ def dummy_photo_collection
958
+ Flickr::PhotoCollection.new(dummy_photos_response)
959
+ end
960
+
961
+ def dummy_photos_response
962
+ { "photos" =>
963
+ { "photo" =>
964
+ [{ "id" => "foo123",
965
+ "key1" => "value1",
966
+ "key2" => "value2" },
967
+ { "id" => "bar456",
968
+ "key3" => "value3"}],
969
+ "page"=>"3",
970
+ "pages"=>"5",
971
+ "perpage"=>"10",
972
+ "total"=>"42" } }
973
+ end
974
+
975
+ def dummy_single_photo_response
976
+ { "photos" =>
977
+ { "photo" =>
978
+ { "id" => "foo123",
979
+ "key1" => "value1",
980
+ "key2" => "value2" } } }
981
+ end
982
+
983
+ def dummy_zero_photo_response
984
+ { "photos" => { "total" => 0 } }
985
+ end
986
+
987
+ def dummy_user_response
988
+ { "user" =>
989
+ { "nsid" => "12037949632@N01",
990
+ "username" => "Stewart" }
991
+ }
992
+ end
993
+
994
+ def dummy_groups_response
995
+ { "groups" =>
996
+ { "group" =>
997
+ [{ "nsid" => "group1",
998
+ "name" => "Group One",
999
+ "eighteenplus" => "0" },
1000
+ { "nsid" => "group2",
1001
+ "name" => "Group Two",
1002
+ "eighteenplus" => "1"}] } }
1003
+ end
1004
+
1005
+ def dummy_single_group_response
1006
+ { "groups" =>
1007
+ { "group" =>
1008
+ { "nsid" => "group1",
1009
+ "name" => "Group One",
1010
+ "eighteenplus" => "0" } } }
1011
+ end
1012
+
1013
+ def successful_xml_response
1014
+ <<-EOF
1015
+ <?xml version="1.0" encoding="utf-8" ?>
1016
+ <rsp stat="ok">
1017
+ <contacts page="1" pages="1" perpage="1000" total="2">
1018
+ <contact nsid="12037949629@N01" username="Eric" iconserver="1"
1019
+ realname="Eric Costello"
1020
+ friend="1" family="0" ignored="1" />
1021
+ <contact nsid="12037949631@N01" username="neb" iconserver="1"
1022
+ realname="Ben Cerveny"
1023
+ friend="0" family="0" ignored="0" />
1024
+ </contacts>
1025
+ </rsp>
1026
+ EOF
1027
+ end
1028
+
1029
+ def unsuccessful_xml_response
1030
+ <<-EOF
1031
+ <?xml version="1.0" encoding="utf-8" ?>
1032
+ <rsp stat="fail">
1033
+ <err code="[error-code]" msg="[error-message]" />
1034
+ </rsp>
1035
+ EOF
1036
+ end
1037
+
1038
+ def photo_info_xml_response
1039
+ <<-EOF
1040
+ <?xml version="1.0" encoding="utf-8" ?>
1041
+ <rsp stat="ok">
1042
+ <photo id="22527834" secret="ae75bd3111" server="3142" farm="4" dateuploaded="1204145093" isfavorite="0" license="0" rotation="0" media="photo">
1043
+ <owner nsid="9383319@N05" username="Rootes_arrow_1725" realname="John" location="U.K" />
1044
+ <title>1964 120 amazon estate</title>
1045
+ <description>1964 Volvo 120 amazon estate spotted in derbyshire.</description>
1046
+ <visibility ispublic="1" isfriend="0" isfamily="0" />
1047
+ <dates posted="1204145093" taken="2007-06-10 13:18:27" takengranularity="0" lastupdate="1204166772" />
1048
+ <editability cancomment="0" canaddmeta="0" />
1049
+ <usage candownload="0" canblog="0" canprint="0" />
1050
+ <comments>1</comments>
1051
+ <notes>
1052
+ <note id="313" author="12037949754@N01" authorname="Bees" x="10" y="10" w="50" h="50">foo</note>
1053
+ </notes>
1054
+ <tags>
1055
+ <tag id="9377979-2296968304-2228" author="9383319@N05" raw="volvo" machine_tag="0">volvo</tag>
1056
+ <tag id="9377979-2296968304-2229" author="9383319@N06" raw="amazon" machine_tag="0">amazon</tag>
1057
+ </tags>
1058
+ <urls>
1059
+ <url type="photopage">http://www.flickr.com/photos/rootes_arrow/2296968304/</url>
1060
+ </urls>
1061
+ </photo>
1062
+ </rsp>
1063
+ EOF
1064
+ end
1065
+
1066
+ def sparse_photo_info_xml_response
1067
+ <<-EOF
1068
+ <?xml version="1.0" encoding="utf-8" ?>
1069
+ <rsp stat="ok">
1070
+ <photo id="22527834" secret="ae75bd3111" server="3142" farm="4" dateuploaded="1204145093" isfavorite="0" license="0" rotation="0" media="photo">
1071
+ <owner nsid="9383319@N05" username="Rootes_arrow_1725" realname="John" location="U.K" />
1072
+ <title>1964 120 amazon estate</title>
1073
+ <description/>
1074
+ <visibility ispublic="1" isfriend="0" isfamily="0" />
1075
+ <dates posted="1204145093" taken="2007-06-10 13:18:27" takengranularity="0" lastupdate="1204166772" />
1076
+ <editability cancomment="0" canaddmeta="0" />
1077
+ <usage candownload="0" canblog="0" canprint="0" />
1078
+ <comments>1</comments>
1079
+ <notes/>
1080
+ <tags/>
1081
+ <urls>
1082
+ <url type="photopage">http://www.flickr.com/photos/rootes_arrow/2296968304/</url>
1083
+ </urls>
1084
+ </photo>
1085
+ </rsp>
1086
+ EOF
1087
+ end
1088
+
1089
+ end