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
@@ -0,0 +1,43 @@
1
+ # coding: utf-8
2
+
3
+ module Tweetwine::Test
4
+ module CommonHelpers
5
+ FIXTURE_DIR = File.join File.dirname(__FILE__), '..', 'fixture'
6
+
7
+ def file_mode(file)
8
+ File.stat(file).mode & 0777
9
+ end
10
+
11
+ def fixture_path(filename)
12
+ File.join FIXTURE_DIR, filename
13
+ end
14
+
15
+ def fixture_file(filename)
16
+ File.open(fixture_path(filename)) do |f|
17
+ f.readlines.join("\n")
18
+ end
19
+ end
20
+
21
+ def tmp_env(vars = {})
22
+ originals = {}
23
+ vars.each_pair do |key, value|
24
+ key = key.to_s
25
+ originals[key] = ENV[key]
26
+ ENV[key] = value
27
+ end
28
+ yield
29
+ ensure
30
+ originals.each_pair do |key, value|
31
+ ENV[key] = value
32
+ end
33
+ end
34
+
35
+ def tmp_kcode(val)
36
+ original = $KCODE
37
+ $KCODE = val
38
+ yield
39
+ ensure
40
+ $KCODE = original
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+
3
+ module Tweetwine::Test
4
+ module Doubles
5
+ def mock_config
6
+ @config = mock('Config')
7
+ Tweetwine::CLI.stubs(:config).returns(@config)
8
+ end
9
+
10
+ def mock_http
11
+ @http = mock('Http')
12
+ Tweetwine::CLI.stubs(:http).returns(@http)
13
+ end
14
+
15
+ def mock_oauth
16
+ @oauth = mock('OAuth')
17
+ Tweetwine::CLI.stubs(:oauth).returns(@oauth)
18
+ end
19
+
20
+ def mock_ui
21
+ @ui = mock('UI')
22
+ Tweetwine::CLI.stubs(:ui).returns(@ui)
23
+ end
24
+
25
+ def mock_url_shortener
26
+ @url_shortener = mock('UrlShortener')
27
+ Tweetwine::CLI.stubs(:url_shortener).returns(@url_shortener)
28
+ end
29
+
30
+ def stub_config(options = {})
31
+ @config = options
32
+ Tweetwine::CLI.stubs(:config).returns(@config)
33
+ end
34
+ end
35
+ end
@@ -7,15 +7,16 @@
7
7
  tempfile
8
8
  time
9
9
  timecop
10
+ support/common
11
+ support/common_helpers
12
+ support/webmock_integration
10
13
  }.each { |lib| require lib }
11
14
 
12
- require 'helper'
13
-
14
15
  module Tweetwine::Test
15
16
  module Integration
16
- module Helper
17
- include Tweetwine::Test::CommonHelper
18
- extend Tweetwine::Test::CommonHelper
17
+ module Helpers
18
+ include CommonHelpers
19
+ extend CommonHelpers
19
20
 
20
21
  SNAPSHOT_CREATED_AT = Time.parse "2009-10-14 01:56:15 +0300"
21
22
 
@@ -62,9 +63,13 @@ module Tweetwine::Test
62
63
 
63
64
  class TestCase < MiniTest::Spec
64
65
  include WebMockIntegration
66
+
67
+ include Helpers
68
+ extend Helpers
69
+
70
+ # Shorten writing tests a bit by making our main namespace available in
71
+ # the test case.
65
72
  include Tweetwine
66
- include Helper
67
- extend Helper
68
73
  end
69
74
  end
70
75
  end
@@ -0,0 +1,16 @@
1
+ # coding: utf-8
2
+
3
+ require 'mocha_standalone'
4
+
5
+ module Tweetwine::Test
6
+ module MochaIntegration
7
+ include Mocha::API
8
+
9
+ def teardown
10
+ mocha_teardown
11
+ super
12
+ end
13
+ end
14
+ end
15
+
16
+ Mocha::Configuration.prevent :stubbing_non_existent_method
@@ -0,0 +1,95 @@
1
+ # coding: utf-8
2
+
3
+ require 'timecop'
4
+
5
+ module Tweetwine::Test
6
+ module Tweets
7
+ FIELD_PATHS = {
8
+ :from_user => %w{screen_name},
9
+ :to_user => %w{status in_reply_to_screen_name},
10
+ :retweet => %w{retweeted_status},
11
+ :created_at => %w{status created_at},
12
+ :status => %w{status text}
13
+ }.freeze
14
+
15
+ DEFAULT_TIMESTAMP = Time.utc(2011, 'feb', 17, 22, 28, 0)
16
+
17
+ DEFAULT_FIELD_VALUES = {
18
+ :from_user => 'fred',
19
+ :to_user => nil,
20
+ :retweet => nil,
21
+ :created_at => DEFAULT_TIMESTAMP.iso8601,
22
+ :status => nil
23
+ }.freeze
24
+
25
+ RECORD_SKELETON = {
26
+ 'screen_name' => nil,
27
+ 'retweeted_status' => nil,
28
+ 'status' => {
29
+ 'in_reply_to_screen_name' => nil,
30
+ 'created_at' => nil,
31
+ 'text' => nil
32
+ }.freeze
33
+ }.freeze
34
+
35
+ def create_record(fields = {})
36
+ record = Tweets.create_nonrt_record(Tweets.nonrt_fields(fields))
37
+ Tweets.modify_to_rt_record(record, fields[:rt_user]) if fields[:rt_user]
38
+ record
39
+ end
40
+
41
+ def create_tweet(fields = {})
42
+ Tweetwine::Tweet.new(create_record(fields), FIELD_PATHS)
43
+ end
44
+
45
+ def at_default_time(&block)
46
+ Timecop.freeze(DEFAULT_TIMESTAMP, &block)
47
+ end
48
+
49
+ def create_timestamp(minus_seconds)
50
+ (DEFAULT_TIMESTAMP - minus_seconds).iso8601
51
+ end
52
+
53
+ class << self
54
+ def nonrt_fields(fields)
55
+ DEFAULT_FIELD_VALUES.merge(fields.reject { |(k, v)| k == :rt_user })
56
+ end
57
+
58
+ def create_nonrt_record(fields)
59
+ FIELD_PATHS.inject(deep_copy(RECORD_SKELETON)) do |result, (path_name, path_actual)|
60
+ hash, field = find_hash_of_field_path(result, path_actual)
61
+ hash[field] = fields[path_name]
62
+ result
63
+ end
64
+ end
65
+
66
+ def modify_to_rt_record(record, rt_user)
67
+ rt_hash, rt_field = find_hash_of_field_path(record, FIELD_PATHS[:retweet])
68
+ fr_hash, fr_field = find_hash_of_field_path(record, FIELD_PATHS[:from_user])
69
+ st_hash, st_field = find_hash_of_field_path(record, FIELD_PATHS[:status])
70
+ rt_hash[rt_field] = {
71
+ fr_field => fr_hash[fr_field].dup,
72
+ 'status' => st_hash.dup
73
+ }
74
+ fr_hash[fr_field] = rt_user
75
+ st_hash[st_field] = 'retweeted status text. you should not see me.'
76
+ cr_hash, cr_field = find_hash_of_field_path(record, FIELD_PATHS[:created_at])
77
+ cr_hash[cr_field] = 'old created timestamp. you should not see me.'
78
+ end
79
+
80
+ def find_hash_of_field_path(hash, path)
81
+ path = [path] unless path.is_a? Array
82
+ if path.size > 1
83
+ hash_path, field = path[0..-2], path.last
84
+ [Tweetwine::Support.find_hash_path(hash, hash_path), field]
85
+ else
86
+ [hash, path.first]
87
+ end
88
+ end
89
+
90
+ def deep_copy(obj)
91
+ Marshal.load(Marshal.dump(obj))
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+
3
+ %w{
4
+ support/common
5
+ support/common_helpers
6
+ support/assertions
7
+ support/doubles
8
+ support/mocha_integration
9
+ support/webmock_integration
10
+ }.each { |lib| require lib }
11
+
12
+ module Tweetwine::Test
13
+ module Unit
14
+ class TestCase < MiniTest::Spec
15
+ include MochaIntegration
16
+ include WebMockIntegration
17
+
18
+ include Assertions
19
+ include Doubles
20
+ include CommonHelpers
21
+ extend CommonHelpers
22
+
23
+ # Shorten writing tests a bit by making our main namespace available in
24
+ # the test case.
25
+ include Tweetwine
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,16 @@
1
+ # coding: utf-8
2
+
3
+ require 'webmock'
4
+
5
+ module Tweetwine::Test
6
+ module WebMockIntegration
7
+ include WebMock::API
8
+
9
+ def teardown
10
+ WebMock.reset!
11
+ super
12
+ end
13
+ end
14
+ end
15
+
16
+ WebMock.disable_net_connect!
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'unit/helper'
3
+ require 'support/unit_test_case'
4
4
 
5
5
  module Tweetwine::Test::Unit
6
6
 
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'unit/helper'
3
+ require 'support/unit_test_case'
4
4
  require 'stringio'
5
5
 
6
6
  module Tweetwine::Test::Unit
@@ -9,13 +9,13 @@ module Tweetwine::Test::Unit
9
9
  class CLITest < TestCase
10
10
  describe "for initialization" do
11
11
  it "disallows using #new to create a new instance" do
12
- assert_raises(NoMethodError) { CLI.new }
12
+ assert_raises(NoMethodError) { Tweetwine::CLI.new }
13
13
  end
14
14
 
15
15
  it "allows defining same option multiple times, last value winning" do
16
16
  winning_option_value = 'second'
17
17
  start_cli %W{-f first -f #{winning_option_value} -v}
18
- assert_equal winning_option_value, CLI.config[:config_file]
18
+ assert_equal winning_option_value, Tweetwine::CLI.config[:config_file]
19
19
  end
20
20
  end
21
21
 
@@ -23,7 +23,7 @@ class CLITest < TestCase
23
23
 
24
24
  def start_cli(args)
25
25
  output = StringIO.new
26
- CLI.start(args, { :out => output })
26
+ Tweetwine::CLI.start(args, { :out => output })
27
27
  output.string.split("\n")
28
28
  end
29
29
  end
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'unit/helper'
3
+ require 'support/unit_test_case'
4
4
  require 'fileutils'
5
5
  require 'tempfile'
6
6
  require 'yaml'
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'unit/helper'
3
+ require 'support/unit_test_case'
4
4
 
5
5
  module Tweetwine::Test::Unit
6
6
 
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'unit/helper'
3
+ require 'support/unit_test_case'
4
4
  require 'fixture/oauth'
5
5
  require 'net/http'
6
6
 
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'unit/helper'
3
+ require 'support/unit_test_case'
4
4
 
5
5
  module Tweetwine::Test::Unit
6
6
 
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'unit/helper'
3
+ require 'support/unit_test_case'
4
4
 
5
5
  module Tweetwine::Test::Unit
6
6
 
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'unit/helper'
3
+ require 'support/unit_test_case'
4
4
 
5
5
  module Tweetwine::Test::Unit
6
6
 
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'unit/helper'
3
+ require 'support/unit_test_case'
4
4
  require 'time'
5
5
 
6
6
  module Tweetwine::Test::Unit
@@ -1,12 +1,12 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'unit/helper'
4
- require 'unit/tweet_helper'
3
+ require 'support/unit_test_case'
4
+ require 'support/tweets'
5
5
 
6
6
  module Tweetwine::Test::Unit
7
7
 
8
8
  class TweetTest < TestCase
9
- include TweetHelper
9
+ include Test::Tweets
10
10
 
11
11
  describe "for initialization" do
12
12
  it "raises exception if from user field is not found" do
@@ -1,10 +1,10 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'unit/helper'
3
+ require 'support/unit_test_case'
4
4
 
5
5
  module Tweetwine::Test::Unit
6
6
 
7
- class ClientTest < TestCase
7
+ class TwitterTest < TestCase
8
8
  before do
9
9
  @config = {
10
10
  :num_tweets => 20,
@@ -383,31 +383,6 @@ class ClientTest < TestCase
383
383
  @twitter.update(long_status)
384
384
  end
385
385
 
386
- it "discards obviously invalid shortened URLs, using originals instead" do
387
- long_urls = ["http://www.google.fi/", "http://www.w3.org/TR/1999/REC-xpath-19991116"]
388
- status = long_urls.join(" and ")
389
- short_urls = [nil, ""]
390
- twitter_records, internal_records = create_rest_api_status_records({
391
- :from_user => @username,
392
- :status => status
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_tweets).with(internal_records)
408
- @twitter.update(status)
409
- end
410
-
411
386
  it "reuses a shortened URL for duplicate long URLs" do
412
387
  long_urls = ["http://www.w3.org/TR/1999/REC-xpath-19991116"] * 2
413
388
  long_status = long_urls.join(" and ")
@@ -443,6 +418,33 @@ class ClientTest < TestCase
443
418
  })
444
419
  end
445
420
 
421
+ it "warns if URLs returned from shortening service are not shortened, using originals instead" do
422
+ long_urls = ["http://www.google.fi/", "http://www.w3.org/TR/1999/REC-xpath-19991116"]
423
+ status = long_urls.join(" and ")
424
+ short_urls = [long_urls.first, ""]
425
+ twitter_records, internal_records = create_rest_api_status_records({
426
+ :from_user => @username,
427
+ :status => status
428
+ })
429
+ @oauth.expects(:request_signer)
430
+ http_subresource = mock
431
+ http_subresource.expects(:post).
432
+ with({ :status => status }).
433
+ returns(twitter_records[0].to_json)
434
+ @rest_api.expects(:[]).
435
+ with("statuses/update.json").
436
+ returns(http_subresource)
437
+ @url_shortener.expects(:shorten).with(long_urls.first).returns(short_urls.first)
438
+ @url_shortener.expects(:shorten).with(long_urls.last).returns(short_urls.last)
439
+ @ui.expects(:warn).with("No short URL for #{long_urls.first}")
440
+ @ui.expects(:warn).with("No short URL for #{long_urls.last}")
441
+ @ui.expects(:show_status_preview).with(status)
442
+ @ui.expects(:confirm).with("Really send?").returns(true)
443
+ @ui.expects(:info).with("Sent status update.\n\n")
444
+ @ui.expects(:show_tweets).with(internal_records)
445
+ @twitter.update(status)
446
+ end
447
+
446
448
  it "skips shortening URLs if required libraries are not found" do
447
449
  Tweetwine::CLI.stubs(:url_shortener).raises(LoadError, 'gem not found')
448
450
  @oauth.expects(:request_signer)
data/test/unit/ui_test.rb CHANGED
@@ -1,12 +1,12 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'unit/helper'
4
- require 'unit/tweet_helper'
3
+ require 'support/unit_test_case'
4
+ require 'support/tweets'
5
5
 
6
6
  module Tweetwine::Test::Unit
7
7
 
8
8
  class UITest < TestCase
9
- include TweetHelper
9
+ include Test::Tweets
10
10
 
11
11
  before do
12
12
  @in = mock
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'unit/helper'
3
+ require 'support/unit_test_case'
4
4
 
5
5
  module Tweetwine::Test::Unit
6
6
 
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'unit/helper'
3
+ require 'support/unit_test_case'
4
4
 
5
5
  module Tweetwine::Test::Unit
6
6
 
data/tweetwine.gemspec CHANGED
@@ -10,14 +10,15 @@ Gem::Specification.new do |s|
10
10
  s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
11
11
 
12
12
  s.add_dependency 'oauth', '~> 0.4.4'
13
- s.add_development_dependency 'gem-man', '~> 0.2.0'
14
- s.add_development_dependency 'minitest', '~> 2.1.0'
13
+ s.add_development_dependency 'gem-man', '~> 0.3.0'
14
+ s.add_development_dependency 'minitest', '~> 2.4.0'
15
15
  s.add_development_dependency 'mocha', '~> 0.9.12'
16
16
  s.add_development_dependency 'open4', '~> 1.0.1'
17
- s.add_development_dependency 'rake', '~> 0.8.7'
17
+ s.add_development_dependency 'perftools.rb', '~> 0.5.6'
18
+ s.add_development_dependency 'rake', '>= 0.8.7'
18
19
  s.add_development_dependency 'ronn', '~> 0.7.3'
19
20
  s.add_development_dependency 'timecop', '~> 0.3.5'
20
- s.add_development_dependency 'webmock', '~> 1.6.2'
21
+ s.add_development_dependency 'webmock', '~> 1.7.7'
21
22
 
22
23
  s.post_install_message = <<-END
23
24