hub_test.rb 24.2 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_pullrequest
M
Mislav Marohnić 已提交
248 249 250
    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"
251 252
  end

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

M
Mislav Marohnić 已提交
257
    expected = "Aborted: 2 commits are not yet pushed to mislav/master\n" <<
258
      "(use `-f` to force submit a pull request anyway)\n"
259 260 261 262 263 264
    assert_output expected, "pull-request hereyougo"
  end

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

266 267 268
    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
269
      }.to_return(:body => mock_pullreq_response(1))
270 271

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

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

279 280
    stub_request(:post, "https://api.github.com/repos/defunkt/hub/pulls").
      with(:body => {'base' => "master", 'head' => "mislav:yay-feature", 'title' => "hereyougo" }).
281 282 283
      to_return(:body => mock_pullreq_response(1))

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

287 288 289 290
  def test_pullrequest_from_branch_tracking_local
    stub_branch('refs/heads/feature')
    stub_tracking('feature', 'refs/heads/master')

291 292
    stub_request(:post, "https://api.github.com/repos/defunkt/hub/pulls").
      with(:body => {'base' => "master", 'head' => "tpw:feature", 'title' => "hereyougo" }).
293 294 295 296 297 298
      to_return(:body => mock_pullreq_response(1))

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

299 300 301 302 303 304 305 306 307
  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

308 309 310 311 312
  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')
313
    stub_command_output "rev-list --cherry-pick --right-only --no-merges origin/feature...", nil
314 315 316
    edit_hub_config do |data|
      data['git.my.org'] = [{'user'=>'myfiname', 'oauth_token' => 'FITOKEN'}]
    end
317

318 319
    stub_request(:post, "https://git.my.org/repos/defunkt/hub/pulls").
      with(:body => {'base' => "master", 'head' => "myfiname:feature", 'title' => "hereyougo" }).
320 321 322 323 324 325
      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

326
  def test_pullrequest_explicit_head
327 328
    stub_request(:post, "https://api.github.com/repos/defunkt/hub/pulls").
      with(:body => {'base' => "master", 'head' => "tpw:yay-feature", 'title' => "hereyougo" }).
329 330 331
      to_return(:body => mock_pullreq_response(1))

    expected = "https://github.com/defunkt/hub/pull/1\n"
332
    assert_output expected, "pull-request hereyougo -h yay-feature -f"
333 334 335
  end

  def test_pullrequest_explicit_head_with_owner
336 337
    stub_request(:post, "https://api.github.com/repos/defunkt/hub/pulls").
      with(:body => {'base' => "master", 'head' => "mojombo:feature", 'title' => "hereyougo" }).
338 339 340
      to_return(:body => mock_pullreq_response(1))

    expected = "https://github.com/defunkt/hub/pull/1\n"
341
    assert_output expected, "pull-request hereyougo -h mojombo:feature -f"
342 343 344
  end

  def test_pullrequest_explicit_base
345 346
    stub_request(:post, "https://api.github.com/repos/defunkt/hub/pulls").
      with(:body => {'base' => "feature", 'head' => "defunkt:master", 'title' => "hereyougo" }).
347 348 349
      to_return(:body => mock_pullreq_response(1))

    expected = "https://github.com/defunkt/hub/pull/1\n"
350
    assert_output expected, "pull-request hereyougo -b feature -f"
351 352 353
  end

  def test_pullrequest_explicit_base_with_owner
354 355 356
    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'))
357

358
    expected = "https://github.com/mojombo/hub/pull/1\n"
359
    assert_output expected, "pull-request hereyougo -b mojombo:feature -f"
360 361
  end

362
  def test_pullrequest_explicit_base_with_repo
363 364 365
    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'))
366

367
    expected = "https://github.com/mojombo/hubbub/pull/1\n"
368
    assert_output expected, "pull-request hereyougo -b mojombo/hubbub:feature -f"
369 370 371
  end

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

376 377
    stub_request(:post, "https://api.github.com/repos/defunkt/hub/pulls").
      with(:body => {'base' => "master", 'head' => "mislav:awesomefix", 'issue' => '92' }).
378 379 380
      to_return(:body => mock_pullreq_response(92))

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

384
  def test_pullrequest_existing_issue_url
M
Mislav Marohnić 已提交
385 386
    stub_branch('refs/heads/myfix')
    stub_tracking('myfix', 'mislav', 'awesomefix')
387
    stub_command_output "rev-list --cherry-pick --right-only --no-merges mislav/awesomefix...", nil
M
Mislav Marohnić 已提交
388

389 390
    stub_request(:post, "https://api.github.com/repos/mojombo/hub/pulls").
      with(:body => {'base' => "master", 'head' => "mislav:awesomefix", 'issue' => '92' }).
391 392 393
      to_return(:body => mock_pullreq_response(92, 'mojombo/hub'))

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

397
  def test_pullrequest_fails
398
    stub_request(:post, "https://api.github.com/repos/defunkt/hub/pulls").
399 400
      to_return(:status => [422, "Unprocessable Entity"],
                :headers => {"Content-type" => "application/json"},
401
                :body => %({"message":["oh no!\\nit failed."]}))
402 403 404 405 406 407

    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

408 409 410 411 412
  def test_checkout_no_changes
    assert_forwarded "checkout master"
  end

  def test_checkout_pullrequest
413
    stub_request(:get, "https://api.github.com/repos/defunkt/hub/pulls/73").
414 415 416
      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ć 已提交
417 418
      'git checkout -f --track -B blueyed-feature blueyed/feature -q',
      "checkout -f https://github.com/defunkt/hub/pull/73/files -q"
419 420
  end

421
  def test_checkout_private_pullrequest
422
    stub_request(:get, "https://api.github.com/repos/defunkt/hub/pulls/73").
423 424 425
      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ć 已提交
426
      'git checkout --track -B blueyed-feature blueyed/feature',
427 428 429
      "checkout https://github.com/defunkt/hub/pull/73/files"
  end

430
  def test_checkout_pullrequest_custom_branch
431
    stub_request(:get, "https://api.github.com/repos/defunkt/hub/pulls/73").
432 433 434
      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ć 已提交
435
      'git checkout --track -B review blueyed/feature',
436 437 438 439 440 441
      "checkout https://github.com/defunkt/hub/pull/73/files review"
  end

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

442
    stub_request(:get, "https://api.github.com/repos/defunkt/hub/pulls/73").
443 444 445 446
      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ć 已提交
447
      'git checkout --track -B blueyed-feature blueyed/feature',
448 449 450
      "checkout https://github.com/defunkt/hub/pull/73/files"
  end

C
Chris Wanstrath 已提交
451
  def test_version
452
    out = hub('--version')
453
    assert_includes "git version 1.7.0.4", out
C
Chris Wanstrath 已提交
454
    assert_includes "hub version #{Hub::Version}", out
C
Chris Wanstrath 已提交
455
  end
C
Chris Wanstrath 已提交
456

457 458 459 460 461 462 463
  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')
464
    assert_equal improved_help_text, out
465 466 467 468 469 470 471
  end

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

C
Chris Wanstrath 已提交
472
  def test_help
473
    assert_equal improved_help_text, hub("help")
C
Chris Wanstrath 已提交
474 475 476
  end

  def test_help_by_default
477
    assert_equal improved_help_text, hub("")
C
Chris Wanstrath 已提交
478
  end
C
Chris Wanstrath 已提交
479

S
Stephen Celis 已提交
480
  def test_help_with_pager
481
    assert_equal improved_help_text, hub("-p")
S
Stephen Celis 已提交
482 483
  end

C
Chris Wanstrath 已提交
484 485 486
  def test_help_hub
    help_manpage = hub("help hub")
    assert_includes "git + hub = github", help_manpage
M
Mislav Marohnić 已提交
487
    assert_includes "Hub will prompt for GitHub username & password", help_manpage.gsub(/ {2,}/, ' ')
C
Chris Wanstrath 已提交
488 489
  end

490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505
  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 已提交
506
  def test_help_hub_no_groff
507 508
    stub_available_commands()
    assert_equal "** Can't find groff(1)\n", hub("help hub")
C
Chris Wanstrath 已提交
509
  end
510

511
  def test_hub_standalone
512
    assert_includes 'This file is generated code', hub("hub standalone")
513 514
  end

C
Chris Wanstrath 已提交
515 516
  def test_hub_compare
    assert_command "compare refactor",
517
      "open https://github.com/defunkt/hub/compare/refactor"
518
  end
C
Chris Wanstrath 已提交
519

520 521 522 523
  def test_hub_compare_nothing
    expected = "Usage: hub compare [USER] [<START>...]<END>\n"
    assert_equal expected, hub("compare")
  end
C
Chris Wanstrath 已提交
524

525 526 527 528 529 530 531 532
  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')
533
    stub_tracking('feature', 'mislav', 'experimental')
534 535

    assert_command "compare",
536
      "open https://github.com/mislav/hub/compare/experimental"
537 538
  end

539
  def test_hub_compare_range
C
Chris Wanstrath 已提交
540
    assert_command "compare 1.0...fix",
541
      "open https://github.com/defunkt/hub/compare/1.0...fix"
542
  end
C
Chris Wanstrath 已提交
543

544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
  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

559 560 561 562 563 564
  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

565
  def test_hub_compare_fork
C
Chris Wanstrath 已提交
566
    assert_command "compare myfork feature",
567
      "open https://github.com/myfork/hub/compare/feature"
568 569 570 571
  end

  def test_hub_compare_url
    assert_command "compare -u 1.0...1.1",
572
      "echo https://github.com/defunkt/hub/compare/1.0...1.1"
573 574 575 576 577
  end

  def test_hub_browse_no_repo
    stub_repo_url(nil)
    assert_equal "Usage: hub browse [<USER>/]<REPOSITORY>\n", hub("browse")
578
  end
579

580 581 582 583 584 585 586
  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

587 588 589 590 591 592 593 594 595
  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
596
      with_host_os("i686-linux") do
597 598 599 600 601 602 603 604
        assert_browser("xdg-open")
      end
    end
  end

  def test_cygwin_browser
    stub_available_commands "open", "cygstart"
    with_browser_env(nil) do
605
      with_host_os("i686-linux") do
606 607 608 609 610 611 612 613 614
        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
615
      with_host_os("i686-linux") do
616 617 618 619 620
        assert_equal expected, hub("browse")
      end
    end
  end

621
  def test_context_method_doesnt_hijack_git_command
622
    assert_forwarded 'remotes'
623 624
  end

625 626 627 628 629
  def test_not_choking_on_ruby_methods
    assert_forwarded 'id'
    assert_forwarded 'name'
  end

630 631
  def test_multiple_remote_urls
    stub_repo_url("git://example.com/other.git\ngit://github.com/my/repo.git")
632
    assert_command "browse", "open https://github.com/my/repo"
633 634
  end

635 636 637
  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'
638
    assert_equal %w[git --bare -c core.awesome=true -c name=value --git-dir=/srv/www], git_reader.executable
639 640
  end

641
  private
642

M
Mislav Marohnić 已提交
643 644
    def stub_repo_url(value, remote_name = 'origin')
      stub_config_value "remote.#{remote_name}.url", value, '--get-all'
645 646 647
    end

    def stub_branch(value)
648
      stub_command_output 'symbolic-ref -q HEAD', value
649 650
    end

651
    def stub_tracking(from, upstream, remote_branch = nil)
652
      stub_command_output "rev-parse --symbolic-full-name #{from}@{upstream}",
653
        remote_branch ? "refs/remotes/#{upstream}/#{remote_branch}" : upstream
654 655
    end

656
    def stub_tracking_nothing(from = 'master')
657
      stub_tracking(from, nil)
658 659
    end

660
    def stub_remotes_group(name, value)
661
      stub_config_value "remotes.#{name}", value
662 663
    end

664
    def stub_no_remotes
665
      stub_command_output 'remote', nil
666 667 668
    end

    def stub_no_git_repo
669
      stub_command_output 'rev-parse -q --git-dir', nil
670 671
    end

M
Mislav Marohnić 已提交
672
    def stub_alias(name, value)
673
      stub_config_value "alias.#{name}", value
M
Mislav Marohnić 已提交
674 675
    end

676 677
    def stub_existing_fork(user, repo = 'hub')
      stub_fork(user, repo, 200)
678 679
    end

680 681
    def stub_nonexisting_fork(user, repo = 'hub')
      stub_fork(user, repo, 404)
682 683
    end

684
    def stub_fork(user, repo, status)
685
      stub_request(:get, "https://api.github.com/repos/#{user}/#{repo}").
686 687 688
        to_return(:status => status)
    end

689 690 691 692
    def stub_available_commands(*names)
      COMMANDS.replace names
    end

693
    def stub_https_is_preferred
694
      stub_config_value 'hub.protocol', 'https'
695 696
    end

697 698 699 700
    def stub_hub_host(names)
      stub_config_value "hub.host", Array(names).join("\n"), '--get-all'
    end

701 702 703 704 705 706 707
    def with_browser_env(value)
      browser, ENV['BROWSER'] = ENV['BROWSER'], value
      yield
    ensure
      ENV['BROWSER'] = browser
    end

708 709 710 711 712 713 714
    def with_tmpdir(value)
      dir, ENV['TMPDIR'] = ENV['TMPDIR'], value
      yield
    ensure
      ENV['TMPDIR'] = dir
    end

715 716 717 718 719 720 721
    def with_host_env(value)
      host, ENV['GITHUB_HOST'] = ENV['GITHUB_HOST'], value
      yield
    ensure
      ENV['GITHUB_HOST'] = host
    end

722
    def assert_browser(browser)
723
      assert_command "browse", "#{browser} https://github.com/defunkt/hub"
724 725
    end

726 727 728 729 730 731 732 733
    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
734 735
    end

736
    def mock_pullreq_response(id, name_with_owner = 'defunkt/hub', host = 'github.com')
737
      Hub::JSON.generate :html_url => "https://#{host}/#{name_with_owner}/pull/#{id}"
738 739
    end

740
    def mock_pull_response(label, priv = false)
741 742 743
      Hub::JSON.generate :head => {
        :label => label,
        :repo => {:private => !!priv}
M
Mislav Marohnić 已提交
744
      }
745 746
    end

747 748 749 750
    def improved_help_text
      Hub::Commands.send :improved_help_text
    end

751 752
    def with_ssh_config
      config_file = File.expand_path '../ssh_config', __FILE__
753
      Hub::SshConfig::CONFIG_FILES.replace [config_file]
754 755 756
      yield
    end

C
Chris Wanstrath 已提交
757
end