tweetwine 0.2.5 → 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/CHANGELOG.rdoc +30 -17
  2. data/README.rdoc +16 -17
  3. data/Rakefile +2 -0
  4. data/bin/tweetwine +3 -68
  5. data/example/example_helper.rb +31 -41
  6. data/example/fixtures/{statuses.json → home.json} +0 -0
  7. data/example/fixtures/mentions.json +1 -0
  8. data/example/fixtures/search.json +1 -0
  9. data/example/fixtures/update.json +1 -0
  10. data/example/fixtures/user.json +1 -0
  11. data/example/fixtures/users.json +1 -0
  12. data/example/search_statuses_example.rb +36 -0
  13. data/example/show_followers_example.rb +23 -0
  14. data/example/show_friends_example.rb +23 -0
  15. data/example/show_home_example.rb +51 -0
  16. data/example/show_mentions_example.rb +23 -0
  17. data/example/show_metadata_example.rb +54 -7
  18. data/example/show_user_example.rb +37 -0
  19. data/example/update_status_example.rb +65 -0
  20. data/lib/tweetwine/cli.rb +241 -0
  21. data/lib/tweetwine/client.rb +94 -57
  22. data/lib/tweetwine/io.rb +39 -28
  23. data/lib/tweetwine/meta.rb +1 -1
  24. data/lib/tweetwine/retrying_http.rb +93 -0
  25. data/lib/tweetwine/startup_config.rb +14 -15
  26. data/lib/tweetwine/url_shortener.rb +13 -8
  27. data/lib/tweetwine/util.rb +14 -0
  28. data/lib/tweetwine.rb +2 -1
  29. data/test/cli_test.rb +16 -0
  30. data/test/client_test.rb +275 -205
  31. data/test/fixtures/test_config.yaml +2 -1
  32. data/test/io_test.rb +89 -62
  33. data/test/retrying_http_test.rb +127 -0
  34. data/test/startup_config_test.rb +52 -27
  35. data/test/test_helper.rb +32 -17
  36. data/test/url_shortener_test.rb +18 -18
  37. data/test/util_test.rb +145 -47
  38. metadata +20 -7
  39. data/example/show_latest_statuses_example.rb +0 -45
  40. data/lib/tweetwine/rest_client_wrapper.rb +0 -37
  41. data/test/rest_client_wrapper_test.rb +0 -68
data/test/client_test.rb CHANGED
@@ -1,18 +1,17 @@
1
1
  require "test_helper"
2
2
  require "json"
3
3
 
4
- Mocha::Configuration.allow(:stubbing_non_existent_method)
5
-
6
4
  module Tweetwine
7
5
 
8
6
  class ClientTest < Test::Unit::TestCase
9
7
  context "A client instance" do
10
8
  setup do
11
9
  @io = mock()
12
- @rest_client = mock()
10
+ @http_resource = mock()
11
+ @http_client = stub({ :as_resource => @http_resource })
13
12
  @url_shortener = mock()
14
- url_shortener = lambda { |options| @url_shortener }
15
- @deps = Client::Dependencies.new @io, @rest_client, url_shortener
13
+ @url_shortener_block = lambda { |options| @url_shortener }
14
+ @deps = Client::Dependencies.new @io, @http_client, @url_shortener_block
16
15
  end
17
16
 
18
17
  context "upon initialization" do
@@ -50,6 +49,13 @@ class ClientTest < Test::Unit::TestCase
50
49
  should "raise an exception for configured page number if not in allowed range" do
51
50
  assert_raise(ArgumentError) { Client.new(@deps, { :username => "foo", :password => "bar", :page_num => 0 }) }
52
51
  end
52
+
53
+ should "user proper base URL and authentication information for HTTP requests" do
54
+ http_client = mock()
55
+ http_client.expects(:as_resource).with("https://twitter.com", :user => "foo", :password => "bar")
56
+ deps = Client::Dependencies.new @io, http_client, @url_shortener_block
57
+ Client.new(deps, { :username => "foo", :password => "bar" })
58
+ end
53
59
  end
54
60
 
55
61
  context "at runtime" do
@@ -57,160 +63,153 @@ class ClientTest < Test::Unit::TestCase
57
63
  @username = "spiky"
58
64
  @password = "lullaby"
59
65
  @client = Client.new(@deps, { :username => @username, :password => @password })
60
- @base_url = "https://#{@username}:#{@password}@twitter.com"
61
- @statuses_query_params = "count=#{Client::DEFAULT_NUM_STATUSES}&page=#{Client::DEFAULT_PAGE_NUM}"
62
- @users_query_params = "page=#{Client::DEFAULT_PAGE_NUM}"
66
+ @rest_api_status_query_str = "count=#{Client::DEFAULT_NUM_STATUSES}&page=#{Client::DEFAULT_PAGE_NUM}"
67
+ @search_api_base_url = "http://search.twitter.com/search.json"
68
+ @search_api_query_str = "rpp=#{Client::DEFAULT_NUM_STATUSES}&page=#{Client::DEFAULT_PAGE_NUM}"
63
69
  end
64
70
 
65
71
  should "fetch friends' statuses (home view)" do
66
- status_records, gen_records = create_test_statuses(
72
+ twitter_records, internal_records = create_test_twitter_status_records_from_rest_api(
67
73
  {
68
- :user => "zanzibar",
69
- :status => {
70
- :created_at => Time.at(1).to_s,
71
- :text => "wassup?",
72
- :in_reply_to => nil
73
- }
74
+ :from_user => "zanzibar",
75
+ :status => "wassup?",
76
+ :created_at => Time.at(1).to_s,
77
+ :to_user => nil
74
78
  },
75
79
  {
76
- :user => "lulzwoo",
77
- :status => {
78
- :created_at => Time.at(1).to_s,
79
- :text => "nuttin'",
80
- :in_reply_to => nil
81
- }
80
+ :from_user => "lulzwoo",
81
+ :status => "nuttin'",
82
+ :created_at => Time.at(1).to_s,
83
+ :to_user => nil
82
84
  }
83
85
  )
84
- @rest_client.expects(:get) \
85
- .with("#{@base_url}/statuses/friends_timeline.json?#{@statuses_query_params}") \
86
- .returns(status_records.to_json)
87
- @io.expects(:show_record).with(gen_records[0])
88
- @io.expects(:show_record).with(gen_records[1])
86
+ @http_resource.expects(:[]) \
87
+ .with("statuses/home_timeline.json?#{@rest_api_status_query_str}") \
88
+ .returns(stub(:get => twitter_records.to_json))
89
+ @io.expects(:show_record).with(internal_records[0])
90
+ @io.expects(:show_record).with(internal_records[1])
89
91
  @client.home
90
92
  end
91
93
 
92
94
  should "fetch mentions" do
93
- status_records, gen_records = create_test_statuses(
95
+ twitter_records, internal_records = create_test_twitter_status_records_from_rest_api(
94
96
  {
95
- :user => "zanzibar",
96
- :status => {
97
- :created_at => Time.at(1).to_s,
98
- :text => "wassup, @#{@username}?",
99
- :in_reply_to => @username
100
- }
97
+ :from_user => "zanzibar",
98
+ :status => "wassup, @#{@username}?",
99
+ :created_at => Time.at(1).to_s,
100
+ :to_user => @username
101
101
  },
102
102
  {
103
- :user => "lulzwoo",
104
- :status => {
105
- :created_at => Time.at(1).to_s,
106
- :text => "@#{@username}, doing nuttin'",
107
- :in_reply_to => @username
108
- }
103
+ :from_user => "lulzwoo",
104
+ :status => "@#{@username}, doing nuttin'",
105
+ :created_at => Time.at(1).to_s,
106
+ :to_user => @username
109
107
  }
110
108
  )
111
- @rest_client.expects(:get) \
112
- .with("#{@base_url}/statuses/mentions.json?#{@statuses_query_params}") \
113
- .returns(status_records.to_json)
114
- @io.expects(:show_record).with(gen_records[0])
115
- @io.expects(:show_record).with(gen_records[1])
109
+ @http_resource.expects(:[]) \
110
+ .with("statuses/mentions.json?#{@rest_api_status_query_str}") \
111
+ .returns(stub(:get => twitter_records.to_json))
112
+ @io.expects(:show_record).with(internal_records[0])
113
+ @io.expects(:show_record).with(internal_records[1])
116
114
  @client.mentions
117
115
  end
118
116
 
119
117
  should "fetch a specific user's statuses, when the user identified by given argument" do
120
118
  user = "spoonman"
121
- status_records, gen_records = create_test_statuses(
119
+ twitter_records, internal_records = create_test_twitter_status_records_from_rest_api(
122
120
  {
123
- :user => user,
124
- :status => {
125
- :created_at => Time.at(1).to_s,
126
- :text => "wassup?",
127
- :in_reply_to => nil
128
- }
121
+ :from_user => user,
122
+ :status => "wassup?",
123
+ :created_at => Time.at(1).to_s,
124
+ :to_user => nil
129
125
  }
130
126
  )
131
- @rest_client.expects(:get) \
132
- .with("#{@base_url}/statuses/user_timeline/#{user}.json?#{@statuses_query_params}") \
133
- .returns(status_records.to_json)
134
- @io.expects(:show_record).with(gen_records[0])
135
- @client.user(user)
127
+ @http_resource.expects(:[]) \
128
+ .with("statuses/user_timeline/#{user}.json?#{@rest_api_status_query_str}") \
129
+ .returns(stub(:get => twitter_records.to_json))
130
+ @io.expects(:show_record).with(internal_records[0])
131
+ @client.user([user])
136
132
  end
137
133
 
138
134
  should "fetch a specific user's statuses, with the user being the authenticated user itself when given no argument" do
139
- status_records, gen_records = create_test_statuses(
135
+ twitter_records, internal_records = create_test_twitter_status_records_from_rest_api(
140
136
  {
141
- :user => @username,
142
- :status => {
143
- :created_at => Time.at(1).to_s,
144
- :text => "wassup?",
145
- :in_reply_to => nil
146
- }
137
+ :from_user => @username,
138
+ :status => "wassup?",
139
+ :created_at => Time.at(1).to_s,
140
+ :to_user => nil
147
141
  }
148
142
  )
149
- @rest_client.expects(:get) \
150
- .with("#{@base_url}/statuses/user_timeline/#{@username}.json?#{@statuses_query_params}") \
151
- .returns(status_records.to_json)
152
- @io.expects(:show_record).with(gen_records[0])
143
+ @http_resource.expects(:[]) \
144
+ .with("statuses/user_timeline/#{@username}.json?#{@rest_api_status_query_str}") \
145
+ .returns(stub(:get => twitter_records.to_json))
146
+ @io.expects(:show_record).with(internal_records[0])
153
147
  @client.user
154
148
  end
155
149
 
156
150
  context "for posting status updates" do
157
151
  should "post a status update via argument, when positive confirmation" do
158
152
  status = "wondering around"
159
- status_records, gen_records = create_test_statuses(
153
+ twitter_records, internal_records = create_test_twitter_status_records_from_rest_api(
160
154
  {
161
- :user => @username,
162
- :status => {
163
- :created_at => Time.at(1).to_s,
164
- :text => status,
165
- :in_reply_to => nil
166
- }
155
+ :from_user => @username,
156
+ :status => status,
157
+ :created_at => Time.at(1).to_s,
158
+ :to_user => nil
167
159
  }
168
160
  )
169
- @rest_client.expects(:post) \
170
- .with("#{@base_url}/statuses/update.json", {:status => status}) \
171
- .returns(status_records[0].to_json)
161
+ http_subresource = mock()
162
+ http_subresource.expects(:post) \
163
+ .with({ :status => status }) \
164
+ .returns(twitter_records[0].to_json)
165
+ @http_resource.expects(:[]) \
166
+ .with("statuses/update.json") \
167
+ .returns(http_subresource)
172
168
  @io.expects(:confirm).with("Really send?").returns(true)
173
169
  @io.expects(:show_status_preview).with(status)
174
170
  @io.expects(:info).with("Sent status update.\n\n")
175
- @io.expects(:show_record).with(gen_records[0])
176
- @client.update(status)
171
+ @io.expects(:show_record).with(internal_records[0])
172
+ @client.update([status])
177
173
  end
178
174
 
179
175
  should "post a status update via prompt, when positive confirmation" do
180
176
  status = "wondering around"
181
- status_records, gen_records = create_test_statuses(
182
- { :user => @username,
183
- :status => {
184
- :created_at => Time.at(1).to_s,
185
- :text => status,
186
- :in_reply_to => nil
187
- }
177
+ twitter_records, internal_records = create_test_twitter_status_records_from_rest_api(
178
+ {
179
+ :from_user => @username,
180
+ :status => status,
181
+ :created_at => Time.at(1).to_s,
182
+ :to_user => nil
188
183
  }
189
184
  )
190
- @rest_client.expects(:post) \
191
- .with("#{@base_url}/statuses/update.json", {:status => status}) \
192
- .returns(status_records[0].to_json)
185
+ http_subresource = mock()
186
+ http_subresource.expects(:post) \
187
+ .with({ :status => status }) \
188
+ .returns(twitter_records[0].to_json)
189
+ @http_resource.expects(:[]) \
190
+ .with("statuses/update.json") \
191
+ .returns(http_subresource)
193
192
  @io.expects(:prompt).with("Status update").returns(status)
194
193
  @io.expects(:show_status_preview).with(status)
195
194
  @io.expects(:confirm).with("Really send?").returns(true)
196
195
  @io.expects(:info).with("Sent status update.\n\n")
197
- @io.expects(:show_record).with(gen_records[0])
196
+ @io.expects(:show_record).with(internal_records[0])
198
197
  @client.update
199
198
  end
200
199
 
201
200
  should "cancel a status update via argument, when negative confirmation" do
202
201
  status = "wondering around"
203
- @rest_client.expects(:post).never
202
+ @http_resource.expects(:[]).never
204
203
  @io.expects(:show_status_preview).with(status)
205
204
  @io.expects(:confirm).with("Really send?").returns(false)
206
205
  @io.expects(:info).with("Cancelled.")
207
206
  @io.expects(:show_record).never
208
- @client.update(status)
207
+ @client.update([status])
209
208
  end
210
209
 
211
210
  should "cancel a status update via prompt, when negative confirmation" do
212
211
  status = "wondering around"
213
- @rest_client.expects(:post).never
212
+ @http_resource.expects(:[]).never
214
213
  @io.expects(:prompt).with("Status update").returns(status)
215
214
  @io.expects(:show_status_preview).with(status)
216
215
  @io.expects(:confirm).with("Really send?").returns(false)
@@ -220,15 +219,15 @@ class ClientTest < Test::Unit::TestCase
220
219
  end
221
220
 
222
221
  should "cancel a status update via argument, when empty status" do
223
- @rest_client.expects(:post).never
222
+ @http_resource.expects(:[]).never
224
223
  @io.expects(:confirm).never
225
224
  @io.expects(:info).with("Cancelled.")
226
225
  @io.expects(:show_record).never
227
- @client.update("")
226
+ @client.update([""])
228
227
  end
229
228
 
230
229
  should "cancel a status update via prompt, when empty status" do
231
- @rest_client.expects(:post).never
230
+ @http_resource.expects(:[]).never
232
231
  @io.expects(:prompt).with("Status update").returns("")
233
232
  @io.expects(:confirm).never
234
233
  @io.expects(:info).with("Cancelled.")
@@ -239,46 +238,52 @@ class ClientTest < Test::Unit::TestCase
239
238
  should "remove excess whitespace around a status update" do
240
239
  whitespaced_status = " oh, i was sloppy \t "
241
240
  stripped_status = "oh, i was sloppy"
242
- status_records, gen_records = create_test_statuses(
243
- { :user => @username,
244
- :status => {
245
- :created_at => Time.at(1).to_s,
246
- :text => stripped_status,
247
- :in_reply_to => nil
248
- }
241
+ twitter_records, internal_records = create_test_twitter_status_records_from_rest_api(
242
+ {
243
+ :from_user => @username,
244
+ :status => stripped_status,
245
+ :created_at => Time.at(1).to_s,
246
+ :to_user => nil
249
247
  }
250
248
  )
251
- @rest_client.expects(:post) \
252
- .with("#{@base_url}/statuses/update.json", {:status => stripped_status}) \
253
- .returns(status_records[0].to_json)
249
+ http_subresource = mock()
250
+ http_subresource.expects(:post) \
251
+ .with({ :status => stripped_status }) \
252
+ .returns(twitter_records[0].to_json)
253
+ @http_resource.expects(:[]) \
254
+ .with("statuses/update.json") \
255
+ .returns(http_subresource)
254
256
  @io.expects(:show_status_preview).with(stripped_status)
255
257
  @io.expects(:confirm).with("Really send?").returns(true)
256
258
  @io.expects(:info).with("Sent status update.\n\n")
257
- @io.expects(:show_record).with(gen_records[0])
258
- @client.update(whitespaced_status)
259
+ @io.expects(:show_record).with(internal_records[0])
260
+ @client.update([whitespaced_status])
259
261
  end
260
262
 
261
263
  should "truncate a status update with too long argument and warn the user" do
262
264
  long_status = "x aaa bbb ccc ddd eee fff ggg hhh iii jjj kkk lll mmm nnn ooo ppp qqq rrr sss ttt uuu vvv www xxx yyy zzz 111 222 333 444 555 666 777 888 999 000"
263
265
  truncated_status = "x aaa bbb ccc ddd eee fff ggg hhh iii jjj kkk lll mmm nnn ooo ppp qqq rrr sss ttt uuu vvv www xxx yyy zzz 111 222 333 444 555 666 777 888 99"
264
- status_records, gen_records = create_test_statuses(
265
- { :user => @username,
266
- :status => {
267
- :created_at => Time.at(1).to_s,
268
- :text => truncated_status,
269
- :in_reply_to => nil
270
- }
266
+ twitter_records, internal_records = create_test_twitter_status_records_from_rest_api(
267
+ {
268
+ :from_user => @username,
269
+ :status => truncated_status,
270
+ :created_at => Time.at(1).to_s,
271
+ :to_user => nil
271
272
  }
272
273
  )
273
- @rest_client.expects(:post) \
274
- .with("#{@base_url}/statuses/update.json", {:status => truncated_status}) \
275
- .returns(status_records[0].to_json)
274
+ http_subresource = mock()
275
+ http_subresource.expects(:post) \
276
+ .with({ :status => truncated_status }) \
277
+ .returns(twitter_records[0].to_json)
278
+ @http_resource.expects(:[]) \
279
+ .with("statuses/update.json") \
280
+ .returns(http_subresource)
276
281
  @io.expects(:warn).with("Status will be truncated.")
277
282
  @io.expects(:show_status_preview).with(truncated_status)
278
283
  @io.expects(:confirm).with("Really send?").returns(true)
279
284
  @io.expects(:info).with("Sent status update.\n\n")
280
- @io.expects(:show_record).with(gen_records[0])
281
- @client.update(long_status)
285
+ @io.expects(:show_record).with(internal_records[0])
286
+ @client.update([long_status])
282
287
  end
283
288
 
284
289
  context "with URL shortening enabled" do
@@ -301,50 +306,56 @@ class ClientTest < Test::Unit::TestCase
301
306
  long_status = long_urls.join(" and ")
302
307
  short_urls = ["http://shorten.it/2k7i8", "http://shorten.it/2k7mk"]
303
308
  shortened_status = short_urls.join(" and ")
304
- status_records, gen_records = create_test_statuses(
305
- { :user => @username,
306
- :status => {
307
- :created_at => Time.at(1).to_s,
308
- :text => shortened_status,
309
- :in_reply_to => nil
310
- }
309
+ twitter_records, internal_records = create_test_twitter_status_records_from_rest_api(
310
+ {
311
+ :from_user => @username,
312
+ :status => shortened_status,
313
+ :created_at => Time.at(1).to_s,
314
+ :to_user => nil
311
315
  }
312
316
  )
313
- @rest_client.expects(:post) \
314
- .with("#{@base_url}/statuses/update.json", {:status => shortened_status}) \
315
- .returns(status_records[0].to_json)
317
+ http_subresource = mock()
318
+ http_subresource.expects(:post) \
319
+ .with({ :status => shortened_status }) \
320
+ .returns(twitter_records[0].to_json)
321
+ @http_resource.expects(:[]) \
322
+ .with("statuses/update.json") \
323
+ .returns(http_subresource)
316
324
  @url_shortener.expects(:shorten).with(long_urls.first).returns(short_urls.first)
317
325
  @url_shortener.expects(:shorten).with(long_urls.last).returns(short_urls.last)
318
326
  @io.expects(:show_status_preview).with(shortened_status)
319
327
  @io.expects(:confirm).with("Really send?").returns(true)
320
328
  @io.expects(:info).with("Sent status update.\n\n")
321
- @io.expects(:show_record).with(gen_records[0])
322
- @client.update(long_status)
329
+ @io.expects(:show_record).with(internal_records[0])
330
+ @client.update([long_status])
323
331
  end
324
332
 
325
333
  should "discard obviously invalid shortened URLs, using originals instead" do
326
334
  long_urls = ["http://www.google.fi/", "http://www.w3.org/TR/1999/REC-xpath-19991116"]
327
335
  status = long_urls.join(" and ")
328
336
  short_urls = [nil, ""]
329
- status_records, gen_records = create_test_statuses(
330
- { :user => @username,
331
- :status => {
332
- :created_at => Time.at(1).to_s,
333
- :text => status,
334
- :in_reply_to => nil
335
- }
337
+ twitter_records, internal_records = create_test_twitter_status_records_from_rest_api(
338
+ {
339
+ :from_user => @username,
340
+ :status => status,
341
+ :created_at => Time.at(1).to_s,
342
+ :to_user => nil
336
343
  }
337
344
  )
338
- @rest_client.expects(:post) \
339
- .with("#{@base_url}/statuses/update.json", {:status => status}) \
340
- .returns(status_records[0].to_json)
345
+ http_subresource = mock()
346
+ http_subresource.expects(:post) \
347
+ .with({ :status => status }) \
348
+ .returns(twitter_records[0].to_json)
349
+ @http_resource.expects(:[]) \
350
+ .with("statuses/update.json") \
351
+ .returns(http_subresource)
341
352
  @url_shortener.expects(:shorten).with(long_urls.first).returns(short_urls.first)
342
353
  @url_shortener.expects(:shorten).with(long_urls.last).returns(short_urls.last)
343
354
  @io.expects(:show_status_preview).with(status)
344
355
  @io.expects(:confirm).with("Really send?").returns(true)
345
356
  @io.expects(:info).with("Sent status update.\n\n")
346
- @io.expects(:show_record).with(gen_records[0])
347
- @client.update(status)
357
+ @io.expects(:show_record).with(internal_records[0])
358
+ @client.update([status])
348
359
  end
349
360
 
350
361
  should "reuse a shortened URL for duplicate long URLs" do
@@ -352,118 +363,177 @@ class ClientTest < Test::Unit::TestCase
352
363
  long_status = long_urls.join(" and ")
353
364
  short_url = "http://shorten.it/2k7mk"
354
365
  short_status = ([short_url] * 2).join(" and ")
355
- status_records, gen_records = create_test_statuses(
356
- { :user => @username,
357
- :status => {
358
- :created_at => Time.at(1).to_s,
359
- :text => short_status,
360
- :in_reply_to => nil
361
- }
366
+ twitter_records, internal_records = create_test_twitter_status_records_from_rest_api(
367
+ {
368
+ :from_user => @username,
369
+ :status => short_status,
370
+ :created_at => Time.at(1).to_s,
371
+ :to_user => nil
362
372
  }
363
373
  )
364
- @rest_client.expects(:post) \
365
- .with("#{@base_url}/statuses/update.json", {:status => short_status}) \
366
- .returns(status_records[0].to_json)
374
+ http_subresource = mock()
375
+ http_subresource.expects(:post) \
376
+ .with({ :status => short_status }) \
377
+ .returns(twitter_records[0].to_json)
378
+ @http_resource.expects(:[]) \
379
+ .with("statuses/update.json") \
380
+ .returns(http_subresource)
367
381
  @url_shortener.expects(:shorten).with(long_urls.first).returns(short_url)
368
382
  @io.expects(:show_status_preview).with(short_status)
369
383
  @io.expects(:confirm).with("Really send?").returns(true)
370
384
  @io.expects(:info).with("Sent status update.\n\n")
371
- @io.expects(:show_record).with(gen_records[0])
372
- @client.update(long_status)
385
+ @io.expects(:show_record).with(internal_records[0])
386
+ @client.update([long_status])
373
387
  end
374
388
 
375
389
  context "in erroneous situations" do
376
390
  setup do
377
391
  @url = "http://www.w3.org/TR/1999/REC-xpath-19991116"
378
392
  @status = "skimming through #{@url}"
379
- @status_records, @gen_records = create_test_statuses(
380
- { :user => @username,
381
- :status => {
382
- :created_at => Time.at(1).to_s,
383
- :text => @status,
384
- :in_reply_to => nil
385
- }
393
+ @twitter_records, @internal_records = create_test_twitter_status_records_from_rest_api(
394
+ {
395
+ :from_user => @username,
396
+ :status => @status,
397
+ :created_at => Time.at(1).to_s,
398
+ :to_user => nil
386
399
  }
387
400
  )
388
401
  end
389
402
 
390
403
  should "skip shortening URLs if required libraries are not found" do
391
- @rest_client.expects(:post) \
392
- .with("#{@base_url}/statuses/update.json", {:status => @status}) \
393
- .returns(@status_records[0].to_json)
404
+ http_subresource = mock()
405
+ http_subresource.expects(:post) \
406
+ .with({ :status => @status }) \
407
+ .returns(@twitter_records[0].to_json)
408
+ @http_resource.expects(:[]) \
409
+ .with("statuses/update.json") \
410
+ .returns(http_subresource)
394
411
  @url_shortener.expects(:shorten).with(@url).raises(LoadError, "gem not found")
395
412
  @io.expects(:warn)
396
413
  @io.expects(:show_status_preview).with(@status)
397
414
  @io.expects(:confirm).with("Really send?").returns(true)
398
415
  @io.expects(:info).with("Sent status update.\n\n")
399
- @io.expects(:show_record).with(@gen_records[0])
400
- @client.update(@status)
416
+ @io.expects(:show_record).with(@internal_records[0])
417
+ @client.update([@status])
401
418
  end
402
419
 
403
420
  should "skip shortening URLs upon connection error to the URL shortening service" do
404
- @rest_client.expects(:post) \
405
- .with("#{@base_url}/statuses/update.json", {:status => @status}) \
406
- .returns(@status_records[0].to_json)
407
- @url_shortener.expects(:shorten).with(@url).raises(ClientError, "connection error")
421
+ http_subresource = mock()
422
+ http_subresource.expects(:post) \
423
+ .with({ :status => @status }) \
424
+ .returns(@twitter_records[0].to_json)
425
+ @http_resource.expects(:[]) \
426
+ .with("statuses/update.json") \
427
+ .returns(http_subresource)
428
+ @url_shortener.expects(:shorten).with(@url).raises(HttpError, "connection error")
408
429
  @io.expects(:warn)
409
430
  @io.expects(:show_status_preview).with(@status)
410
431
  @io.expects(:confirm).with("Really send?").returns(true)
411
432
  @io.expects(:info).with("Sent status update.\n\n")
412
- @io.expects(:show_record).with(@gen_records[0])
413
- @client.update(@status)
433
+ @io.expects(:show_record).with(@internal_records[0])
434
+ @client.update([@status])
414
435
  end
415
436
  end
416
437
  end
417
438
  end
418
439
 
419
440
  should "fetch friends" do
420
- user_records, gen_records = create_test_users(
441
+ twitter_records, internal_records = create_test_twitter_user_records_from_rest_api(
421
442
  {
422
- :user => "zanzibar",
423
- :status => {
424
- :created_at => Time.at(1).to_s,
425
- :text => "wassup, @foo?",
426
- :in_reply_to => "foo"
427
- }
443
+ :from_user => "zanzibar",
444
+ :status => "wassup, @foo?",
445
+ :created_at => Time.at(1).to_s,
446
+ :to_user => "foo"
428
447
  },
429
448
  {
430
- :user => "lulzwoo",
431
- :status => {
432
- :created_at => Time.at(1).to_s,
433
- :text => "@foo, doing nuttin'",
434
- :in_reply_to => "foo"
435
- }
449
+ :from_user => "lulzwoo",
450
+ :status => "@foo, doing nuttin'",
451
+ :created_at => Time.at(1).to_s,
452
+ :to_user => "foo"
436
453
  }
437
454
  )
438
- @rest_client.expects(:get) \
439
- .with("#{@base_url}/statuses/friends/#{@username}.json?#{@users_query_params}") \
440
- .returns(user_records.to_json)
441
- @io.expects(:show_record).with(gen_records[0])
442
- @io.expects(:show_record).with(gen_records[1])
455
+ @http_resource.expects(:[]) \
456
+ .with("statuses/friends/#{@username}.json") \
457
+ .returns(stub(:get => twitter_records.to_json))
458
+ @io.expects(:show_record).with(internal_records[0])
459
+ @io.expects(:show_record).with(internal_records[1])
443
460
  @client.friends
444
461
  end
445
462
 
446
463
  should "fetch followers" do
447
- user_records, gen_records = create_test_users(
464
+ twitter_records, internal_records = create_test_twitter_user_records_from_rest_api(
448
465
  {
449
- :user => "zanzibar",
450
- :status => {
451
- :created_at => Time.at(1).to_s,
452
- :text => "wassup, @foo?",
453
- :in_reply_to => "foo"
454
- }
466
+ :from_user => "zanzibar",
467
+ :status => "wassup, @foo?",
468
+ :created_at => Time.at(1).to_s,
469
+ :to_user => "foo"
455
470
  },
456
471
  {
457
- :user => "lulzwoo"
472
+ :from_user => "lulzwoo",
473
+ :status => nil,
474
+ :created_at => nil,
475
+ :to_user => nil
458
476
  }
459
477
  )
460
- @rest_client.expects(:get) \
461
- .with("#{@base_url}/statuses/followers/#{@username}.json?#{@users_query_params}") \
462
- .returns(user_records.to_json)
463
- @io.expects(:show_record).with(gen_records[0])
464
- @io.expects(:show_record).with(gen_records[1])
478
+ @http_resource.expects(:[]) \
479
+ .with("statuses/followers/#{@username}.json") \
480
+ .returns(stub(:get => twitter_records.to_json))
481
+ @io.expects(:show_record).with(internal_records[0])
482
+ @io.expects(:show_record).with(internal_records[1])
465
483
  @client.followers
466
484
  end
485
+
486
+ context "for searching tweets" do
487
+ should "raise exception if no search word is given" do
488
+ assert_raise(ArgumentError) { @client.search() }
489
+ end
490
+
491
+ should "allow searching for tweets that match all the given words" do
492
+ twitter_response, internal_records = create_test_twitter_records_from_search_api(
493
+ {
494
+ :from_user => "zanzibar",
495
+ :status => "@foo, wassup? #greets",
496
+ :created_at => Time.at(1).to_s,
497
+ :to_user => "foo"
498
+ },
499
+ {
500
+ :from_user => "spoonman",
501
+ :status => "@foo long time no see #greets",
502
+ :created_at => Time.at(1).to_s,
503
+ :to_user => "foo"
504
+ }
505
+ )
506
+ @http_client.expects(:get) \
507
+ .with("#{@search_api_base_url}?q=%23greets%20%40foo&#{@search_api_query_str}") \
508
+ .returns(twitter_response.to_json)
509
+ @io.expects(:show_record).with(internal_records[0])
510
+ @io.expects(:show_record).with(internal_records[1])
511
+ @client.search(["#greets", "@foo"])
512
+ end
513
+
514
+ should "allow searching for tweets that match any of the given words" do
515
+ twitter_response, internal_records = create_test_twitter_records_from_search_api(
516
+ {
517
+ :from_user => "zanzibar",
518
+ :status => "spinning around the floor #habits",
519
+ :created_at => Time.at(1).to_s,
520
+ :to_user => "foo"
521
+ },
522
+ {
523
+ :from_user => "spoonman",
524
+ :status => "drinking coffee, again #neurotic",
525
+ :created_at => Time.at(1).to_s,
526
+ :to_user => "foo"
527
+ }
528
+ )
529
+ @http_client.expects(:get) \
530
+ .with("#{@search_api_base_url}?q=%23habits%20OR%20%23neurotic&#{@search_api_query_str}") \
531
+ .returns(twitter_response.to_json)
532
+ @io.expects(:show_record).with(internal_records[0])
533
+ @io.expects(:show_record).with(internal_records[1])
534
+ @client.search(["#habits", "#neurotic"], {:bin_op => :or})
535
+ end
536
+ end
467
537
  end
468
538
  end
469
539
  end