joelind-twitter 0.9.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. data/History +290 -0
  2. data/License +20 -0
  3. data/Notes +33 -0
  4. data/README.rdoc +19 -0
  5. data/Rakefile +40 -0
  6. data/VERSION.yml +5 -0
  7. data/examples/connect.rb +30 -0
  8. data/examples/friendship_existence.rb +13 -0
  9. data/examples/helpers/config_store.rb +38 -0
  10. data/examples/httpauth.rb +11 -0
  11. data/examples/ids.rb +13 -0
  12. data/examples/lists.rb +11 -0
  13. data/examples/oauth.rb +27 -0
  14. data/examples/search.rb +15 -0
  15. data/examples/timeline.rb +19 -0
  16. data/examples/tumblr.rb +9 -0
  17. data/examples/unauthorized.rb +16 -0
  18. data/examples/update.rb +11 -0
  19. data/examples/user.rb +5 -0
  20. data/lib/twitter/base.rb +390 -0
  21. data/lib/twitter/geo.rb +25 -0
  22. data/lib/twitter/httpauth.rb +53 -0
  23. data/lib/twitter/local_trends.rb +30 -0
  24. data/lib/twitter/oauth.rb +85 -0
  25. data/lib/twitter/request.rb +71 -0
  26. data/lib/twitter/search.rb +163 -0
  27. data/lib/twitter/trends.rb +55 -0
  28. data/lib/twitter.rb +156 -0
  29. data/test/fixtures/blocking.json +1632 -0
  30. data/test/fixtures/firehose.json +1 -0
  31. data/test/fixtures/follower_ids.json +1 -0
  32. data/test/fixtures/followers.json +1 -0
  33. data/test/fixtures/friend_ids.json +1 -0
  34. data/test/fixtures/friends_timeline.json +1 -0
  35. data/test/fixtures/friendship.json +1 -0
  36. data/test/fixtures/friendship_exists.json +1 -0
  37. data/test/fixtures/geo_place.json +1 -0
  38. data/test/fixtures/geo_reverse_geocode.json +1 -0
  39. data/test/fixtures/geo_reverse_geocode_granularity.json +1 -0
  40. data/test/fixtures/geo_reverse_geocode_limit.json +1 -0
  41. data/test/fixtures/geo_search.json +1 -0
  42. data/test/fixtures/geo_search_ip_address.json +1 -0
  43. data/test/fixtures/geo_search_query.json +1 -0
  44. data/test/fixtures/home_timeline.json +1 -0
  45. data/test/fixtures/ids.json +1 -0
  46. data/test/fixtures/list.json +1 -0
  47. data/test/fixtures/list_statuses.json +1 -0
  48. data/test/fixtures/list_statuses_1_1.json +1 -0
  49. data/test/fixtures/list_statuses_2_1.json +1 -0
  50. data/test/fixtures/list_subscriptions.json +1 -0
  51. data/test/fixtures/list_users.json +1 -0
  52. data/test/fixtures/lists.json +1 -0
  53. data/test/fixtures/memberships.json +1 -0
  54. data/test/fixtures/mentions.json +1 -0
  55. data/test/fixtures/not_found.json +1 -0
  56. data/test/fixtures/people_search.json +39 -0
  57. data/test/fixtures/rate_limit_exceeded.json +1 -0
  58. data/test/fixtures/report_spam.json +41 -0
  59. data/test/fixtures/retweet.json +1 -0
  60. data/test/fixtures/retweeted_by_me.json +1 -0
  61. data/test/fixtures/retweeted_to_me.json +1 -0
  62. data/test/fixtures/retweeters_of_tweet.json +166 -0
  63. data/test/fixtures/retweets.json +1 -0
  64. data/test/fixtures/retweets_of_me.json +1 -0
  65. data/test/fixtures/sample-image.png +0 -0
  66. data/test/fixtures/saved_search.json +7 -0
  67. data/test/fixtures/saved_searches.json +16 -0
  68. data/test/fixtures/search.json +1 -0
  69. data/test/fixtures/search_from_jnunemaker.json +1 -0
  70. data/test/fixtures/status.json +1 -0
  71. data/test/fixtures/status_show.json +1 -0
  72. data/test/fixtures/trends_available.json +253 -0
  73. data/test/fixtures/trends_current.json +1 -0
  74. data/test/fixtures/trends_current_exclude.json +1 -0
  75. data/test/fixtures/trends_daily.json +1925 -0
  76. data/test/fixtures/trends_daily_date.json +1 -0
  77. data/test/fixtures/trends_daily_exclude.json +1 -0
  78. data/test/fixtures/trends_location.json +57 -0
  79. data/test/fixtures/trends_weekly.json +1 -0
  80. data/test/fixtures/trends_weekly_date.json +1 -0
  81. data/test/fixtures/trends_weekly_exclude.json +1 -0
  82. data/test/fixtures/unauthorized.json +1 -0
  83. data/test/fixtures/update_profile_background_image.json +1 -0
  84. data/test/fixtures/update_profile_image.json +1 -0
  85. data/test/fixtures/user.json +1 -0
  86. data/test/fixtures/user_timeline.json +710 -0
  87. data/test/fixtures/users.json +1 -0
  88. data/test/test_helper.rb +47 -0
  89. data/test/twitter/base_test.rb +426 -0
  90. data/test/twitter/geo_test.rb +79 -0
  91. data/test/twitter/httpauth_test.rb +86 -0
  92. data/test/twitter/oauth_test.rb +127 -0
  93. data/test/twitter/request_test.rb +217 -0
  94. data/test/twitter/search_test.rb +208 -0
  95. data/test/twitter/trends_test.rb +112 -0
  96. data/test/twitter_test.rb +106 -0
  97. metadata +305 -0
@@ -0,0 +1 @@
1
+ [{"created_at":"Mon Jul 16 12:59:01 +0000 2007","friends_count":50,"description":"Captain","statuses_count":1948,"profile_text_color":"333333","screen_name":"sferik","status":{"created_at":"Thu Mar 18 18:13:19 +0000 2010","truncated":false,"in_reply_to_status_id":null,"source":"<a href=\"http://www.atebits.com/\" rel=\"nofollow\">Tweetie</a>","in_reply_to_screen_name":null,"favorited":false,"in_reply_to_user_id":null,"id":10682865729,"text":"If the earth was square, what shape would web browser icons be? #rhetorical"},"following":false,"profile_background_image_url":"http://a3.twimg.com/profile_background_images/58220609/gem.png","favourites_count":494,"contributors_enabled":false,"profile_link_color":"BF1238","url":null,"geo_enabled":true,"profile_background_tile":false,"profile_background_color":"000000","location":"California","verified":false,"profile_sidebar_fill_color":"EFEFEF","protected":true,"name":"Erik Michaels-Ober","notifications":false,"time_zone":"Pacific Time (US & Canada)","profile_sidebar_border_color":"FFFFFF","followers_count":799,"id":7505382,"lang":"en","utc_offset":-28800,"profile_image_url":"http://a1.twimg.com/profile_images/323331048/me_normal.jpg"},{"created_at":"Tue Dec 12 06:39:24 +0000 2006","friends_count":39,"description":"Full-time inventor.\r\nI don't do drugs. I AM drugs.","statuses_count":2157,"profile_text_color":"333333","screen_name":"jm3","status":{"created_at":"Thu Mar 18 21:32:31 +0000 2010","in_reply_to_status_id":null,"truncated":false,"source":"<a href=\"http://foursquare.com\" rel=\"nofollow\">foursquare</a>","in_reply_to_screen_name":null,"in_reply_to_user_id":null,"id":10690325085,"favorited":false,"text":"\"Social media is the new porn.\" Not sure I agree. (@ OMMA Global SF w/ 21 others) http://4sq.com/aURoO4"},"following":true,"profile_background_image_url":"http://a1.twimg.com/profile_background_images/67143062/drucker.jpg","favourites_count":4179,"contributors_enabled":false,"profile_link_color":"038543","url":"http://jm3.net","geo_enabled":true,"profile_background_tile":true,"profile_background_color":"ACDED6","location":"SF Yay Area","verified":false,"profile_sidebar_fill_color":"F6F6F6","protected":false,"name":"John Manoogian III","notifications":true,"time_zone":"Pacific Time (US & Canada)","profile_sidebar_border_color":"EEEEEE","followers_count":477,"id":59593,"lang":"en","utc_offset":-28800,"profile_image_url":"http://a3.twimg.com/profile_images/689856229/jm3-stripes_normal.jpg"},{"created_at":"Thu Feb 15 16:28:04 +0000 2007","friends_count":223,"description":"Internet researcher & open source hacker. I created Know Your Meme and taught the Internet Famous class","contributors_enabled":false,"profile_text_color":"000000","screen_name":"jamiew","status":{"created_at":"Tue Mar 16 02:00:21 +0000 2010","favorited":false,"in_reply_to_user_id":null,"in_reply_to_status_id":null,"source":"web","in_reply_to_screen_name":null,"id":10547290021,"truncated":false,"text":"Chat Roulette Piano Improv http://www.youtube.com/watch?v=32vpgNiAH60 A++, I'm in love"},"following":true,"profile_background_image_url":"http://a1.twimg.com/profile_background_images/83556904/fat_NBC_diagram_cooper_40.jpg","favourites_count":496,"profile_link_color":"061e6f","url":"http://jamiedubs.com","geo_enabled":false,"profile_background_tile":true,"profile_background_color":"ffffff","location":"San Francisco","verified":false,"profile_sidebar_fill_color":"ededed","protected":false,"name":"Jamie Wilkinson","notifications":false,"time_zone":"Pacific Time (US & Canada)","profile_sidebar_border_color":"e3c4c9","followers_count":1135,"id":774010,"lang":"en","statuses_count":918,"utc_offset":-28800,"profile_image_url":"http://a1.twimg.com/profile_images/698063756/jamie_beards-big_normal.jpg"}]
@@ -0,0 +1,47 @@
1
+ require "test/unit"
2
+ require "pathname"
3
+ require "shoulda"
4
+ require "matchy"
5
+ require "mocha"
6
+ require "fakeweb"
7
+ require "redgreen"
8
+
9
+ FakeWeb.allow_net_connect = false
10
+
11
+ dir = (Pathname(__FILE__).dirname + "../lib").expand_path
12
+ require dir + "twitter"
13
+
14
+ class Test::Unit::TestCase
15
+ end
16
+
17
+ def sample_image(filename)
18
+ File.expand_path(File.dirname(__FILE__) + "/fixtures/" + filename)
19
+ end
20
+
21
+ def fixture_file(filename)
22
+ return "" if filename == ""
23
+ file_path = File.expand_path(File.dirname(__FILE__) + "/fixtures/" + filename)
24
+ File.read(file_path)
25
+ end
26
+
27
+ def twitter_url(url)
28
+ url =~ /^http/ ? url : "http://api.twitter.com:80#{url}"
29
+ end
30
+
31
+ def stub_get(url, filename, status=nil)
32
+ options = {:body => fixture_file(filename)}
33
+ options.merge!({:status => status}) unless status.nil?
34
+ FakeWeb.register_uri(:get, twitter_url(url), options)
35
+ end
36
+
37
+ def stub_post(url, filename)
38
+ FakeWeb.register_uri(:post, twitter_url(url), :body => fixture_file(filename))
39
+ end
40
+
41
+ def stub_put(url, filename)
42
+ FakeWeb.register_uri(:put, twitter_url(url), :body => fixture_file(filename))
43
+ end
44
+
45
+ def stub_delete(url, filename)
46
+ FakeWeb.register_uri(:delete, twitter_url(url), :body => fixture_file(filename))
47
+ end
@@ -0,0 +1,426 @@
1
+ require "test_helper"
2
+
3
+ class BaseTest < Test::Unit::TestCase
4
+ context "base" do
5
+ setup do
6
+ oauth = Twitter::OAuth.new("token", "secret")
7
+ @access_token = OAuth::AccessToken.new(oauth.consumer, "atoken", "asecret")
8
+ oauth.stubs(:access_token).returns(@access_token)
9
+ @twitter = Twitter::Base.new(oauth)
10
+ end
11
+
12
+ context "initialize" do
13
+ should "require a client" do
14
+ @twitter.client.should respond_to(:get)
15
+ @twitter.client.should respond_to(:post)
16
+ end
17
+ end
18
+
19
+ should "delegate get to the client" do
20
+ @access_token.expects(:get).with("/foo").returns(nil)
21
+ @twitter.get("/foo")
22
+ end
23
+
24
+ should "delegate post to the client" do
25
+ @access_token.expects(:post).with("/foo", {:bar => "baz"}).returns(nil)
26
+ @twitter.post("/foo", {:bar => "baz"})
27
+ end
28
+
29
+ context "hitting the api" do
30
+ should "be able to get home timeline" do
31
+ stub_get("/statuses/home_timeline.json", "home_timeline.json")
32
+ timeline = @twitter.home_timeline
33
+ timeline.size.should == 20
34
+ first = timeline.first
35
+ first.source.should == '<a href="http://www.atebits.com/software/tweetie/">Tweetie</a>'
36
+ first.user.name.should == "John Nunemaker"
37
+ first.user.url.should == "http://railstips.org/about"
38
+ first.id.should == 1441588944
39
+ first.favorited.should be(false)
40
+ end
41
+
42
+ should "be able to get friends timeline" do
43
+ stub_get("/statuses/friends_timeline.json", "friends_timeline.json")
44
+ timeline = @twitter.friends_timeline
45
+ timeline.size.should == 20
46
+ first = timeline.first
47
+ first.source.should == '<a href="http://www.atebits.com/software/tweetie/">Tweetie</a>'
48
+ first.user.name.should == "John Nunemaker"
49
+ first.user.url.should == "http://railstips.org/about"
50
+ first.id.should == 1441588944
51
+ first.favorited.should be(false)
52
+ end
53
+
54
+ should "be able to get user timeline" do
55
+ stub_get("/statuses/user_timeline.json", "user_timeline.json")
56
+ timeline = @twitter.user_timeline
57
+ timeline.size.should == 20
58
+ first = timeline.first
59
+ first.text.should == "Colder out today than expected. Headed to the Beanery for some morning wakeup drink. Latte or coffee...hmmm..."
60
+ first.user.name.should == "John Nunemaker"
61
+ end
62
+
63
+ should "be able to get a status" do
64
+ stub_get("/statuses/show/1441588944.json", "status.json")
65
+ status = @twitter.status(1441588944)
66
+ status.user.name.should == "John Nunemaker"
67
+ status.id.should == 1441588944
68
+ end
69
+
70
+ should "be able to update status" do
71
+ stub_post("/statuses/update.json", "status.json")
72
+ status = @twitter.update("Rob Dyrdek is the funniest man alive. That is all.")
73
+ status.user.name.should == "John Nunemaker"
74
+ status.text.should == "Rob Dyrdek is the funniest man alive. That is all."
75
+ end
76
+
77
+ should "be able to retweet a status" do
78
+ stub_post("/statuses/retweet/6235127466.json", "retweet.json")
79
+ status = @twitter.retweet(6235127466)
80
+ status.user.name.should == "Michael D. Ivey"
81
+ status.text.should == "RT @jstetser: I'm not actually awake. My mind's on autopilot for food and I managed to take a detour along the way."
82
+ status.retweeted_status.user.screen_name.should == "jstetser"
83
+ status.retweeted_status.text.should == "I'm not actually awake. My mind's on autopilot for food and I managed to take a detour along the way."
84
+ end
85
+
86
+ should "be able to get retweets of a status" do
87
+ stub_get("/statuses/retweets/6192831130.json", "retweets.json")
88
+ retweets = @twitter.retweets(6192831130)
89
+ retweets.size.should == 6
90
+ first = retweets.first
91
+ first.user.name.should == "josephholsten"
92
+ first.text.should == "RT @Moltz: Personally, I won't be satisfied until a Buddhist monk lights himself on fire for web standards."
93
+ end
94
+
95
+ should "be able to get mentions" do
96
+ stub_get("/statuses/mentions.json", "mentions.json")
97
+ mentions = @twitter.mentions
98
+ mentions.size.should == 19
99
+ first = mentions.first
100
+ first.user.name.should == "-oAk-"
101
+ first.text.should == "@jnunemaker cold out today. cold yesterday. even colder today."
102
+ end
103
+
104
+ should "be able to get retweets by me" do
105
+ stub_get("/statuses/retweeted_by_me.json", "retweeted_by_me.json")
106
+ retweeted_by_me = @twitter.retweeted_by_me
107
+ retweeted_by_me.size.should == 20
108
+ first = retweeted_by_me.first.retweeted_status
109
+ first.user.name.should == "Troy Davis"
110
+ first.text.should == "I'm the mayor of win a free MacBook Pro with promo code Cyber Monday RT for a good time"
111
+ end
112
+
113
+ should "be able to get retweets to me" do
114
+ stub_get("/statuses/retweeted_to_me.json", "retweeted_to_me.json")
115
+ retweeted_to_me = @twitter.retweeted_to_me
116
+ retweeted_to_me.size.should == 20
117
+ first = retweeted_to_me.first.retweeted_status
118
+ first.user.name.should == "Cloudvox"
119
+ first.text.should == "Testing counts with voice apps too:\n\"the voice told residents to dial 'nine hundred eleven' rather than '9-1-1'\" \342\200\224 http://j.mp/7mqe2B"
120
+ end
121
+
122
+ should "be able to get retweets of me" do
123
+ stub_get("/statuses/retweets_of_me.json", "retweets_of_me.json")
124
+ retweets_of_me = @twitter.retweets_of_me
125
+ retweets_of_me.size.should == 11
126
+ first = retweets_of_me.first
127
+ first.user.name.should == "Michael D. Ivey"
128
+ first.text.should == "Trying out geotweets in Birdfeed. No \"new RT\" support, though. Any iPhone client with RTs yet?"
129
+ end
130
+
131
+ should "be able to get users who retweeted a tweet" do
132
+ stub_get("/statuses/9021932472/retweeted_by.json", "retweeters_of_tweet.json")
133
+ retweeters = @twitter.retweeters_of("9021932472")
134
+ retweeters.size.should == 4
135
+ first = retweeters.first
136
+ first.screen_name.should == "bryanl"
137
+ end
138
+
139
+ should "be able to get ids of users who retweeted a tweet" do
140
+ stub_get("/statuses/9021932472/retweeted_by/ids.json", "ids.json")
141
+ retweeters = @twitter.retweeters_of("9021932472", :ids_only => true)
142
+ retweeters.first.should == 61940910
143
+ end
144
+
145
+ should "be able to get follower ids" do
146
+ stub_get("/followers/ids.json", "follower_ids.json")
147
+ follower_ids = @twitter.follower_ids
148
+ follower_ids.size.should == 1252
149
+ follower_ids.first.should == 613
150
+ end
151
+
152
+ should "be able to get friend ids" do
153
+ stub_get("/friends/ids.json", "friend_ids.json")
154
+ friend_ids = @twitter.friend_ids
155
+ friend_ids.size.should == 161
156
+ friend_ids.first.should == 15323
157
+ end
158
+
159
+ should "correctly hash statuses" do
160
+ stub_get("/statuses/friends_timeline.json", "friends_timeline.json")
161
+ hashes = @twitter.friends_timeline.map{ |s| s.hash }
162
+ hashes.should == @twitter.friends_timeline.map{ |s| s.hash }
163
+ end
164
+
165
+ should "be able to test whether a friendship exists" do
166
+ stub_get("/friendships/exists.json?user_a=pengwynn&user_b=sferik", "friendship_exists.json")
167
+ @twitter.friendship_exists?("pengwynn", "sferik").should == true
168
+ end
169
+
170
+ should "be able to get a friendship" do
171
+ stub_get("/friendships/show.json?source_screen_name=dcrec1&target_screen_name=pengwynn", "friendship.json")
172
+ @twitter.friendship_show(:source_screen_name => "dcrec1", :target_screen_name => "pengwynn").relationship.target.followed_by == false
173
+ end
174
+
175
+ should "be able to lookup a user" do
176
+ stub_get("/users/show/4243.json", "user.json")
177
+ user = @twitter.user(4243)
178
+ user.screen_name.should == "jnunemaker"
179
+ end
180
+
181
+ should "be able to lookup users in bulk" do
182
+ stub_get("/users/lookup.json?screen_name=sferik&user_id=59593,774010", "users.json")
183
+ users = @twitter.users("sferik", 59593, 774010)
184
+ users.first.screen_name.should == "sferik"
185
+ end
186
+
187
+ should "be able to search people" do
188
+ stub_get("/users/search.json?q=Wynn%20Netherland", "people_search.json")
189
+ people = @twitter.user_search("Wynn Netherland")
190
+ people.first.screen_name.should == "pengwynn"
191
+ end
192
+
193
+ should "be able to get followers' stauses" do
194
+ stub_get("/statuses/followers.json", "followers.json")
195
+ followers = @twitter.followers
196
+ followers.should == @twitter.followers
197
+ end
198
+
199
+ should "be able to get blocked users' IDs" do
200
+ stub_get("/blocks/blocking/ids.json", "ids.json")
201
+ blocked = @twitter.blocked_ids
202
+ blocked.should == @twitter.blocked_ids
203
+ end
204
+
205
+ should "be able to get an array of blocked users" do
206
+ stub_get("/blocks/blocking.json", "blocking.json")
207
+ blocked = @twitter.blocking
208
+ blocked.last.screen_name.should == "euciavkvyplx"
209
+ end
210
+
211
+ should "report a spammer" do
212
+ stub_post("/report_spam.json", "report_spam.json")
213
+ spammer = @twitter.report_spam(:screen_name => 'lucaasvaz00')
214
+ spammer.screen_name.should == "lucaasvaz00"
215
+ end
216
+
217
+ should "upload a profile image" do
218
+ stub_post("/account/update_profile_image.json", "update_profile_image.json")
219
+ user = @twitter.update_profile_image(File.new(sample_image("sample-image.png")))
220
+ user.name.should == "John Nunemaker" # update_profile_image responds with the user
221
+ end
222
+
223
+ should "upload a background image" do
224
+ stub_post("/account/update_profile_background_image.json", "update_profile_background_image.json")
225
+ user = @twitter.update_profile_background(File.new(sample_image("sample-image.png")))
226
+ user.name.should == "John Nunemaker" # update_profile_background responds with the user
227
+ end
228
+ end
229
+
230
+ context "when using saved searches" do
231
+ should "be able to retrieve my saved searches" do
232
+ stub_get('/saved_searches.json', 'saved_searches.json')
233
+ searches = @twitter.saved_searches
234
+ searches[0].query.should == "great danes"
235
+ searches[1].query.should == "rubyconf OR railsconf"
236
+ end
237
+
238
+ should "be able to retrieve a saved search by id" do
239
+ stub_get('/saved_searches/show/7095598.json', 'saved_search.json')
240
+ search = @twitter.saved_search(7095598)
241
+ search.query.should == "great danes"
242
+ end
243
+
244
+ should "be able to create a saved search" do
245
+ stub_post('/saved_searches/create.json', 'saved_search.json')
246
+ search = @twitter.saved_search_create('great danes')
247
+ search.query.should == "great danes"
248
+ end
249
+
250
+ should "be able to delete a saved search" do
251
+ stub_delete('/saved_searches/destroy/7095598.json', 'saved_search.json')
252
+ search = @twitter.saved_search_destroy(7095598)
253
+ search.query.should == "great danes"
254
+ end
255
+ end
256
+
257
+ context "when using lists" do
258
+
259
+ should "be able to create a new list" do
260
+ stub_post("/pengwynn/lists.json", "list.json")
261
+ list = @twitter.list_create("pengwynn", {:name => "Rubyists"})
262
+ list.name.should == "Rubyists"
263
+ list.slug.should == "rubyists"
264
+ list.mode.should == "public"
265
+ end
266
+
267
+ should "be able to update a list" do
268
+ stub_put("/pengwynn/lists/rubyists.json", "list.json")
269
+ list = @twitter.list_update("pengwynn", "rubyists", {:name => "Rubyists"})
270
+ list.name.should == "Rubyists"
271
+ list.slug.should == "rubyists"
272
+ list.mode.should == "public"
273
+ end
274
+
275
+ should "be able to delete a list" do
276
+ stub_delete("/pengwynn/lists/rubyists.json", "list.json")
277
+ list = @twitter.list_delete("pengwynn", "rubyists")
278
+ list.name.should == "Rubyists"
279
+ list.slug.should == "rubyists"
280
+ list.mode.should == "public"
281
+ end
282
+
283
+ should "be able to view lists to which a user belongs" do
284
+ stub_get("/pengwynn/lists/memberships.json", "memberships.json")
285
+ lists = @twitter.memberships("pengwynn").lists
286
+ lists.size.should == 16
287
+ lists.first.name.should == "web-dev"
288
+ lists.first.member_count.should == 38
289
+ end
290
+
291
+ should "be able to view lists for the authenticated user" do
292
+ stub_get("/pengwynn/lists.json", "lists.json")
293
+ lists = @twitter.lists("pengwynn").lists
294
+ lists.size.should == 1
295
+ lists.first.name.should == "Rubyists"
296
+ lists.first.slug.should == "rubyists"
297
+ end
298
+
299
+ should "be able to view the user owned lists without passing the username" do
300
+ stub_get('/lists.json', 'lists.json')
301
+ lists = @twitter.lists().lists
302
+ lists.size.should == 1
303
+ lists.first.name.should == 'Rubyists'
304
+ lists.first.slug.should == 'rubyists'
305
+ end
306
+
307
+ should "be able to view lists for the authenticated user by passing in a cursor" do
308
+ stub_get('/pengwynn/lists.json?cursor=-1', 'lists.json')
309
+ lists = @twitter.lists('pengwynn', :cursor => -1).lists
310
+ lists.size.should == 1
311
+ lists.first.name.should == 'Rubyists'
312
+ lists.first.slug.should == 'rubyists'
313
+ end
314
+
315
+ should "be able to view the user owned lists without passing the username and passing in a cursor" do
316
+ stub_get('/lists.json?cursor=-1', 'lists.json')
317
+ lists = @twitter.lists(:cursor => -1).lists
318
+ lists.size.should == 1
319
+ lists.first.name.should == 'Rubyists'
320
+ lists.first.slug.should == 'rubyists'
321
+ end
322
+
323
+ should "be able to view list details" do
324
+ stub_get("/pengwynn/lists/rubyists.json", "list.json")
325
+ list = @twitter.list("pengwynn", "rubyists")
326
+ list.name.should == "Rubyists"
327
+ list.subscriber_count.should == 0
328
+ end
329
+
330
+ should "be able to view list timeline" do
331
+ stub_get("/pengwynn/lists/rubyists/statuses.json", "list_statuses.json")
332
+ tweets = @twitter.list_timeline("pengwynn", "rubyists")
333
+ tweets.size.should == 20
334
+ tweets.first.id.should == 5272535583
335
+ tweets.first.user.name.should == "John Nunemaker"
336
+ end
337
+
338
+ should "be able to limit number of tweets in list timeline" do
339
+ stub_get("/pengwynn/lists/rubyists/statuses.json?per_page=1", "list_statuses_1_1.json")
340
+ tweets = @twitter.list_timeline("pengwynn", "rubyists", :per_page => 1)
341
+ tweets.size.should == 1
342
+ tweets.first.id.should == 5272535583
343
+ tweets.first.user.name.should == "John Nunemaker"
344
+ end
345
+
346
+ should "be able to paginate through the timeline" do
347
+ stub_get("/pengwynn/lists/rubyists/statuses.json?page=1&per_page=1", "list_statuses_1_1.json")
348
+ stub_get("/pengwynn/lists/rubyists/statuses.json?page=2&per_page=1", "list_statuses_2_1.json")
349
+ tweets = @twitter.list_timeline("pengwynn", "rubyists", { :page => 1, :per_page => 1 })
350
+ tweets.size.should == 1
351
+ tweets.first.id.should == 5272535583
352
+ tweets.first.user.name.should == "John Nunemaker"
353
+ tweets = @twitter.list_timeline("pengwynn", "rubyists", { :page => 2, :per_page => 1 })
354
+ tweets.size.should == 1
355
+ tweets.first.id.should == 5264324712
356
+ tweets.first.user.name.should == "John Nunemaker"
357
+ end
358
+
359
+ should "be able to view list members" do
360
+ stub_get("/pengwynn/rubyists/members.json", "list_users.json")
361
+ members = @twitter.list_members("pengwynn", "rubyists").users
362
+ members.size.should == 2
363
+ members.first.name.should == "John Nunemaker"
364
+ members.first.screen_name.should == "jnunemaker"
365
+ end
366
+
367
+ should "be able to add a member to a list" do
368
+ stub_post("/pengwynn/rubyists/members.json", "user.json")
369
+ user = @twitter.list_add_member("pengwynn", "rubyists", 4243)
370
+ user.screen_name.should == "jnunemaker"
371
+ end
372
+
373
+ should "be able to remove a member from a list" do
374
+ stub_delete("/pengwynn/rubyists/members.json?id=4243", "user.json")
375
+ user = @twitter.list_remove_member("pengwynn", "rubyists", 4243)
376
+ user.screen_name.should == "jnunemaker"
377
+ end
378
+
379
+ should "be able to check if a user is member of a list" do
380
+ stub_get("/pengwynn/rubyists/members/4243.json", "user.json")
381
+ @twitter.is_list_member?("pengwynn", "rubyists", 4243).should == true
382
+ end
383
+
384
+ should "be able to view list subscribers" do
385
+ stub_get("/pengwynn/rubyists/subscribers.json", "list_users.json")
386
+ subscribers = @twitter.list_subscribers("pengwynn", "rubyists").users
387
+ subscribers.size.should == 2
388
+ subscribers.first.name.should == "John Nunemaker"
389
+ subscribers.first.screen_name.should == "jnunemaker"
390
+ end
391
+
392
+ should "be able to subscribe to a list" do
393
+ stub_post("/pengwynn/rubyists/subscribers.json", "user.json")
394
+ user = @twitter.list_subscribe("pengwynn", "rubyists")
395
+ user.screen_name.should == "jnunemaker"
396
+ end
397
+
398
+ should "be able to unsubscribe from a list" do
399
+ stub_delete("/pengwynn/rubyists/subscribers.json", "user.json")
400
+ user = @twitter.list_unsubscribe("pengwynn", "rubyists")
401
+ user.screen_name.should == "jnunemaker"
402
+ end
403
+
404
+ should "be able to view a members list subscriptions" do
405
+ stub_get('/pengwynn/lists/subscriptions.json', 'list_subscriptions.json')
406
+ subscriptions = @twitter.subscriptions('pengwynn').lists
407
+ subscriptions.size.should == 1
408
+ subscriptions.first.full_name.should == "@chriseppstein/sass-users"
409
+ subscriptions.first.slug.should == "sass-users"
410
+ end
411
+
412
+ end
413
+ end
414
+
415
+ context "when using a non-twitter service" do
416
+ setup do
417
+ @twitter = Twitter::Base.new(Twitter::HTTPAuth.new("wynn@example.com", "mypass", :api_endpoint => "tumblr.com"))
418
+ end
419
+
420
+ should "get the home timeline" do
421
+ stub_get("http://wynn%40example.com:mypass@tumblr.com/1/statuses/home_timeline.json", "home_timeline.json")
422
+ timeline = @twitter.home_timeline
423
+ timeline.size.should == 20
424
+ end
425
+ end
426
+ end
@@ -0,0 +1,79 @@
1
+ require 'test_helper'
2
+
3
+ class GeoTest < Test::Unit::TestCase
4
+ include Twitter
5
+
6
+ context "Geographic place lookup" do
7
+
8
+ should "work" do
9
+ stub_get 'http://api.twitter.com/1/geo/id/ea76a36c5bc2bdff.json', 'geo_place.json'
10
+ place = Geo.place('ea76a36c5bc2bdff')
11
+ place.country.should == 'The United States of America'
12
+ place.full_name.should == 'Ballantyne West, Charlotte'
13
+ place.geometry.coordinates.should be_kind_of(Array)
14
+ end
15
+
16
+ end
17
+
18
+ context "Geographic search" do
19
+
20
+ should "work" do
21
+ stub_get 'http://api.twitter.com:80/1/geo/search.json?lat=35.061161&long=-80.854568', 'geo_search.json'
22
+ places = Geo.search(:lat => 35.061161, :long => -80.854568)
23
+ places.size.should == 3
24
+ places[0].full_name.should eql('Ballantyne West, Charlotte')
25
+ places[0].name.should eql('Ballantyne West')
26
+ end
27
+
28
+ should "be able to search with free form text" do
29
+ stub_get 'http://api.twitter.com/1/geo/search.json?query=princeton%20record%20exchange', 'geo_search_query.json'
30
+ places = Geo.search(:query => 'princeton record exchange')
31
+ places.size.should == 1
32
+ places[0].name.should eql('Princeton Record Exchange')
33
+ places[0].place_type.should eql('poi')
34
+ places[0].attributes.street_address.should eql('20 S Tulane St')
35
+ end
36
+
37
+ should "be able to search by ip address" do
38
+ stub_get 'http://api.twitter.com/1/geo/search.json?ip=74.125.19.104', 'geo_search_ip_address.json'
39
+ places = Geo.search(:ip => '74.125.19.104')
40
+ places.size.should == 4
41
+ places[0].full_name.should eql("Mountain View, CA")
42
+ places[0].name.should eql("Mountain View")
43
+ places[1].full_name.should eql("Sunnyvale, CA")
44
+ places[1].name.should eql('Sunnyvale')
45
+ end
46
+
47
+ end
48
+
49
+ context "Geographic reverse_geocode" do
50
+
51
+ should "work" do
52
+ stub_get 'http://api.twitter.com:80/1/geo/reverse_geocode.json?lat=35.061161&long=-80.854568', 'geo_reverse_geocode.json'
53
+ places = Geo.reverse_geocode(:lat => 35.061161, :long => -80.854568)
54
+ places.size.should == 4
55
+ places[0].full_name.should eql('Ballantyne West, Charlotte')
56
+ places[0].name.should eql('Ballantyne West')
57
+ end
58
+
59
+ should "be able to limit the number of results returned" do
60
+ stub_get 'http://api.twitter.com/1/geo/reverse_geocode.json?lat=35.061161&max_results=2&long=-80.854568', 'geo_reverse_geocode_limit.json'
61
+ places = Geo.reverse_geocode(:lat => 35.061161, :long => -80.854568, :max_results => 2)
62
+ places.size.should == 2
63
+ places[0].full_name.should eql('Ballantyne West, Charlotte')
64
+ places[0].name.should eql('Ballantyne West')
65
+ end
66
+
67
+ should "be able to lookup with granularity" do
68
+ stub_get 'http://api.twitter.com/1/geo/reverse_geocode.json?lat=35.061161&long=-80.854568&granularity=city', 'geo_reverse_geocode_granularity.json'
69
+ places = Geo.reverse_geocode(:lat => 35.061161, :long => -80.854568, :granularity => 'city')
70
+ places.size.should == 3
71
+ places[0].full_name.should eql('Charlotte, NC')
72
+ places[0].name.should eql('Charlotte')
73
+ places[1].full_name.should eql('North Carolina, US')
74
+ places[1].name.should eql('North Carolina')
75
+ end
76
+
77
+ end
78
+
79
+ end
@@ -0,0 +1,86 @@
1
+ require 'test_helper'
2
+
3
+ class HTTPAuthTest < Test::Unit::TestCase
4
+ context "Creating new instance" do
5
+ should "should take user and password" do
6
+ twitter = Twitter::HTTPAuth.new('username', 'password')
7
+ twitter.username.should == 'username'
8
+ twitter.password.should == 'password'
9
+ end
10
+
11
+ should "accept options" do
12
+ twitter = Twitter::HTTPAuth.new('username', 'password', :ssl => true)
13
+ twitter.options.should == {:ssl => true}
14
+ end
15
+
16
+ should "default ssl to false" do
17
+ twitter = Twitter::HTTPAuth.new('username', 'password')
18
+ twitter.options[:ssl].should be(false)
19
+ end
20
+
21
+ should "use https if ssl is true" do
22
+ Twitter::HTTPAuth.expects(:base_uri).with('https://api.twitter.com/' + Twitter::API_VERSION)
23
+ twitter = Twitter::HTTPAuth.new('username', 'password', :ssl => true)
24
+ end
25
+
26
+ should "use http if ssl is false" do
27
+ Twitter::HTTPAuth.expects(:base_uri).with('http://api.twitter.com/' + Twitter::API_VERSION)
28
+ twitter = Twitter::HTTPAuth.new('username', 'password', :ssl => false)
29
+ end
30
+
31
+ should "use api version if provided" do
32
+ Twitter::HTTPAuth.expects(:base_uri).with('http://api.twitter.com/2')
33
+ twitter = Twitter::HTTPAuth.new('username', 'password', {:ssl => false, :api_version => 2})
34
+ end
35
+
36
+ should "not use api versioning if api_version is false " do
37
+ Twitter::HTTPAuth.expects(:base_uri).with('http://api.twitter.com')
38
+ twitter = Twitter::HTTPAuth.new('username', 'password', {:ssl => false, :api_version => false})
39
+ end
40
+ end
41
+
42
+ context "Client methods" do
43
+ setup do
44
+ @twitter = Twitter::HTTPAuth.new('username', 'password')
45
+ end
46
+
47
+ should "not throw error when accessing response message" do
48
+ stub_get('http://api.twitter.com:80/1/statuses/user_timeline.json', 'user_timeline.json')
49
+ response = @twitter.get('/statuses/user_timeline.json')
50
+ response.message.should == 'OK'
51
+ end
52
+
53
+ should "be able to get" do
54
+ stub_get('http://username:password@api.twitter.com:80/1/statuses/user_timeline.json', 'user_timeline.json')
55
+ response = @twitter.get('/statuses/user_timeline.json')
56
+ response.should == fixture_file('user_timeline.json')
57
+ end
58
+
59
+ should "be able to get with headers" do
60
+ @twitter.class.expects(:get).with(
61
+ '/statuses/user_timeline.json', {
62
+ :basic_auth => {:username => 'username', :password => 'password'},
63
+ :headers => {'Foo' => 'Bar'}
64
+ }
65
+ ).returns(fixture_file('user_timeline.json'))
66
+ @twitter.get('/statuses/user_timeline.json', {'Foo' => 'Bar'})
67
+ end
68
+
69
+ should "be able to post" do
70
+ stub_post('http://username:password@api.twitter.com:80/1/statuses/update.json', 'status.json')
71
+ response = @twitter.post('/statuses/update.json', :text => 'My update.')
72
+ response.should == fixture_file('status.json')
73
+ end
74
+
75
+ should "be able to post with headers" do
76
+ @twitter.class.expects(:post).with(
77
+ '/statuses/update.json', {
78
+ :headers => {'Foo' => 'Bar'},
79
+ :body => {:text => 'My update.'},
80
+ :basic_auth => {:username => 'username', :password => 'password'}
81
+ }
82
+ ).returns(fixture_file('status.json'))
83
+ @twitter.post('/statuses/update.json', {:text => 'My update.'}, {'Foo' => 'Bar'})
84
+ end
85
+ end
86
+ end