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

6 7 8 9 10 11
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 已提交
12
class HubTest < Test::Unit::TestCase
13 14 15 16 17
  if defined? WebMock::API
    include WebMock::API
  else
    include WebMock
  end
C
Chris Wanstrath 已提交
18

19 20
  COMMANDS = []

21 22 23 24
  Hub::Context.class_eval do
    remove_method :which
    define_method :which do |name|
      COMMANDS.include?(name) ? "/usr/bin/#{name}" : nil
25 26 27
    end
  end

28
  def setup
29
    COMMANDS.replace %w[open groff]
30
    Hub::Context::DIRNAME.replace 'hub'
31
    Hub::Context::REMOTES.clear
32
    Hub::Context::Remote.clear!
33

34 35
    Hub::Context::GIT_CONFIG.executable = 'git'

36
    @git = Hub::Context::GIT_CONFIG.replace(Hash.new { |h, k|
M
Mislav Marohnić 已提交
37 38 39
      unless k.index('config alias.') == 0
        raise ArgumentError, "`git #{k}` not stubbed"
      end
40
    }).update(
41
      'remote' => "mislav\norigin",
42 43 44
      'symbolic-ref -q HEAD' => 'refs/heads/master',
      'config github.user'   => 'tpw',
      'config github.token'  => 'abc123',
45 46
      'config --get-all remote.origin.url' => 'git://github.com/defunkt/hub.git',
      'config --get-all remote.mislav.url' => 'git://github.com/mislav/hub.git',
47
      "name-rev master@{upstream} --name-only --refs='refs/remotes/*' --no-undefined" => 'remotes/origin/master',
48
      'config --bool hub.http-clone' => 'false',
49
      'config hub.protocol' => nil,
50
      'rev-parse --git-dir' => '.git'
51
    )
52
    super
53 54
  end

C
Chris Wanstrath 已提交
55
  def test_private_clone
56 57
    input   = "clone -p rtomayko/ronn"
    command = "git clone git@github.com:rtomayko/ronn.git"
C
Chris Wanstrath 已提交
58
    assert_command input, command
C
Chris Wanstrath 已提交
59 60
  end

61 62 63 64 65 66 67
  def test_https_clone
    stub_https_is_preferred
    input   = "clone rtomayko/ronn"
    command = "git clone https://github.com/rtomayko/ronn.git"
    assert_command input, command
  end

C
Chris Wanstrath 已提交
68
  def test_public_clone
69 70
    input   = "clone rtomayko/ronn"
    command = "git clone git://github.com/rtomayko/ronn.git"
C
Chris Wanstrath 已提交
71
    assert_command input, command
C
Chris Wanstrath 已提交
72 73
  end

74 75 76 77 78 79 80 81 82 83 84 85
  def test_your_private_clone
    input   = "clone -p resque"
    command = "git clone git@github.com:tpw/resque.git"
    assert_command input, command
  end

  def test_your_public_clone
    input   = "clone resque"
    command = "git clone git://github.com/tpw/resque.git"
    assert_command input, command
  end

86 87 88
  def test_clone_with_arguments
    input   = "clone --bare -o master resque"
    command = "git clone --bare -o master git://github.com/tpw/resque.git"
89 90 91
    assert_command input, command
  end

92 93 94 95
  def test_clone_with_arguments_and_destination
    assert_forwarded "clone --template=one/two git://github.com/tpw/resque.git --origin master resquetastic"
  end

96 97
  def test_your_private_clone_fails_without_config
    out = hub("clone -p mustache") do
98
      stub_github_user(nil)
99 100
    end

101
    assert_equal "** No GitHub user set. See http://help.github.com/git-email-settings/\n", out
102 103 104 105
  end

  def test_your_public_clone_fails_without_config
    out = hub("clone mustache") do
106
      stub_github_user(nil)
107 108
    end

109
    assert_equal "** No GitHub user set. See http://help.github.com/git-email-settings/\n", out
110 111
  end

112
  def test_private_clone_left_alone
113
    assert_forwarded "clone git@github.com:rtomayko/ronn.git"
114 115 116
  end

  def test_public_clone_left_alone
117
    assert_forwarded "clone git://github.com/rtomayko/ronn.git"
118
  end
C
Chris Wanstrath 已提交
119 120

  def test_normal_public_clone_with_path
121
    assert_forwarded "clone git://github.com/rtomayko/ronn.git ronn-dev"
C
Chris Wanstrath 已提交
122
  end
123 124

  def test_normal_clone_from_path
125
    assert_forwarded "clone ./test"
126
  end
127

M
Mislav Marohnić 已提交
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
  def test_alias_expand
    stub_alias 'c', 'clone --bare'
    input   = "c rtomayko/ronn"
    command = "git clone --bare git://github.com/rtomayko/ronn.git"
    assert_command input, command
  end

  def test_alias_expand_advanced
    stub_alias 'c', 'clone --template="white space"'
    input   = "c rtomayko/ronn"
    command = "git clone '--template=white space' git://github.com/rtomayko/ronn.git"
    assert_command input, command
  end

  def test_alias_doesnt_expand_for_unknown_commands
    stub_alias 'c', 'compute --fast'
    assert_forwarded "c rtomayko/ronn"
  end

147 148 149 150 151 152 153 154 155 156 157 158
  def test_remote_origin
    input   = "remote add origin"
    command = "git remote add origin git://github.com/tpw/hub.git"
    assert_command input, command
  end

  def test_private_remote_origin
    input   = "remote add -p origin"
    command = "git remote add origin git@github.com:tpw/hub.git"
    assert_command input, command
  end

159 160 161 162 163 164
  def test_public_remote_origin_as_normal
    input   = "remote add origin http://github.com/defunkt/resque.git"
    command = "git remote add origin http://github.com/defunkt/resque.git"
    assert_command input, command
  end

165
  def test_remote_from_rel_path
166
    assert_forwarded "remote add origin ./path"
167 168 169
  end

  def test_remote_from_abs_path
170
    assert_forwarded "remote add origin /path"
171 172
  end

173
  def test_private_remote_origin_as_normal
174
    assert_forwarded "remote add origin git@github.com:defunkt/resque.git"
C
Chris Wanstrath 已提交
175 176
  end

S
Stephen Celis 已提交
177 178
  def test_public_submodule
    input   = "submodule add wycats/bundler vendor/bundler"
J
Justin Ridgewell 已提交
179 180
    command = "git submodule add git://github.com/wycats/bundler.git vendor/bundler"
    assert_command input, command
S
Stephen Celis 已提交
181 182 183 184
  end

  def test_private_submodule
    input   = "submodule add -p grit vendor/grit"
J
Justin Ridgewell 已提交
185 186 187 188 189 190 191 192
    command = "git submodule add git@github.com:tpw/grit.git vendor/grit"
    assert_command input, command
  end

  def test_submodule_branch
    input   = "submodule add -b ryppl ryppl/pip vendor/pip"
    command = "git submodule add -b ryppl git://github.com/ryppl/pip.git vendor/pip"
    assert_command input, command
S
Stephen Celis 已提交
193 194 195 196 197
  end

  def test_submodule_with_args
    input   = "submodule -q add --bare -- grit grit"
    command = "git submodule -q add --bare -- git://github.com/tpw/grit.git grit"
J
Justin Ridgewell 已提交
198
    assert_command input, command
S
Stephen Celis 已提交
199 200
  end

C
Chris Wanstrath 已提交
201
  def test_private_remote
202
    input   = "remote add -p rtomayko"
C
Chris Wanstrath 已提交
203 204
    command = "git remote add rtomayko git@github.com:rtomayko/hub.git"
    assert_command input, command
C
Chris Wanstrath 已提交
205 206
  end

207 208 209 210 211 212 213
  def test_https_protocol_remote
    stub_https_is_preferred
    input   = "remote add rtomayko"
    command = "git remote add rtomayko https://github.com/rtomayko/hub.git"
    assert_command input, command
  end

C
Chris Wanstrath 已提交
214
  def test_public_remote
215
    input   = "remote add rtomayko"
C
Chris Wanstrath 已提交
216 217
    command = "git remote add rtomayko git://github.com/rtomayko/hub.git"
    assert_command input, command
C
Chris Wanstrath 已提交
218 219
  end

C
Chris Wanstrath 已提交
220 221 222 223 224 225
  def test_public_remote_f
    input   = "remote add -f rtomayko"
    command = "git remote add -f rtomayko git://github.com/rtomayko/hub.git"
    assert_command input, command
  end

226 227 228 229 230 231
  def test_named_public_remote
    input   = "remote add origin rtomayko"
    command = "git remote add origin git://github.com/rtomayko/hub.git"
    assert_command input, command
  end

232 233 234 235 236 237
  def test_named_public_remote_f
    input   = "remote add -f origin rtomayko"
    command = "git remote add -f origin git://github.com/rtomayko/hub.git"
    assert_command input, command
  end

C
Chris Wanstrath 已提交
238
  def test_private_remote_with_repo
239 240
    input   = "remote add -p jashkenas/coffee-script"
    command = "git remote add jashkenas git@github.com:jashkenas/coffee-script.git"
C
Chris Wanstrath 已提交
241 242 243 244
    assert_command input, command
  end

  def test_public_remote_with_repo
245 246
    input   = "remote add jashkenas/coffee-script"
    command = "git remote add jashkenas git://github.com/jashkenas/coffee-script.git"
247 248 249 250
    assert_command input, command
  end

  def test_public_remote_f_with_repo
251 252
    input   = "remote add -f jashkenas/coffee-script"
    command = "git remote add -f jashkenas git://github.com/jashkenas/coffee-script.git"
C
Chris Wanstrath 已提交
253 254 255
    assert_command input, command
  end

256
  def test_named_private_remote_with_repo
257 258
    input   = "remote add -p origin jashkenas/coffee-script"
    command = "git remote add origin git@github.com:jashkenas/coffee-script.git"
259 260 261
    assert_command input, command
  end

262
  def test_fetch_existing_remote
263
    assert_forwarded "fetch mislav"
264 265 266 267 268 269
  end

  def test_fetch_new_remote
    stub_remotes_group('xoebus', nil)
    stub_existing_fork('xoebus')

270 271 272
    assert_commands "git remote add xoebus git://github.com/xoebus/hub.git",
                    "git fetch xoebus",
                    "fetch xoebus"
273 274 275 276 277 278
  end

  def test_fetch_new_remote_with_options
    stub_remotes_group('xoebus', nil)
    stub_existing_fork('xoebus')

279 280 281
    assert_commands "git remote add xoebus git://github.com/xoebus/hub.git",
                    "git fetch --depth=1 --prune xoebus",
                    "fetch --depth=1 --prune xoebus"
282 283 284 285 286 287 288 289
  end

  def test_fetch_multiple_new_remotes
    stub_remotes_group('xoebus', nil)
    stub_remotes_group('rtomayko', nil)
    stub_existing_fork('xoebus')
    stub_existing_fork('rtomayko')

290 291 292 293
    assert_commands "git remote add xoebus git://github.com/xoebus/hub.git",
                    "git remote add rtomayko git://github.com/rtomayko/hub.git",
                    "git fetch --multiple xoebus rtomayko",
                    "fetch --multiple xoebus rtomayko"
294 295 296 297 298 299 300 301
  end

  def test_fetch_multiple_comma_separated_remotes
    stub_remotes_group('xoebus', nil)
    stub_remotes_group('rtomayko', nil)
    stub_existing_fork('xoebus')
    stub_existing_fork('rtomayko')

302 303 304 305
    assert_commands "git remote add xoebus git://github.com/xoebus/hub.git",
                    "git remote add rtomayko git://github.com/rtomayko/hub.git",
                    "git fetch --multiple xoebus rtomayko",
                    "fetch xoebus,rtomayko"
306 307 308 309 310 311 312 313 314 315 316 317 318 319
  end

  def test_fetch_multiple_new_remotes_with_filtering
    stub_remotes_group('xoebus', nil)
    stub_remotes_group('mygrp', 'one two')
    stub_remotes_group('typo', nil)
    stub_existing_fork('xoebus')
    stub_nonexisting_fork('typo')

    # mislav: existing remote; skipped
    # xoebus: new remote, fork exists; added
    # mygrp:  a remotes group; skipped
    # URL:    can't be a username; skipped
    # typo:   fork doesn't exist; skipped
320 321 322
    assert_commands "git remote add xoebus git://github.com/xoebus/hub.git",
                    "git fetch --multiple mislav xoebus mygrp git://example.com typo",
                    "fetch --multiple mislav xoebus mygrp git://example.com typo"
323 324
  end

325
  def test_cherry_pick
326
    assert_forwarded "cherry-pick a319d88"
327 328 329
  end

  def test_cherry_pick_url
330
    url = 'http://github.com/mislav/hub/commit/a319d88'
331
    assert_commands "git fetch mislav", "git cherry-pick a319d88", "cherry-pick #{url}"
332 333
  end

334 335
  def test_cherry_pick_url_with_fragment
    url = 'http://github.com/mislav/hub/commit/abcdef0123456789#comments'
336
    assert_commands "git fetch mislav", "git cherry-pick abcdef0123456789", "cherry-pick #{url}"
337 338
  end

339 340
  def test_cherry_pick_url_with_remote_add
    url = 'https://github.com/xoebus/hub/commit/a319d88'
341
    assert_commands "git remote add -f xoebus git://github.com/xoebus/hub.git",
342 343
                    "git cherry-pick a319d88",
                    "cherry-pick #{url}"
344 345 346 347
  end

  def test_cherry_pick_origin_url
    url = 'https://github.com/defunkt/hub/commit/a319d88'
348
    assert_commands "git fetch origin", "git cherry-pick a319d88", "cherry-pick #{url}"
349 350 351
  end

  def test_cherry_pick_github_user_notation
352
    assert_commands "git fetch mislav", "git cherry-pick 368af20", "cherry-pick mislav@368af20"
353 354 355 356
  end

  def test_cherry_pick_github_user_repo_notation
    # not supported
357
    assert_forwarded "cherry-pick mislav/hubbub@a319d88"
358 359 360
  end

  def test_cherry_pick_github_notation_too_short
361
    assert_forwarded "cherry-pick mislav@a319"
362 363 364
  end

  def test_cherry_pick_github_notation_with_remote_add
365 366 367
    assert_commands "git remote add -f xoebus git://github.com/xoebus/hub.git",
                    "git cherry-pick a319d88",
                    "cherry-pick xoebus@a319d88"
368 369
  end

370 371 372 373 374 375 376 377 378
  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",
                      "am --signoff https://github.com/defunkt/hub/pull/55 -p2"
379 380 381

      cmd = Hub("am https://github.com/defunkt/hub/pull/55/files").command
      assert_includes '/pull/55.patch', cmd
382 383 384 385 386 387 388 389 390 391 392 393 394
    end
  end

  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

395 396 397 398 399 400 401 402 403 404
  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

405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
  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 已提交
440
  def test_init
441
    assert_commands "git init", "git remote add origin git@github.com:tpw/hub.git", "init -g"
442 443 444 445
  end

  def test_init_no_login
    out = hub("init -g") do
446
      stub_github_user(nil)
447 448
    end

449
    assert_equal "** No GitHub user set. See http://help.github.com/git-email-settings/\n", out
C
Chris Wanstrath 已提交
450 451
  end

452 453 454 455
  def test_push_untouched
    assert_forwarded "push"
  end

456
  def test_push_two
457 458
    assert_commands "git push origin cool-feature", "git push staging cool-feature",
                    "push origin,staging cool-feature"
459 460
  end

461 462 463 464 465 466
  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 已提交
467
  def test_push_more
468 469 470 471
    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 已提交
472
  end
C
Chris Wanstrath 已提交
473

474
  def test_create
475
    stub_no_remotes
476
    stub_nonexisting_fork('tpw')
477 478
    stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/create").
      with(:body => { 'name' => 'hub' })
479

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

485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506
  def test_create_custom_name
    stub_no_remotes
    stub_nonexisting_fork('tpw', 'hubbub')
    stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/create").
      with(:body => { 'name' => 'hubbub' })

    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')
    stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/create").
      with(:body => { 'name' => 'acme/hubbub' })

    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

507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522
  def test_create_no_openssl
    stub_no_remotes
    stub_nonexisting_fork('tpw')
    stub_request(:post, "http://#{auth}github.com/api/v2/yaml/repos/create").
      with(:body => { 'name' => 'hub' })

    expected = "remote add -f origin git@github.com:tpw/hub.git\n"
    expected << "created repository: tpw/hub\n"

    assert_equal expected, hub("create") {
      ENV['GIT'] = 'echo'
      require 'net/https'
      Object.send :remove_const, :OpenSSL
    }
  end

523 524 525
  def test_create_failed
    stub_no_remotes
    stub_nonexisting_fork('tpw')
526
    stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/create").
527 528
      to_return(:status => [401, "Your token is fail"])

529 530
    expected = "Error creating repository: Your token is fail (HTTP 401)\n"
    expected << "Check your token configuration (`git config github.token`)\n"
531 532 533
    assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
  end

534 535 536 537 538 539 540 541 542
  def test_create_with_env_authentication
    stub_no_remotes
    stub_nonexisting_fork('mojombo')

    old_user  = ENV['GITHUB_USER']
    old_token = ENV['GITHUB_TOKEN']
    ENV['GITHUB_USER']  = 'mojombo'
    ENV['GITHUB_TOKEN'] = '123abc'

543 544
    stub_request(:post, "https://#{auth('mojombo', '123abc')}github.com/api/v2/yaml/repos/create").
      with(:body => { 'name' => 'hub' })
545 546 547 548 549 550 551 552 553 554

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

  ensure
    ENV['GITHUB_USER']  = old_user
    ENV['GITHUB_TOKEN'] = old_token
  end

555
  def test_create_private_repository
556
    stub_no_remotes
557
    stub_nonexisting_fork('tpw')
558 559
    stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/create").
      with(:body => { 'name' => 'hub', 'public' => '0' })
560

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

566
  def test_create_with_description_and_homepage
567
    stub_no_remotes
568
    stub_nonexisting_fork('tpw')
569 570
    stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/create").with(:body => {
      'name' => 'hub', 'description' => 'toyproject', 'homepage' => 'http://example.com'
571 572
    })

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

578 579 580 581 582
  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

583
  def test_create_with_existing_repository
584
    stub_no_remotes
585 586 587 588
    stub_existing_fork('tpw')

    expected = "tpw/hub already exists on GitHub\n"
    expected << "remote add -f origin git@github.com:tpw/hub.git\n"
589
    expected << "set remote origin: tpw/hub\n"
590 591 592
    assert_equal expected, hub("create") { ENV['GIT'] = 'echo' }
  end

593 594 595 596 597 598 599 600 601 602 603
  def test_create_https_protocol
    stub_no_remotes
    stub_existing_fork('tpw')
    stub_https_is_preferred

    expected = "tpw/hub already exists on GitHub\n"
    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

604
  def test_create_no_user
605
    stub_no_remotes
606 607 608
    out = hub("create") do
      stub_github_token(nil)
    end
609
    assert_equal "** No GitHub token set. See http://help.github.com/git-email-settings/\n", out
610 611
  end

612
  def test_create_outside_git_repo
613
    stub_no_git_repo
614 615
    assert_equal "'create' must be run from inside a git repository\n", hub("create")
  end
616 617

  def test_create_origin_already_exists
C
Chris Wanstrath 已提交
618
    stub_nonexisting_fork('tpw')
619 620
    stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/create").
      with(:body => { 'name' => 'hub' })
C
Chris Wanstrath 已提交
621 622

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

626
  def test_fork
C
Chris Wanstrath 已提交
627
    stub_nonexisting_fork('tpw')
628
    stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/fork/defunkt/hub")
C
Chris Wanstrath 已提交
629

C
Chris Wanstrath 已提交
630
    expected = "remote add -f tpw git@github.com:tpw/hub.git\n"
631 632 633 634
    expected << "new remote: tpw\n"
    assert_equal expected, hub("fork") { ENV['GIT'] = 'echo' }
  end

635 636
  def test_fork_failed
    stub_nonexisting_fork('tpw')
637
    stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/fork/defunkt/hub").
638 639
      to_return(:status => [500, "Your fork is fail"])

640
    expected = "Error creating fork: Your fork is fail (HTTP 500)\n"
641 642 643
    assert_equal expected, hub("fork") { ENV['GIT'] = 'echo' }
  end

644
  def test_fork_no_remote
645
    stub_nonexisting_fork('tpw')
646
    stub_request(:post, "https://#{auth}github.com/api/v2/yaml/repos/fork/defunkt/hub")
C
Chris Wanstrath 已提交
647

648 649 650 651
    assert_equal "", hub("fork --no-remote") { ENV['GIT'] = 'echo' }
  end

  def test_fork_already_exists
652
    stub_existing_fork('tpw')
C
Chris Wanstrath 已提交
653

654
    expected = "tpw/hub already exists on GitHub\n"
C
Chris Wanstrath 已提交
655
    expected << "remote add -f tpw git@github.com:tpw/hub.git\n"
656 657 658
    expected << "new remote: tpw\n"
    assert_equal expected, hub("fork") { ENV['GIT'] = 'echo' }
  end
C
Chris Wanstrath 已提交
659

660 661 662 663 664 665 666 667 668 669
  def test_fork_https_protocol
    stub_existing_fork('tpw')
    stub_https_is_preferred

    expected = "tpw/hub already exists on GitHub\n"
    expected << "remote add -f tpw https://github.com/tpw/hub.git\n"
    expected << "new remote: tpw\n"
    assert_equal expected, hub("fork") { ENV['GIT'] = 'echo' }
  end

670 671 672 673 674 675
  def test_pullrequest
    stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/defunkt/hub").
      with(:body => { 'pull' => {'base' => "master", 'head' => "tpw:master", 'title' => "hereyougo"} }).
      to_return(:body => mock_pullreq_response(1))

    expected = "https://github.com/defunkt/hub/pull/1\n"
676 677 678 679 680 681 682 683
    assert_output expected, "pull-request hereyougo -f"
  end

  def test_pullrequest_with_checks
    @git["rev-list --cherry origin/master..."] = "+abcd1234\n+bcde2345"

    expected = "Aborted: 2 commits are not yet pushed to origin/master\n" <<
      "(use `-f` to force submit a pull request anyway)\n"
684 685 686 687 688 689 690 691 692 693 694
    assert_output expected, "pull-request hereyougo"
  end

  def test_pullrequest_from_branch
    stub_branch('refs/heads/feature')
    stub_tracking_nothing('feature')
    stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/defunkt/hub").
      with(:body => { 'pull' => {'base' => "master", 'head' => "tpw:feature", 'title' => "hereyougo"} }).
      to_return(:body => mock_pullreq_response(1))

    expected = "https://github.com/defunkt/hub/pull/1\n"
695
    assert_output expected, "pull-request hereyougo -f"
696 697 698 699 700 701 702 703 704 705
  end

  def test_pullrequest_from_tracking_branch
    stub_branch('refs/heads/feature')
    stub_tracking('feature', 'tpw', 'yay-feature')
    stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/defunkt/hub").
      with(:body => { 'pull' => {'base' => "master", 'head' => "tpw:yay-feature", 'title' => "hereyougo"} }).
      to_return(:body => mock_pullreq_response(1))

    expected = "https://github.com/defunkt/hub/pull/1\n"
706
    assert_output expected, "pull-request hereyougo -f"
707 708 709 710 711 712 713 714
  end

  def test_pullrequest_explicit_head
    stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/defunkt/hub").
      with(:body => { 'pull' => {'base' => "master", 'head' => "tpw:yay-feature", 'title' => "hereyougo"} }).
      to_return(:body => mock_pullreq_response(1))

    expected = "https://github.com/defunkt/hub/pull/1\n"
715
    assert_output expected, "pull-request hereyougo -h yay-feature -f"
716 717 718 719 720 721 722 723
  end

  def test_pullrequest_explicit_head_with_owner
    stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/defunkt/hub").
      with(:body => { 'pull' => {'base' => "master", 'head' => "mojombo:feature", 'title' => "hereyougo"} }).
      to_return(:body => mock_pullreq_response(1))

    expected = "https://github.com/defunkt/hub/pull/1\n"
724
    assert_output expected, "pull-request hereyougo -h mojombo:feature -f"
725 726 727 728 729 730 731 732
  end

  def test_pullrequest_explicit_base
    stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/defunkt/hub").
      with(:body => { 'pull' => {'base' => "feature", 'head' => "tpw:master", 'title' => "hereyougo"} }).
      to_return(:body => mock_pullreq_response(1))

    expected = "https://github.com/defunkt/hub/pull/1\n"
733
    assert_output expected, "pull-request hereyougo -b feature -f"
734 735 736 737 738 739 740 741
  end

  def test_pullrequest_explicit_base_with_owner
    stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/mojombo/hub").
      with(:body => { 'pull' => {'base' => "feature", 'head' => "tpw:master", 'title' => "hereyougo"} }).
      to_return(:body => mock_pullreq_response(1))

    expected = "https://github.com/defunkt/hub/pull/1\n"
742
    assert_output expected, "pull-request hereyougo -b mojombo:feature -f"
743 744
  end

745 746 747 748 749 750
  def test_pullrequest_explicit_base_with_repo
    stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/mojombo/hubbub").
      with(:body => { 'pull' => {'base' => "feature", 'head' => "tpw:master", 'title' => "hereyougo"} }).
      to_return(:body => mock_pullreq_response(1))

    expected = "https://github.com/defunkt/hub/pull/1\n"
751
    assert_output expected, "pull-request hereyougo -b mojombo/hubbub:feature -f"
752 753 754
  end

  def test_pullrequest_existing_issue
755 756 757 758 759
    stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/defunkt/hub").
      with(:body => { 'pull' => {'base' => "master", 'head' => "tpw:master", 'issue' => '92'} }).
      to_return(:body => mock_pullreq_response(92))

    expected = "https://github.com/defunkt/hub/pull/92\n"
760
    assert_output expected, "pull-request #92 -f"
761 762
  end

763 764 765 766 767 768
  def test_pullrequest_existing_issue_url
    stub_request(:post, "https://#{auth}github.com/api/v2/yaml/pulls/mojombo/hub").
      with(:body => { 'pull' => {'base' => "master", 'head' => "tpw:master", 'issue' => '92'} }).
      to_return(:body => mock_pullreq_response(92, 'mojombo/hub'))

    expected = "https://github.com/mojombo/hub/pull/92\n"
769
    assert_output expected, "pull-request https://github.com/mojombo/hub/issues/92#comment_4 -f"
770 771
  end

C
Chris Wanstrath 已提交
772
  def test_version
773
    out = hub('--version')
774
    assert_includes "git version 1.7.0.4", out
C
Chris Wanstrath 已提交
775
    assert_includes "hub version #{Hub::Version}", out
C
Chris Wanstrath 已提交
776
  end
C
Chris Wanstrath 已提交
777

778 779 780 781 782 783 784
  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')
785
    assert_equal Hub::Commands.improved_help_text, out
786 787 788 789 790 791 792
  end

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

C
Chris Wanstrath 已提交
793 794 795 796 797 798 799
  def test_help
    assert_equal Hub::Commands.improved_help_text, hub("help")
  end

  def test_help_by_default
    assert_equal Hub::Commands.improved_help_text, hub("")
  end
C
Chris Wanstrath 已提交
800

S
Stephen Celis 已提交
801 802 803 804
  def test_help_with_pager
    assert_equal Hub::Commands.improved_help_text, hub("-p")
  end

C
Chris Wanstrath 已提交
805 806 807 808
  def test_help_hub
    help_manpage = hub("help hub")
    assert_includes "git + hub = github", help_manpage
    assert_includes <<-config, help_manpage
C
Chris Wanstrath 已提交
809
Use git-config(1) to display the currently configured GitHub username:
C
Chris Wanstrath 已提交
810 811 812 813
config
  end

  def test_help_hub_no_groff
814 815
    stub_available_commands()
    assert_equal "** Can't find groff(1)\n", hub("help hub")
C
Chris Wanstrath 已提交
816
  end
817

818 819 820 821 822
  def test_hub_standalone
    help_standalone = hub("hub standalone")
    assert_equal Hub::Standalone.build, help_standalone
  end

C
Chris Wanstrath 已提交
823 824
  def test_hub_compare
    assert_command "compare refactor",
825
      "open https://github.com/defunkt/hub/compare/refactor"
826
  end
C
Chris Wanstrath 已提交
827

828 829 830 831
  def test_hub_compare_nothing
    expected = "Usage: hub compare [USER] [<START>...]<END>\n"
    assert_equal expected, hub("compare")
  end
C
Chris Wanstrath 已提交
832

833 834 835 836 837 838 839 840
  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')
841
    stub_tracking('feature', 'mislav', 'experimental')
842 843

    assert_command "compare",
844
      "open https://github.com/mislav/hub/compare/experimental"
845 846
  end

847
  def test_hub_compare_range
C
Chris Wanstrath 已提交
848
    assert_command "compare 1.0...fix",
849
      "open https://github.com/defunkt/hub/compare/1.0...fix"
850
  end
C
Chris Wanstrath 已提交
851

852 853 854 855 856 857 858 859 860 861 862 863 864 865 866
  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

867 868 869 870 871 872
  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

873
  def test_hub_compare_fork
C
Chris Wanstrath 已提交
874
    assert_command "compare myfork feature",
875
      "open https://github.com/myfork/hub/compare/feature"
876 877 878 879
  end

  def test_hub_compare_url
    assert_command "compare -u 1.0...1.1",
880
      "echo https://github.com/defunkt/hub/compare/1.0...1.1"
881 882 883
  end

  def test_hub_browse
884
    assert_command "browse mojombo/bert", "open https://github.com/mojombo/bert"
885 886
  end

887 888 889 890
  def test_hub_browse_commit
    assert_command "browse mojombo/bert commit/5d5582", "open https://github.com/mojombo/bert/commit/5d5582"
  end

891 892
  def test_hub_browse_tracking_nothing
    stub_tracking_nothing
893
    assert_command "browse mojombo/bert", "open https://github.com/mojombo/bert"
894 895
  end

896
  def test_hub_browse_url
897
    assert_command "browse -u mojombo/bert", "echo https://github.com/mojombo/bert"
898 899
  end

900
  def test_hub_browse_self
901
    assert_command "browse resque", "open https://github.com/tpw/resque"
902 903
  end

904 905
  def test_hub_browse_subpage
    assert_command "browse resque commits",
906
      "open https://github.com/tpw/resque/commits/master"
907
    assert_command "browse resque issues",
908
      "open https://github.com/tpw/resque/issues"
909
    assert_command "browse resque wiki",
910
      "open https://github.com/tpw/resque/wiki"
911 912 913 914
  end

  def test_hub_browse_on_branch
    stub_branch('refs/heads/feature')
915
    stub_tracking('feature', 'mislav', 'experimental')
916

917
    assert_command "browse resque", "open https://github.com/tpw/resque"
918
    assert_command "browse resque commits",
919
      "open https://github.com/tpw/resque/commits/master"
920 921

    assert_command "browse",
922
      "open https://github.com/mislav/hub/tree/experimental"
923
    assert_command "browse -- tree",
924
      "open https://github.com/mislav/hub/tree/experimental"
925
    assert_command "browse -- commits",
926
      "open https://github.com/mislav/hub/commits/experimental"
927
  end
928

929
  def test_hub_browse_current
930 931
    assert_command "browse", "open https://github.com/defunkt/hub"
    assert_command "browse --", "open https://github.com/defunkt/hub"
932 933
  end

934 935 936 937
  def test_hub_browse_commit_from_current
    assert_command "browse -- commit/6616e4", "open https://github.com/defunkt/hub/commit/6616e4"
  end

938 939 940 941 942 943 944
  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')
945
    stub_tracking_nothing('feature')
946 947 948
    assert_command "browse", "open https://github.com/defunkt/hub"
  end

949 950 951 952 953 954 955 956 957
  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

958 959
  def test_hub_browse_current_subpage
    assert_command "browse -- network",
960
      "open https://github.com/defunkt/hub/network"
961
    assert_command "browse -- anything/everything",
962
      "open https://github.com/defunkt/hub/anything/everything"
963 964
  end

965 966 967 968
  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
969 970
  end

971 972 973
  def test_hub_browse_no_repo
    stub_repo_url(nil)
    assert_equal "Usage: hub browse [<USER>/]<REPOSITORY>\n", hub("browse")
974
  end
975 976 977 978 979 980 981 982 983 984

  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
985
      with_host_os("i686-linux") do
986 987 988 989 990 991 992 993
        assert_browser("xdg-open")
      end
    end
  end

  def test_cygwin_browser
    stub_available_commands "open", "cygstart"
    with_browser_env(nil) do
994
      with_host_os("i686-linux") do
995 996 997 998 999 1000 1001 1002 1003
        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
1004
      with_host_os("i686-linux") do
1005 1006 1007 1008 1009
        assert_equal expected, hub("browse")
      end
    end
  end

1010
  def test_context_method_doesnt_hijack_git_command
1011
    assert_forwarded 'remotes'
1012 1013
  end

1014 1015 1016 1017 1018
  def test_not_choking_on_ruby_methods
    assert_forwarded 'id'
    assert_forwarded 'name'
  end

1019 1020
  def test_multiple_remote_urls
    stub_repo_url("git://example.com/other.git\ngit://github.com/my/repo.git")
1021
    assert_command "browse", "open https://github.com/my/repo"
1022 1023
  end

1024 1025 1026 1027 1028 1029
  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'
    assert_equal %w[git --bare -c core.awesome=true -c name=value --git-dir=/srv/www], @git.executable
  end

1030 1031
  protected

1032 1033 1034 1035
    def stub_github_user(name)
      @git['config github.user'] = name
    end

1036 1037 1038 1039
    def stub_github_token(token)
      @git['config github.token'] = token
    end

1040
    def stub_repo_url(value)
1041
      @git['config --get-all remote.origin.url'] = value
1042 1043 1044 1045 1046 1047 1048
      Hub::Context::REMOTES.clear
    end

    def stub_branch(value)
      @git['symbolic-ref -q HEAD'] = value
    end

1049
    def stub_tracking(from, remote_name, remote_branch)
1050
      value = remote_branch ? "remotes/#{remote_name}/#{remote_branch}" : nil
1051
      @git["name-rev #{from}@{upstream} --name-only --refs='refs/remotes/*' --no-undefined"] = value
1052 1053
    end

1054 1055
    def stub_tracking_nothing(from = 'master')
      stub_tracking(from, nil, nil)
1056 1057
    end

1058 1059 1060 1061
    def stub_remotes_group(name, value)
      @git["config remotes.#{name}"] = value
    end

1062 1063 1064 1065 1066 1067 1068 1069
    def stub_no_remotes
      @git['remote'] = ''
    end

    def stub_no_git_repo
      @git.replace({})
    end

M
Mislav Marohnić 已提交
1070 1071 1072 1073
    def stub_alias(name, value)
      @git["config alias.#{name}"] = value
    end

1074 1075
    def stub_existing_fork(user, repo = 'hub')
      stub_fork(user, repo, 200)
1076 1077
    end

1078 1079
    def stub_nonexisting_fork(user, repo = 'hub')
      stub_fork(user, repo, 404)
1080 1081
    end

1082 1083
    def stub_fork(user, repo, status)
      stub_request(:get, "github.com/api/v2/yaml/repos/show/#{user}/#{repo}").
1084 1085 1086
        to_return(:status => status)
    end

1087 1088 1089 1090
    def stub_available_commands(*names)
      COMMANDS.replace names
    end

1091 1092 1093 1094
    def stub_https_is_preferred
      @git['config hub.protocol'] = 'https'
    end

1095 1096 1097 1098 1099 1100 1101
    def with_browser_env(value)
      browser, ENV['BROWSER'] = ENV['BROWSER'], value
      yield
    ensure
      ENV['BROWSER'] = browser
    end

1102 1103 1104 1105 1106 1107 1108
    def with_tmpdir(value)
      dir, ENV['TMPDIR'] = ENV['TMPDIR'], value
      yield
    ensure
      ENV['TMPDIR'] = dir
    end

1109
    def assert_browser(browser)
1110
      assert_command "browse", "#{browser} https://github.com/defunkt/hub"
1111 1112
    end

1113 1114 1115 1116 1117 1118 1119 1120
    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
1121 1122
    end

1123 1124 1125 1126
    def auth(user = @git['config github.user'], password = @git['config github.token'])
      "#{user}%2Ftoken:#{password}@"
    end

1127 1128 1129 1130 1131 1132
    def mock_pullreq_response(id, name_with_owner = 'defunkt/hub')
      YAML.dump('pull' => {
        'html_url' => "https://github.com/#{name_with_owner}/pull/#{id}"
      })
    end

C
Chris Wanstrath 已提交
1133
end