tweetwine 0.4.2 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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