tweetwine 0.2.12 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +7 -0
- data/Gemfile +17 -0
- data/README.md +57 -47
- data/Rakefile +17 -26
- data/bin/tweetwine +11 -12
- data/contrib/tweetwine-completion.bash +2 -3
- data/example/application_behavior_example.rb +173 -0
- data/example/example_helper.rb +44 -28
- data/example/fixture/config.yaml +8 -0
- data/example/fixture/shorten_rubygems.html +5 -0
- data/example/fixture/shorten_rubylang.html +5 -0
- data/example/fixture/update_utf8.json +1 -0
- data/example/fixture/update_with_urls.json +1 -0
- data/example/fixture/{update.json → update_without_urls.json} +0 -0
- data/example/search_statuses_example.rb +49 -16
- data/example/show_followers_example.rb +7 -8
- data/example/show_friends_example.rb +7 -8
- data/example/show_home_example.rb +19 -16
- data/example/show_mentions_example.rb +8 -9
- data/example/show_user_example.rb +16 -13
- data/example/update_status_example.rb +143 -26
- data/example/use_http_proxy_example.rb +40 -20
- data/lib/tweetwine/basic_object.rb +19 -0
- data/lib/tweetwine/character_encoding.rb +59 -0
- data/lib/tweetwine/cli.rb +354 -230
- data/lib/tweetwine/config.rb +65 -0
- data/lib/tweetwine/http.rb +120 -0
- data/lib/tweetwine/oauth.rb +104 -0
- data/lib/tweetwine/obfuscate.rb +21 -0
- data/lib/tweetwine/option_parser.rb +31 -0
- data/lib/tweetwine/promise.rb +39 -0
- data/lib/tweetwine/twitter.rb +211 -0
- data/lib/tweetwine/{io.rb → ui.rb} +30 -21
- data/lib/tweetwine/url_shortener.rb +15 -9
- data/lib/tweetwine/util.rb +30 -15
- data/lib/tweetwine.rb +72 -12
- data/man/tweetwine.7 +43 -69
- data/man/tweetwine.7.ronn +57 -47
- data/test/character_encoding_test.rb +87 -0
- data/test/cli_test.rb +19 -6
- data/test/config_test.rb +244 -0
- data/test/fixture/oauth.rb +21 -0
- data/test/fixture/test_config.yaml +4 -4
- data/test/http_test.rb +199 -0
- data/test/oauth_test.rb +77 -0
- data/test/obfuscate_test.rb +16 -0
- data/test/option_parser_test.rb +60 -0
- data/test/promise_test.rb +56 -0
- data/test/test_helper.rb +76 -8
- data/test/twitter_test.rb +625 -0
- data/test/{io_test.rb → ui_test.rb} +92 -74
- data/test/url_shortener_test.rb +115 -135
- data/test/util_test.rb +136 -85
- data/tweetwine.gemspec +53 -0
- metadata +112 -56
- data/example/show_metadata_example.rb +0 -86
- data/lib/tweetwine/client.rb +0 -187
- data/lib/tweetwine/meta.rb +0 -5
- data/lib/tweetwine/options.rb +0 -24
- data/lib/tweetwine/retrying_http.rb +0 -99
- data/lib/tweetwine/startup_config.rb +0 -50
- data/man/tweetwine.1 +0 -109
- data/man/tweetwine.1.ronn +0 -69
- data/test/client_test.rb +0 -544
- data/test/options_test.rb +0 -45
- data/test/retrying_http_test.rb +0 -147
- data/test/startup_config_test.rb +0 -162
@@ -0,0 +1,625 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require "test_helper"
|
4
|
+
require "json"
|
5
|
+
|
6
|
+
module Tweetwine::Test
|
7
|
+
|
8
|
+
class ClientTest < UnitTestCase
|
9
|
+
context "for initialization" do
|
10
|
+
should "use default number of statuses if not configured" do
|
11
|
+
@twitter = Twitter.new
|
12
|
+
assert_equal Twitter::DEFAULT_NUM_STATUSES, @twitter.num_statuses
|
13
|
+
end
|
14
|
+
|
15
|
+
should "use configured number of statuses if in allowed range" do
|
16
|
+
@twitter = Twitter.new(:num_statuses => 12)
|
17
|
+
assert_equal 12, @twitter.num_statuses
|
18
|
+
end
|
19
|
+
|
20
|
+
should "raise exception if configured number of status not in allowed range" do
|
21
|
+
assert_raise(ArgumentError) { Twitter.new(:num_statuses => 0) }
|
22
|
+
end
|
23
|
+
|
24
|
+
should "use default page number if not configured otherwise" do
|
25
|
+
@twitter = Twitter.new
|
26
|
+
assert_equal Twitter::DEFAULT_PAGE_NUM, @twitter.page
|
27
|
+
end
|
28
|
+
|
29
|
+
should "use configured page number if in allowed range" do
|
30
|
+
@twitter = Twitter.new(:page => 12)
|
31
|
+
assert_equal 12, @twitter.page
|
32
|
+
end
|
33
|
+
|
34
|
+
should "raise exception if configured page number not in allowed range" do
|
35
|
+
assert_raise(ArgumentError) { Twitter.new(:page => 0) }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "at runtime" do
|
40
|
+
setup do
|
41
|
+
mock_http
|
42
|
+
mock_oauth
|
43
|
+
mock_ui
|
44
|
+
@username = "spiky"
|
45
|
+
@rest_api = mock("Http's REST API")
|
46
|
+
@search_api = mock("Http's Search API")
|
47
|
+
@http.stubs(:as_resource).with("https://api.twitter.com/1").returns(@rest_api)
|
48
|
+
@http.stubs(:as_resource).with("http://search.twitter.com").returns(@search_api)
|
49
|
+
@twitter = Twitter.new(:username => @username)
|
50
|
+
@rest_api_status_query_str = "count=#{Twitter::DEFAULT_NUM_STATUSES}&page=#{Twitter::DEFAULT_PAGE_NUM}"
|
51
|
+
@search_api_query_str = "page=#{Twitter::DEFAULT_PAGE_NUM}&rpp=#{Twitter::DEFAULT_NUM_STATUSES}"
|
52
|
+
end
|
53
|
+
|
54
|
+
should "fetch friends' statuses (home view)" do
|
55
|
+
twitter_records, internal_records = create_test_twitter_status_records_from_rest_api(
|
56
|
+
{
|
57
|
+
:from_user => "zanzibar",
|
58
|
+
:status => "wassup?",
|
59
|
+
:created_at => Time.at(1).to_s,
|
60
|
+
:to_user => nil
|
61
|
+
},
|
62
|
+
{
|
63
|
+
:from_user => "lulzwoo",
|
64
|
+
:status => "nuttin'",
|
65
|
+
:created_at => Time.at(1).to_s,
|
66
|
+
:to_user => nil
|
67
|
+
})
|
68
|
+
@oauth.expects(:request_signer)
|
69
|
+
@rest_api.expects(:[]).
|
70
|
+
with("statuses/home_timeline.json?#{@rest_api_status_query_str}").
|
71
|
+
returns(stub(:get => twitter_records.to_json))
|
72
|
+
@ui.expects(:show_record).with(internal_records[0])
|
73
|
+
@ui.expects(:show_record).with(internal_records[1])
|
74
|
+
@twitter.home
|
75
|
+
end
|
76
|
+
|
77
|
+
should "fetch mentions" do
|
78
|
+
twitter_records, internal_records = create_test_twitter_status_records_from_rest_api(
|
79
|
+
{
|
80
|
+
:from_user => "zanzibar",
|
81
|
+
:status => "wassup, @#{@username}?",
|
82
|
+
:created_at => Time.at(1).to_s,
|
83
|
+
:to_user => @username
|
84
|
+
},
|
85
|
+
{
|
86
|
+
:from_user => "lulzwoo",
|
87
|
+
:status => "@#{@username}, doing nuttin'",
|
88
|
+
:created_at => Time.at(1).to_s,
|
89
|
+
:to_user => @username
|
90
|
+
})
|
91
|
+
@oauth.expects(:request_signer)
|
92
|
+
@rest_api.expects(:[]).
|
93
|
+
with("statuses/mentions.json?#{@rest_api_status_query_str}").
|
94
|
+
returns(stub(:get => twitter_records.to_json))
|
95
|
+
@ui.expects(:show_record).with(internal_records[0])
|
96
|
+
@ui.expects(:show_record).with(internal_records[1])
|
97
|
+
@twitter.mentions
|
98
|
+
end
|
99
|
+
|
100
|
+
should "fetch a specific user's statuses, when user is given as argument" do
|
101
|
+
username = "spoonman"
|
102
|
+
twitter_records, internal_records = create_test_twitter_status_records_from_rest_api({
|
103
|
+
:from_user => username,
|
104
|
+
:status => "wassup?",
|
105
|
+
:created_at => Time.at(1).to_s,
|
106
|
+
:to_user => nil
|
107
|
+
})
|
108
|
+
@oauth.expects(:request_signer)
|
109
|
+
@rest_api.expects(:[]).
|
110
|
+
with("statuses/user_timeline.json?#{@rest_api_status_query_str}&screen_name=#{username}").
|
111
|
+
returns(stub(:get => twitter_records.to_json))
|
112
|
+
@ui.expects(:show_record).with(internal_records[0])
|
113
|
+
@twitter.user(username)
|
114
|
+
end
|
115
|
+
|
116
|
+
should "fetch a specific user's statuses, with user being the authenticated user itself when given no argument" do
|
117
|
+
twitter_records, internal_records = create_test_twitter_status_records_from_rest_api({
|
118
|
+
:from_user => @username,
|
119
|
+
:status => "wassup?",
|
120
|
+
:created_at => Time.at(1).to_s,
|
121
|
+
:to_user => nil
|
122
|
+
})
|
123
|
+
@oauth.expects(:request_signer)
|
124
|
+
@rest_api.expects(:[]).
|
125
|
+
with("statuses/user_timeline.json?#{@rest_api_status_query_str}&screen_name=#{@username}").
|
126
|
+
returns(stub(:get => twitter_records.to_json))
|
127
|
+
@ui.expects(:show_record).with(internal_records[0])
|
128
|
+
@twitter.user
|
129
|
+
end
|
130
|
+
|
131
|
+
context "when posting status updates" do
|
132
|
+
should "post a status update via argument, when positive confirmation" do
|
133
|
+
status = "wondering around"
|
134
|
+
twitter_records, internal_records = create_test_twitter_status_records_from_rest_api({
|
135
|
+
:from_user => @username,
|
136
|
+
:status => status,
|
137
|
+
:created_at => Time.at(1).to_s,
|
138
|
+
:to_user => nil
|
139
|
+
})
|
140
|
+
@oauth.expects(:request_signer)
|
141
|
+
http_subresource = mock
|
142
|
+
http_subresource.expects(:post).
|
143
|
+
with({ :status => status }).
|
144
|
+
returns(twitter_records[0].to_json)
|
145
|
+
@rest_api.expects(:[]).
|
146
|
+
with("statuses/update.json").
|
147
|
+
returns(http_subresource)
|
148
|
+
@ui.expects(:confirm).with("Really send?").returns(true)
|
149
|
+
@ui.expects(:show_status_preview).with(status)
|
150
|
+
@ui.expects(:info).with("Sent status update.\n\n")
|
151
|
+
@ui.expects(:show_record).with(internal_records[0])
|
152
|
+
@twitter.update(status)
|
153
|
+
end
|
154
|
+
|
155
|
+
should "post a status update via prompt, when positive confirmation" do
|
156
|
+
status = "wondering around"
|
157
|
+
twitter_records, internal_records = create_test_twitter_status_records_from_rest_api({
|
158
|
+
:from_user => @username,
|
159
|
+
:status => status,
|
160
|
+
:created_at => Time.at(1).to_s,
|
161
|
+
:to_user => nil
|
162
|
+
})
|
163
|
+
@oauth.expects(:request_signer)
|
164
|
+
http_subresource = mock
|
165
|
+
http_subresource.expects(:post).
|
166
|
+
with({ :status => status }).
|
167
|
+
returns(twitter_records[0].to_json)
|
168
|
+
@rest_api.expects(:[]).
|
169
|
+
with("statuses/update.json").
|
170
|
+
returns(http_subresource)
|
171
|
+
@ui.expects(:prompt).with("Status update").returns(status)
|
172
|
+
@ui.expects(:show_status_preview).with(status)
|
173
|
+
@ui.expects(:confirm).with("Really send?").returns(true)
|
174
|
+
@ui.expects(:info).with("Sent status update.\n\n")
|
175
|
+
@ui.expects(:show_record).with(internal_records[0])
|
176
|
+
@twitter.update
|
177
|
+
end
|
178
|
+
|
179
|
+
should "cancel a status update via argument, when negative confirmation" do
|
180
|
+
status = "wondering around"
|
181
|
+
@rest_api.expects(:[]).never
|
182
|
+
@ui.expects(:show_status_preview).with(status)
|
183
|
+
@ui.expects(:confirm).with("Really send?").returns(false)
|
184
|
+
@ui.expects(:info).with("Cancelled.")
|
185
|
+
@ui.expects(:show_record).never
|
186
|
+
@twitter.update(status)
|
187
|
+
end
|
188
|
+
|
189
|
+
should "cancel a status update via prompt, when negative confirmation" do
|
190
|
+
status = "wondering around"
|
191
|
+
@rest_api.expects(:[]).never
|
192
|
+
@ui.expects(:prompt).with("Status update").returns(status)
|
193
|
+
@ui.expects(:show_status_preview).with(status)
|
194
|
+
@ui.expects(:confirm).with("Really send?").returns(false)
|
195
|
+
@ui.expects(:info).with("Cancelled.")
|
196
|
+
@ui.expects(:show_record).never
|
197
|
+
@twitter.update
|
198
|
+
end
|
199
|
+
|
200
|
+
should "cancel a status update via argument, when empty status" do
|
201
|
+
@rest_api.expects(:[]).never
|
202
|
+
@ui.expects(:prompt).with("Status update").returns("")
|
203
|
+
@ui.expects(:confirm).never
|
204
|
+
@ui.expects(:info).with("Cancelled.")
|
205
|
+
@ui.expects(:show_record).never
|
206
|
+
@twitter.update("")
|
207
|
+
end
|
208
|
+
|
209
|
+
should "cancel a status update via prompt, when empty status" do
|
210
|
+
@rest_api.expects(:[]).never
|
211
|
+
@ui.expects(:prompt).with("Status update").returns("")
|
212
|
+
@ui.expects(:confirm).never
|
213
|
+
@ui.expects(:info).with("Cancelled.")
|
214
|
+
@ui.expects(:show_record).never
|
215
|
+
@twitter.update
|
216
|
+
end
|
217
|
+
|
218
|
+
should "remove excess whitespace around a status update" do
|
219
|
+
whitespaced_status = " oh, i was sloppy \t "
|
220
|
+
stripped_status = "oh, i was sloppy"
|
221
|
+
twitter_records, internal_records = create_test_twitter_status_records_from_rest_api({
|
222
|
+
:from_user => @username,
|
223
|
+
:status => stripped_status,
|
224
|
+
:created_at => Time.at(1).to_s,
|
225
|
+
:to_user => nil
|
226
|
+
})
|
227
|
+
@oauth.expects(:request_signer)
|
228
|
+
http_subresource = mock
|
229
|
+
http_subresource.expects(:post).
|
230
|
+
with({ :status => stripped_status }).
|
231
|
+
returns(twitter_records[0].to_json)
|
232
|
+
@rest_api.expects(:[]).
|
233
|
+
with("statuses/update.json").
|
234
|
+
returns(http_subresource)
|
235
|
+
@ui.expects(:show_status_preview).with(stripped_status)
|
236
|
+
@ui.expects(:confirm).with("Really send?").returns(true)
|
237
|
+
@ui.expects(:info).with("Sent status update.\n\n")
|
238
|
+
@ui.expects(:show_record).with(internal_records[0])
|
239
|
+
@twitter.update(whitespaced_status)
|
240
|
+
end
|
241
|
+
|
242
|
+
should "truncate a status update with too long argument and warn the user" do
|
243
|
+
truncated_status = "ab c" * 35 # 4 * 35 = 140
|
244
|
+
long_status = "#{truncated_status} dd"
|
245
|
+
twitter_records, internal_records = create_test_twitter_status_records_from_rest_api({
|
246
|
+
:from_user => @username,
|
247
|
+
:status => truncated_status,
|
248
|
+
:created_at => Time.at(1).to_s,
|
249
|
+
:to_user => nil
|
250
|
+
})
|
251
|
+
@oauth.expects(:request_signer)
|
252
|
+
http_subresource = mock
|
253
|
+
http_subresource.expects(:post).
|
254
|
+
with({ :status => truncated_status }).
|
255
|
+
returns(twitter_records[0].to_json)
|
256
|
+
@rest_api.expects(:[]).
|
257
|
+
with("statuses/update.json").
|
258
|
+
returns(http_subresource)
|
259
|
+
@ui.expects(:warn).with("Status will be truncated.")
|
260
|
+
@ui.expects(:show_status_preview).with(truncated_status)
|
261
|
+
@ui.expects(:confirm).with("Really send?").returns(true)
|
262
|
+
@ui.expects(:info).with("Sent status update.\n\n")
|
263
|
+
@ui.expects(:show_record).with(internal_records[0])
|
264
|
+
@twitter.update(long_status)
|
265
|
+
end
|
266
|
+
|
267
|
+
if "".respond_to?(:encode)
|
268
|
+
should "encode status in UTF-8 (String supports encoding)" do
|
269
|
+
status_utf8, status_latin1 = "résumé", "résumé".encode('ISO-8859-1')
|
270
|
+
twitter_records, internal_records = create_test_twitter_status_records_from_rest_api({
|
271
|
+
:from_user => @username,
|
272
|
+
:status => status_utf8,
|
273
|
+
:created_at => Time.at(1).to_s,
|
274
|
+
:to_user => nil
|
275
|
+
})
|
276
|
+
@oauth.expects(:request_signer)
|
277
|
+
http_subresource = mock
|
278
|
+
http_subresource.expects(:post).
|
279
|
+
with({ :status => status_utf8 }).
|
280
|
+
returns(twitter_records[0].to_json)
|
281
|
+
@rest_api.expects(:[]).
|
282
|
+
with("statuses/update.json").
|
283
|
+
returns(http_subresource)
|
284
|
+
@ui.expects(:confirm).with("Really send?").returns(true)
|
285
|
+
@ui.expects(:show_status_preview).with(status_latin1)
|
286
|
+
@ui.expects(:info).with("Sent status update.\n\n")
|
287
|
+
@ui.expects(:show_record).with(internal_records[0])
|
288
|
+
@twitter.update(status_latin1)
|
289
|
+
end
|
290
|
+
else
|
291
|
+
should "encode status in UTF-8 (String does not support encoding)" do
|
292
|
+
tmp_kcode('NONE') do
|
293
|
+
tmp_env(:LANG => 'ISO-8859-1') do
|
294
|
+
status_utf8, status_latin1 = "r\xc3\xa9sum\xc3\xa9", "r\xe9sum\xe9"
|
295
|
+
twitter_records, internal_records = create_test_twitter_status_records_from_rest_api({
|
296
|
+
:from_user => @username,
|
297
|
+
:status => status_utf8,
|
298
|
+
:created_at => Time.at(1).to_s,
|
299
|
+
:to_user => nil
|
300
|
+
})
|
301
|
+
@oauth.expects(:request_signer)
|
302
|
+
http_subresource = mock
|
303
|
+
http_subresource.expects(:post).
|
304
|
+
with({ :status => status_utf8 }).
|
305
|
+
returns(twitter_records[0].to_json)
|
306
|
+
@rest_api.expects(:[]).
|
307
|
+
with("statuses/update.json").
|
308
|
+
returns(http_subresource)
|
309
|
+
@ui.expects(:confirm).with("Really send?").returns(true)
|
310
|
+
@ui.expects(:show_status_preview).with(status_latin1)
|
311
|
+
@ui.expects(:info).with("Sent status update.\n\n")
|
312
|
+
@ui.expects(:show_record).with(internal_records[0])
|
313
|
+
@twitter.update(status_latin1)
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
context "with URL shortening" do
|
320
|
+
setup do
|
321
|
+
mock_url_shortener
|
322
|
+
stub_config(
|
323
|
+
:shorten_urls => {
|
324
|
+
:service_url => "http://shorten.it/create",
|
325
|
+
:method => "post",
|
326
|
+
:url_param_name => "url",
|
327
|
+
:xpath_selector => "//input[@id='short_url']/@value"
|
328
|
+
})
|
329
|
+
end
|
330
|
+
|
331
|
+
should "not shorten URLs if not configured" do
|
332
|
+
stub_config
|
333
|
+
status = "reading http://www.w3.org/TR/1999/REC-xpath-19991116"
|
334
|
+
twitter_records, internal_records = create_test_twitter_status_records_from_rest_api({
|
335
|
+
:from_user => @username,
|
336
|
+
:status => status,
|
337
|
+
:created_at => Time.at(1).to_s,
|
338
|
+
:to_user => nil
|
339
|
+
})
|
340
|
+
@oauth.expects(:request_signer)
|
341
|
+
http_subresource = mock
|
342
|
+
http_subresource.expects(:post).
|
343
|
+
with({ :status => status }).
|
344
|
+
returns(twitter_records[0].to_json)
|
345
|
+
@url_shortener.expects(:shorten).never
|
346
|
+
@rest_api.expects(:[]).
|
347
|
+
with("statuses/update.json").
|
348
|
+
returns(http_subresource)
|
349
|
+
@ui.expects(:confirm).with("Really send?").returns(true)
|
350
|
+
@ui.expects(:show_status_preview).with(status)
|
351
|
+
@ui.expects(:info).with("Sent status update.\n\n")
|
352
|
+
@ui.expects(:show_record).with(internal_records[0])
|
353
|
+
@twitter.update(status)
|
354
|
+
end
|
355
|
+
|
356
|
+
should "shorten URLs, avoiding truncation with long URLs" do
|
357
|
+
long_urls = ["http://www.google.fi/search?q=ruby+nokogiri&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:en-US:official&client=firefox-a", "http://www.w3.org/TR/1999/REC-xpath-19991116"]
|
358
|
+
long_status = long_urls.join(" and ")
|
359
|
+
short_urls = ["http://shorten.it/2k7i8", "http://shorten.it/2k7mk"]
|
360
|
+
shortened_status = short_urls.join(" and ")
|
361
|
+
twitter_records, internal_records = create_test_twitter_status_records_from_rest_api({
|
362
|
+
:from_user => @username,
|
363
|
+
:status => shortened_status,
|
364
|
+
:created_at => Time.at(1).to_s,
|
365
|
+
:to_user => nil
|
366
|
+
})
|
367
|
+
@oauth.expects(:request_signer)
|
368
|
+
http_subresource = mock
|
369
|
+
http_subresource.expects(:post).
|
370
|
+
with({ :status => shortened_status }).
|
371
|
+
returns(twitter_records[0].to_json)
|
372
|
+
@rest_api.expects(:[]).
|
373
|
+
with("statuses/update.json").
|
374
|
+
returns(http_subresource)
|
375
|
+
@url_shortener.expects(:shorten).with(long_urls.first).returns(short_urls.first)
|
376
|
+
@url_shortener.expects(:shorten).with(long_urls.last).returns(short_urls.last)
|
377
|
+
@ui.expects(:show_status_preview).with(shortened_status)
|
378
|
+
@ui.expects(:confirm).with("Really send?").returns(true)
|
379
|
+
@ui.expects(:info).with("Sent status update.\n\n")
|
380
|
+
@ui.expects(:show_record).with(internal_records[0])
|
381
|
+
@twitter.update(long_status)
|
382
|
+
end
|
383
|
+
|
384
|
+
should "discard obviously invalid shortened URLs, using originals instead" do
|
385
|
+
long_urls = ["http://www.google.fi/", "http://www.w3.org/TR/1999/REC-xpath-19991116"]
|
386
|
+
status = long_urls.join(" and ")
|
387
|
+
short_urls = [nil, ""]
|
388
|
+
twitter_records, internal_records = create_test_twitter_status_records_from_rest_api({
|
389
|
+
:from_user => @username,
|
390
|
+
:status => status,
|
391
|
+
:created_at => Time.at(1).to_s,
|
392
|
+
:to_user => nil
|
393
|
+
})
|
394
|
+
@oauth.expects(:request_signer)
|
395
|
+
http_subresource = mock
|
396
|
+
http_subresource.expects(:post).
|
397
|
+
with({ :status => status }).
|
398
|
+
returns(twitter_records[0].to_json)
|
399
|
+
@rest_api.expects(:[]).
|
400
|
+
with("statuses/update.json").
|
401
|
+
returns(http_subresource)
|
402
|
+
@url_shortener.expects(:shorten).with(long_urls.first).returns(short_urls.first)
|
403
|
+
@url_shortener.expects(:shorten).with(long_urls.last).returns(short_urls.last)
|
404
|
+
@ui.expects(:show_status_preview).with(status)
|
405
|
+
@ui.expects(:confirm).with("Really send?").returns(true)
|
406
|
+
@ui.expects(:info).with("Sent status update.\n\n")
|
407
|
+
@ui.expects(:show_record).with(internal_records[0])
|
408
|
+
@twitter.update(status)
|
409
|
+
end
|
410
|
+
|
411
|
+
should "reuse a shortened URL for duplicate long URLs" do
|
412
|
+
long_urls = ["http://www.w3.org/TR/1999/REC-xpath-19991116"] * 2
|
413
|
+
long_status = long_urls.join(" and ")
|
414
|
+
short_url = "http://shorten.it/2k7mk"
|
415
|
+
short_status = ([short_url] * 2).join(" and ")
|
416
|
+
twitter_records, internal_records = create_test_twitter_status_records_from_rest_api({
|
417
|
+
:from_user => @username,
|
418
|
+
:status => short_status,
|
419
|
+
:created_at => Time.at(1).to_s,
|
420
|
+
:to_user => nil
|
421
|
+
})
|
422
|
+
@oauth.expects(:request_signer)
|
423
|
+
http_subresource = mock
|
424
|
+
http_subresource.expects(:post).
|
425
|
+
with({ :status => short_status }).
|
426
|
+
returns(twitter_records[0].to_json)
|
427
|
+
@rest_api.expects(:[]).
|
428
|
+
with("statuses/update.json").
|
429
|
+
returns(http_subresource)
|
430
|
+
@url_shortener.expects(:shorten).with(long_urls.first).returns(short_url)
|
431
|
+
@ui.expects(:show_status_preview).with(short_status)
|
432
|
+
@ui.expects(:confirm).with("Really send?").returns(true)
|
433
|
+
@ui.expects(:info).with("Sent status update.\n\n")
|
434
|
+
@ui.expects(:show_record).with(internal_records[0])
|
435
|
+
@twitter.update(long_status)
|
436
|
+
end
|
437
|
+
|
438
|
+
context "in erroneous situations" do
|
439
|
+
setup do
|
440
|
+
@url = "http://www.w3.org/TR/1999/REC-xpath-19991116"
|
441
|
+
@status = "skimming through #{@url}"
|
442
|
+
@twitter_records, @internal_records = create_test_twitter_status_records_from_rest_api({
|
443
|
+
:from_user => @username,
|
444
|
+
:status => @status,
|
445
|
+
:created_at => Time.at(1).to_s,
|
446
|
+
:to_user => nil
|
447
|
+
})
|
448
|
+
end
|
449
|
+
|
450
|
+
should "skip shortening URLs if required libraries are not found" do
|
451
|
+
@oauth.expects(:request_signer)
|
452
|
+
http_subresource = mock
|
453
|
+
http_subresource.expects(:post).
|
454
|
+
with({ :status => @status }).
|
455
|
+
returns(@twitter_records[0].to_json)
|
456
|
+
@rest_api.expects(:[]).
|
457
|
+
with("statuses/update.json").
|
458
|
+
returns(http_subresource)
|
459
|
+
@url_shortener.expects(:shorten).with(@url).raises(LoadError, "gem not found")
|
460
|
+
@ui.expects(:warn)
|
461
|
+
@ui.expects(:show_status_preview).with(@status)
|
462
|
+
@ui.expects(:confirm).with("Really send?").returns(true)
|
463
|
+
@ui.expects(:info).with("Sent status update.\n\n")
|
464
|
+
@ui.expects(:show_record).with(@internal_records[0])
|
465
|
+
@twitter.update(@status)
|
466
|
+
end
|
467
|
+
|
468
|
+
should "skip shortening URLs upon connection error to the URL shortening service" do
|
469
|
+
@oauth.expects(:request_signer)
|
470
|
+
http_subresource = mock
|
471
|
+
http_subresource.expects(:post).
|
472
|
+
with({ :status => @status }).
|
473
|
+
returns(@twitter_records[0].to_json)
|
474
|
+
@rest_api.expects(:[]).
|
475
|
+
with("statuses/update.json").
|
476
|
+
returns(http_subresource)
|
477
|
+
@url_shortener.expects(:shorten).with(@url).raises(HttpError.new(404, "Not Found"))
|
478
|
+
@ui.expects(:warn)
|
479
|
+
@ui.expects(:show_status_preview).with(@status)
|
480
|
+
@ui.expects(:confirm).with("Really send?").returns(true)
|
481
|
+
@ui.expects(:info).with("Sent status update.\n\n")
|
482
|
+
@ui.expects(:show_record).with(@internal_records[0])
|
483
|
+
@twitter.update(@status)
|
484
|
+
end
|
485
|
+
end
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
should "fetch friends" do
|
490
|
+
twitter_records, internal_records = create_test_twitter_user_records_from_rest_api(
|
491
|
+
{
|
492
|
+
:from_user => "zanzibar",
|
493
|
+
:status => "wassup, @foo?",
|
494
|
+
:created_at => Time.at(1).to_s,
|
495
|
+
:to_user => "foo"
|
496
|
+
},
|
497
|
+
{
|
498
|
+
:from_user => "lulzwoo",
|
499
|
+
:status => "@foo, doing nuttin'",
|
500
|
+
:created_at => Time.at(1).to_s,
|
501
|
+
:to_user => "foo"
|
502
|
+
})
|
503
|
+
@oauth.expects(:request_signer)
|
504
|
+
@rest_api.expects(:[]).
|
505
|
+
with("statuses/friends.json?#{@rest_api_status_query_str}").
|
506
|
+
returns(stub(:get => twitter_records.to_json))
|
507
|
+
@ui.expects(:show_record).with(internal_records[0])
|
508
|
+
@ui.expects(:show_record).with(internal_records[1])
|
509
|
+
@twitter.friends
|
510
|
+
end
|
511
|
+
|
512
|
+
should "fetch followers" do
|
513
|
+
twitter_records, internal_records = create_test_twitter_user_records_from_rest_api(
|
514
|
+
{
|
515
|
+
:from_user => "zanzibar",
|
516
|
+
:status => "wassup, @foo?",
|
517
|
+
:created_at => Time.at(1).to_s,
|
518
|
+
:to_user => "foo"
|
519
|
+
},
|
520
|
+
{
|
521
|
+
:from_user => "lulzwoo",
|
522
|
+
:status => nil,
|
523
|
+
:created_at => nil,
|
524
|
+
:to_user => nil
|
525
|
+
})
|
526
|
+
@oauth.expects(:request_signer)
|
527
|
+
@rest_api.expects(:[]).
|
528
|
+
with("statuses/followers.json?#{@rest_api_status_query_str}").
|
529
|
+
returns(stub(:get => twitter_records.to_json))
|
530
|
+
@ui.expects(:show_record).with(internal_records[0])
|
531
|
+
@ui.expects(:show_record).with(internal_records[1])
|
532
|
+
@twitter.followers
|
533
|
+
end
|
534
|
+
|
535
|
+
context "when searching tweets" do
|
536
|
+
should "raise exception if no search word is given" do
|
537
|
+
assert_raise(ArgumentError) { @twitter.search }
|
538
|
+
end
|
539
|
+
|
540
|
+
[
|
541
|
+
[nil, "no operator"],
|
542
|
+
[:and, "and operator"]
|
543
|
+
].each do |op, desc|
|
544
|
+
should "search tweets matching all the given words with #{desc}" do
|
545
|
+
twitter_response, internal_records = create_test_twitter_records_from_search_api(
|
546
|
+
{
|
547
|
+
:from_user => "zanzibar",
|
548
|
+
:status => "@foo, wassup? #greets",
|
549
|
+
:created_at => Time.at(1).to_s,
|
550
|
+
:to_user => "foo"
|
551
|
+
},
|
552
|
+
{
|
553
|
+
:from_user => "spoonman",
|
554
|
+
:status => "@foo long time no see #greets",
|
555
|
+
:created_at => Time.at(1).to_s,
|
556
|
+
:to_user => "foo"
|
557
|
+
})
|
558
|
+
@search_api.expects(:[]).
|
559
|
+
with("search.json?q=%23greets%20%40foo&#{@search_api_query_str}").
|
560
|
+
returns(stub(:get => twitter_response.to_json))
|
561
|
+
@ui.expects(:show_record).with(internal_records[0])
|
562
|
+
@ui.expects(:show_record).with(internal_records[1])
|
563
|
+
@twitter.search(["#greets", "@foo"], op)
|
564
|
+
end
|
565
|
+
end
|
566
|
+
|
567
|
+
should "search tweets matching any of the given words with or operator" do
|
568
|
+
twitter_response, internal_records = create_test_twitter_records_from_search_api(
|
569
|
+
{
|
570
|
+
:from_user => "zanzibar",
|
571
|
+
:status => "spinning around the floor #habits",
|
572
|
+
:created_at => Time.at(1).to_s,
|
573
|
+
:to_user => "foo"
|
574
|
+
},
|
575
|
+
{
|
576
|
+
:from_user => "spoonman",
|
577
|
+
:status => "drinking coffee, again #neurotic",
|
578
|
+
:created_at => Time.at(1).to_s,
|
579
|
+
:to_user => "foo"
|
580
|
+
})
|
581
|
+
@search_api.expects(:[]).
|
582
|
+
with("search.json?q=%23habits%20OR%20%23neurotic&#{@search_api_query_str}").
|
583
|
+
returns(stub(:get => twitter_response.to_json))
|
584
|
+
@ui.expects(:show_record).with(internal_records[0])
|
585
|
+
@ui.expects(:show_record).with(internal_records[1])
|
586
|
+
@twitter.search(["#habits", "#neurotic"], :or)
|
587
|
+
end
|
588
|
+
end
|
589
|
+
|
590
|
+
context "when authorization fails with HTTP 401 response" do
|
591
|
+
setup do
|
592
|
+
mock_config
|
593
|
+
end
|
594
|
+
|
595
|
+
should "authorize with OAuth and save config" do
|
596
|
+
twitter_records, internal_records = create_test_twitter_status_records_from_rest_api({
|
597
|
+
:from_user => @username,
|
598
|
+
:status => "wassup?",
|
599
|
+
:created_at => Time.at(1).to_s,
|
600
|
+
:to_user => nil
|
601
|
+
})
|
602
|
+
access_token = 'access token'
|
603
|
+
user_has_authorized = states('User has authorized?').starts_as(false)
|
604
|
+
@oauth.expects(:request_signer).twice
|
605
|
+
@oauth.expects(:authorize).
|
606
|
+
yields(access_token).
|
607
|
+
then(user_has_authorized.is(true))
|
608
|
+
http_subresource = mock
|
609
|
+
http_subresource.expects(:get).
|
610
|
+
raises(HttpError.new(401, 'Unauthorized')).
|
611
|
+
when(user_has_authorized.is(false))
|
612
|
+
http_subresource.expects(:get).
|
613
|
+
returns(twitter_records.to_json).
|
614
|
+
when(user_has_authorized.is(true))
|
615
|
+
@rest_api.expects(:[]).returns(http_subresource)
|
616
|
+
@config.expects(:[]=).with(:oauth_access, access_token)
|
617
|
+
@config.expects(:save)
|
618
|
+
@ui.expects(:show_record).with(internal_records[0])
|
619
|
+
@twitter.home
|
620
|
+
end
|
621
|
+
end
|
622
|
+
end
|
623
|
+
end
|
624
|
+
|
625
|
+
end
|