1#!/bin/sh
   2#
   3# Copyright (c) 2006 Junio C Hamano
   4#
   5test_description='various format-patch tests'
   7. ./test-lib.sh
   9test_expect_success setup '
  11        for i in 1 2 3 4 5 6 7 8 9 10; do echo "$i"; done >file &&
  13        cat file >elif &&
  14        git add file elif &&
  15        git commit -m Initial &&
  16        git checkout -b side &&
  17        for i in 1 2 5 6 A B C 7 8 9 10; do echo "$i"; done >file &&
  19        test_chmod +x elif &&
  20        git commit -m "Side changes #1" &&
  21        for i in D E F; do echo "$i"; done >>file &&
  23        git update-index file &&
  24        git commit -m "Side changes #2" &&
  25        git tag C2 &&
  26        for i in 5 6 1 2 3 A 4 B C 7 8 9 10 D E F; do echo "$i"; done >file &&
  28        git update-index file &&
  29        git commit -m "Side changes #3 with \\n backslash-n in it." &&
  30        git checkout master &&
  32        git diff-tree -p C2 | git apply --index &&
  33        git commit -m "Master accepts moral equivalent of #2"
  34'
  36test_expect_success "format-patch --ignore-if-in-upstream" '
  38        git format-patch --stdout master..side >patch0 &&
  40        cnt=`grep "^From " patch0 | wc -l` &&
  41        test $cnt = 3
  42'
  44test_expect_success "format-patch --ignore-if-in-upstream" '
  46        git format-patch --stdout \
  48                --ignore-if-in-upstream master..side >patch1 &&
  49        cnt=`grep "^From " patch1 | wc -l` &&
  50        test $cnt = 2
  51'
  53test_expect_success "format-patch result applies" '
  55        git checkout -b rebuild-0 master &&
  57        git am -3 patch0 &&
  58        cnt=`git rev-list master.. | wc -l` &&
  59        test $cnt = 2
  60'
  61test_expect_success "format-patch --ignore-if-in-upstream result applies" '
  63        git checkout -b rebuild-1 master &&
  65        git am -3 patch1 &&
  66        cnt=`git rev-list master.. | wc -l` &&
  67        test $cnt = 2
  68'
  69test_expect_success 'commit did not screw up the log message' '
  71        git cat-file commit side | grep "^Side .* with .* backslash-n"
  73'
  75test_expect_success 'format-patch did not screw up the log message' '
  77        grep "^Subject: .*Side changes #3 with .* backslash-n" patch0 &&
  79        grep "^Subject: .*Side changes #3 with .* backslash-n" patch1
  80'
  82test_expect_success 'replay did not screw up the log message' '
  84        git cat-file commit rebuild-1 | grep "^Side .* with .* backslash-n"
  86'
  88test_expect_success 'extra headers' '
  90        git config format.headers "To: R. E. Cipient <rcipient@example.com>
  92" &&
  93        git config --add format.headers "Cc: S. E. Cipient <scipient@example.com>
  94" &&
  95        git format-patch --stdout master..side > patch2 &&
  96        sed -e "/^$/q" patch2 > hdrs2 &&
  97        grep "^To: R. E. Cipient <rcipient@example.com>$" hdrs2 &&
  98        grep "^Cc: S. E. Cipient <scipient@example.com>$" hdrs2
  99'
 101test_expect_success 'extra headers without newlines' '
 103        git config --replace-all format.headers "To: R. E. Cipient <rcipient@example.com>" &&
 105        git config --add format.headers "Cc: S. E. Cipient <scipient@example.com>" &&
 106        git format-patch --stdout master..side >patch3 &&
 107        sed -e "/^$/q" patch3 > hdrs3 &&
 108        grep "^To: R. E. Cipient <rcipient@example.com>$" hdrs3 &&
 109        grep "^Cc: S. E. Cipient <scipient@example.com>$" hdrs3
 110'
 112test_expect_success 'extra headers with multiple To:s' '
 114        git config --replace-all format.headers "To: R. E. Cipient <rcipient@example.com>" &&
 116        git config --add format.headers "To: S. E. Cipient <scipient@example.com>" &&
 117        git format-patch --stdout master..side > patch4 &&
 118        sed -e "/^$/q" patch4 > hdrs4 &&
 119        grep "^To: R. E. Cipient <rcipient@example.com>,$" hdrs4 &&
 120        grep "^ *S. E. Cipient <scipient@example.com>$" hdrs4
 121'
 122test_expect_success 'additional command line cc' '
 124        git config --replace-all format.headers "Cc: R. E. Cipient <rcipient@example.com>" &&
 126        git format-patch --cc="S. E. Cipient <scipient@example.com>" --stdout master..side | sed -e "/^$/q" >patch5 &&
 127        grep "^Cc: R. E. Cipient <rcipient@example.com>,$" patch5 &&
 128        grep "^ *S. E. Cipient <scipient@example.com>$" patch5
 129'
 130test_expect_success 'command line headers' '
 132        git config --unset-all format.headers &&
 134        git format-patch --add-header="Cc: R. E. Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^$/q" >patch6 &&
 135        grep "^Cc: R. E. Cipient <rcipient@example.com>$" patch6
 136'
 137test_expect_success 'configuration headers and command line headers' '
 139        git config --replace-all format.headers "Cc: R. E. Cipient <rcipient@example.com>" &&
 141        git format-patch --add-header="Cc: S. E. Cipient <scipient@example.com>" --stdout master..side | sed -e "/^$/q" >patch7 &&
 142        grep "^Cc: R. E. Cipient <rcipient@example.com>,$" patch7 &&
 143        grep "^ *S. E. Cipient <scipient@example.com>$" patch7
 144'
 145test_expect_success 'multiple files' '
 147        rm -rf patches/ &&
 149        git checkout side &&
 150        git format-patch -o patches/ master &&
 151        ls patches/0001-Side-changes-1.patch patches/0002-Side-changes-2.patch patches/0003-Side-changes-3-with-n-backslash-n-in-it.patch
 152'
 153check_threading () {
 155        expect="$1" &&
 156        shift &&
 157        (git format-patch --stdout "$@"; echo $? > status.out) |
 158        # Prints everything between the Message-ID and In-Reply-To,
 159        # and replaces all Message-ID-lookalikes by a sequence number
 160        perl -ne '
 161                if (/^(message-id|references|in-reply-to)/i) {
 162                        $printing = 1;
 163                } elsif (/^\S/) {
 164                        $printing = 0;
 165                }
 166                if ($printing) {
 167                        $h{$1}=$i++ if (/<([^>]+)>/ and !exists $h{$1});
 168                        for $k (keys %h) {s/$k/$h{$k}/};
 169                        print;
 170                }
 171                print "---\n" if /^From /i;
 172        ' > actual &&
 173        test 0 = "$(cat status.out)" &&
 174        test_cmp "$expect" actual
 175}
 176cat >> expect.no-threading <<EOF
 178---
 179---
 180---
 181EOF
 182test_expect_success 'no threading' '
 184        git checkout side &&
 185        check_threading expect.no-threading master
 186'
 187cat > expect.thread <<EOF
 189---
 190Message-Id: <0>
 191---
 192Message-Id: <1>
 193In-Reply-To: <0>
 194References: <0>
 195---
 196Message-Id: <2>
 197In-Reply-To: <0>
 198References: <0>
 199EOF
 200test_expect_success 'thread' '
 202        check_threading expect.thread --thread master
 203'
 204cat > expect.in-reply-to <<EOF
 206---
 207Message-Id: <0>
 208In-Reply-To: <1>
 209References: <1>
 210---
 211Message-Id: <2>
 212In-Reply-To: <1>
 213References: <1>
 214---
 215Message-Id: <3>
 216In-Reply-To: <1>
 217References: <1>
 218EOF
 219test_expect_success 'thread in-reply-to' '
 221        check_threading expect.in-reply-to --in-reply-to="<test.message>" \
 222                --thread master
 223'
 224cat > expect.cover-letter <<EOF
 226---
 227Message-Id: <0>
 228---
 229Message-Id: <1>
 230In-Reply-To: <0>
 231References: <0>
 232---
 233Message-Id: <2>
 234In-Reply-To: <0>
 235References: <0>
 236---
 237Message-Id: <3>
 238In-Reply-To: <0>
 239References: <0>
 240EOF
 241test_expect_success 'thread cover-letter' '
 243        check_threading expect.cover-letter --cover-letter --thread master
 244'
 245cat > expect.cl-irt <<EOF
 247---
 248Message-Id: <0>
 249In-Reply-To: <1>
 250References: <1>
 251---
 252Message-Id: <2>
 253In-Reply-To: <0>
 254References: <1>
 255        <0>
 256---
 257Message-Id: <3>
 258In-Reply-To: <0>
 259References: <1>
 260        <0>
 261---
 262Message-Id: <4>
 263In-Reply-To: <0>
 264References: <1>
 265        <0>
 266EOF
 267test_expect_success 'thread cover-letter in-reply-to' '
 269        check_threading expect.cl-irt --cover-letter \
 270                --in-reply-to="<test.message>" --thread master
 271'
 272test_expect_success 'thread explicit shallow' '
 274        check_threading expect.cl-irt --cover-letter \
 275                --in-reply-to="<test.message>" --thread=shallow master
 276'
 277cat > expect.deep <<EOF
 279---
 280Message-Id: <0>
 281---
 282Message-Id: <1>
 283In-Reply-To: <0>
 284References: <0>
 285---
 286Message-Id: <2>
 287In-Reply-To: <1>
 288References: <0>
 289        <1>
 290EOF
 291test_expect_success 'thread deep' '
 293        check_threading expect.deep --thread=deep master
 294'
 295cat > expect.deep-irt <<EOF
 297---
 298Message-Id: <0>
 299In-Reply-To: <1>
 300References: <1>
 301---
 302Message-Id: <2>
 303In-Reply-To: <0>
 304References: <1>
 305        <0>
 306---
 307Message-Id: <3>
 308In-Reply-To: <2>
 309References: <1>
 310        <0>
 311        <2>
 312EOF
 313test_expect_success 'thread deep in-reply-to' '
 315        check_threading expect.deep-irt  --thread=deep \
 316                --in-reply-to="<test.message>" master
 317'
 318cat > expect.deep-cl <<EOF
 320---
 321Message-Id: <0>
 322---
 323Message-Id: <1>
 324In-Reply-To: <0>
 325References: <0>
 326---
 327Message-Id: <2>
 328In-Reply-To: <1>
 329References: <0>
 330        <1>
 331---
 332Message-Id: <3>
 333In-Reply-To: <2>
 334References: <0>
 335        <1>
 336        <2>
 337EOF
 338test_expect_success 'thread deep cover-letter' '
 340        check_threading expect.deep-cl --cover-letter --thread=deep master
 341'
 342cat > expect.deep-cl-irt <<EOF
 344---
 345Message-Id: <0>
 346In-Reply-To: <1>
 347References: <1>
 348---
 349Message-Id: <2>
 350In-Reply-To: <0>
 351References: <1>
 352        <0>
 353---
 354Message-Id: <3>
 355In-Reply-To: <2>
 356References: <1>
 357        <0>
 358        <2>
 359---
 360Message-Id: <4>
 361In-Reply-To: <3>
 362References: <1>
 363        <0>
 364        <2>
 365        <3>
 366EOF
 367test_expect_success 'thread deep cover-letter in-reply-to' '
 369        check_threading expect.deep-cl-irt --cover-letter \
 370                --in-reply-to="<test.message>" --thread=deep master
 371'
 372test_expect_success 'thread via config' '
 374        git config format.thread true &&
 375        check_threading expect.thread master
 376'
 377test_expect_success 'thread deep via config' '
 379        git config format.thread deep &&
 380        check_threading expect.deep master
 381'
 382test_expect_success 'thread config + override' '
 384        git config format.thread deep &&
 385        check_threading expect.thread --thread master
 386'
 387test_expect_success 'thread config + --no-thread' '
 389        git config format.thread deep &&
 390        check_threading expect.no-threading --no-thread master
 391'
 392test_expect_success 'excessive subject' '
 394        rm -rf patches/ &&
 396        git checkout side &&
 397        for i in 5 6 1 2 3 A 4 B C 7 8 9 10 D E F; do echo "$i"; done >>file &&
 398        git update-index file &&
 399        git commit -m "This is an excessively long subject line for a message due to the habit some projects have of not having a short, one-line subject at the start of the commit message, but rather sticking a whole paragraph right at the start as the only thing in the commit message. It had better not become the filename for the patch." &&
 400        git format-patch -o patches/ master..side &&
 401        ls patches/0004-This-is-an-excessively-long-subject-line-for-a-messa.patch
 402'
 403test_expect_success 'cover-letter inherits diff options' '
 405        git mv file foo &&
 407        git commit -m foo &&
 408        git format-patch --cover-letter -1 &&
 409        ! grep "file => foo .* 0 *$" 0000-cover-letter.patch &&
 410        git format-patch --cover-letter -1 -M &&
 411        grep "file => foo .* 0 *$" 0000-cover-letter.patch
 412'
 414cat > expect << EOF
 416  This is an excessively long subject line for a message due to the
 417    habit some projects have of not having a short, one-line subject at
 418    the start of the commit message, but rather sticking a whole
 419    paragraph right at the start as the only thing in the commit
 420    message. It had better not become the filename for the patch.
 421  foo
 422EOF
 424test_expect_success 'shortlog of cover-letter wraps overly-long onelines' '
 426        git format-patch --cover-letter -2 &&
 428        sed -e "1,/A U Thor/d" -e "/^$/q" < 0000-cover-letter.patch > output &&
 429        test_cmp expect output
 430'
 432cat > expect << EOF
 434---
 435 file |   16 ++++++++++++++++
 436 1 files changed, 16 insertions(+), 0 deletions(-)
 437diff --git a/file b/file
 439index 40f36c6..2dc5c23 100644
 440--- a/file
 441+++ b/file
 442@@ -13,4 +13,20 @@ C
 443 10
 444 D
 445 E
 446 F
 447+5
 448EOF
 449test_expect_success 'format-patch respects -U' '
 451        git format-patch -U4 -2 &&
 453        sed -e "1,/^$/d" -e "/^+5/q" < 0001-This-is-an-excessively-long-subject-line-for-a-messa.patch > output &&
 454        test_cmp expect output
 455'
 457test_expect_success 'format-patch from a subdirectory (1)' '
 459        filename=$(
 460                rm -rf sub &&
 461                mkdir -p sub/dir &&
 462                cd sub/dir &&
 463                git format-patch -1
 464        ) &&
 465        case "$filename" in
 466        0*)
 467                ;; # ok
 468        *)
 469                echo "Oops? $filename"
 470                false
 471                ;;
 472        esac &&
 473        test -f "$filename"
 474'
 475test_expect_success 'format-patch from a subdirectory (2)' '
 477        filename=$(
 478                rm -rf sub &&
 479                mkdir -p sub/dir &&
 480                cd sub/dir &&
 481                git format-patch -1 -o ..
 482        ) &&
 483        case "$filename" in
 484        ../0*)
 485                ;; # ok
 486        *)
 487                echo "Oops? $filename"
 488                false
 489                ;;
 490        esac &&
 491        basename=$(expr "$filename" : ".*/\(.*\)") &&
 492        test -f "sub/$basename"
 493'
 494test_expect_success 'format-patch from a subdirectory (3)' '
 496        rm -f 0* &&
 497        filename=$(
 498                rm -rf sub &&
 499                mkdir -p sub/dir &&
 500                cd sub/dir &&
 501                git format-patch -1 -o "$TRASH_DIRECTORY"
 502        ) &&
 503        basename=$(expr "$filename" : ".*/\(.*\)") &&
 504        test -f "$basename"
 505'
 506test_expect_success 'format-patch --in-reply-to' '
 508        git format-patch -1 --stdout --in-reply-to "baz@foo.bar" > patch8 &&
 509        grep "^In-Reply-To: <baz@foo.bar>" patch8 &&
 510        grep "^References: <baz@foo.bar>" patch8
 511'
 512test_expect_success 'format-patch --signoff' '
 514        git format-patch -1 --signoff --stdout |
 515        grep "^Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
 516'
 517test_done