8ac77d997ba99fc564d40e62977fd8f65ef23b8e
   1#!/bin/sh
   2#
   3# Copyright (c) 2005 Jon Seymour
   4#
   5
   6test_description='Tests git-rev-list --merge-order functionality'
   7
   8. ./test-lib.sh
   9
  10#
  11# TODO: move the following block (upto --- end ...) into testlib.sh
  12#
  13[ -d .git/refs/tags ] || mkdir -p .git/refs/tags
  14
  15sed_script="";
  16
  17# Answer the sha1 has associated with the tag. The tag must exist in .git or .git/refs/tags
  18tag()
  19{
  20        _tag=$1
  21        [ -f .git/refs/tags/$_tag ] || error "tag: \"$_tag\" does not exist"
  22        cat .git/refs/tags/$_tag
  23}
  24
  25# Generate a commit using the text specified to make it unique and the tree
  26# named by the tag specified.
  27unique_commit()
  28{
  29        _text=$1
  30        _tree=$2
  31        shift 2
  32        echo $_text | git-commit-tree $(tag $_tree) "$@"
  33}
  34
  35# Save the output of a command into the tag specified. Prepend
  36# a substitution script for the tag onto the front of $sed_script
  37save_tag()
  38{
  39        _tag=$1 
  40        [ -n "$_tag" ] || error "usage: save_tag tag commit-args ..."
  41        shift 1
  42        "$@" >.git/refs/tags/$_tag
  43        sed_script="s/$(tag $_tag)/$_tag/g${sed_script+;}$sed_script"
  44}
  45
  46# Replace unhelpful sha1 hashses with their symbolic equivalents 
  47entag()
  48{
  49        sed "$sed_script"
  50}
  51
  52# Execute a command after first saving, then setting the GIT_AUTHOR_EMAIL
  53# tag to a specified value. Restore the original value on return.
  54as_author()
  55{
  56        _author=$1
  57        shift 1
  58        _save=$GIT_AUTHOR_EMAIL
  59
  60        export GIT_AUTHOR_EMAIL="$_author"
  61        "$@"
  62        export GIT_AUTHOR_EMAIL="$_save"
  63}
  64
  65commit_date()
  66{
  67        _commit=$1
  68        git-cat-file commit $_commit | sed -n "s/^committer .*> \([0-9]*\) .*/\1/p" 
  69}
  70
  71on_committer_date()
  72{
  73    _date=$1
  74    shift 1
  75    GIT_COMMITTER_DATE=$_date "$@"
  76}
  77
  78# Execute a command and suppress any error output.
  79hide_error()
  80{
  81        "$@" 2>/dev/null
  82}
  83
  84check_output()
  85{
  86        _name=$1
  87        shift 1
  88        if "$@" | entag > $_name.actual
  89        then
  90                diff $_name.expected $_name.actual
  91        else
  92                return 1;
  93        fi
  94        
  95}
  96
  97# Turn a reasonable test description into a reasonable test name.
  98# All alphanums translated into -'s which are then compressed and stripped
  99# from front and back.
 100name_from_description()
 101{
 102        tr "'" '-' | tr '~`!@#$%^&*()_+={}[]|\;:"<>,/? ' '-' | tr -s '-' | tr '[A-Z]' '[a-z]' | sed "s/^-*//;s/-*\$//"
 103}
 104
 105
 106# Execute the test described by the first argument, by eval'ing
 107# command line specified in the 2nd argument. Check the status code
 108# is zero and that the output matches the stream read from 
 109# stdin.
 110test_output_expect_success()
 111{       
 112        _description=$1
 113        _test=$2
 114        [ $# -eq 2 ] || error "usage: test_output_expect_success description test <<EOF ... EOF"
 115        _name=$(echo $_description | name_from_description)
 116        cat > $_name.expected
 117        test_expect_success "$_description" "check_output $_name $_test" 
 118}
 119
 120# --- end of stuff to move ---
 121
 122# test-case specific test function
 123check_adjacency()
 124{
 125    read previous
 126    echo "= $previous"
 127    while read next
 128    do
 129        if ! (git-cat-file commit $previous | grep "^parent $next" >/dev/null)
 130        then
 131            echo "^ $next"
 132        else
 133            echo "| $next"
 134        fi
 135        previous=$next
 136    done
 137}
 138
 139list_duplicates()
 140{
 141    "$@" | sort | uniq -d
 142}
 143
 144grep_stderr()
 145{
 146    args=$1
 147    shift 1
 148    "$@" 2>&1 | grep "$args"
 149}
 150
 151date >path0
 152git-update-cache --add path0
 153save_tag tree git-write-tree
 154on_committer_date "1971-08-16 00:00:00" hide_error save_tag root unique_commit root tree
 155on_committer_date "1971-08-16 00:00:01" save_tag l0 unique_commit l0 tree -p root
 156on_committer_date "1971-08-16 00:00:02" save_tag l1 unique_commit l1 tree -p l0
 157on_committer_date "1971-08-16 00:00:03" save_tag l2 unique_commit l2 tree -p l1
 158on_committer_date "1971-08-16 00:00:04" save_tag a0 unique_commit a0 tree -p l2
 159on_committer_date "1971-08-16 00:00:05" save_tag a1 unique_commit a1 tree -p a0
 160on_committer_date "1971-08-16 00:00:06" save_tag b1 unique_commit b1 tree -p a0
 161on_committer_date "1971-08-16 00:00:07" save_tag c1 unique_commit c1 tree -p b1
 162on_committer_date "1971-08-16 00:00:08" as_author foobar@example.com save_tag b2 unique_commit b2 tree -p b1
 163on_committer_date "1971-08-16 00:00:09" save_tag b3 unique_commit b2 tree -p b2
 164on_committer_date "1971-08-16 00:00:10" save_tag c2 unique_commit c2 tree -p c1 -p b2
 165on_committer_date "1971-08-16 00:00:11" save_tag c3 unique_commit c3 tree -p c2
 166on_committer_date "1971-08-16 00:00:12" save_tag a2 unique_commit a2 tree -p a1
 167on_committer_date "1971-08-16 00:00:13" save_tag a3 unique_commit a3 tree -p a2
 168on_committer_date "1971-08-16 00:00:14" save_tag b4 unique_commit b4 tree -p b3 -p a3
 169on_committer_date "1971-08-16 00:00:15" save_tag a4 unique_commit a4 tree -p a3 -p b4 -p c3
 170on_committer_date "1971-08-16 00:00:16" save_tag l3 unique_commit l3 tree -p a4
 171on_committer_date "1971-08-16 00:00:17" save_tag l4 unique_commit l4 tree -p l3
 172on_committer_date "1971-08-16 00:00:18" save_tag l5 unique_commit l5 tree -p l4
 173on_committer_date "1971-08-16 00:00:19" save_tag m1 unique_commit m1 tree -p a4 -p c3
 174on_committer_date "1971-08-16 00:00:20" save_tag m2 unique_commit m2 tree -p c3 -p a4
 175on_committer_date "1971-08-16 00:00:21" hide_error save_tag alt_root unique_commit alt_root tree
 176on_committer_date "1971-08-16 00:00:22" save_tag r0 unique_commit r0 tree -p alt_root
 177on_committer_date "1971-08-16 00:00:23" save_tag r1 unique_commit r1 tree -p r0
 178on_committer_date "1971-08-16 00:00:24" save_tag l5r1 unique_commit l5r1 tree -p l5 -p r1
 179on_committer_date "1971-08-16 00:00:25" save_tag r1l5 unique_commit r1l5 tree -p r1 -p l5
 180
 181
 182#
 183# note: as of 20/6, it isn't possible to create duplicate parents, so this
 184# can't be tested.
 185#
 186#on_committer_date "1971-08-16 00:00:20" save_tag m3 unique_commit m3 tree -p c3 -p a4 -p c3
 187hide_error save_tag e1 as_author e@example.com unique_commit e1 tree
 188save_tag e2 as_author e@example.com unique_commit e2 tree -p e1
 189save_tag f1 as_author f@example.com unique_commit f1 tree -p e1
 190save_tag e3 as_author e@example.com unique_commit e3 tree -p e2
 191save_tag f2 as_author f@example.com unique_commit f2 tree -p f1
 192save_tag e4 as_author e@example.com unique_commit e4 tree -p e3 -p f2
 193save_tag e5 as_author e@example.com unique_commit e5 tree -p e4
 194save_tag f3 as_author f@example.com unique_commit f3 tree -p f2
 195save_tag f4 as_author f@example.com unique_commit f4 tree -p f3
 196save_tag e6 as_author e@example.com unique_commit e6 tree -p e5 -p f4
 197save_tag f5 as_author f@example.com unique_commit f5 tree -p f4
 198save_tag f6 as_author f@example.com unique_commit f6 tree -p f5 -p e6
 199save_tag e7 as_author e@example.com unique_commit e7 tree -p e6
 200save_tag e8 as_author e@example.com unique_commit e8 tree -p e7
 201save_tag e9 as_author e@example.com unique_commit e9 tree -p e8
 202save_tag f7 as_author f@example.com unique_commit f7 tree -p f6
 203save_tag f8 as_author f@example.com unique_commit f8 tree -p f7
 204save_tag f9 as_author f@example.com unique_commit f9 tree -p f8
 205save_tag e10 as_author e@example.com unique_commit e1 tree -p e9 -p f8
 206
 207hide_error save_tag g0 unique_commit g0 tree
 208save_tag g1 unique_commit g1 tree -p g0
 209save_tag h1 unique_commit g2 tree -p g0
 210save_tag g2 unique_commit g3 tree -p g1 -p h1
 211save_tag h2 unique_commit g4 tree -p g2
 212save_tag g3 unique_commit g5 tree -p g2
 213save_tag g4 unique_commit g6 tree -p g3 -p h2
 214
 215tag l5 > .git/HEAD
 216
 217#
 218# cd to t/trash and use 
 219#
 220#    git-rev-list ... 2>&1 | sed "$(cat sed.script)" 
 221#
 222# if you ever want to manually debug the operation of git-rev-list
 223#
 224echo $sed_script > sed.script
 225
 226test_expect_success 'rev-list has correct number of entries' 'git-rev-list HEAD | wc -l | tr -s " "' <<EOF
 22719
 228EOF
 229
 230normal_adjacency_count=$(git-rev-list HEAD | check_adjacency | grep -c "\^" | tr -d ' ')
 231merge_order_adjacency_count=$(git-rev-list --merge-order HEAD | check_adjacency | grep -c "\^" | tr -d ' ')
 232test_expect_success '--merge-order produces as many or fewer discontinuities' '[ $merge_order_adjacency_count -le $normal_adjacency_count ]'
 233test_output_expect_success 'simple merge order' 'git-rev-list --merge-order --show-breaks HEAD' <<EOF
 234= l5
 235| l4
 236| l3
 237= a4
 238| c3
 239| c2
 240| c1
 241^ b4
 242| b3
 243| b2
 244| b1
 245^ a3
 246| a2
 247| a1
 248= a0
 249| l2
 250| l1
 251| l0
 252= root
 253EOF
 254
 255test_output_expect_success 'two diamonds merge order (g6)' 'git-rev-list --merge-order --show-breaks g4' <<EOF
 256= g4
 257| h2
 258^ g3
 259= g2
 260| h1
 261^ g1
 262= g0
 263EOF
 264
 265test_output_expect_success 'multiple heads' 'git-rev-list --merge-order a3 b3 c3' <<EOF
 266c3
 267c2
 268c1
 269b3
 270b2
 271b1
 272a3
 273a2
 274a1
 275a0
 276l2
 277l1
 278l0
 279root
 280EOF
 281
 282test_output_expect_success 'multiple heads, prune at a1' 'git-rev-list --merge-order a3 b3 c3 ^a1' <<EOF
 283c3
 284c2
 285c1
 286b3
 287b2
 288b1
 289a3
 290a2
 291EOF
 292
 293test_output_expect_success 'multiple heads, prune at l1' 'git-rev-list --merge-order a3 b3 c3 ^l1' <<EOF
 294c3
 295c2
 296c1
 297b3
 298b2
 299b1
 300a3
 301a2
 302a1
 303a0
 304l2
 305EOF
 306
 307test_output_expect_success 'cross-epoch, head at l5, prune at l1' 'git-rev-list --merge-order l5 ^l1' <<EOF
 308l5
 309l4
 310l3
 311a4
 312c3
 313c2
 314c1
 315b4
 316b3
 317b2
 318b1
 319a3
 320a2
 321a1
 322a0
 323l2
 324EOF
 325
 326test_output_expect_success 'duplicated head arguments' 'git-rev-list --merge-order l5 l5 ^l1' <<EOF
 327l5
 328l4
 329l3
 330a4
 331c3
 332c2
 333c1
 334b4
 335b3
 336b2
 337b1
 338a3
 339a2
 340a1
 341a0
 342l2
 343EOF
 344
 345test_output_expect_success 'prune near merge' 'git-rev-list --merge-order a4 ^c3' <<EOF
 346a4
 347b4
 348b3
 349a3
 350a2
 351a1
 352EOF
 353
 354test_output_expect_success "head has no parent" 'git-rev-list --merge-order --show-breaks root' <<EOF
 355= root
 356EOF
 357
 358test_output_expect_success "two nodes - one head, one base" 'git-rev-list --merge-order --show-breaks l0' <<EOF
 359= l0
 360= root
 361EOF
 362
 363test_output_expect_success "three nodes one head, one internal, one base" 'git-rev-list --merge-order --show-breaks l1' <<EOF
 364= l1
 365| l0
 366= root
 367EOF
 368
 369test_output_expect_success "linear prune l2 ^root" 'git-rev-list --merge-order --show-breaks l2 ^root' <<EOF
 370^ l2
 371| l1
 372| l0
 373EOF
 374
 375test_output_expect_success "linear prune l2 ^l0" 'git-rev-list --merge-order --show-breaks l2 ^l0' <<EOF
 376^ l2
 377| l1
 378EOF
 379
 380test_output_expect_success "linear prune l2 ^l1" 'git-rev-list --merge-order --show-breaks l2 ^l1' <<EOF
 381^ l2
 382EOF
 383
 384test_output_expect_success "linear prune l5 ^a4" 'git-rev-list --merge-order --show-breaks l5 ^a4' <<EOF
 385^ l5
 386| l4
 387| l3
 388EOF
 389
 390test_output_expect_success "linear prune l5 ^l3" 'git-rev-list --merge-order --show-breaks l5 ^l3' <<EOF
 391^ l5
 392| l4
 393EOF
 394
 395test_output_expect_success "linear prune l5 ^l4" 'git-rev-list --merge-order --show-breaks l5 ^l4' <<EOF
 396^ l5
 397EOF
 398
 399test_output_expect_success "max-count 10 - merge order" 'git-rev-list --merge-order --show-breaks --max-count=10 l5' <<EOF
 400= l5
 401| l4
 402| l3
 403= a4
 404| c3
 405| c2
 406| c1
 407^ b4
 408| b3
 409| b2
 410EOF
 411
 412test_output_expect_success "max-count 10 - non merge order" 'git-rev-list --max-count=10 l5 | sort' <<EOF
 413a4
 414b2
 415b3
 416b4
 417c1
 418c2
 419c3
 420l3
 421l4
 422l5
 423EOF
 424
 425test_output_expect_success '--max-age=c3, no --merge-order' "git-rev-list --max-age=$(commit_date c3) l5" <<EOF
 426l5
 427l4
 428l3
 429a4
 430b4
 431a3
 432a2
 433c3
 434EOF
 435
 436test_output_expect_success '--max-age=c3, --merge-order' "git-rev-list --merge-order --max-age=$(commit_date c3) l5" <<EOF
 437l5
 438l4
 439l3
 440a4
 441c3
 442b4
 443a3
 444a2
 445EOF
 446
 447test_output_expect_success 'one specified head reachable from another a4, c3, --merge-order' "list_duplicates git-rev-list --merge-order a4 c3" <<EOF
 448EOF
 449
 450test_output_expect_success 'one specified head reachable from another c3, a4, --merge-order' "list_duplicates git-rev-list --merge-order c3 a4" <<EOF
 451EOF
 452
 453test_output_expect_success 'one specified head reachable from another a4, c3, no --merge-order' "list_duplicates git-rev-list a4 c3" <<EOF
 454EOF
 455
 456test_output_expect_success 'one specified head reachable from another c3, a4, no --merge-order' "list_duplicates git-rev-list c3 a4" <<EOF
 457EOF
 458
 459test_output_expect_success 'graph with c3 and a4 parents of head' "list_duplicates git-rev-list m1" <<EOF
 460EOF
 461
 462test_output_expect_success 'graph with a4 and c3 parents of head' "list_duplicates git-rev-list m2" <<EOF
 463EOF
 464
 465test_expect_success "head ^head --merge-order" 'git-rev-list --merge-order --show-breaks a3 ^a3' <<EOF
 466EOF
 467
 468#
 469# can't test this now - duplicate parents can't be created
 470#
 471#test_output_expect_success 'duplicate parents' 'git-rev-list --parents --merge-order --show-breaks m3' <<EOF
 472#= m3 c3 a4 c3
 473#| a4 c3 b4 a3
 474#| b4 a3 b3
 475#| b3 b2
 476#^ a3 a2
 477#| a2 a1
 478#| a1 a0
 479#^ c3 c2
 480#| c2 b2 c1
 481#| b2 b1
 482#^ c1 b1
 483#| b1 a0
 484#= a0 l2
 485#| l2 l1
 486#| l1 l0
 487#| l0 root
 488#= root
 489#EOF
 490
 491test_expect_success "head ^head no --merge-order" 'git-rev-list a3 ^a3' <<EOF
 492EOF
 493
 494test_output_expect_success 'simple merge order (l5r1)' 'git-rev-list --merge-order --show-breaks l5r1' <<EOF
 495= l5r1
 496| r1
 497| r0
 498| alt_root
 499^ l5
 500| l4
 501| l3
 502| a4
 503| c3
 504| c2
 505| c1
 506^ b4
 507| b3
 508| b2
 509| b1
 510^ a3
 511| a2
 512| a1
 513| a0
 514| l2
 515| l1
 516| l0
 517= root
 518EOF
 519
 520test_output_expect_success 'simple merge order (r1l5)' 'git-rev-list --merge-order --show-breaks r1l5' <<EOF
 521= r1l5
 522| l5
 523| l4
 524| l3
 525| a4
 526| c3
 527| c2
 528| c1
 529^ b4
 530| b3
 531| b2
 532| b1
 533^ a3
 534| a2
 535| a1
 536| a0
 537| l2
 538| l1
 539| l0
 540| root
 541^ r1
 542| r0
 543= alt_root
 544EOF
 545
 546test_output_expect_success "don't print things unreachable from one branch" "git-rev-list a3 ^b3 --merge-order" <<EOF
 547a3
 548a2
 549a1
 550EOF
 551
 552#
 553#
 554
 555test_done