tweetwine 0.4.2 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/CHANGELOG.rdoc +5 -0
  2. data/Gemfile +1 -1
  3. data/README.md +2 -2
  4. data/Rakefile +5 -0
  5. data/benchmark/home_bm.rb +36 -0
  6. data/lib/tweetwine/character_encoding.rb +1 -1
  7. data/lib/tweetwine/http.rb +1 -1
  8. data/lib/tweetwine/support.rb +28 -26
  9. data/lib/tweetwine/twitter.rb +8 -5
  10. data/lib/tweetwine/version.rb +1 -1
  11. data/lib/tweetwine.rb +0 -2
  12. data/man/tweetwine.7 +3 -3
  13. data/man/tweetwine.7.ronn +2 -2
  14. data/project.rb +2 -0
  15. data/test/fixture/config_integration.yaml +1 -1
  16. data/test/integration/authorization_test.rb +1 -1
  17. data/test/integration/global_options_test.rb +1 -1
  18. data/test/integration/invalid_config_file_test.rb +1 -1
  19. data/test/integration/search_statuses_test.rb +1 -1
  20. data/test/integration/show_followers_test.rb +1 -1
  21. data/test/integration/show_friends_test.rb +1 -1
  22. data/test/integration/show_home_test.rb +1 -1
  23. data/test/integration/show_mentions_test.rb +1 -1
  24. data/test/integration/show_user_test.rb +1 -1
  25. data/test/integration/update_status_test.rb +42 -21
  26. data/test/integration/use_http_proxy_test.rb +6 -6
  27. data/test/integration/user_help_test.rb +2 -2
  28. data/test/support/assertions.rb +58 -0
  29. data/test/support/common.rb +10 -0
  30. data/test/support/common_helpers.rb +43 -0
  31. data/test/support/doubles.rb +35 -0
  32. data/test/{integration/helper.rb → support/integration_test_case.rb} +12 -7
  33. data/test/support/mocha_integration.rb +16 -0
  34. data/test/support/tweets.rb +95 -0
  35. data/test/support/unit_test_case.rb +28 -0
  36. data/test/support/webmock_integration.rb +16 -0
  37. data/test/unit/character_encoding_test.rb +1 -1
  38. data/test/unit/cli_test.rb +4 -4
  39. data/test/unit/config_test.rb +1 -1
  40. data/test/unit/http_test.rb +1 -1
  41. data/test/unit/oauth_test.rb +1 -1
  42. data/test/unit/obfuscate_test.rb +1 -1
  43. data/test/unit/option_parser_test.rb +1 -1
  44. data/test/unit/promise_test.rb +1 -1
  45. data/test/unit/support_test.rb +1 -1
  46. data/test/unit/tweet_test.rb +3 -3
  47. data/test/unit/twitter_test.rb +29 -27
  48. data/test/unit/ui_test.rb +3 -3
  49. data/test/unit/uri_test.rb +1 -1
  50. data/test/unit/url_shortener_test.rb +1 -1
  51. data/tweetwine.gemspec +5 -4
  52. metadata +122 -97
  53. data/test/helper.rb +0 -60
  54. data/test/unit/helper.rb +0 -108
  55. data/test/unit/tweet_helper.rb +0 -95
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,8 @@
1
+ === 0.4.3 released 2011-11-01
2
+
3
+ * Warn if URL shortening results in no shortened URL
4
+ * Minor cleanups
5
+
1
6
  === 0.4.2 released 2011-05-18
2
7
 
3
8
  * Fail graciously if config file is invalid
data/Gemfile CHANGED
@@ -6,4 +6,4 @@ gemspec
6
6
 
7
7
  # Special handling at runtime.
8
8
  gem 'json', '>= 1.0.0', :platforms => [:ruby_18, :jruby]
9
- gem 'nokogiri', '~> 1.4.4'
9
+ gem 'nokogiri', '~> 1.5.0'
data/README.md CHANGED
@@ -24,7 +24,7 @@ Install Tweetwine with RubyGems:
24
24
 
25
25
  $ gem install tweetwine
26
26
 
27
- The program is tested with Ruby 1.8.7 and 1.9.2.
27
+ The program is tested with MRI 1.8.7, 1.9.2, and 1.9.3.
28
28
 
29
29
  The program requires [oauth](http://oauth.rubyforge.org/) gem to be installed.
30
30
  In addition, the program needs a JSON parser library, such as
@@ -81,7 +81,7 @@ enabled via `shorten_urls` field in the configuration file; for example:
81
81
  shorten_urls:
82
82
  service_url: http://is.gd/create.php
83
83
  method: post
84
- url_param_name: URL
84
+ url_param_name: url
85
85
  xpath_selector: //input[@id='short_url']/@value
86
86
  disable: false # optional
87
87
 
data/Rakefile CHANGED
@@ -80,6 +80,11 @@ namespace :test do
80
80
  task :all => [:unit, :integration]
81
81
  end
82
82
 
83
+ desc "Profile fetching home timeline"
84
+ task :profile do
85
+ sh %{bundle exec ruby -I lib -I test benchmark/home_bm.rb}
86
+ end
87
+
83
88
  desc "Find code smells"
84
89
  task :roodi do
85
90
  sh %{roodi "**/*.rb"}
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+ # coding: utf-8
3
+
4
+ require 'tweetwine'
5
+ require 'perftools'
6
+ require 'support/common_helpers'
7
+ require 'webmock'
8
+
9
+ WebMock.disable_net_connect!
10
+
11
+ module Driver
12
+ extend WebMock::API
13
+ extend Tweetwine::Test::CommonHelpers
14
+
15
+ def self.run
16
+ stub_http_request(:get, "https://api.twitter.com/1/statuses/home_timeline.json?count=20&page=1").to_return(:body => fixture_file('home.json'))
17
+ yield
18
+ ensure
19
+ WebMock.reset!
20
+ end
21
+ end
22
+
23
+ Driver.run do
24
+ output_path = "/tmp/tweetwine_home_bm"
25
+
26
+ PerfTools::CpuProfiler.start(output_path) do
27
+ 1_000.times do
28
+ Tweetwine::CLI.start %w{home}
29
+ end
30
+ end
31
+
32
+ system %{pprof.rb --gif #{output_path} > #{output_path}.gif}
33
+
34
+ puts "Profiling output: #{output_path}"
35
+ puts "Visualization: #{output_path}.gif"
36
+ end
@@ -1,7 +1,7 @@
1
1
  # coding: utf-8
2
2
 
3
3
  module Tweetwine
4
- class CharacterEncoding
4
+ module CharacterEncoding
5
5
  class << self
6
6
  if defined? Encoding
7
7
  def to_utf8(str)
@@ -17,7 +17,7 @@ module Tweetwine
17
17
  if retries < max_retries
18
18
  retries += 1
19
19
  timeout = retry_base_wait_timeout**retries
20
- CLI.ui.warn("Could not connect -- retrying in #{timeout} seconds")
20
+ CLI.ui.warn "Could not connect -- retrying in #{timeout} seconds"
21
21
  sleep timeout
22
22
  retry
23
23
  else
@@ -36,15 +36,15 @@ module Tweetwine
36
36
  else [(difference/86400.0).round, "day"]
37
37
  end
38
38
 
39
- [value, pluralize_unit(value, unit)]
39
+ [value, Helper.pluralize_unit(value, unit)]
40
40
  end
41
41
 
42
42
  def stringify_hash_keys(hash)
43
- recursive_copy_hash(hash) { |key, value| [key.to_s, value] }
43
+ Helper.recursive_copy_hash(hash) { |key, value| [key.to_s, value] }
44
44
  end
45
45
 
46
46
  def symbolize_hash_keys(hash)
47
- recursive_copy_hash(hash) { |key, value| [key.to_sym, value] }
47
+ Helper.recursive_copy_hash(hash) { |key, value| [key.to_sym, value] }
48
48
  end
49
49
 
50
50
  def parse_int_gt(value, default, min, name_for_error)
@@ -64,7 +64,7 @@ module Tweetwine
64
64
  dup_str = str.dup
65
65
  str_pos, dup_pos = 0, 0
66
66
  while str_pos < str.size && (match_data = regexp.match(str[str_pos..-1]))
67
- matching_group_indexes = indexes_of_filled_matches(match_data)
67
+ matching_group_indexes = Helper.indexes_of_filled_matches(match_data)
68
68
 
69
69
  matching_group_indexes.each do |i|
70
70
  replacement = (yield match_data[i]).to_s
@@ -93,30 +93,32 @@ module Tweetwine
93
93
  end
94
94
  end
95
95
 
96
- private
97
-
98
- def recursive_copy_hash(hash, &pair_modifier)
99
- hash.inject({}) do |result, pair|
100
- value = pair.last
101
- value = recursive_copy_hash(value, &pair_modifier) if value.is_a? Hash
102
- key, value = pair_modifier.call(pair.first, value)
103
- result[key] = value
104
- result
105
- end
106
- end
96
+ module Helper
97
+ class << self
98
+ def recursive_copy_hash(hash, &pair_modifier)
99
+ hash.inject({}) do |result, pair|
100
+ value = pair.last
101
+ value = recursive_copy_hash(value, &pair_modifier) if value.is_a? Hash
102
+ key, value = pair_modifier.call(pair.first, value)
103
+ result[key] = value
104
+ result
105
+ end
106
+ end
107
107
 
108
- def pluralize_unit(value, unit)
109
- if %w{hour day}.include?(unit) && value > 1
110
- unit = unit + 's'
111
- end
112
- unit
113
- end
108
+ def pluralize_unit(value, unit)
109
+ if %w{hour day}.include?(unit) && value > 1
110
+ unit = unit + 's'
111
+ end
112
+ unit
113
+ end
114
114
 
115
- def indexes_of_filled_matches(match_data)
116
- if match_data.size > 1
117
- (1...match_data.size).to_a.reject { |i| match_data[i].nil? }
118
- else
119
- [0]
115
+ def indexes_of_filled_matches(match_data)
116
+ if match_data.size > 1
117
+ (1...match_data.size).to_a.reject { |i| match_data[i].nil? }
118
+ else
119
+ [0]
120
+ end
121
+ end
120
122
  end
121
123
  end
122
124
  end
@@ -184,8 +184,8 @@ module Tweetwine
184
184
  status.dup
185
185
  end
186
186
  status.strip!
187
- shorten_urls_in(status) if CLI.config[:shorten_urls] && !CLI.config[:shorten_urls][:disable]
188
- truncate_status(status) if status.length > MAX_STATUS_LENGTH
187
+ shorten_urls_in status if CLI.config[:shorten_urls] && !CLI.config[:shorten_urls][:disable]
188
+ truncate_status status if status.length > MAX_STATUS_LENGTH
189
189
  status
190
190
  end
191
191
 
@@ -193,9 +193,12 @@ module Tweetwine
193
193
  url_pairs = Uri.
194
194
  extract(status, %w{http https}).
195
195
  uniq.
196
- map { |full_url| [full_url, CLI.url_shortener.shorten(full_url)] }.
197
- reject { |(full_url, short_url)| Support.blank? short_url }
198
- url_pairs.each { |(full_url, short_url)| status.gsub!(full_url, short_url) }
196
+ map { |url| [ url, CLI.url_shortener.shorten(url) ] }
197
+ failed, succeeded = *url_pairs.partition do |(full_url, short_url)|
198
+ Support.blank? short_url or full_url == short_url
199
+ end
200
+ failed.each { |(full_url, _)| CLI.ui.warn "No short URL for #{full_url}" }
201
+ succeeded.each { |(full_url, short_url)| status.gsub! full_url, short_url }
199
202
  rescue HttpError, LoadError => e
200
203
  CLI.ui.warn "#{e}\nSkipping URL shortening..."
201
204
  end
@@ -1,7 +1,7 @@
1
1
  # coding: utf-8
2
2
 
3
3
  module Tweetwine
4
- VERSION = '0.4.2'.freeze
4
+ VERSION = '0.4.3'.freeze
5
5
 
6
6
  class << self
7
7
  def version
data/lib/tweetwine.rb CHANGED
@@ -6,8 +6,6 @@ rescue LoadError
6
6
  raise 'Could not load JSON library; do you have one installed as a gem?'
7
7
  end unless defined? JSON
8
8
 
9
- gem 'oauth', '~> 0.4.4'
10
-
11
9
  require 'tweetwine/version'
12
10
 
13
11
  module Tweetwine
data/man/tweetwine.7 CHANGED
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "TWEETWINE" "7" "February 2011" "Tuomas Kareinen" "Tweetwine Manual"
4
+ .TH "TWEETWINE" "7" "November 2011" "Tuomas Kareinen" "Tweetwine Manual"
5
5
  .
6
6
  .SH "DESCRIPTION"
7
7
  Tweetwine shows the latest tweets from the command line quickly\.
@@ -40,7 +40,7 @@ $ gem install tweetwine
40
40
  .IP "" 0
41
41
  .
42
42
  .P
43
- The program is tested with Ruby 1\.8\.7 and 1\.9\.2\.
43
+ The program is tested with MRI 1\.8\.7, 1\.9\.2, and 1\.9\.3\.
44
44
  .
45
45
  .P
46
46
  The program requires oauth \fIhttp://oauth\.rubyforge\.org/\fR gem to be installed\. In addition, the program needs a JSON parser library, such as json \fIhttp://json\.rubyforge\.org/\fR gem, on Ruby 1\.8\.
@@ -130,7 +130,7 @@ show_reverse: true
130
130
  shorten_urls:
131
131
  service_url: http://is\.gd/create\.php
132
132
  method: post
133
- url_param_name: URL
133
+ url_param_name: url
134
134
  xpath_selector: //input[@id=\'short_url\']/@value
135
135
  disable: false # optional
136
136
  .
data/man/tweetwine.7.ronn CHANGED
@@ -24,7 +24,7 @@ Install Tweetwine with RubyGems:
24
24
 
25
25
  $ gem install tweetwine
26
26
 
27
- The program is tested with Ruby 1.8.7 and 1.9.2.
27
+ The program is tested with MRI 1.8.7, 1.9.2, and 1.9.3.
28
28
 
29
29
  The program requires [oauth](http://oauth.rubyforge.org/) gem to be installed.
30
30
  In addition, the program needs a JSON parser library, such as
@@ -81,7 +81,7 @@ enabled via `shorten_urls` field in the configuration file; for example:
81
81
  shorten_urls:
82
82
  service_url: http://is.gd/create.php
83
83
  method: post
84
- url_param_name: URL
84
+ url_param_name: url
85
85
  xpath_selector: //input[@id='short_url']/@value
86
86
  disable: false # optional
87
87
 
data/project.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  # coding: utf-8
2
2
 
3
3
  name = 'tweetwine'
4
+ # Add lib dir to $LOAD_PATH so that `require 'tweetwine/version'`
5
+ # (executed in tests) loads the version file only once on MRI 1.8.7.
4
6
  $LOAD_PATH.unshift File.expand_path('lib', File.dirname(__FILE__))
5
7
  require "#{name}/version"
6
8
 
@@ -4,5 +4,5 @@ colors: false
4
4
  shorten_urls:
5
5
  service_url: http://is.gd/create.php
6
6
  method: post
7
- url_param_name: URL
7
+ url_param_name: url
8
8
  xpath_selector: //input[@id='short_url']/@value
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'integration/helper'
3
+ require 'support/integration_test_case'
4
4
  require 'fixture/oauth'
5
5
 
6
6
  module Tweetwine::Test::Integration
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'integration/helper'
3
+ require 'support/integration_test_case'
4
4
 
5
5
  module Tweetwine::Test::Integration
6
6
 
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'integration/helper'
3
+ require 'support/integration_test_case'
4
4
  require 'fileutils'
5
5
 
6
6
  module Tweetwine::Test::Integration
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'integration/helper'
3
+ require 'support/integration_test_case'
4
4
 
5
5
  module Tweetwine::Test::Integration
6
6
 
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'integration/helper'
3
+ require 'support/integration_test_case'
4
4
 
5
5
  module Tweetwine::Test::Integration
6
6
 
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'integration/helper'
3
+ require 'support/integration_test_case'
4
4
 
5
5
  module Tweetwine::Test::Integration
6
6
 
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'integration/helper'
3
+ require 'support/integration_test_case'
4
4
 
5
5
  module Tweetwine::Test::Integration
6
6
 
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'integration/helper'
3
+ require 'support/integration_test_case'
4
4
 
5
5
  module Tweetwine::Test::Integration
6
6
 
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'integration/helper'
3
+ require 'support/integration_test_case'
4
4
 
5
5
  module Tweetwine::Test::Integration
6
6
 
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'integration/helper'
3
+ require 'support/integration_test_case'
4
4
  require 'yaml'
5
5
 
6
6
  module Tweetwine::Test::Integration
@@ -8,17 +8,14 @@ module Tweetwine::Test::Integration
8
8
  class UpdateStatusTest < TestCase
9
9
  RUBYGEMS_FIXTURE = fixture_file 'shorten_rubygems.html'
10
10
  RUBYGEMS_FULL_URL = 'http://rubygems.org/'
11
- RUBYGEMS_FULL_URL_ENC = 'http%3a%2f%2frubygems.org%2f'
12
11
  RUBYGEMS_SHORT_URL = 'http://is.gd/gGazV'
13
- RUBYGEMS_SHORT_URL_ENC = 'http%3a%2f%2fis.gd%2fgGazV'
14
12
  RUBYLANG_FIXTURE = fixture_file 'shorten_rubylang.html'
15
13
  RUBYLANG_FULL_URL = 'http://ruby-lang.org/'
16
- RUBYLANG_FULL_URL_ENC = 'http%3a%2f%2fruby-lang.org%2f'
17
14
  RUBYLANG_SHORT_URL = 'http://is.gd/gGaM3'
18
- RUBYLANG_SHORT_URL_ENC = 'http%3a%2f%2fis.gd%2fgGaM3'
19
15
  SHORTEN_CONFIG = read_shorten_config
20
16
  SHORTEN_METHOD = SHORTEN_CONFIG[:method].to_sym
21
17
  STATUS_WITH_FULL_URLS = "ruby links: #{RUBYGEMS_FULL_URL} #{RUBYLANG_FULL_URL}"
18
+ STATUS_WITH_MIXED_URLS = "ruby links: #{RUBYGEMS_SHORT_URL} #{RUBYLANG_FULL_URL}"
22
19
  STATUS_WITH_SHORT_URLS = "ruby links: #{RUBYGEMS_SHORT_URL} #{RUBYLANG_SHORT_URL}"
23
20
  STATUS_WITHOUT_URLS = "bored. going to sleep."
24
21
  UPDATE_FIXTURE_WITH_URLS = fixture_file 'update_with_urls.json'
@@ -26,8 +23,9 @@ class UpdateStatusTest < TestCase
26
23
  UPDATE_FIXTURE_UTF8 = fixture_file 'update_utf8.json'
27
24
  UPDATE_URL = "https://api.twitter.com/1/statuses/update.json"
28
25
 
29
- BODY_WITH_SHORT_URLS = "status=ruby%20links%3a%20#{RUBYGEMS_SHORT_URL_ENC}%20#{RUBYLANG_SHORT_URL_ENC}"
30
- BODY_WITHOUT_URLS = "status=bored.%20going%20to%20sleep."
26
+ BODY_WITH_SHORT_URLS = { 'status' => STATUS_WITH_SHORT_URLS }
27
+ BODY_WITH_MIXED_URLS = { 'status' => STATUS_WITH_MIXED_URLS }
28
+ BODY_WITHOUT_URLS = { 'status' => STATUS_WITHOUT_URLS }
31
29
 
32
30
  describe "update my status from command line with colorization disabled" do
33
31
  before do
@@ -111,8 +109,7 @@ class UpdateStatusTest < TestCase
111
109
  before do
112
110
  @status_utf8 = "résumé"
113
111
  @status_latin1 = @status_utf8.encode('ISO-8859-1')
114
- url_encoded_body = "status=r%c3%a9sum%c3%a9"
115
- stub_http_request(:post, UPDATE_URL).with(:body => url_encoded_body).to_return(:body => UPDATE_FIXTURE_UTF8)
112
+ stub_http_request(:post, UPDATE_URL).with(:body => { 'status' => @status_utf8 }).to_return(:body => UPDATE_FIXTURE_UTF8)
116
113
  at_snapshot do
117
114
  @output = start_cli %W{--no-colors update #{@status_latin1}}, %w{y}
118
115
  end
@@ -131,8 +128,7 @@ class UpdateStatusTest < TestCase
131
128
  before do
132
129
  @status_latin1 = "r\xe9sum\xe9"
133
130
  @status_utf8 = "r\xc3\xa9sum\xc3\xa9"
134
- url_encoded_body = "status=r%c3%a9sum%c3%a9"
135
- stub_http_request(:post, UPDATE_URL).with(:body => url_encoded_body).to_return(:body => UPDATE_FIXTURE_UTF8)
131
+ stub_http_request(:post, UPDATE_URL).with(:body => { 'status' => @status_utf8 }).to_return(:body => UPDATE_FIXTURE_UTF8)
136
132
  tmp_kcode('NONE') do
137
133
  tmp_env(:LANG => 'latin1') do
138
134
  Tweetwine::CharacterEncoding.forget_guess
@@ -153,14 +149,7 @@ class UpdateStatusTest < TestCase
153
149
 
154
150
  describe "shorten URLs in status update" do
155
151
  before do
156
- @shorten_rubygems_body = "#{SHORTEN_CONFIG[:url_param_name]}=#{RUBYGEMS_FULL_URL_ENC}"
157
- @shorten_rubylang_body = "#{SHORTEN_CONFIG[:url_param_name]}=#{RUBYLANG_FULL_URL_ENC}"
158
- stub_http_request(SHORTEN_METHOD, SHORTEN_CONFIG[:service_url]).
159
- with(:body => @shorten_rubygems_body).
160
- to_return(:body => RUBYGEMS_FIXTURE)
161
- stub_http_request(SHORTEN_METHOD, SHORTEN_CONFIG[:service_url]).
162
- with(:body => @shorten_rubylang_body).
163
- to_return(:body => RUBYLANG_FIXTURE)
152
+ stub_url_shortening(:rubygems => RUBYGEMS_FIXTURE, :rubylang => RUBYLANG_FIXTURE)
164
153
  stub_http_request(:post, UPDATE_URL).
165
154
  with(:body => BODY_WITH_SHORT_URLS).
166
155
  to_return(:body => UPDATE_FIXTURE_WITH_URLS)
@@ -170,14 +159,31 @@ class UpdateStatusTest < TestCase
170
159
  end
171
160
 
172
161
  it "shortens the URLs in the status before sending it" do
173
- assert_requested(SHORTEN_METHOD, SHORTEN_CONFIG[:service_url], :body => @shorten_rubygems_body)
174
- assert_requested(SHORTEN_METHOD, SHORTEN_CONFIG[:service_url], :body => @shorten_rubylang_body)
162
+ assert_requested(SHORTEN_METHOD, SHORTEN_CONFIG[:service_url], :body => @request_bodies[:rubygems])
163
+ assert_requested(SHORTEN_METHOD, SHORTEN_CONFIG[:service_url], :body => @request_bodies[:rubylang])
175
164
  @output[1].must_equal STATUS_WITH_SHORT_URLS
176
165
  @output[5].must_equal "#{USER}, 9 hours ago:"
177
166
  @output[6].must_equal STATUS_WITH_SHORT_URLS
178
167
  end
179
168
  end
180
169
 
170
+ describe "warn if URL shortening results in no shortened URL in status update" do
171
+ before do
172
+ stub_url_shortening(:rubygems => RUBYGEMS_FIXTURE, :rubylang => '')
173
+ stub_http_request(:post, UPDATE_URL).
174
+ with(:body => BODY_WITH_MIXED_URLS).
175
+ to_return(:body => UPDATE_FIXTURE_WITH_URLS)
176
+ at_snapshot do
177
+ @output = start_cli %W{--no-colors update #{STATUS_WITH_FULL_URLS}}, %w{y}
178
+ end
179
+ end
180
+
181
+ it "warns which URL was not shortened, falling back to using the original URL" do
182
+ @output[0].must_equal "Warning: No short URL for #{RUBYLANG_FULL_URL}"
183
+ @output[2].must_equal STATUS_WITH_MIXED_URLS
184
+ end
185
+ end
186
+
181
187
  describe "disable URL shortening for status updates" do
182
188
  before do
183
189
  stub_http_request(:post, UPDATE_URL).
@@ -194,6 +200,21 @@ class UpdateStatusTest < TestCase
194
200
  @output[6].must_equal STATUS_WITH_SHORT_URLS
195
201
  end
196
202
  end
203
+
204
+ private
205
+
206
+ def stub_url_shortening(response_bodies)
207
+ @request_bodies = {
208
+ :rubygems => { SHORTEN_CONFIG[:url_param_name] => RUBYGEMS_FULL_URL },
209
+ :rubylang => { SHORTEN_CONFIG[:url_param_name] => RUBYLANG_FULL_URL }
210
+ }
211
+ stub_http_request(SHORTEN_METHOD, SHORTEN_CONFIG[:service_url]).
212
+ with(:body => @request_bodies[:rubygems]).
213
+ to_return(:body => response_bodies[:rubygems])
214
+ stub_http_request(SHORTEN_METHOD, SHORTEN_CONFIG[:service_url]).
215
+ with(:body => @request_bodies[:rubylang]).
216
+ to_return(:body => response_bodies[:rubylang])
217
+ end
197
218
  end
198
219
 
199
220
  end
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'integration/helper'
3
+ require 'support/integration_test_case'
4
4
 
5
5
  module Tweetwine::Test::Integration
6
6
 
@@ -22,7 +22,7 @@ class UseHttpProxyTest < TestCase
22
22
  end
23
23
 
24
24
  it "uses the proxy to fetch my home timeline" do
25
- must_use_proxy
25
+ assert_use_proxy
26
26
  end
27
27
  end
28
28
 
@@ -33,7 +33,7 @@ class UseHttpProxyTest < TestCase
33
33
  end
34
34
 
35
35
  it "uses the proxy to fetch my home timeline" do
36
- must_use_proxy
36
+ assert_use_proxy
37
37
  end
38
38
  end
39
39
 
@@ -50,16 +50,16 @@ class UseHttpProxyTest < TestCase
50
50
 
51
51
  private
52
52
 
53
- def must_use_proxy
53
+ def assert_use_proxy
54
54
  nh = net_http
55
- nh.proxy_class?.must_equal true
55
+ assert nh.proxy_class?
56
56
  nh.instance_variable_get(:@proxy_address).must_equal PROXY_HOST
57
57
  nh.instance_variable_get(:@proxy_port).must_equal PROXY_PORT
58
58
  assert_requested(:get, HOME_URL)
59
59
  end
60
60
 
61
61
  def refute_use_proxy
62
- net_http.proxy_class?.must_equal false
62
+ refute net_http.proxy_class?
63
63
  assert_requested(:get, HOME_URL)
64
64
  end
65
65
 
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'integration/helper'
3
+ require 'support/integration_test_case'
4
4
 
5
5
  module Tweetwine::Test::Integration
6
6
 
@@ -14,7 +14,7 @@ class UserHelpTest < TestCase
14
14
  end
15
15
 
16
16
  it "shows version and exists with success status" do
17
- @output.must_match(/\d+\.\d+\.\d+$/)
17
+ @output.must_match(/\d+\.\d+\.\d+[\w\.]*$/)
18
18
  @status.exitstatus.must_equal 0
19
19
  end
20
20
  end
@@ -0,0 +1,58 @@
1
+ # coding: utf-8
2
+
3
+ module Tweetwine::Test
4
+ module Assertions
5
+ # Asserts whether an Enumeration-like object contains all the elements.
6
+ # Fails unless +actual+ contains the same elements as +expected+,
7
+ # ignoring the order of the elements.
8
+ def assert_contains_exactly(expected, actual, msg_diff_size = nil, msg_diff_elems = nil)
9
+ assert_equal(expected.size, actual.size, message(msg_diff_size) {
10
+ 'Expected %s to be of same size as %s' % [actual.inspect, expected.inspect]
11
+ })
12
+ assert(Assertions.enumerable_minus_each_element(actual, expected).empty?, message(msg_diff_elems) {
13
+ 'Expected %s to contain all the elements of %s' % [actual.inspect, expected.inspect]
14
+ })
15
+ end
16
+
17
+ # Fails unless +str+ is a full match to +regex+.
18
+ def assert_full_match(regex, str, msg = nil)
19
+ match_data = regex.match(str)
20
+ assert(str == match_data.to_s, message(msg) {
21
+ 'Expected %s to be a full match to %s' % [str, regex.inspect]
22
+ })
23
+ end
24
+
25
+ # Fails if +str+ is a full match to +regex+.
26
+ def assert_no_full_match(regex, str, msg = nil)
27
+ match_data = regex.match(str)
28
+ assert(str != match_data.to_s, message(msg) {
29
+ 'Expected %s not to be a full match to %s' % [str, regex.inspect]
30
+ })
31
+ end
32
+
33
+ # Fails unless +fun.call(*args)+ is equal to +expected+ and
34
+ # +fun.call(*args)+ is equal to +fun.call(*args.reverse)+.
35
+ def assert_commutative(expected, args, msg_not_expected = nil, msg_not_commutative = nil, &fun)
36
+ left_args = args
37
+ left_actual = fun.call(left_args)
38
+ assert_equal(expected, left_actual, message(msg_not_expected) {
39
+ 'Expected %s, not %s' % [expected.inspect, left_actual.inspect]
40
+ })
41
+ right_args = args.reverse
42
+ right_actual = fun.call(*right_args)
43
+ assert_equal(left_actual, right_actual, message(msg_not_commutative) {
44
+ 'Expected fun%s => %s to be commutative with fun%s => %s' %
45
+ [left_args.inspect, left_actual.inspect, right_args.inspect, right_actual.inspect]
46
+ })
47
+ end
48
+
49
+ def self.enumerable_minus_each_element(enumerable, elements)
50
+ remaining = enumerable.dup.to_a
51
+ elements.each do |e|
52
+ index = remaining.index(e)
53
+ remaining.delete_at(index) if index
54
+ end
55
+ remaining
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,10 @@
1
+ # coding: utf-8
2
+
3
+ require 'minitest/spec'
4
+ require 'tweetwine'
5
+
6
+ module Tweetwine
7
+ module Test; end
8
+ end
9
+
10
+ MiniTest::Unit.autorun