tweetwine 0.4.1 → 0.4.2

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 (52) hide show
  1. data/CHANGELOG.rdoc +6 -0
  2. data/Rakefile +22 -23
  3. data/lib/tweetwine/cli.rb +167 -165
  4. data/lib/tweetwine/config.rb +3 -2
  5. data/lib/tweetwine/exceptions.rb +1 -0
  6. data/lib/tweetwine/version.rb +1 -1
  7. data/project.rb +16 -16
  8. data/test/fixture/{config_example.yaml → config_integration.yaml} +0 -0
  9. data/test/fixture/oauth.rb +11 -11
  10. data/test/{test_helper.rb → helper.rb} +16 -7
  11. data/test/{example/authorization_example.rb → integration/authorization_test.rb} +17 -17
  12. data/test/integration/global_options_test.rb +67 -0
  13. data/test/integration/helper.rb +70 -0
  14. data/test/integration/invalid_config_file_test.rb +28 -0
  15. data/test/integration/search_statuses_test.rb +81 -0
  16. data/test/integration/show_followers_test.rb +24 -0
  17. data/test/integration/show_friends_test.rb +24 -0
  18. data/test/integration/show_home_test.rb +47 -0
  19. data/test/integration/show_mentions_test.rb +24 -0
  20. data/test/integration/show_user_test.rb +48 -0
  21. data/test/integration/update_status_test.rb +199 -0
  22. data/test/integration/use_http_proxy_test.rb +71 -0
  23. data/test/{example/user_help_example.rb → integration/user_help_test.rb} +36 -36
  24. data/test/unit/character_encoding_test.rb +19 -15
  25. data/test/unit/cli_test.rb +9 -10
  26. data/test/unit/config_test.rb +73 -71
  27. data/test/unit/helper.rb +108 -0
  28. data/test/unit/http_test.rb +39 -39
  29. data/test/unit/oauth_test.rb +15 -16
  30. data/test/unit/obfuscate_test.rb +4 -4
  31. data/test/unit/option_parser_test.rb +12 -12
  32. data/test/unit/promise_test.rb +10 -10
  33. data/test/unit/support_test.rb +44 -45
  34. data/test/unit/tweet_helper.rb +1 -1
  35. data/test/unit/tweet_test.rb +42 -42
  36. data/test/unit/twitter_test.rb +300 -303
  37. data/test/unit/ui_test.rb +310 -312
  38. data/test/unit/uri_test.rb +7 -7
  39. data/test/unit/url_shortener_test.rb +77 -79
  40. data/tweetwine.gemspec +6 -15
  41. metadata +55 -145
  42. data/test/example/example_helper.rb +0 -58
  43. data/test/example/global_options_example.rb +0 -64
  44. data/test/example/search_statuses_example.rb +0 -76
  45. data/test/example/show_followers_example.rb +0 -24
  46. data/test/example/show_friends_example.rb +0 -24
  47. data/test/example/show_home_example.rb +0 -44
  48. data/test/example/show_mentions_example.rb +0 -24
  49. data/test/example/show_user_example.rb +0 -44
  50. data/test/example/update_status_example.rb +0 -183
  51. data/test/example/use_http_proxy_example.rb +0 -68
  52. data/test/unit/unit_helper.rb +0 -111
@@ -1,22 +1,23 @@
1
1
  # coding: utf-8
2
2
 
3
- require "tweetwine"
4
-
5
- require "webmock/test_unit"
3
+ %w{
4
+ minitest/spec
5
+ tweetwine
6
+ webmock
7
+ }.each { |lib| require lib }
6
8
 
9
+ MiniTest::Unit.autorun
7
10
  WebMock.disable_net_connect!
8
11
 
9
12
  module Tweetwine
10
13
  module Test
11
- module Helper
12
- extend self
13
-
14
+ module CommonHelper
14
15
  def file_mode(file)
15
16
  File.stat(file).mode & 0777
16
17
  end
17
18
 
18
19
  def fixture_path(filename)
19
- File.dirname(__FILE__) << "/fixture/" << filename
20
+ File.join(File.dirname(__FILE__), 'fixture', filename)
20
21
  end
21
22
 
22
23
  def fixture_file(filename)
@@ -47,5 +48,13 @@ module Tweetwine
47
48
  $KCODE = original
48
49
  end
49
50
  end
51
+
52
+ module WebMockIntegration
53
+ include WebMock::API
54
+
55
+ def teardown
56
+ WebMock.reset!
57
+ end
58
+ end
50
59
  end
51
60
  end
@@ -1,24 +1,22 @@
1
1
  # coding: utf-8
2
2
 
3
- require "example_helper"
4
- require "fixture/oauth"
3
+ require 'integration/helper'
4
+ require 'fixture/oauth'
5
5
 
6
- include Tweetwine::Test::Fixture::OAuth
6
+ module Tweetwine::Test::Integration
7
7
 
8
- Feature "authorization" do
9
- as_a "user"
10
- i_want_to "see authorize myself"
11
- in_order_to "use the service"
8
+ class AuthorizationTest < TestCase
9
+ include Test::Fixture::OAuth
12
10
 
13
- Scenario "authorize user with OAuth and save access token" do
14
- When "I start the application with 'home' command and the command fails due to me being unauthorized" do
11
+ describe "authorize user with OAuth and save access token" do
12
+ before do
15
13
  @command_url = "https://api.twitter.com/1/statuses/home_timeline.json?count=20&page=1"
16
14
  stub_http_request(METHOD, REQUEST_TOKEN_URL).to_return(:body => REQUEST_TOKEN_RESPONSE)
17
15
  stub_http_request(METHOD, ACCESS_TOKEN_URL).to_return(:body => ACCESS_TOKEN_RESPONSE)
18
16
  stub_http_request(:get, @command_url).
19
17
  to_return(:status => [401, 'Unauthorized']).then.
20
18
  to_return(:body => fixture_file('home.json'))
21
- in_temp_dir do
19
+ in_tmp_dir do
22
20
  config_file = 'tweetwine.tmp'
23
21
  @output = start_cli %W{--no-colors -f #{config_file} home}, [PIN], {}
24
22
  @config_contents = YAML.load_file(config_file)
@@ -26,15 +24,17 @@ Feature "authorization" do
26
24
  end
27
25
  end
28
26
 
29
- Then "the application authorizes me, saves access token to config file, and tries the command again" do
27
+ it "authorizes me, saves access token to config file, and tries the command again" do
30
28
  assert_requested(METHOD, REQUEST_TOKEN_URL)
31
29
  assert_requested(METHOD, ACCESS_TOKEN_URL)
32
30
  assert_requested(:get, @command_url, :headers => {'Authorization' => /^OAuth /}, :times => 2)
33
- @output[0].should == "Please authorize: #{AUTHORIZE_URL}"
34
- @output[1].should =~ /^Enter PIN:/
35
- @output[2].should == "F1-kausi alkaa marraskuussa http://bit.ly/1qQwjQ"
36
- @config_contents['oauth_access'].empty?.should == false
37
- @config_mode.should == 0600
31
+ @output[0].must_equal "Please authorize: #{AUTHORIZE_URL}"
32
+ @output[1].must_match(/^Enter PIN:/)
33
+ @output[2].must_equal "F1-kausi alkaa marraskuussa http://bit.ly/1qQwjQ"
34
+ @config_contents['oauth_access'].empty?.must_equal false
35
+ @config_mode.must_equal 0600
38
36
  end
39
37
  end
40
- end
38
+ end
39
+
40
+ end
@@ -0,0 +1,67 @@
1
+ # coding: utf-8
2
+
3
+ require 'integration/helper'
4
+
5
+ module Tweetwine::Test::Integration
6
+
7
+ class GlobalOptionsTest < TestCase
8
+ before do
9
+ stub_http_request(:get, %r{https://api.twitter.com/1/statuses/home_timeline\.json\?count=\d+&page=\d+}).to_return(:body => fixture_file('home.json'))
10
+ end
11
+
12
+ describe "colors" do
13
+ before do
14
+ at_snapshot do
15
+ @output = start_cli %w{--colors}
16
+ end
17
+ end
18
+
19
+ it "shows tweets with colors" do
20
+ @output[0].must_equal "\e[32mpelit\e[0m, 11 days ago:"
21
+ @output[1].must_equal "F1-kausi alkaa marraskuussa \e[36mhttp://bit.ly/1qQwjQ\e[0m"
22
+ @output[2].must_equal ""
23
+ @output[58].must_equal "\e[32mradar\e[0m, 15 days ago:"
24
+ @output[59].must_equal "Four short links: 29 September 2009 \e[36mhttp://bit.ly/dYxay\e[0m"
25
+ end
26
+ end
27
+
28
+ describe "show reverse" do
29
+ before do
30
+ at_snapshot do
31
+ @output = start_cli %w{--reverse}
32
+ end
33
+ end
34
+
35
+ it "shows tweets in reverse order" do
36
+ @output[0].must_equal "radar, 15 days ago:"
37
+ @output[1].must_equal "Four short links: 29 September 2009 http://bit.ly/dYxay"
38
+ @output[2].must_equal ""
39
+ @output[58].must_equal "pelit, 11 days ago:"
40
+ @output[59].must_equal "F1-kausi alkaa marraskuussa http://bit.ly/1qQwjQ"
41
+ end
42
+ end
43
+
44
+ describe "num" do
45
+ before do
46
+ @num = 2
47
+ @output = start_cli %W{--num #{@num}}
48
+ end
49
+
50
+ it "requests the specified number of tweets" do
51
+ assert_requested(:get, %r{/home_timeline\.json\?count=#{@num}&page=\d+})
52
+ end
53
+ end
54
+
55
+ describe "page" do
56
+ before do
57
+ @page = 2
58
+ @output = start_cli %W{--page #{@page}}
59
+ end
60
+
61
+ it "requests the specified page number for tweets" do
62
+ assert_requested(:get, %r{/home_timeline\.json\?count=\d+&page=#{@page}})
63
+ end
64
+ end
65
+ end
66
+
67
+ end
@@ -0,0 +1,70 @@
1
+ # coding: utf-8
2
+
3
+ %w{
4
+ open4
5
+ shellwords
6
+ stringio
7
+ tempfile
8
+ time
9
+ timecop
10
+ }.each { |lib| require lib }
11
+
12
+ require 'helper'
13
+
14
+ module Tweetwine::Test
15
+ module Integration
16
+ module Helper
17
+ include Tweetwine::Test::CommonHelper
18
+ extend Tweetwine::Test::CommonHelper
19
+
20
+ SNAPSHOT_CREATED_AT = Time.parse "2009-10-14 01:56:15 +0300"
21
+
22
+ CONFIG_FILE = fixture_path 'config_integration.yaml'
23
+ PROJECT_DIR = File.expand_path '../..', File.dirname(__FILE__)
24
+ PROXY_HOST = "proxy.net"
25
+ PROXY_PORT = 8123
26
+ PROXY_URL = "http://#{PROXY_HOST}:#{PROXY_PORT}"
27
+ USER = "fooman"
28
+
29
+ def start_app(args, &blk)
30
+ lib = PROJECT_DIR + '/lib'
31
+ executable = PROJECT_DIR + '/bin/tweetwine'
32
+ launch_cmd = [
33
+ 'env', "USER=#{USER}", 'ruby', '-rubygems', '-I', lib, '--',
34
+ executable, '-f', CONFIG_FILE, args
35
+ ].flatten.shelljoin
36
+ Open4::popen4(launch_cmd, &blk)
37
+ end
38
+
39
+ def start_cli(args, input = [], options = {:config_file => CONFIG_FILE})
40
+ input, output = StringIO.new(input.join("\n")), StringIO.new
41
+ options.merge!({ :in => input, :out => output })
42
+ Tweetwine::CLI.start(args, options)
43
+ output.string.split("\n")
44
+ end
45
+
46
+ def at_snapshot(&block)
47
+ Timecop.freeze(SNAPSHOT_CREATED_AT, &block)
48
+ end
49
+
50
+ def in_tmp_dir
51
+ Dir.mktmpdir do |tmp_dir|
52
+ Dir.chdir(tmp_dir) do |dir|
53
+ yield dir
54
+ end
55
+ end
56
+ end
57
+
58
+ def read_shorten_config
59
+ Tweetwine::Support.symbolize_hash_keys(YAML.load_file(CONFIG_FILE))[:shorten_urls]
60
+ end
61
+ end
62
+
63
+ class TestCase < MiniTest::Spec
64
+ include WebMockIntegration
65
+ include Tweetwine
66
+ include Helper
67
+ extend Helper
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+
3
+ require 'integration/helper'
4
+ require 'fileutils'
5
+
6
+ module Tweetwine::Test::Integration
7
+
8
+ class InvalidConfigFileTest < TestCase
9
+ before do
10
+ in_tmp_dir do
11
+ config_file = 'tweetwine.tmp'
12
+ FileUtils.touch config_file
13
+ @status = start_app %W{--no-colors -f #{config_file}} do |_, _, _, stderr|
14
+ @output = stderr.readlines.join.chomp
15
+ end
16
+ end
17
+ end
18
+
19
+ it "shows just the error message (not the whole stack trace)" do
20
+ @output.must_match(/\AERROR: invalid config file; it must be a mapping style YAML document: /)
21
+ end
22
+
23
+ it "exists with failure status" do
24
+ @status.exitstatus.must_equal ConfigError.status_code
25
+ end
26
+ end
27
+
28
+ end
@@ -0,0 +1,81 @@
1
+ # coding: utf-8
2
+
3
+ require 'integration/helper'
4
+
5
+ module Tweetwine::Test::Integration
6
+
7
+ class SearchStatusesTest < TestCase
8
+ SEARCH_BASE_URL = "http://search.twitter.com/search.json"
9
+ SEARCH_OR_URL = "#{SEARCH_BASE_URL}?q=braid%20OR%20game&rpp=2&page=1"
10
+ SEARCH_AND_URL = "#{SEARCH_BASE_URL}?q=braid%20game&rpp=2&page=1"
11
+ SEARCH_FIXTURE = fixture_file 'search.json'
12
+
13
+ before do
14
+ stub_http_request(:get, SEARCH_AND_URL).to_return(:body => SEARCH_FIXTURE)
15
+ stub_http_request(:get, SEARCH_OR_URL).to_return(:body => SEARCH_FIXTURE)
16
+ end
17
+
18
+ describe "search tweets matching all words" do
19
+ before do
20
+ at_snapshot do
21
+ @output = start_cli %w{-n 2 search -a braid game}
22
+ end
23
+ end
24
+
25
+ it "requests tweets matching all the words and shows them" do
26
+ assert_requested(:get, SEARCH_AND_URL)
27
+ must_output_tweets
28
+ end
29
+ end
30
+
31
+ describe "search tweets matching any words" do
32
+ before do
33
+ at_snapshot do
34
+ @output = start_cli %w{-n 2 search -o braid game}
35
+ end
36
+ end
37
+
38
+ it "requests tweets matching any of the words and shows them" do
39
+ assert_requested(:get, SEARCH_OR_URL)
40
+ must_output_tweets
41
+ end
42
+ end
43
+
44
+ describe "searching for all words is implied unless other is specified" do
45
+ before do
46
+ at_snapshot do
47
+ @output = start_cli %w{-n 2 search braid game}
48
+ end
49
+ end
50
+
51
+ it "requests tweets matching all the words and shows them" do
52
+ assert_requested(:get, SEARCH_AND_URL)
53
+ must_output_tweets
54
+ end
55
+ end
56
+
57
+ describe "search without words" do
58
+ before do
59
+ @status = start_app %w{-n 2 search} do |_, _, _, stderr|
60
+ @output = stderr.gets
61
+ end
62
+ end
63
+
64
+ it "shows error message and exists with error status" do
65
+ @output.must_equal "ERROR: No search words.\n"
66
+ @status.exitstatus.must_equal CommandLineError.status_code
67
+ end
68
+ end
69
+
70
+ private
71
+
72
+ def must_output_tweets
73
+ @output[0].must_equal "thatswhatshesaid, in reply to hatguy, 5 hours ago:"
74
+ @output[1].must_equal "@hatguy braid, perhaps the best indie game of 2009"
75
+ @output[2].must_equal ""
76
+ @output[3].must_equal "jillv, 11 hours ago:"
77
+ @output[4].must_equal "braid is even better than of the games i'm in, expect re4"
78
+ end
79
+ end
80
+
81
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+
3
+ require 'integration/helper'
4
+
5
+ module Tweetwine::Test::Integration
6
+
7
+ class ShowFollowersTest < TestCase
8
+ before do
9
+ stub_http_request(:get, "https://api.twitter.com/1/statuses/followers.json?count=20&page=1").to_return(:body => fixture_file('users.json'))
10
+ at_snapshot do
11
+ @output = start_cli %w{followers}
12
+ end
13
+ end
14
+
15
+ it "shows followers and their latest tweets (if any)" do
16
+ @output[0].must_equal "jillv, 12 hours ago:"
17
+ @output[1].must_equal "choosing next target"
18
+ @output[2].must_equal ""
19
+ @output[3].must_equal "ham"
20
+ @output[4].must_equal nil
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+
3
+ require 'integration/helper'
4
+
5
+ module Tweetwine::Test::Integration
6
+
7
+ class ShowFriendsTest < TestCase
8
+ before do
9
+ stub_http_request(:get, "https://api.twitter.com/1/statuses/friends.json?count=20&page=1").to_return(:body => fixture_file('users.json'))
10
+ at_snapshot do
11
+ @output = start_cli %w{friends}
12
+ end
13
+ end
14
+
15
+ it "shows friends and their latest tweets (if any)" do
16
+ @output[0].must_equal "jillv, 12 hours ago:"
17
+ @output[1].must_equal "choosing next target"
18
+ @output[2].must_equal ""
19
+ @output[3].must_equal "ham"
20
+ @output[4].must_equal nil
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,47 @@
1
+ # coding: utf-8
2
+
3
+ require 'integration/helper'
4
+
5
+ module Tweetwine::Test::Integration
6
+
7
+ class ShowHomeTest < TestCase
8
+ before do
9
+ stub_http_request(:get, "https://api.twitter.com/1/statuses/home_timeline.json?count=20&page=1").to_return(:body => fixture_file('home.json'))
10
+ end
11
+
12
+ describe "show home timeline" do
13
+ before do
14
+ at_snapshot do
15
+ @output = start_cli %w{--no-colors home}
16
+ end
17
+ end
18
+
19
+ it "shows tweets from home timeline" do
20
+ must_output_tweets
21
+ end
22
+ end
23
+
24
+ describe "show home timeline is default command" do
25
+ before do
26
+ at_snapshot do
27
+ @output = start_cli %w{--no-colors}
28
+ end
29
+ end
30
+
31
+ it "shows tweets from home timeline" do
32
+ must_output_tweets
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def must_output_tweets
39
+ @output[0].must_equal "pelit, 11 days ago:"
40
+ @output[1].must_equal "F1-kausi alkaa marraskuussa http://bit.ly/1qQwjQ"
41
+ @output[2].must_equal ""
42
+ @output[58].must_equal "radar, 15 days ago:"
43
+ @output[59].must_equal "Four short links: 29 September 2009 http://bit.ly/dYxay"
44
+ end
45
+ end
46
+
47
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+
3
+ require 'integration/helper'
4
+
5
+ module Tweetwine::Test::Integration
6
+
7
+ class ShowMentionsTest < TestCase
8
+ before do
9
+ stub_http_request(:get, "https://api.twitter.com/1/statuses/mentions.json?count=20&page=1").to_return(:body => fixture_file('mentions.json'))
10
+ at_snapshot do
11
+ @output = start_cli %w{mentions}
12
+ end
13
+ end
14
+
15
+ it "shows tweets mentioning me" do
16
+ @output[0].must_equal "jillv, in reply to fooman, 3 days ago:"
17
+ @output[1].must_equal "@fooman, did you see their eyes glow yellow after sunset?"
18
+ @output[2].must_equal ""
19
+ @output[3].must_equal "redfield, in reply to fooman, 5 days ago:"
20
+ @output[4].must_equal "sometimes it is just best to run, just like @fooman"
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,48 @@
1
+ # coding: utf-8
2
+
3
+ require 'integration/helper'
4
+
5
+ module Tweetwine::Test::Integration
6
+
7
+ class ShowUserTest < TestCase
8
+ USER_URL = "https://api.twitter.com/1/statuses/user_timeline.json?count=20&page=1&screen_name=%s"
9
+ USER_FIXTURE = fixture_file 'user.json'
10
+
11
+ describe "show my tweets" do
12
+ before do
13
+ stub_http_request(:get, USER_URL % USER).to_return(:body => USER_FIXTURE)
14
+ at_snapshot do
15
+ @output = start_cli %w{user}
16
+ end
17
+ end
18
+
19
+ it "shows my tweets" do
20
+ must_output_tweets
21
+ end
22
+ end
23
+
24
+ describe "show another user's tweets" do
25
+ before do
26
+ stub_http_request(:get, USER_URL % 'jillv').to_return(:body => USER_FIXTURE)
27
+ at_snapshot do
28
+ @output = start_cli %w{user jillv}
29
+ end
30
+ end
31
+
32
+ it "shows the user's tweets" do
33
+ must_output_tweets
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def must_output_tweets
40
+ @output[0].must_equal "jillv, in reply to chris, 9 hours ago:"
41
+ @output[1].must_equal "@chris wait me until the garden"
42
+ @output[2].must_equal ""
43
+ @output[3].must_equal "jillv, 3 days ago:"
44
+ @output[4].must_equal "so boring to wait"
45
+ end
46
+ end
47
+
48
+ end