#!/bin/sh global test_description := ''git blame corner cases'' source ./test-lib.sh global pick_fc := ''s/^[0-9a-f^]* *\([^ ]*\) *(\([^ ]*\) .*/\1-\2/'' test_expect_success setup ' echo A A A A A >one && echo B B B B B >two && echo C C C C C >tres && echo ABC >mouse && for i in 1 2 3 4 5 6 7 8 9 do echo $i done >nine_lines && for i in 1 2 3 4 5 6 7 8 9 a do echo $i done >ten_lines && git add one two tres mouse nine_lines ten_lines && test_tick && GIT_AUTHOR_NAME=Initial git commit -m Initial && cat one >uno && mv two dos && cat one >>tres && echo DEF >>mouse && git add uno dos tres mouse && test_tick && GIT_AUTHOR_NAME=Second git commit -a -m Second && echo GHIJK >>mouse && git add mouse && test_tick && GIT_AUTHOR_NAME=Third git commit -m Third && cat mouse >cow && git add cow && test_tick && GIT_AUTHOR_NAME=Fourth git commit -m Fourth && cat >cow <<-\EOF && ABC DEF XXXX GHIJK EOF git add cow && test_tick && GIT_AUTHOR_NAME=Fifth git commit -m Fifth ' test_expect_success 'straight copy without -C' ' git blame uno | grep Second ' test_expect_success 'straight move without -C' ' git blame dos | grep Initial ' test_expect_success 'straight copy with -C' ' git blame -C1 uno | grep Second ' test_expect_success 'straight move with -C' ' git blame -C1 dos | grep Initial ' test_expect_success 'straight copy with -C -C' ' git blame -C -C1 uno | grep Initial ' test_expect_success 'straight move with -C -C' ' git blame -C -C1 dos | grep Initial ' test_expect_success 'append without -C' ' git blame -L2 tres | grep Second ' test_expect_success 'append with -C' ' git blame -L2 -C1 tres | grep Second ' test_expect_success 'append with -C -C' ' git blame -L2 -C -C1 tres | grep Second ' test_expect_success 'append with -C -C -C' ' git blame -L2 -C -C -C1 tres | grep Initial ' test_expect_success 'blame wholesale copy' ' git blame -f -C -C1 HEAD^ -- cow | sed -e "$pick_fc" >current && cat >expected <<-\EOF && mouse-Initial mouse-Second mouse-Third EOF test_cmp expected current ' test_expect_success 'blame wholesale copy and more' ' git blame -f -C -C1 HEAD -- cow | sed -e "$pick_fc" >current && cat >expected <<-\EOF && mouse-Initial mouse-Second cow-Fifth mouse-Third EOF test_cmp expected current ' test_expect_success 'blame wholesale copy and more in the index' ' cat >horse <<-\EOF && ABC DEF XXXX YYYY GHIJK EOF git add horse && test_when_finished "git rm -f horse" && git blame -f -C -C1 -- horse | sed -e "$pick_fc" >current && cat >expected <<-\EOF && mouse-Initial mouse-Second cow-Fifth horse-Not mouse-Third EOF test_cmp expected current ' test_expect_success 'blame during cherry-pick with file rename conflict' ' test_when_finished "git reset --hard && git checkout master" && git checkout HEAD~3 && echo MOUSE >> mouse && git mv mouse rodent && git add rodent && GIT_AUTHOR_NAME=Rodent git commit -m "rodent" && git checkout --detach master && (git cherry-pick HEAD@{1} || test $? -eq 1) && git show HEAD@{1}:rodent > rodent && git add rodent && git blame -f -C -C1 rodent | sed -e "$pick_fc" >current && cat current && cat >expected <<-\EOF && mouse-Initial mouse-Second rodent-Not EOF test_cmp expected current ' test_expect_success 'blame path that used to be a directory' ' mkdir path && echo A A A A A >path/file && echo B B B B B >path/elif && git add path && test_tick && git commit -m "path was a directory" && rm -fr path && echo A A A A A >path && git add path && test_tick && git commit -m "path is a regular file" && git blame HEAD^.. -- path ' test_expect_success 'blame to a commit with no author name' ' TREE=$(git rev-parse HEAD:) && cat >badcommit < 1234567890 +0000 committer David Reiss 1234567890 +0000 some message EOF COMMIT=$(git hash-object -t commit -w badcommit) && git --no-pager blame $COMMIT -- uno >/dev/null ' test_expect_success 'blame -L with invalid start' ' test_must_fail git blame -L5 tres 2>errors && test_i18ngrep "has only 2 lines" errors ' test_expect_success 'blame -L with invalid end' ' test_must_fail git blame -L1,5 tres 2>errors && test_i18ngrep "has only 2 lines" errors ' test_expect_success 'blame parses part of -L' ' git blame -L1,1 tres >out && cat out && test $(wc -l < out) -eq 1 ' test_expect_success 'indent of line numbers, nine lines' ' git blame nine_lines >actual && test $(grep -c " " actual) = 0 ' test_expect_success 'indent of line numbers, ten lines' ' git blame ten_lines >actual && test $(grep -c " " actual) = 9 ' test_expect_success 'setup file with CRLF newlines' ' git config core.autocrlf false && printf "testcase\n" >crlffile && git add crlffile && git commit -m testcase && printf "testcase\r\n" >crlffile ' test_expect_success 'blame file with CRLF core.autocrlf true' ' git config core.autocrlf true && git blame crlffile >actual && grep "A U Thor" actual ' test_expect_success 'blame file with CRLF attributes text' ' git config core.autocrlf false && echo "crlffile text" >.gitattributes && git blame crlffile >actual && grep "A U Thor" actual ' test_expect_success 'blame file with CRLF core.autocrlf=true' ' git config core.autocrlf false && printf "testcase\r\n" >crlfinrepo && >.gitattributes && git add crlfinrepo && git commit -m "add crlfinrepo" && git config core.autocrlf true && mv crlfinrepo tmp && git checkout crlfinrepo && rm tmp && git blame crlfinrepo >actual && grep "A U Thor" actual ' test_done (CommandList children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:test_description) op: Equal rhs: {(SQ <"git blame corner cases">)} spids: [4] ) ] spids: [4] ) (C {(.)} {(./test-lib.sh)}) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:pick_fc) op: Equal rhs: {(SQ <"s/^[0-9a-f^]* *\\([^ ]*\\) *(\\([^ ]*\\) .*/\\1-\\2/">)} spids: [14] ) ] spids: [14] ) (C {(test_expect_success)} {(setup)} { (SQ <"\n"> <"\n"> <"\techo A A A A A >one &&\n"> <"\techo B B B B B >two &&\n"> <"\techo C C C C C >tres &&\n"> <"\techo ABC >mouse &&\n"> <"\tfor i in 1 2 3 4 5 6 7 8 9\n"> <"\tdo\n"> <"\t\techo $i\n"> <"\tdone >nine_lines &&\n"> <"\tfor i in 1 2 3 4 5 6 7 8 9 a\n"> <"\tdo\n"> <"\t\techo $i\n"> <"\tdone >ten_lines &&\n"> <"\tgit add one two tres mouse nine_lines ten_lines &&\n"> <"\ttest_tick &&\n"> <"\tGIT_AUTHOR_NAME=Initial git commit -m Initial &&\n"> <"\n"> <"\tcat one >uno &&\n"> <"\tmv two dos &&\n"> <"\tcat one >>tres &&\n"> <"\techo DEF >>mouse &&\n"> <"\tgit add uno dos tres mouse &&\n"> <"\ttest_tick &&\n"> <"\tGIT_AUTHOR_NAME=Second git commit -a -m Second &&\n"> <"\n"> <"\techo GHIJK >>mouse &&\n"> <"\tgit add mouse &&\n"> <"\ttest_tick &&\n"> <"\tGIT_AUTHOR_NAME=Third git commit -m Third &&\n"> <"\n"> <"\tcat mouse >cow &&\n"> <"\tgit add cow &&\n"> <"\ttest_tick &&\n"> <"\tGIT_AUTHOR_NAME=Fourth git commit -m Fourth &&\n"> <"\n"> <"\tcat >cow <<-\\EOF &&\n"> <"\tABC\n"> <"\tDEF\n"> <"\tXXXX\n"> <"\tGHIJK\n"> <"\tEOF\n"> <"\tgit add cow &&\n"> <"\ttest_tick &&\n"> <"\tGIT_AUTHOR_NAME=Fifth git commit -m Fifth\n"> ) } ) (C {(test_expect_success)} {(SQ <"straight copy without -C">)} {(SQ <"\n"> <"\n"> <"\tgit blame uno | grep Second\n"> <"\n">)} ) (C {(test_expect_success)} {(SQ <"straight move without -C">)} {(SQ <"\n"> <"\n"> <"\tgit blame dos | grep Initial\n"> <"\n">)} ) (C {(test_expect_success)} {(SQ <"straight copy with -C">)} {(SQ <"\n"> <"\n"> <"\tgit blame -C1 uno | grep Second\n"> <"\n">)} ) (C {(test_expect_success)} {(SQ <"straight move with -C">)} {(SQ <"\n"> <"\n"> <"\tgit blame -C1 dos | grep Initial\n"> <"\n">)} ) (C {(test_expect_success)} {(SQ <"straight copy with -C -C">)} {(SQ <"\n"> <"\n"> <"\tgit blame -C -C1 uno | grep Initial\n"> <"\n">)} ) (C {(test_expect_success)} {(SQ <"straight move with -C -C">)} {(SQ <"\n"> <"\n"> <"\tgit blame -C -C1 dos | grep Initial\n"> <"\n">)} ) (C {(test_expect_success)} {(SQ <"append without -C">)} {(SQ <"\n"> <"\n"> <"\tgit blame -L2 tres | grep Second\n"> <"\n">)} ) (C {(test_expect_success)} {(SQ <"append with -C">)} {(SQ <"\n"> <"\n"> <"\tgit blame -L2 -C1 tres | grep Second\n"> <"\n">)} ) (C {(test_expect_success)} {(SQ <"append with -C -C">)} {(SQ <"\n"> <"\n"> <"\tgit blame -L2 -C -C1 tres | grep Second\n"> <"\n">)} ) (C {(test_expect_success)} {(SQ <"append with -C -C -C">)} {(SQ <"\n"> <"\n"> <"\tgit blame -L2 -C -C -C1 tres | grep Initial\n"> <"\n">)} ) (C {(test_expect_success)} {(SQ <"blame wholesale copy">)} { (SQ <"\n"> <"\n"> <"\tgit blame -f -C -C1 HEAD^ -- cow | sed -e \"$pick_fc\" >current &&\n"> <"\tcat >expected <<-\\EOF &&\n"> <"\tmouse-Initial\n"> <"\tmouse-Second\n"> <"\tmouse-Third\n"> <"\tEOF\n"> <"\ttest_cmp expected current\n"> <"\n"> ) } ) (C {(test_expect_success)} {(SQ <"blame wholesale copy and more">)} { (SQ <"\n"> <"\n"> <"\tgit blame -f -C -C1 HEAD -- cow | sed -e \"$pick_fc\" >current &&\n"> <"\tcat >expected <<-\\EOF &&\n"> <"\tmouse-Initial\n"> <"\tmouse-Second\n"> <"\tcow-Fifth\n"> <"\tmouse-Third\n"> <"\tEOF\n"> <"\ttest_cmp expected current\n"> <"\n"> ) } ) (C {(test_expect_success)} {(SQ <"blame wholesale copy and more in the index">)} { (SQ <"\n"> <"\n"> <"\tcat >horse <<-\\EOF &&\n"> <"\tABC\n"> <"\tDEF\n"> <"\tXXXX\n"> <"\tYYYY\n"> <"\tGHIJK\n"> <"\tEOF\n"> <"\tgit add horse &&\n"> <"\ttest_when_finished \"git rm -f horse\" &&\n"> <"\tgit blame -f -C -C1 -- horse | sed -e \"$pick_fc\" >current &&\n"> <"\tcat >expected <<-\\EOF &&\n"> <"\tmouse-Initial\n"> <"\tmouse-Second\n"> <"\tcow-Fifth\n"> <"\thorse-Not\n"> <"\tmouse-Third\n"> <"\tEOF\n"> <"\ttest_cmp expected current\n"> <"\n"> ) } ) (C {(test_expect_success)} {(SQ <"blame during cherry-pick with file rename conflict">)} { (SQ <"\n"> <"\n"> <"\ttest_when_finished \"git reset --hard && git checkout master\" &&\n"> <"\tgit checkout HEAD~3 &&\n"> <"\techo MOUSE >> mouse &&\n"> <"\tgit mv mouse rodent &&\n"> <"\tgit add rodent &&\n"> <"\tGIT_AUTHOR_NAME=Rodent git commit -m \"rodent\" &&\n"> <"\tgit checkout --detach master &&\n"> <"\t(git cherry-pick HEAD@{1} || test $? -eq 1) &&\n"> <"\tgit show HEAD@{1}:rodent > rodent &&\n"> <"\tgit add rodent &&\n"> <"\tgit blame -f -C -C1 rodent | sed -e \"$pick_fc\" >current &&\n"> <"\tcat current &&\n"> <"\tcat >expected <<-\\EOF &&\n"> <"\tmouse-Initial\n"> <"\tmouse-Second\n"> <"\trodent-Not\n"> <"\tEOF\n"> <"\ttest_cmp expected current\n"> ) } ) (C {(test_expect_success)} {(SQ <"blame path that used to be a directory">)} { (SQ <"\n"> <"\tmkdir path &&\n"> <"\techo A A A A A >path/file &&\n"> <"\techo B B B B B >path/elif &&\n"> <"\tgit add path &&\n"> <"\ttest_tick &&\n"> <"\tgit commit -m \"path was a directory\" &&\n"> <"\trm -fr path &&\n"> <"\techo A A A A A >path &&\n"> <"\tgit add path &&\n"> <"\ttest_tick &&\n"> <"\tgit commit -m \"path is a regular file\" &&\n"> <"\tgit blame HEAD^.. -- path\n"> ) } ) (C {(test_expect_success)} {(SQ <"blame to a commit with no author name">)} { (SQ <"\n"> <" TREE=$(git rev-parse HEAD:) &&\n"> <" cat >badcommit < <"tree $TREE\n"> <"author 1234567890 +0000\n"> <"committer David Reiss 1234567890 +0000\n"> <"\n"> <"some message\n"> <"EOF\n"> <" COMMIT=$(git hash-object -t commit -w badcommit) &&\n"> <" git --no-pager blame $COMMIT -- uno >/dev/null\n"> ) } ) (C {(test_expect_success)} {(SQ <"blame -L with invalid start">)} { (SQ <"\n"> <"\ttest_must_fail git blame -L5 tres 2>errors &&\n"> <"\ttest_i18ngrep \"has only 2 lines\" errors\n"> ) } ) (C {(test_expect_success)} {(SQ <"blame -L with invalid end">)} { (SQ <"\n"> <"\ttest_must_fail git blame -L1,5 tres 2>errors &&\n"> <"\ttest_i18ngrep \"has only 2 lines\" errors\n"> ) } ) (C {(test_expect_success)} {(SQ <"blame parses part of -L">)} { (SQ <"\n"> <"\tgit blame -L1,1 tres >out &&\n"> <"\tcat out &&\n"> <"\ttest $(wc -l < out) -eq 1\n"> ) } ) (C {(test_expect_success)} {(SQ <"indent of line numbers, nine lines">)} {(SQ <"\n"> <"\tgit blame nine_lines >actual &&\n"> <"\ttest $(grep -c \" \" actual) = 0\n">)} ) (C {(test_expect_success)} {(SQ <"indent of line numbers, ten lines">)} {(SQ <"\n"> <"\tgit blame ten_lines >actual &&\n"> <"\ttest $(grep -c \" \" actual) = 9\n">)} ) (C {(test_expect_success)} {(SQ <"setup file with CRLF newlines">)} { (SQ <"\n"> <"\tgit config core.autocrlf false &&\n"> <"\tprintf \"testcase\\n\" >crlffile &&\n"> <"\tgit add crlffile &&\n"> <"\tgit commit -m testcase &&\n"> <"\tprintf \"testcase\\r\\n\" >crlffile\n"> ) } ) (C {(test_expect_success)} {(SQ <"blame file with CRLF core.autocrlf true">)} { (SQ <"\n"> <"\tgit config core.autocrlf true &&\n"> <"\tgit blame crlffile >actual &&\n"> <"\tgrep \"A U Thor\" actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"blame file with CRLF attributes text">)} { (SQ <"\n"> <"\tgit config core.autocrlf false &&\n"> <"\techo \"crlffile text\" >.gitattributes &&\n"> <"\tgit blame crlffile >actual &&\n"> <"\tgrep \"A U Thor\" actual\n"> ) } ) (C {(test_expect_success)} {(SQ <"blame file with CRLF core.autocrlf=true">)} { (SQ <"\n"> <"\tgit config core.autocrlf false &&\n"> <"\tprintf \"testcase\\r\\n\" >crlfinrepo &&\n"> <"\t>.gitattributes &&\n"> <"\tgit add crlfinrepo &&\n"> <"\tgit commit -m \"add crlfinrepo\" &&\n"> <"\tgit config core.autocrlf true &&\n"> <"\tmv crlfinrepo tmp &&\n"> <"\tgit checkout crlfinrepo &&\n"> <"\trm tmp &&\n"> <"\tgit blame crlfinrepo >actual &&\n"> <"\tgrep \"A U Thor\" actual\n"> ) } ) (C {(test_done)}) ] )