hub_test.rb 32.1 KB
Newer Older
1
require 'helper'
2
require 'webmock/test_unit'
3
require 'rbconfig'
4
require 'yaml'
5
require 'forwardable'
6
require 'fileutils'
C
Chris Wanstrath 已提交
7

8 9 10 11 12 13
WebMock::BodyPattern.class_eval do
  undef normalize_hash
  # override normalizing hash since it otherwise requires JSON
  def normalize_hash(hash) hash end
end

C
Chris Wanstrath 已提交
14
class HubTest < Test::Unit::TestCase
15 16
  extend Forwardable

17 18 19 20 21
  if defined? WebMock::API
    include WebMock::API
  else
    include WebMock
  end
C
Chris Wanstrath 已提交
22

23 24
  COMMANDS = []

25
  Hub::Context::System.class_eval do
26 27 28
    remove_method :which
    define_method :which do |name|
      COMMANDS.include?(name) ? "/usr/bin/#{name}" : nil
29 30 31
    end
  end

32 33 34 35
  attr_reader :git_reader
  include Hub::Context::GitReaderMethods
  def_delegators :git_reader, :stub_config_value, :stub_command_output

36
  def setup
37
    super
38
    COMMANDS.replace %w[open groff]
39
    Hub::Context::PWD.replace '/path/to/hub'
40
    Hub::SshConfig::CONFIG_FILES.replace []
41

42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
    @prompt_stubs = prompt_stubs = []
    @password_prompt_stubs = password_prompt_stubs = []

    Hub::GitHubAPI::Configuration.class_eval do
      undef prompt
      undef prompt_password

      define_method :prompt do |what|
        prompt_stubs.shift.call(what)
      end
      define_method :prompt_password do |host, user|
        password_prompt_stubs.shift.call(host, user)
      end
    end

57 58 59
    @git_reader = Hub::Context::GitReader.new 'git' do |cache, cmd|
      unless cmd.index('config --get alias.') == 0
        raise ArgumentError, "`git #{cmd}` not stubbed"
M
Mislav Marohnić 已提交
60
      end
61 62 63 64
    end

    Hub::Commands.instance_variable_set :@git_reader, @git_reader
    Hub::Commands.instance_variable_set :@local_repo, nil
65 66 67 68 69 70 71
    Hub::Commands.instance_variable_set :@api_client, nil

    FileUtils.rm_rf ENV['HUB_CONFIG']

    edit_hub_config do |data|
      data['github.com'] = [{'user' => 'tpw', 'oauth_token' => 'OTOKEN'}]
    end
72 73

    @git_reader.stub! \
74
      'remote' => "mislav\norigin",
75
      'symbolic-ref -q HEAD' => 'refs/heads/master',
76 77
      'config --get-all remote.origin.url' => 'git://github.com/defunkt/hub.git',
      'config --get-all remote.mislav.url' => 'git://github.com/mislav/hub.git',
78
      'rev-parse --symbolic-full-name master@{upstream}' => 'refs/remotes/origin/master',
79 80
      'config --get --bool hub.http-clone' => 'false',
      'config --get hub.protocol' => nil,
81
      'config --get-all hub.host' => nil,
82
      'rev-parse -q --git-dir' => '.git'
83 84
  end

85
  def test_cherry_pick
86
    assert_forwarded "cherry-pick a319d88"
87 88 89
  end

  def test_cherry_pick_url
90
    url = 'http://github.com/mislav/hub/commit/a319d88'
91
    assert_commands "git fetch mislav", "git cherry-pick a319d88", "cherry-pick #{url}"
92 93
  end

94 95
  def test_cherry_pick_url_with_fragment
    url = 'http://github.com/mislav/hub/commit/abcdef0123456789#comments'
96
    assert_commands "git fetch mislav", "git cherry-pick abcdef0123456789", "cherry-pick #{url}"
97 98
  end

99 100
  def test_cherry_pick_url_with_remote_add
    url = 'https://github.com/xoebus/hub/commit/a319d88'
101
    assert_commands "git remote add -f xoebus git://github.com/xoebus/hub.git",
102 103
                    "git cherry-pick a319d88",
                    "cherry-pick #{url}"
104 105 106 107
  end

  def test_cherry_pick_origin_url
    url = 'https://github.com/defunkt/hub/commit/a319d88'
108
    assert_commands "git fetch origin", "git cherry-pick a319d88", "cherry-pick #{url}"
109 110 111
  end

  def test_cherry_pick_github_user_notation
112
    assert_commands "git fetch mislav", "git cherry-pick 368af20", "cherry-pick mislav@368af20"
113 114 115 116
  end

  def test_cherry_pick_github_user_repo_notation
    # not supported
117
    assert_forwarded "cherry-pick mislav/hubbub@a319d88"
118 119 120
  end

  def test_cherry_pick_github_notation_too_short
121
    assert_forwarded "cherry-pick mislav@a319"
122 123 124
  end

  def test_cherry_pick_github_notation_with_remote_add
125 126 127
    assert_commands "git remote add -f xoebus git://github.com/xoebus/hub.git",
                    "git cherry-pick a319d88",
                    "cherry-pick xoebus@a319d88"
128 129
  end

130 131 132 133 134 135 136 137
  def test_am_untouched
    assert_forwarded "am some.patch"
  end

  def test_am_pull_request
    with_tmpdir('/tmp/') do
      assert_commands "curl -#LA 'hub #{Hub::Version}' https://github.com/defunkt/hub/pull/55.patch -o /tmp/55.patch",
                      "git am --signoff /tmp/55.patch -p2",
138
                      "am --signoff https://github.com/defunkt/hub/pull/55#comment_123 -p2"
139 140 141

      cmd = Hub("am https://github.com/defunkt/hub/pull/55/files").command
      assert_includes '/pull/55.patch', cmd
142 143 144
    end
  end

145 146 147 148 149 150 151
  def test_am_no_tmpdir
    with_tmpdir(nil) do
      cmd = Hub("am https://github.com/defunkt/hub/pull/55").command
      assert_includes '/tmp/55.patch', cmd
    end
  end

152 153 154 155 156 157 158 159 160 161
  def test_am_commit_url
    with_tmpdir('/tmp/') do
      url = 'https://github.com/davidbalbert/hub/commit/fdb9921'

      assert_commands "curl -#LA 'hub #{Hub::Version}' #{url}.patch -o /tmp/fdb9921.patch",
                      "git am --signoff /tmp/fdb9921.patch -p2",
                      "am --signoff #{url} -p2"
    end
  end

162 163 164 165 166 167 168 169 170 171
  def test_am_gist
    with_tmpdir('/tmp/') do
      url = 'https://gist.github.com/8da7fb575debd88c54cf'

      assert_commands "curl -#LA 'hub #{Hub::Version}' #{url}.txt -o /tmp/gist-8da7fb575debd88c54cf.txt",
                      "git am --signoff /tmp/gist-8da7fb575debd88c54cf.txt -p2",
                      "am --signoff #{url} -p2"
    end
  end

172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
  def test_apply_untouched
    assert_forwarded "apply some.patch"
  end

  def test_apply_pull_request
    with_tmpdir('/tmp/') do
      assert_commands "curl -#LA 'hub #{Hub::Version}' https://github.com/defunkt/hub/pull/55.patch -o /tmp/55.patch",
                      "git apply /tmp/55.patch -p2",
                      "apply https://github.com/defunkt/hub/pull/55 -p2"

      cmd = Hub("apply https://github.com/defunkt/hub/pull/55/files").command
      assert_includes '/pull/55.patch', cmd
    end
  end

  def test_apply_commit_url
    with_tmpdir('/tmp/') do
      url = 'https://github.com/davidbalbert/hub/commit/fdb9921'

      assert_commands "curl -#LA 'hub #{Hub::Version}' #{url}.patch -o /tmp/fdb9921.patch",
                      "git apply /tmp/fdb9921.patch -p2",
                      "apply #{url} -p2"
    end
  end

  def test_apply_gist
    with_tmpdir('/tmp/') do
      url = 'https://gist.github.com/8da7fb575debd88c54cf'

      assert_commands "curl -#LA 'hub #{Hub::Version}' #{url}.txt -o /tmp/gist-8da7fb575debd88c54cf.txt",
                      "git apply /tmp/gist-8da7fb575debd88c54cf.txt -p2",
                      "apply #{url} -p2"
    end
  end

C
Chris Wanstrath 已提交
207
  def test_init
M
Mislav Marohnić 已提交
208 209
    stub_no_remotes
    stub_no_git_repo
210
    assert_commands "git init", "git remote add origin git@github.com:tpw/hub.git", "init -g"
211 212
  end

213 214 215
  def test_init_enterprise
    stub_no_remotes
    stub_no_git_repo
216 217 218 219
    edit_hub_config do |data|
      data['git.my.org'] = [{'user'=>'myfiname'}]
    end

220 221 222 223 224
    with_host_env('git.my.org') do
      assert_commands "git init", "git remote add origin git@git.my.org:myfiname/hub.git", "init -g"
    end
  end

225 226 227 228
  def test_push_untouched
    assert_forwarded "push"
  end

229
  def test_push_two
230 231
    assert_commands "git push origin cool-feature", "git push staging cool-feature",
                    "push origin,staging cool-feature"
232 233
  end

234 235 236 237 238 239
  def test_push_current_branch
    stub_branch('refs/heads/cool-feature')
    assert_commands "git push origin cool-feature", "git push staging cool-feature",
                    "push origin,staging"
  end

C
Chris Wanstrath 已提交
240
  def test_push_more
241 242 243 244
    assert_commands "git push origin cool-feature",
                    "git push staging cool-feature",
                    "git push qa cool-feature",
                    "push origin,staging,qa cool-feature"
C
Chris Wanstrath 已提交
245
  end
C
Chris Wanstrath 已提交
246

247
  def test_create
248
    stub_no_remotes
249
    stub_nonexisting_fork('tpw')
250 251
    stub_request(:post, "https://api.github.com/user/repos").
      with(:body => { 'name' => 'hub', 'private' => false })
252

253
    expected = "remote add -f origin git@github.com:tpw/hub.git\n"
254
    expected << "created repository: tpw/hub\n"
255 256 257
    assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
  end

258 259 260
  def test_create_custom_name
    stub_no_remotes
    stub_nonexisting_fork('tpw', 'hubbub')
261 262
    stub_request(:post, "https://api.github.com/user/repos").
      with(:body => { 'name' => 'hubbub', 'private' => false })
263 264 265 266 267 268 269 270 271

    expected = "remote add -f origin git@github.com:tpw/hubbub.git\n"
    expected << "created repository: tpw/hubbub\n"
    assert_equal expected, hub("create hubbub") { ENV['GIT'] = 'echo' }
  end

  def test_create_in_organization
    stub_no_remotes
    stub_nonexisting_fork('acme', 'hubbub')
272 273
    stub_request(:post, "https://api.github.com/orgs/acme/repos").
      with(:body => { 'name' => 'hubbub', 'private' => false })
274 275 276 277 278 279

    expected = "remote add -f origin git@github.com:acme/hubbub.git\n"
    expected << "created repository: acme/hubbub\n"
    assert_equal expected, hub("create acme/hubbub") { ENV['GIT'] = 'echo' }
  end

280 281 282
  def test_create_failed
    stub_no_remotes
    stub_nonexisting_fork('tpw')
283
    stub_request(:post, "https://api.github.com/user/repos").
284 285
      to_return(:status => [401, "Your token is fail"])

286
    expected = "Error creating repository: Your token is fail (HTTP 401)\n"
287 288 289
    assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
  end

290
  def test_create_private_repository
291
    stub_no_remotes
292
    stub_nonexisting_fork('tpw')
293 294
    stub_request(:post, "https://api.github.com/user/repos").
      with(:body => { 'name' => 'hub', 'private' => true })
295

296
    expected = "remote add -f origin git@github.com:tpw/hub.git\n"
297
    expected << "created repository: tpw/hub\n"
298 299 300
    assert_equal expected, hub("create -p") { ENV['GIT'] = 'echo' }
  end

301 302 303
  def test_create_private_repository_fails
    stub_no_remotes
    stub_nonexisting_fork('tpw')
304
    stub_request(:post, "https://api.github.com/user/repos").
305 306
      to_return(:status => [422, "Unprocessable Entity"],
                :headers => {"Content-type" => "application/json"},
307
                :body => %({"message":"repository creation failed: You are over your quota."}))
308 309 310 311 312 313

    expected = "Error creating repository: Unprocessable Entity (HTTP 422)\n"
    expected << "repository creation failed: You are over your quota.\n"
    assert_equal expected, hub("create -p") { ENV['GIT'] = 'echo' }
  end

314
  def test_create_with_description_and_homepage
315
    stub_no_remotes
316
    stub_nonexisting_fork('tpw')
317 318 319
    stub_request(:post, "https://api.github.com/user/repos").with(:body => {
      'name' => 'hub', 'private' => false,
      'description' => 'toyproject', 'homepage' => 'http://example.com'
320 321
    })

322
    expected = "remote add -f origin git@github.com:tpw/hub.git\n"
323
    expected << "created repository: tpw/hub\n"
324
    assert_equal expected, hub("create -d toyproject -h http://example.com") { ENV['GIT'] = 'echo' }
325 326
  end

327 328 329 330 331
  def test_create_with_invalid_arguments
    assert_equal "invalid argument: -a\n",   hub("create -a blah")   { ENV['GIT'] = 'echo' }
    assert_equal "invalid argument: bleh\n", hub("create blah bleh") { ENV['GIT'] = 'echo' }
  end

332
  def test_create_with_existing_repository
333
    stub_no_remotes
334 335
    stub_existing_fork('tpw')

336
    expected = "tpw/hub already exists on github.com\n"
337
    expected << "remote add -f origin git@github.com:tpw/hub.git\n"
338
    expected << "set remote origin: tpw/hub\n"
339 340 341
    assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
  end

342 343 344 345 346
  def test_create_https_protocol
    stub_no_remotes
    stub_existing_fork('tpw')
    stub_https_is_preferred

347
    expected = "tpw/hub already exists on github.com\n"
348 349 350 351 352
    expected << "remote add -f origin https://github.com/tpw/hub.git\n"
    expected << "set remote origin: tpw/hub\n"
    assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
  end

353
  def test_create_outside_git_repo
354
    stub_no_git_repo
355 356
    assert_equal "'create' must be run from inside a git repository\n", hub("create")
  end
357 358

  def test_create_origin_already_exists
C
Chris Wanstrath 已提交
359
    stub_nonexisting_fork('tpw')
360 361
    stub_request(:post, "https://api.github.com/user/repos").
      with(:body => { 'name' => 'hub', 'private' => false })
C
Chris Wanstrath 已提交
362 363

    expected = "remote -v\ncreated repository: tpw/hub\n"
364 365
    assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
  end
C
Chris Wanstrath 已提交
366

367
  def test_pullrequest
M
Mislav Marohnić 已提交
368 369 370
    expected = "Aborted: head branch is the same as base (\"master\")\n" <<
      "(use `-h <branch>` to specify an explicit pull request head)\n"
    assert_output expected, "pull-request hereyougo"
371 372
  end

M
Mislav Marohnić 已提交
373 374
  def test_pullrequest_with_unpushed_commits
    stub_tracking('master', 'mislav', 'master')
375
    stub_command_output "rev-list --cherry-pick --right-only --no-merges mislav/master...", "+abcd1234\n+bcde2345"
376

M
Mislav Marohnić 已提交
377
    expected = "Aborted: 2 commits are not yet pushed to mislav/master\n" <<
378
      "(use `-f` to force submit a pull request anyway)\n"
379 380 381 382 383 384
    assert_output expected, "pull-request hereyougo"
  end

  def test_pullrequest_from_branch
    stub_branch('refs/heads/feature')
    stub_tracking_nothing('feature')
M
Mislav Marohnić 已提交
385

386 387 388
    stub_request(:post, "https://api.github.com/repos/defunkt/hub/pulls").
      with(:body => { 'base' => "master", 'head' => "tpw:feature", 'title' => "hereyougo" }) { |req|
        req.headers['Content-Length'] == 63
389
      }.to_return(:body => mock_pullreq_response(1))
390 391

    expected = "https://github.com/defunkt/hub/pull/1\n"
392
    assert_output expected, "pull-request hereyougo -f"
393 394 395 396
  end

  def test_pullrequest_from_tracking_branch
    stub_branch('refs/heads/feature')
M
Mislav Marohnić 已提交
397
    stub_tracking('feature', 'mislav', 'yay-feature')
398

399 400
    stub_request(:post, "https://api.github.com/repos/defunkt/hub/pulls").
      with(:body => {'base' => "master", 'head' => "mislav:yay-feature", 'title' => "hereyougo" }).
401 402 403
      to_return(:body => mock_pullreq_response(1))

    expected = "https://github.com/defunkt/hub/pull/1\n"
404
    assert_output expected, "pull-request hereyougo -f"
405 406
  end

407 408 409 410
  def test_pullrequest_from_branch_tracking_local
    stub_branch('refs/heads/feature')
    stub_tracking('feature', 'refs/heads/master')

411 412
    stub_request(:post, "https://api.github.com/repos/defunkt/hub/pulls").
      with(:body => {'base' => "master", 'head' => "tpw:feature", 'title' => "hereyougo" }).
413 414 415 416 417 418
      to_return(:body => mock_pullreq_response(1))

    expected = "https://github.com/defunkt/hub/pull/1\n"
    assert_output expected, "pull-request hereyougo -f"
  end

419 420 421 422 423 424 425 426 427
  def test_pullrequest_invalid_remote
    stub_repo_url('gh:singingwolfboy/sekrit.git')
    stub_branch('refs/heads/feature')
    stub_tracking('feature', 'origin', 'feature')

    expected = "Aborted: the origin remote doesn't point to a GitHub repository.\n"
    assert_output expected, "pull-request hereyougo"
  end

428 429 430 431 432
  def test_pullrequest_enterprise_no_tracking
    stub_hub_host('git.my.org')
    stub_repo_url('git@git.my.org:defunkt/hub.git')
    stub_branch('refs/heads/feature')
    stub_tracking_nothing('feature')
433
    stub_command_output "rev-list --cherry-pick --right-only --no-merges origin/feature...", nil
434 435 436
    edit_hub_config do |data|
      data['git.my.org'] = [{'user'=>'myfiname', 'oauth_token' => 'FITOKEN'}]
    end
437

438 439
    stub_request(:post, "https://git.my.org/repos/defunkt/hub/pulls").
      with(:body => {'base' => "master", 'head' => "myfiname:feature", 'title' => "hereyougo" }).
440 441 442 443 444 445
      to_return(:body => mock_pullreq_response(1, 'defunkt/hub', 'git.my.org'))

    expected = "https://git.my.org/defunkt/hub/pull/1\n"
    assert_output expected, "pull-request hereyougo -f"
  end

446
  def test_pullrequest_explicit_head
447 448
    stub_request(:post, "https://api.github.com/repos/defunkt/hub/pulls").
      with(:body => {'base' => "master", 'head' => "tpw:yay-feature", 'title' => "hereyougo" }).
449 450 451
      to_return(:body => mock_pullreq_response(1))

    expected = "https://github.com/defunkt/hub/pull/1\n"
452
    assert_output expected, "pull-request hereyougo -h yay-feature -f"
453 454 455
  end

  def test_pullrequest_explicit_head_with_owner
456 457
    stub_request(:post, "https://api.github.com/repos/defunkt/hub/pulls").
      with(:body => {'base' => "master", 'head' => "mojombo:feature", 'title' => "hereyougo" }).
458 459 460
      to_return(:body => mock_pullreq_response(1))

    expected = "https://github.com/defunkt/hub/pull/1\n"
461
    assert_output expected, "pull-request hereyougo -h mojombo:feature -f"
462 463 464
  end

  def test_pullrequest_explicit_base
465 466
    stub_request(:post, "https://api.github.com/repos/defunkt/hub/pulls").
      with(:body => {'base' => "feature", 'head' => "defunkt:master", 'title' => "hereyougo" }).
467 468 469
      to_return(:body => mock_pullreq_response(1))

    expected = "https://github.com/defunkt/hub/pull/1\n"
470
    assert_output expected, "pull-request hereyougo -b feature -f"
471 472 473
  end

  def test_pullrequest_explicit_base_with_owner
474 475 476
    stub_request(:post, "https://api.github.com/repos/mojombo/hub/pulls").
      with(:body => {'base' => "feature", 'head' => "defunkt:master", 'title' => "hereyougo" }).
      to_return(:body => mock_pullreq_response(1, 'mojombo/hub'))
477

478
    expected = "https://github.com/mojombo/hub/pull/1\n"
479
    assert_output expected, "pull-request hereyougo -b mojombo:feature -f"
480 481
  end

482
  def test_pullrequest_explicit_base_with_repo
483 484 485
    stub_request(:post, "https://api.github.com/repos/mojombo/hubbub/pulls").
      with(:body => {'base' => "feature", 'head' => "defunkt:master", 'title' => "hereyougo" }).
      to_return(:body => mock_pullreq_response(1, 'mojombo/hubbub'))
486

487
    expected = "https://github.com/mojombo/hubbub/pull/1\n"
488
    assert_output expected, "pull-request hereyougo -b mojombo/hubbub:feature -f"
489 490 491
  end

  def test_pullrequest_existing_issue
M
Mislav Marohnić 已提交
492 493
    stub_branch('refs/heads/myfix')
    stub_tracking('myfix', 'mislav', 'awesomefix')
494
    stub_command_output "rev-list --cherry-pick --right-only --no-merges mislav/awesomefix...", nil
M
Mislav Marohnić 已提交
495

496 497
    stub_request(:post, "https://api.github.com/repos/defunkt/hub/pulls").
      with(:body => {'base' => "master", 'head' => "mislav:awesomefix", 'issue' => '92' }).
498 499 500
      to_return(:body => mock_pullreq_response(92))

    expected = "https://github.com/defunkt/hub/pull/92\n"
M
Mislav Marohnić 已提交
501
    assert_output expected, "pull-request -i 92"
502 503
  end

504
  def test_pullrequest_existing_issue_url
M
Mislav Marohnić 已提交
505 506
    stub_branch('refs/heads/myfix')
    stub_tracking('myfix', 'mislav', 'awesomefix')
507
    stub_command_output "rev-list --cherry-pick --right-only --no-merges mislav/awesomefix...", nil
M
Mislav Marohnić 已提交
508

509 510
    stub_request(:post, "https://api.github.com/repos/mojombo/hub/pulls").
      with(:body => {'base' => "master", 'head' => "mislav:awesomefix", 'issue' => '92' }).
511 512 513
      to_return(:body => mock_pullreq_response(92, 'mojombo/hub'))

    expected = "https://github.com/mojombo/hub/pull/92\n"
M
Mislav Marohnić 已提交
514
    assert_output expected, "pull-request https://github.com/mojombo/hub/issues/92#comment_4"
515 516
  end

517
  def test_pullrequest_fails
518
    stub_request(:post, "https://api.github.com/repos/defunkt/hub/pulls").
519 520
      to_return(:status => [422, "Unprocessable Entity"],
                :headers => {"Content-type" => "application/json"},
521
                :body => %({"message":["oh no!\\nit failed."]}))
522 523 524 525 526 527

    expected = "Error creating pull request: Unprocessable Entity (HTTP 422)\n"
    expected << "oh no!\nit failed.\n"
    assert_output expected, "pull-request hereyougo -b feature -f"
  end

528 529 530 531 532
  def test_checkout_no_changes
    assert_forwarded "checkout master"
  end

  def test_checkout_pullrequest
533
    stub_request(:get, "https://api.github.com/repos/defunkt/hub/pulls/73").
534 535 536
      to_return(:body => mock_pull_response('blueyed:feature'))

    assert_commands 'git remote add -f -t feature blueyed git://github.com/blueyed/hub.git',
M
Mislav Marohnić 已提交
537 538
      'git checkout -f --track -B blueyed-feature blueyed/feature -q',
      "checkout -f https://github.com/defunkt/hub/pull/73/files -q"
539 540
  end

541
  def test_checkout_private_pullrequest
542
    stub_request(:get, "https://api.github.com/repos/defunkt/hub/pulls/73").
543 544 545
      to_return(:body => mock_pull_response('blueyed:feature', :private))

    assert_commands 'git remote add -f -t feature blueyed git@github.com:blueyed/hub.git',
M
Mislav Marohnić 已提交
546
      'git checkout --track -B blueyed-feature blueyed/feature',
547 548 549
      "checkout https://github.com/defunkt/hub/pull/73/files"
  end

550
  def test_checkout_pullrequest_custom_branch
551
    stub_request(:get, "https://api.github.com/repos/defunkt/hub/pulls/73").
552 553 554
      to_return(:body => mock_pull_response('blueyed:feature'))

    assert_commands 'git remote add -f -t feature blueyed git://github.com/blueyed/hub.git',
M
Mislav Marohnić 已提交
555
      'git checkout --track -B review blueyed/feature',
556 557 558 559 560 561
      "checkout https://github.com/defunkt/hub/pull/73/files review"
  end

  def test_checkout_pullrequest_existing_remote
    stub_command_output 'remote', "origin\nblueyed"

562
    stub_request(:get, "https://api.github.com/repos/defunkt/hub/pulls/73").
563 564 565 566
      to_return(:body => mock_pull_response('blueyed:feature'))

    assert_commands 'git remote set-branches --add blueyed feature',
      'git fetch blueyed +refs/heads/feature:refs/remotes/blueyed/feature',
M
Mislav Marohnić 已提交
567
      'git checkout --track -B blueyed-feature blueyed/feature',
568 569 570
      "checkout https://github.com/defunkt/hub/pull/73/files"
  end

C
Chris Wanstrath 已提交
571
  def test_version
572
    out = hub('--version')
573
    assert_includes "git version 1.7.0.4", out
C
Chris Wanstrath 已提交
574
    assert_includes "hub version #{Hub::Version}", out
C
Chris Wanstrath 已提交
575
  end
C
Chris Wanstrath 已提交
576

577 578 579 580 581 582 583
  def test_exec_path
    out = hub('--exec-path')
    assert_equal "/usr/lib/git-core\n", out
  end

  def test_exec_path_arg
    out = hub('--exec-path=/home/wombat/share/my-l33t-git-core')
584
    assert_equal improved_help_text, out
585 586 587 588 589 590 591
  end

  def test_html_path
    out = hub('--html-path')
    assert_equal "/usr/share/doc/git-doc\n", out
  end

C
Chris Wanstrath 已提交
592
  def test_help
593
    assert_equal improved_help_text, hub("help")
C
Chris Wanstrath 已提交
594 595 596
  end

  def test_help_by_default
597
    assert_equal improved_help_text, hub("")
C
Chris Wanstrath 已提交
598
  end
C
Chris Wanstrath 已提交
599

S
Stephen Celis 已提交
600
  def test_help_with_pager
601
    assert_equal improved_help_text, hub("-p")
S
Stephen Celis 已提交
602 603
  end

C
Chris Wanstrath 已提交
604 605 606
  def test_help_hub
    help_manpage = hub("help hub")
    assert_includes "git + hub = github", help_manpage
M
Mislav Marohnić 已提交
607
    assert_includes "Hub will prompt for GitHub username & password", help_manpage.gsub(/ {2,}/, ' ')
C
Chris Wanstrath 已提交
608 609
  end

610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
  def test_help_flag_on_command
    help_manpage = hub("browse --help")
    assert_includes "git + hub = github", help_manpage
    assert_includes "git browse", help_manpage
  end

  def test_help_short_flag_on_command
    usage_help = hub("create -h")
    expected = "Usage: git create [NAME] [-p] [-d DESCRIPTION] [-h HOMEPAGE]\n"
    assert_equal expected, usage_help

    usage_help = hub("pull-request -h")
    expected = "Usage: git pull-request [-f] [TITLE|-i ISSUE] [-b BASE] [-h HEAD]\n"
    assert_equal expected, usage_help
  end

C
Chris Wanstrath 已提交
626
  def test_help_hub_no_groff
627 628
    stub_available_commands()
    assert_equal "** Can't find groff(1)\n", hub("help hub")
C
Chris Wanstrath 已提交
629
  end
630

631
  def test_hub_standalone
632
    assert_includes 'This file is generated code', hub("hub standalone")
633 634
  end

C
Chris Wanstrath 已提交
635 636
  def test_hub_compare
    assert_command "compare refactor",
637
      "open https://github.com/defunkt/hub/compare/refactor"
638
  end
C
Chris Wanstrath 已提交
639

640 641 642 643
  def test_hub_compare_nothing
    expected = "Usage: hub compare [USER] [<START>...]<END>\n"
    assert_equal expected, hub("compare")
  end
C
Chris Wanstrath 已提交
644

645 646 647 648 649 650 651 652
  def test_hub_compare_tracking_nothing
    stub_tracking_nothing
    expected = "Usage: hub compare [USER] [<START>...]<END>\n"
    assert_equal expected, hub("compare")
  end

  def test_hub_compare_tracking_branch
    stub_branch('refs/heads/feature')
653
    stub_tracking('feature', 'mislav', 'experimental')
654 655

    assert_command "compare",
656
      "open https://github.com/mislav/hub/compare/experimental"
657 658
  end

659
  def test_hub_compare_range
C
Chris Wanstrath 已提交
660
    assert_command "compare 1.0...fix",
661
      "open https://github.com/defunkt/hub/compare/1.0...fix"
662
  end
C
Chris Wanstrath 已提交
663

664 665 666 667 668 669 670 671 672 673 674 675 676 677 678
  def test_hub_compare_range_fixes_two_dots_for_tags
    assert_command "compare 1.0..fix",
      "open https://github.com/defunkt/hub/compare/1.0...fix"
  end

  def test_hub_compare_range_fixes_two_dots_for_shas
    assert_command "compare 1234abc..3456cde",
      "open https://github.com/defunkt/hub/compare/1234abc...3456cde"
  end

  def test_hub_compare_range_ignores_two_dots_for_complex_ranges
    assert_command "compare @{a..b}..@{c..d}",
      "open https://github.com/defunkt/hub/compare/@{a..b}..@{c..d}"
  end

679 680 681 682 683 684
  def test_hub_compare_on_wiki
    stub_repo_url 'git://github.com/defunkt/hub.wiki.git'
    assert_command "compare 1.0...fix",
      "open https://github.com/defunkt/hub/wiki/_compare/1.0...fix"
  end

685
  def test_hub_compare_fork
C
Chris Wanstrath 已提交
686
    assert_command "compare myfork feature",
687
      "open https://github.com/myfork/hub/compare/feature"
688 689 690 691
  end

  def test_hub_compare_url
    assert_command "compare -u 1.0...1.1",
692
      "echo https://github.com/defunkt/hub/compare/1.0...1.1"
693 694 695
  end

  def test_hub_browse
696
    assert_command "browse mojombo/bert", "open https://github.com/mojombo/bert"
697 698
  end

699 700 701 702
  def test_hub_browse_commit
    assert_command "browse mojombo/bert commit/5d5582", "open https://github.com/mojombo/bert/commit/5d5582"
  end

703 704
  def test_hub_browse_tracking_nothing
    stub_tracking_nothing
705
    assert_command "browse mojombo/bert", "open https://github.com/mojombo/bert"
706 707
  end

708
  def test_hub_browse_url
709
    assert_command "browse -u mojombo/bert", "echo https://github.com/mojombo/bert"
710 711
  end

712
  def test_hub_browse_self
713
    assert_command "browse resque", "open https://github.com/tpw/resque"
714 715
  end

716 717
  def test_hub_browse_subpage
    assert_command "browse resque commits",
718
      "open https://github.com/tpw/resque/commits/master"
719
    assert_command "browse resque issues",
720
      "open https://github.com/tpw/resque/issues"
721
    assert_command "browse resque wiki",
722
      "open https://github.com/tpw/resque/wiki"
723 724 725 726
  end

  def test_hub_browse_on_branch
    stub_branch('refs/heads/feature')
727
    stub_tracking('feature', 'mislav', 'experimental')
728

729
    assert_command "browse resque", "open https://github.com/tpw/resque"
730
    assert_command "browse resque commits",
731
      "open https://github.com/tpw/resque/commits/master"
732 733

    assert_command "browse",
734
      "open https://github.com/mislav/hub/tree/experimental"
735
    assert_command "browse -- tree",
736
      "open https://github.com/mislav/hub/tree/experimental"
737
    assert_command "browse -- commits",
738
      "open https://github.com/mislav/hub/commits/experimental"
739
  end
740

741 742 743 744 745 746 747 748
  def test_hub_browse_on_complex_branch
    stub_branch('refs/heads/feature/foo')
    stub_tracking('feature/foo', 'mislav', 'feature/bar')

    assert_command 'browse',
      'open https://github.com/mislav/hub/tree/feature/bar'
  end

749 750 751 752 753
  def test_hub_browse_no_branch
    stub_branch(nil)
    assert_command 'browse', 'open https://github.com/defunkt/hub'
  end

754
  def test_hub_browse_current
755 756
    assert_command "browse", "open https://github.com/defunkt/hub"
    assert_command "browse --", "open https://github.com/defunkt/hub"
757 758
  end

759 760 761 762 763
  def test_hub_browse_current_https_uri
    stub_repo_url "https://github.com/defunkt/hub"
    assert_command "browse", "open https://github.com/defunkt/hub"
  end

764 765 766 767
  def test_hub_browse_commit_from_current
    assert_command "browse -- commit/6616e4", "open https://github.com/defunkt/hub/commit/6616e4"
  end

768 769 770 771 772 773 774
  def test_hub_browse_no_tracking
    stub_tracking_nothing
    assert_command "browse", "open https://github.com/defunkt/hub"
  end

  def test_hub_browse_no_tracking_on_branch
    stub_branch('refs/heads/feature')
775
    stub_tracking_nothing('feature')
776 777 778
    assert_command "browse", "open https://github.com/defunkt/hub"
  end

779 780 781 782 783 784 785 786 787
  def test_hub_browse_current_wiki
    stub_repo_url 'git://github.com/defunkt/hub.wiki.git'

    assert_command "browse", "open https://github.com/defunkt/hub/wiki"
    assert_command "browse -- wiki", "open https://github.com/defunkt/hub/wiki"
    assert_command "browse -- commits", "open https://github.com/defunkt/hub/wiki/_history"
    assert_command "browse -- pages", "open https://github.com/defunkt/hub/wiki/_pages"
  end

788 789
  def test_hub_browse_current_subpage
    assert_command "browse -- network",
790
      "open https://github.com/defunkt/hub/network"
791
    assert_command "browse -- anything/everything",
792
      "open https://github.com/defunkt/hub/anything/everything"
793 794
  end

795 796 797 798
  def test_hub_browse_deprecated_private
    with_browser_env('echo') do
      assert_includes "Warning: the `-p` flag has no effect anymore\n", hub("browse -p defunkt/hub")
    end
799 800
  end

801 802 803
  def test_hub_browse_no_repo
    stub_repo_url(nil)
    assert_equal "Usage: hub browse [<USER>/]<REPOSITORY>\n", hub("browse")
804
  end
805

806 807 808 809 810 811 812
  def test_hub_browse_ssh_alias
    with_ssh_config do
      stub_repo_url "gh:singingwolfboy/sekrit.git"
      assert_command "browse", "open https://github.com/singingwolfboy/sekrit"
    end
  end

813 814 815 816 817 818 819 820 821
  def test_custom_browser
    with_browser_env("custom") do
      assert_browser("custom")
    end
  end

  def test_linux_browser
    stub_available_commands "open", "xdg-open", "cygstart"
    with_browser_env(nil) do
822
      with_host_os("i686-linux") do
823 824 825 826 827 828 829 830
        assert_browser("xdg-open")
      end
    end
  end

  def test_cygwin_browser
    stub_available_commands "open", "cygstart"
    with_browser_env(nil) do
831
      with_host_os("i686-linux") do
832 833 834 835 836 837 838 839 840
        assert_browser("cygstart")
      end
    end
  end

  def test_no_browser
    stub_available_commands()
    expected = "Please set $BROWSER to a web launcher to use this command.\n"
    with_browser_env(nil) do
841
      with_host_os("i686-linux") do
842 843 844 845 846
        assert_equal expected, hub("browse")
      end
    end
  end

847
  def test_context_method_doesnt_hijack_git_command
848
    assert_forwarded 'remotes'
849 850
  end

851 852 853 854 855
  def test_not_choking_on_ruby_methods
    assert_forwarded 'id'
    assert_forwarded 'name'
  end

856 857
  def test_multiple_remote_urls
    stub_repo_url("git://example.com/other.git\ngit://github.com/my/repo.git")
858
    assert_command "browse", "open https://github.com/my/repo"
859 860
  end

861 862 863
  def test_global_flags_preserved
    cmd = '--no-pager --bare -c core.awesome=true -c name=value --git-dir=/srv/www perform'
    assert_command cmd, 'git --bare -c core.awesome=true -c name=value --git-dir=/srv/www --no-pager perform'
864
    assert_equal %w[git --bare -c core.awesome=true -c name=value --git-dir=/srv/www], git_reader.executable
865 866
  end

867
  private
868

M
Mislav Marohnić 已提交
869 870
    def stub_repo_url(value, remote_name = 'origin')
      stub_config_value "remote.#{remote_name}.url", value, '--get-all'
871 872 873
    end

    def stub_branch(value)
874
      stub_command_output 'symbolic-ref -q HEAD', value
875 876
    end

877
    def stub_tracking(from, upstream, remote_branch = nil)
878
      stub_command_output "rev-parse --symbolic-full-name #{from}@{upstream}",
879
        remote_branch ? "refs/remotes/#{upstream}/#{remote_branch}" : upstream
880 881
    end

882
    def stub_tracking_nothing(from = 'master')
883
      stub_tracking(from, nil)
884 885
    end

886
    def stub_remotes_group(name, value)
887
      stub_config_value "remotes.#{name}", value
888 889
    end

890
    def stub_no_remotes
891
      stub_command_output 'remote', nil
892 893 894
    end

    def stub_no_git_repo
895
      stub_command_output 'rev-parse -q --git-dir', nil
896 897
    end

M
Mislav Marohnić 已提交
898
    def stub_alias(name, value)
899
      stub_config_value "alias.#{name}", value
M
Mislav Marohnić 已提交
900 901
    end

902 903
    def stub_existing_fork(user, repo = 'hub')
      stub_fork(user, repo, 200)
904 905
    end

906 907
    def stub_nonexisting_fork(user, repo = 'hub')
      stub_fork(user, repo, 404)
908 909
    end

910
    def stub_fork(user, repo, status)
911
      stub_request(:get, "https://api.github.com/repos/#{user}/#{repo}").
912 913 914
        to_return(:status => status)
    end

915 916 917 918
    def stub_available_commands(*names)
      COMMANDS.replace names
    end

919
    def stub_https_is_preferred
920
      stub_config_value 'hub.protocol', 'https'
921 922
    end

923 924 925 926
    def stub_hub_host(names)
      stub_config_value "hub.host", Array(names).join("\n"), '--get-all'
    end

927 928 929 930 931 932 933
    def with_browser_env(value)
      browser, ENV['BROWSER'] = ENV['BROWSER'], value
      yield
    ensure
      ENV['BROWSER'] = browser
    end

934 935 936 937 938 939 940
    def with_tmpdir(value)
      dir, ENV['TMPDIR'] = ENV['TMPDIR'], value
      yield
    ensure
      ENV['TMPDIR'] = dir
    end

941 942 943 944 945 946 947
    def with_host_env(value)
      host, ENV['GITHUB_HOST'] = ENV['GITHUB_HOST'], value
      yield
    ensure
      ENV['GITHUB_HOST'] = host
    end

948
    def assert_browser(browser)
949
      assert_command "browse", "#{browser} https://github.com/defunkt/hub"
950 951
    end

952 953 954 955 956 957 958 959
    def with_host_os(value)
      host_os = RbConfig::CONFIG['host_os']
      RbConfig::CONFIG['host_os'] = value
      begin
        yield
      ensure
        RbConfig::CONFIG['host_os'] = host_os
      end
960 961
    end

962
    def mock_pullreq_response(id, name_with_owner = 'defunkt/hub', host = 'github.com')
963
      Hub::JSON.generate :html_url => "https://#{host}/#{name_with_owner}/pull/#{id}"
964 965
    end

966
    def mock_pull_response(label, priv = false)
967 968 969
      Hub::JSON.generate :head => {
        :label => label,
        :repo => {:private => !!priv}
J
John Firebaugh 已提交
970
      }, :title => "Make eyes blue"
971 972
    end

973 974 975 976
    def improved_help_text
      Hub::Commands.send :improved_help_text
    end

977 978
    def with_ssh_config
      config_file = File.expand_path '../ssh_config', __FILE__
979
      Hub::SshConfig::CONFIG_FILES.replace [config_file]
980 981 982
      yield
    end

C
Chris Wanstrath 已提交
983
end