hub_test.rb 24.6 KB
Newer Older
1
require 'helper'
2
require 'webmock/test_unit'
3
require 'rbconfig'
4
require 'yaml'
5
require 'forwardable'
6
require 'fileutils'
M
Mislav Marohnić 已提交
7
require 'tempfile'
C
Chris Wanstrath 已提交
8

9 10 11 12 13 14
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 已提交
15
class HubTest < Test::Unit::TestCase
16 17
  extend Forwardable

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

24 25
  COMMANDS = []

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

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

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

43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
    @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

58 59 60
    @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ć 已提交
61
      end
62 63 64 65
    end

    Hub::Commands.instance_variable_set :@git_reader, @git_reader
    Hub::Commands.instance_variable_set :@local_repo, nil
66 67 68 69 70 71 72
    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
73 74

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

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

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

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

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

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

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

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

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

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

131 132 133 134 135 136 137 138
  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",
139
                      "am --signoff https://github.com/defunkt/hub/pull/55#comment_123 -p2"
140 141 142

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

146 147 148 149 150 151 152
  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

153 154 155 156 157 158 159 160 161 162
  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

163 164 165 166 167 168 169 170 171 172
  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

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 207
  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 已提交
208
  def test_init
M
Mislav Marohnić 已提交
209 210
    stub_no_remotes
    stub_no_git_repo
211
    assert_commands "git init", "git remote add origin git@github.com:tpw/hub.git", "init -g"
212 213
  end

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

221 222 223 224 225
    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

226 227 228 229
  def test_push_untouched
    assert_forwarded "push"
  end

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

235 236 237 238 239 240
  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 已提交
241
  def test_push_more
242 243 244 245
    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 已提交
246
  end
C
Chris Wanstrath 已提交
247

248
  def test_pullrequest
M
Mislav Marohnić 已提交
249 250 251
    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"
252 253
  end

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

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

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

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

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

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

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

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

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

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

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

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

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

319
    stub_request(:post, "https://git.my.org/api/v3/repos/defunkt/hub/pulls").
320
      with(:body => {'base' => "master", 'head' => "myfiname:feature", 'title' => "hereyougo" }).
321
      to_return(:body => mock_pullreq_response(1, 'api/v3/defunkt/hub', 'git.my.org'))
322

323
    expected = "https://git.my.org/api/v3/defunkt/hub/pull/1\n"
324 325 326
    assert_output expected, "pull-request hereyougo -f"
  end

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

581
  def test_hub_browse_ssh_alias
M
Mislav Marohnić 已提交
582
    with_ssh_config "Host gh\n User git\n HostName github.com" do
583 584 585 586 587
      stub_repo_url "gh:singingwolfboy/sekrit.git"
      assert_command "browse", "open https://github.com/singingwolfboy/sekrit"
    end
  end

M
Mislav Marohnić 已提交
588 589 590 591 592 593 594
  def test_hub_browse_ssh_github_alias
    with_ssh_config "Host github.com\n HostName ssh.github.com" do
      stub_repo_url "git@github.com:suan/git-sanity.git"
      assert_command "browse", "open https://github.com/suan/git-sanity"
    end
  end

595 596 597 598 599 600 601 602 603
  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
604
      with_host_os("i686-linux") do
605 606 607 608 609 610 611 612
        assert_browser("xdg-open")
      end
    end
  end

  def test_cygwin_browser
    stub_available_commands "open", "cygstart"
    with_browser_env(nil) do
613
      with_host_os("i686-linux") do
614 615 616 617 618 619 620 621 622
        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
623
      with_host_os("i686-linux") do
624 625 626 627 628
        assert_equal expected, hub("browse")
      end
    end
  end

629
  def test_context_method_doesnt_hijack_git_command
630
    assert_forwarded 'remotes'
631 632
  end

633 634 635 636 637
  def test_not_choking_on_ruby_methods
    assert_forwarded 'id'
    assert_forwarded 'name'
  end

638 639
  def test_multiple_remote_urls
    stub_repo_url("git://example.com/other.git\ngit://github.com/my/repo.git")
640
    assert_command "browse", "open https://github.com/my/repo"
641 642
  end

643 644 645
  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'
646
    assert_equal %w[git --bare -c core.awesome=true -c name=value --git-dir=/srv/www], git_reader.executable
647 648
  end

649
  private
650

M
Mislav Marohnić 已提交
651 652
    def stub_repo_url(value, remote_name = 'origin')
      stub_config_value "remote.#{remote_name}.url", value, '--get-all'
653 654 655
    end

    def stub_branch(value)
656
      stub_command_output 'symbolic-ref -q HEAD', value
657 658
    end

659
    def stub_tracking(from, upstream, remote_branch = nil)
660
      stub_command_output "rev-parse --symbolic-full-name #{from}@{upstream}",
661
        remote_branch ? "refs/remotes/#{upstream}/#{remote_branch}" : upstream
662 663
    end

664
    def stub_tracking_nothing(from = 'master')
665
      stub_tracking(from, nil)
666 667
    end

668
    def stub_remotes_group(name, value)
669
      stub_config_value "remotes.#{name}", value
670 671
    end

672
    def stub_no_remotes
673
      stub_command_output 'remote', nil
674 675 676
    end

    def stub_no_git_repo
677
      stub_command_output 'rev-parse -q --git-dir', nil
678 679
    end

M
Mislav Marohnić 已提交
680
    def stub_alias(name, value)
681
      stub_config_value "alias.#{name}", value
M
Mislav Marohnić 已提交
682 683
    end

684 685
    def stub_existing_fork(user, repo = 'hub')
      stub_fork(user, repo, 200)
686 687
    end

688 689
    def stub_nonexisting_fork(user, repo = 'hub')
      stub_fork(user, repo, 404)
690 691
    end

692
    def stub_fork(user, repo, status)
693
      stub_request(:get, "https://api.github.com/repos/#{user}/#{repo}").
694 695 696
        to_return(:status => status)
    end

697 698 699 700
    def stub_available_commands(*names)
      COMMANDS.replace names
    end

701
    def stub_https_is_preferred
702
      stub_config_value 'hub.protocol', 'https'
703 704
    end

705 706 707 708
    def stub_hub_host(names)
      stub_config_value "hub.host", Array(names).join("\n"), '--get-all'
    end

709 710 711 712 713 714 715
    def with_browser_env(value)
      browser, ENV['BROWSER'] = ENV['BROWSER'], value
      yield
    ensure
      ENV['BROWSER'] = browser
    end

716 717 718 719 720 721 722
    def with_tmpdir(value)
      dir, ENV['TMPDIR'] = ENV['TMPDIR'], value
      yield
    ensure
      ENV['TMPDIR'] = dir
    end

723 724 725 726 727 728 729
    def with_host_env(value)
      host, ENV['GITHUB_HOST'] = ENV['GITHUB_HOST'], value
      yield
    ensure
      ENV['GITHUB_HOST'] = host
    end

730
    def assert_browser(browser)
731
      assert_command "browse", "#{browser} https://github.com/defunkt/hub"
732 733
    end

734 735 736 737 738 739 740 741
    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
742 743
    end

744
    def mock_pullreq_response(id, name_with_owner = 'defunkt/hub', host = 'github.com')
745
      Hub::JSON.generate :html_url => "https://#{host}/#{name_with_owner}/pull/#{id}"
746 747
    end

748
    def mock_pull_response(label, priv = false)
749 750 751
      Hub::JSON.generate :head => {
        :label => label,
        :repo => {:private => !!priv}
M
Mislav Marohnić 已提交
752
      }
753 754
    end

755 756 757 758
    def improved_help_text
      Hub::Commands.send :improved_help_text
    end

M
Mislav Marohnić 已提交
759 760 761 762 763 764 765 766 767 768 769
    def with_ssh_config content
      config_file = Tempfile.open 'ssh_config'
      config_file << content
      config_file.close

      begin
        Hub::SshConfig::CONFIG_FILES.replace [config_file.path]
        yield
      ensure
        config_file.unlink
      end
770 771
    end

C
Chris Wanstrath 已提交
772
end