# This file isn't used as a test script directly, instead it is # sourced from t8001-annotate.sh and t8002-blame.sh. if test_have_prereq MINGW { proc sanitize_L { echo $1 | sed 'sX\(^-L\|,\)\^\?/X&\\;*Xg' } } else { proc sanitize_L { echo $1 } } proc check_count { global head := '' && global file := ''file'' && global options := '' && while : { matchstr $1 { -h { global head := $2; shift; shift } -f { global file := $2; shift; shift } -L* { global options := ""$options $[sanitize_L $1]""; shift } -* { global options := ""$options $1""; shift } * { break } } } && echo "$PROG $options $file $head" > !4 && $PROG $options $file $head >actual && perl -e ' my %expect = (@ARGV); my %count = map { $_ => 0 } keys %expect; while () { if (/^[0-9a-f]+\t\(([^\t]+)\t/) { my $author = $1; for ($author) { s/^\s*//; s/\s*$//; } $count{$author}++; } } my $bad = 0; while (my ($author, $count) = each %count) { my $ok; my $value = 0; $value = $expect{$author} if defined $expect{$author}; if ($value != $count) { $bad = 1; $ok = "bad"; } else { $ok = "good"; } print STDERR "Author $author (expected $value, attributed $count) $ok\n"; } exit($bad); ' @Argv file && echo "lazy dog" >>file && git add file && GIT_AUTHOR_NAME="A" GIT_AUTHOR_EMAIL="A@test.git" \ git commit -a -m "Initial." ' test_expect_success 'blame 1 author' ' check_count A 2 ' test_expect_success 'blame by tag objects' ' git tag -m "test tag" testTag && git tag -m "test tag #2" testTag2 testTag && check_count -h testTag A 2 && check_count -h testTag2 A 2 ' test_expect_success 'setup B lines' ' echo "2A quick brown fox jumps over the" >>file && echo "lazy dog" >>file && GIT_AUTHOR_NAME="B" GIT_AUTHOR_EMAIL="B@test.git" \ git commit -a -m "Second." ' test_expect_success 'blame 2 authors' ' check_count A 2 B 2 ' test_expect_success 'setup B1 lines (branch1)' ' git checkout -b branch1 master && echo "3A slow green fox jumps into the" >>file && echo "well." >>file && GIT_AUTHOR_NAME="B1" GIT_AUTHOR_EMAIL="B1@test.git" \ git commit -a -m "Branch1-1" ' test_expect_success 'blame 2 authors + 1 branch1 author' ' check_count A 2 B 2 B1 2 ' test_expect_success 'setup B2 lines (branch2)' ' git checkout -b branch2 master && sed -e "s/2A quick brown/4A quick brown lazy dog/" file.new && mv file.new file && GIT_AUTHOR_NAME="B2" GIT_AUTHOR_EMAIL="B2@test.git" \ git commit -a -m "Branch2-1" ' test_expect_success 'blame 2 authors + 1 branch2 author' ' check_count A 2 B 1 B2 1 ' test_expect_success 'merge branch1 & branch2' ' git merge branch1 ' test_expect_success 'blame 2 authors + 2 merged-in authors' ' check_count A 2 B 1 B1 2 B2 1 ' test_expect_success 'blame --first-parent blames merge for branch1' ' check_count --first-parent A 2 B 1 "A U Thor" 2 B2 1 ' test_expect_success 'blame ancestor' ' check_count -h master A 2 B 2 ' test_expect_success 'blame great-ancestor' ' check_count -h master^ A 2 ' test_expect_success 'setup evil merge' ' echo "evil merge." >>file && git commit -a --amend ' test_expect_success 'blame evil merge' ' check_count A 2 B 1 B1 2 B2 1 "A U Thor" 1 ' test_expect_success 'blame huge graft' ' test_when_finished "git checkout branch2" && test_when_finished "rm -f .git/info/grafts" && graft= && for i in 0 1 2 do for j in 0 1 2 3 4 5 6 7 8 9 do git checkout --orphan "$i$j" && printf "%s\n" "$i" "$j" >file && test_tick && GIT_AUTHOR_NAME=$i$j GIT_AUTHOR_EMAIL=$i$j@test.git \ git commit -a -m "$i$j" && commit=$(git rev-parse --verify HEAD) && graft="$graft$commit " done done && printf "%s " $graft >.git/info/grafts && check_count -h 00 01 1 10 1 ' test_expect_success 'setup incomplete line' ' echo "incomplete" | tr -d "\\012" >>file && GIT_AUTHOR_NAME="C" GIT_AUTHOR_EMAIL="C@test.git" \ git commit -a -m "Incomplete" ' test_expect_success 'blame incomplete line' ' check_count A 2 B 1 B1 2 B2 1 "A U Thor" 1 C 1 ' test_expect_success 'setup edits' ' mv file file.orig && { cat file.orig && echo } | sed -e "s/^3A/99/" -e "/^1A/d" -e "/^incomplete/d" >file && echo "incomplete" | tr -d "\\012" >>file && GIT_AUTHOR_NAME="D" GIT_AUTHOR_EMAIL="D@test.git" \ git commit -a -m "edit" ' test_expect_success 'blame edits' ' check_count A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1 ' test_expect_success 'setup obfuscated email' ' echo "No robots allowed" >file.new && cat file >>file.new && mv file.new file && GIT_AUTHOR_NAME="E" GIT_AUTHOR_EMAIL="E at test dot git" \ git commit -a -m "norobots" ' test_expect_success 'blame obfuscated email' ' check_count A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1 E 1 ' test_expect_success 'blame -L 1 (all)' ' check_count -L1 A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1 E 1 ' test_expect_success 'blame -L , (all)' ' check_count -L, A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1 E 1 ' test_expect_success 'blame -L X (X to end)' ' check_count -L5 B1 1 C 1 D 1 "A U Thor" 1 ' test_expect_success 'blame -L X, (X to end)' ' check_count -L5, B1 1 C 1 D 1 "A U Thor" 1 ' test_expect_success 'blame -L ,Y (up to Y)' ' check_count -L,3 A 1 B2 1 E 1 ' test_expect_success 'blame -L X,X' ' check_count -L3,3 B2 1 ' test_expect_success 'blame -L X,Y' ' check_count -L3,6 B 1 B1 1 B2 1 D 1 ' test_expect_success 'blame -L Y,X (undocumented)' ' check_count -L6,3 B 1 B1 1 B2 1 D 1 ' test_expect_success 'blame -L -X' ' test_must_fail $PROG -L-1 file ' test_expect_success 'blame -L 0' ' test_must_fail $PROG -L0 file ' test_expect_success 'blame -L ,0' ' test_must_fail $PROG -L,0 file ' test_expect_success 'blame -L ,+0' ' test_must_fail $PROG -L,+0 file ' test_expect_success 'blame -L X,+0' ' test_must_fail $PROG -L1,+0 file ' test_expect_success 'blame -L X,+1' ' check_count -L3,+1 B2 1 ' test_expect_success 'blame -L X,+N' ' check_count -L3,+4 B 1 B1 1 B2 1 D 1 ' test_expect_success 'blame -L ,-0' ' test_must_fail $PROG -L,-0 file ' test_expect_success 'blame -L X,-0' ' test_must_fail $PROG -L1,-0 file ' test_expect_success 'blame -L X,-1' ' check_count -L3,-1 B2 1 ' test_expect_success 'blame -L X,-N' ' check_count -L6,-4 B 1 B1 1 B2 1 D 1 ' test_expect_success 'blame -L /RE/ (RE to end)' ' check_count -L/evil/ C 1 "A U Thor" 1 ' test_expect_success 'blame -L /RE/,/RE2/' ' check_count -L/robot/,/green/ A 1 B 1 B2 1 D 1 E 1 ' test_expect_success 'blame -L X,/RE/' ' check_count -L5,/evil/ B1 1 D 1 "A U Thor" 1 ' test_expect_success 'blame -L /RE/,Y' ' check_count -L/99/,7 B1 1 D 1 "A U Thor" 1 ' test_expect_success 'blame -L /RE/,+N' ' check_count -L/99/,+3 B1 1 D 1 "A U Thor" 1 ' test_expect_success 'blame -L /RE/,-N' ' check_count -L/99/,-3 B 1 B2 1 D 1 ' # 'file' ends with an incomplete line, so 'wc' reports one fewer lines than # git-blame sees, hence the last line is actually $(wc...)+1. test_expect_success 'blame -L X (X == nlines)' ' n=$(expr $(wc -l nlines)' ' test_must_fail $PROG -L12345 file ' test_expect_success 'blame -L ,Y (Y == nlines)' ' n=$(expr $(wc -l nlines)' ' test_must_fail $PROG -L,12345 file ' test_expect_success 'blame -L multiple (disjoint)' ' check_count -L2,3 -L6,7 A 1 B1 1 B2 1 "A U Thor" 1 ' test_expect_success 'blame -L multiple (disjoint: unordered)' ' check_count -L6,7 -L2,3 A 1 B1 1 B2 1 "A U Thor" 1 ' test_expect_success 'blame -L multiple (adjacent)' ' check_count -L2,3 -L4,5 A 1 B 1 B2 1 D 1 ' test_expect_success 'blame -L multiple (adjacent: unordered)' ' check_count -L4,5 -L2,3 A 1 B 1 B2 1 D 1 ' test_expect_success 'blame -L multiple (overlapping)' ' check_count -L2,4 -L3,5 A 1 B 1 B2 1 D 1 ' test_expect_success 'blame -L multiple (overlapping: unordered)' ' check_count -L3,5 -L2,4 A 1 B 1 B2 1 D 1 ' test_expect_success 'blame -L multiple (superset/subset)' ' check_count -L2,8 -L3,5 A 1 B 1 B1 1 B2 1 C 1 D 1 "A U Thor" 1 ' test_expect_success 'blame -L multiple (superset/subset: unordered)' ' check_count -L3,5 -L2,8 A 1 B 1 B1 1 B2 1 C 1 D 1 "A U Thor" 1 ' test_expect_success 'blame -L /RE/ (relative)' ' check_count -L3,3 -L/fox/ B1 1 B2 1 C 1 D 1 "A U Thor" 1 ' test_expect_success 'blame -L /RE/ (relative: no preceding range)' ' check_count -L/dog/ A 1 B 1 B1 1 B2 1 C 1 D 1 "A U Thor" 1 ' test_expect_success 'blame -L /RE/ (relative: adjacent)' ' check_count -L1,1 -L/dog/,+1 A 1 E 1 ' test_expect_success 'blame -L /RE/ (relative: not found)' ' test_must_fail $PROG -L4,4 -L/dog/ file ' test_expect_success 'blame -L /RE/ (relative: end-of-file)' ' test_must_fail $PROG -L, -L/$/ file ' test_expect_success 'blame -L ^/RE/ (absolute)' ' check_count -L3,3 -L^/dog/,+2 A 1 B2 1 ' test_expect_success 'blame -L ^/RE/ (absolute: no preceding range)' ' check_count -L^/dog/,+2 A 1 B2 1 ' test_expect_success 'blame -L ^/RE/ (absolute: not found)' ' test_must_fail $PROG -L4,4 -L^/tambourine/ file ' test_expect_success 'blame -L ^/RE/ (absolute: end-of-file)' ' n=$(expr $(wc -l hello.c <<-\EOF && int main(int argc, const char *argv[]) { Qputs("hello"); } EOF git add hello.c && GIT_AUTHOR_NAME="F" GIT_AUTHOR_EMAIL="F@test.git" \ git commit -m "hello" && mv hello.c hello.orig && sed -e "/}/ {x; s/$/Qputs(\"goodbye\");/; G;}" hello.c && GIT_AUTHOR_NAME="G" GIT_AUTHOR_EMAIL="G@test.git" \ git commit -a -m "goodbye" && mv hello.c hello.orig && echo "#include " >hello.c && cat hello.orig >>hello.c && tr Q "\\t" >>hello.c <<-\EOF && void mail() { Qputs("mail"); } EOF GIT_AUTHOR_NAME="H" GIT_AUTHOR_EMAIL="H@test.git" \ git commit -a -m "mail" ' test_expect_success 'blame -L :literal' ' check_count -f hello.c -L:main F 4 G 1 ' test_expect_success 'blame -L :regex' ' check_count -f hello.c "-L:m[a-z][a-z]l" H 4 ' test_expect_success 'blame -L :nomatch' ' test_must_fail $PROG -L:nomatch hello.c ' test_expect_success 'blame -L :RE (relative)' ' check_count -f hello.c -L3,3 -L:ma.. F 1 H 4 ' test_expect_success 'blame -L :RE (relative: no preceding range)' ' check_count -f hello.c -L:ma.. F 4 G 1 ' test_expect_success 'blame -L :RE (relative: not found)' ' test_must_fail $PROG -L3,3 -L:tambourine hello.c ' test_expect_success 'blame -L :RE (relative: end-of-file)' ' test_must_fail $PROG -L, -L:main hello.c ' test_expect_success 'blame -L ^:RE (absolute)' ' check_count -f hello.c -L3,3 -L^:ma.. F 4 G 1 ' test_expect_success 'blame -L ^:RE (absolute: no preceding range)' ' check_count -f hello.c -L^:ma.. F 4 G 1 ' test_expect_success 'blame -L ^:RE (absolute: not found)' ' test_must_fail $PROG -L4,4 -L^:tambourine hello.c ' test_expect_success 'blame -L ^:RE (absolute: end-of-file)' ' n=$(printf "%d" $(wc -l incremental && git add incremental && git commit -m "step 0" && printf "partial" >>incremental && git commit -a -m "step 0.5" && echo >>incremental && git commit -a -m "step 1" ) ' test_expect_success 'blame empty' ' check_count -h HEAD^^ -f incremental ' test_expect_success 'blame -L 0 empty' ' test_must_fail $PROG -L0 incremental HEAD^^ ' test_expect_success 'blame -L 1 empty' ' test_must_fail $PROG -L1 incremental HEAD^^ ' test_expect_success 'blame -L 2 empty' ' test_must_fail $PROG -L2 incremental HEAD^^ ' test_expect_success 'blame half' ' check_count -h HEAD^ -f incremental I 1 ' test_expect_success 'blame -L 0 half' ' test_must_fail $PROG -L0 incremental HEAD^ ' test_expect_success 'blame -L 1 half' ' check_count -h HEAD^ -f incremental -L1 I 1 ' test_expect_success 'blame -L 2 half' ' test_must_fail $PROG -L2 incremental HEAD^ ' test_expect_success 'blame -L 3 half' ' test_must_fail $PROG -L3 incremental HEAD^ ' test_expect_success 'blame full' ' check_count -f incremental I 1 ' test_expect_success 'blame -L 0 full' ' test_must_fail $PROG -L0 incremental ' test_expect_success 'blame -L 1 full' ' check_count -f incremental -L1 I 1 ' test_expect_success 'blame -L 2 full' ' test_must_fail $PROG -L2 incremental ' test_expect_success 'blame -L 3 full' ' test_must_fail $PROG -L3 incremental ' test_expect_success 'blame -L' ' test_must_fail $PROG -L file ' test_expect_success 'blame -L X,+' ' test_must_fail $PROG -L1,+ file ' test_expect_success 'blame -L X,-' ' test_must_fail $PROG -L1,- file ' test_expect_success 'blame -L X (non-numeric X)' ' test_must_fail $PROG -LX file ' test_expect_success 'blame -L X,Y (non-numeric Y)' ' test_must_fail $PROG -L1,Y file ' test_expect_success 'blame -L X,+N (non-numeric N)' ' test_must_fail $PROG -L1,+N file ' test_expect_success 'blame -L X,-N (non-numeric N)' ' test_must_fail $PROG -L1,-N file ' test_expect_success 'blame -L ,^/RE/' ' test_must_fail $PROG -L1,^/99/ file ' (CommandList children: [ (If arms: [ (if_arm cond: [(C {(test_have_prereq)} {(MINGW)})] action: [ (FuncDef name: sanitize_L body: (BraceGroup children: [ (Pipeline children: [ (C {(echo)} {(DQ ($ VSub_Number "$1"))}) (C {(sed)} {(SQ <"sX\\(^-L\\|,\\)\\^\\?/X&\\\\;*Xg">)}) ] negated: False ) ] spids: [21] ) spids: [16 20] ) ] spids: [-1 13] ) ] else_action: [ (FuncDef name: sanitize_L body: (BraceGroup children:[(C {(echo)} {(DQ ($ VSub_Number "$1"))})] spids:[49]) spids: [44 48] ) ] spids: [41 61] ) (FuncDef name: check_count body: (BraceGroup children: [ (AndOr children: [ (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:head) op:Equal rhs:{(SQ )} spids:[72])] spids: [72] ) (AndOr children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:file) op: Equal rhs: {(SQ )} spids: [77] ) ] spids: [77] ) (AndOr children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:options) op: Equal rhs: {(SQ )} spids: [85] ) ] spids: [85] ) (AndOr children: [ (While cond: [(C {(Lit_Other ":")})] body: (DoGroup children: [ (Case to_match: {(DQ ($ VSub_Number "$1"))} arms: [ (case_arm pat_list: [{(-h)}] action: [ (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:head) op: Equal rhs: {(DQ ($ VSub_Number "$2"))} spids: [110] ) ] spids: [110] ) terminator: ) (Sentence child: (C {(shift)}) terminator: ) (C {(shift)}) ] spids: [107 108 121 -1] ) (case_arm pat_list: [{(-f)}] action: [ (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:file) op: Equal rhs: {(DQ ($ VSub_Number "$2"))} spids: [127] ) ] spids: [127] ) terminator: ) (Sentence child: (C {(shift)}) terminator: ) (C {(shift)}) ] spids: [124 125 138 -1] ) (case_arm pat_list: [{(-L) (Lit_Other "*")}] action: [ (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:options) op: Equal rhs: { (DQ ($ VSub_Name "$options") (" ") (CommandSubPart command_list: (CommandList children: [ (C {(sanitize_L)} {(DQ ($ VSub_Number "$1"))} ) ] ) left_token: spids: [149 155] ) ) } spids: [145] ) ] spids: [145] ) terminator: ) (C {(shift)}) ] spids: [141 143 161 -1] ) (case_arm pat_list: [{(-) (Lit_Other "*")}] action: [ (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:options) op: Equal rhs: { (DQ ($ VSub_Name "$options") (" ") ($ VSub_Number "$1") ) } spids: [168] ) ] spids: [168] ) terminator: ) (C {(shift)}) ] spids: [164 166 178 -1] ) (case_arm pat_list: [{(Lit_Other "*")}] action: [(ControlFlow token:)] spids: [181 182 186 -1] ) ] spids: [98 104 189] ) ] spids: [95 192] ) ) (AndOr children: [ (SimpleCommand words: [ {(echo)} { (DQ ($ VSub_Name "$PROG") (" ") ($ VSub_Name "$options") (" ") ($ VSub_Name "$file") (" ") ($ VSub_Name "$head") ) } ] redirects: [ (Redir op_id: Redir_GreatAnd fd: -1 arg_word: {(4)} spids: [209] ) ] ) (AndOr children: [ (SimpleCommand words: [ {($ VSub_Name "$PROG")} {($ VSub_Name "$options")} {($ VSub_Name "$file")} {($ VSub_Name "$head")} ] redirects: [ (Redir op_id: Redir_Great fd: -1 arg_word: {(actual)} spids: [223] ) ] ) (SimpleCommand words: [ {(perl)} {(-e)} { (SQ <"\n"> <"\t\tmy %expect = (@ARGV);\n"> <"\t\tmy %count = map { $_ => 0 } keys %expect;\n"> <"\t\twhile () {\n"> <"\t\t\tif (/^[0-9a-f]+\\t\\(([^\\t]+)\\t/) {\n"> <"\t\t\t\tmy $author = $1;\n"> <"\t\t\t\tfor ($author) { s/^\\s*//; s/\\s*$//; }\n"> <"\t\t\t\t$count{$author}++;\n"> <"\t\t\t}\n"> <"\t\t}\n"> <"\t\tmy $bad = 0;\n"> <"\t\twhile (my ($author, $count) = each %count) {\n"> <"\t\t\tmy $ok;\n"> <"\t\t\tmy $value = 0;\n"> <"\t\t\t$value = $expect{$author} if defined $expect{$author};\n"> <"\t\t\tif ($value != $count) {\n"> <"\t\t\t\t$bad = 1;\n"> <"\t\t\t\t$ok = \"bad\";\n"> <"\t\t\t}\n"> <"\t\t\telse {\n"> <"\t\t\t\t$ok = \"good\";\n"> <"\t\t\t}\n"> < "\t\t\tprint STDERR \"Author $author (expected $value, attributed $count) $ok\\n\";\n" > <"\t\t}\n"> <"\t\texit($bad);\n"> <"\t"> ) } {(DQ ($ VSub_At "$@"))} ] redirects: [ (Redir op_id: Redir_Less fd: -1 arg_word: {(actual)} spids: [266] ) ] ) ] op_id: Op_DAmp ) ] op_id: Op_DAmp ) ] op_id: Op_DAmp ) ] op_id: Op_DAmp ) ] op_id: Op_DAmp ) ] op_id: Op_DAmp ) ] spids: [69] ) spids: [64 68] ) (C {(test_expect_success)} {(SQ <"setup A lines">)} { (SQ <"\n"> <"\techo \"1A quick brown fox jumps over the\" >file &&\n"> <"\techo \"lazy dog\" >>file &&\n"> <"\tgit add file &&\n"> <"\tGIT_AUTHOR_NAME=\"A\" GIT_AUTHOR_EMAIL=\"A@test.git\" \\\n"> <"\tgit commit -a -m \"Initial.\"\n"> ) } ) (C {(test_expect_success)} {(SQ <"blame 1 author">)} {(SQ <"\n"> <"\tcheck_count A 2\n">)}) (C {(test_expect_success)} {(SQ <"blame by tag objects">)} { (SQ <"\n"> <"\tgit tag -m \"test tag\" testTag &&\n"> <"\tgit tag -m \"test tag #2\" testTag2 testTag &&\n"> <"\tcheck_count -h testTag A 2 &&\n"> <"\tcheck_count -h testTag2 A 2\n"> ) } ) (C {(test_expect_success)} {(SQ <"setup B lines">)} { (SQ <"\n"> <"\techo \"2A quick brown fox jumps over the\" >>file &&\n"> <"\techo \"lazy dog\" >>file &&\n"> <"\tGIT_AUTHOR_NAME=\"B\" GIT_AUTHOR_EMAIL=\"B@test.git\" \\\n"> <"\tgit commit -a -m \"Second.\"\n"> ) } ) (C {(test_expect_success)} {(SQ <"blame 2 authors">)} {(SQ <"\n"> <"\tcheck_count A 2 B 2\n">)}) (C {(test_expect_success)} {(SQ <"setup B1 lines (branch1)">)} { (SQ <"\n"> <"\tgit checkout -b branch1 master &&\n"> <"\techo \"3A slow green fox jumps into the\" >>file &&\n"> <"\techo \"well.\" >>file &&\n"> <"\tGIT_AUTHOR_NAME=\"B1\" GIT_AUTHOR_EMAIL=\"B1@test.git\" \\\n"> <"\tgit commit -a -m \"Branch1-1\"\n"> ) } ) (C {(test_expect_success)} {(SQ <"blame 2 authors + 1 branch1 author">)} {(SQ <"\n"> <"\tcheck_count A 2 B 2 B1 2\n">)} ) (C {(test_expect_success)} {(SQ <"setup B2 lines (branch2)">)} { (SQ <"\n"> <"\tgit checkout -b branch2 master &&\n"> <"\tsed -e \"s/2A quick brown/4A quick brown lazy dog/\" file.new &&\n"> <"\tmv file.new file &&\n"> <"\tGIT_AUTHOR_NAME=\"B2\" GIT_AUTHOR_EMAIL=\"B2@test.git\" \\\n"> <"\tgit commit -a -m \"Branch2-1\"\n"> ) } ) (C {(test_expect_success)} {(SQ <"blame 2 authors + 1 branch2 author">)} {(SQ <"\n"> <"\tcheck_count A 2 B 1 B2 1\n">)} ) (C {(test_expect_success)} {(SQ <"merge branch1 & branch2">)} {(SQ <"\n"> <"\tgit merge branch1\n">)}) (C {(test_expect_success)} {(SQ <"blame 2 authors + 2 merged-in authors">)} {(SQ <"\n"> <"\tcheck_count A 2 B 1 B1 2 B2 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame --first-parent blames merge for branch1">)} {(SQ <"\n"> <"\tcheck_count --first-parent A 2 B 1 \"A U Thor\" 2 B2 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame ancestor">)} {(SQ <"\n"> <"\tcheck_count -h master A 2 B 2\n">)} ) (C {(test_expect_success)} {(SQ <"blame great-ancestor">)} {(SQ <"\n"> <"\tcheck_count -h master^ A 2\n">)} ) (C {(test_expect_success)} {(SQ <"setup evil merge">)} {(SQ <"\n"> <"\techo \"evil merge.\" >>file &&\n"> <"\tgit commit -a --amend\n">)} ) (C {(test_expect_success)} {(SQ <"blame evil merge">)} {(SQ <"\n"> <"\tcheck_count A 2 B 1 B1 2 B2 1 \"A U Thor\" 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame huge graft">)} { (SQ <"\n"> <"\ttest_when_finished \"git checkout branch2\" &&\n"> <"\ttest_when_finished \"rm -f .git/info/grafts\" &&\n"> <"\tgraft= &&\n"> <"\tfor i in 0 1 2\n"> <"\tdo\n"> <"\t\tfor j in 0 1 2 3 4 5 6 7 8 9\n"> <"\t\tdo\n"> <"\t\t\tgit checkout --orphan \"$i$j\" &&\n"> <"\t\t\tprintf \"%s\\n\" \"$i\" \"$j\" >file &&\n"> <"\t\t\ttest_tick &&\n"> <"\t\t\tGIT_AUTHOR_NAME=$i$j GIT_AUTHOR_EMAIL=$i$j@test.git \\\n"> <"\t\t\tgit commit -a -m \"$i$j\" &&\n"> <"\t\t\tcommit=$(git rev-parse --verify HEAD) &&\n"> <"\t\t\tgraft=\"$graft$commit \"\n"> <"\t\tdone\n"> <"\tdone &&\n"> <"\tprintf \"%s \" $graft >.git/info/grafts &&\n"> <"\tcheck_count -h 00 01 1 10 1\n"> ) } ) (C {(test_expect_success)} {(SQ <"setup incomplete line">)} { (SQ <"\n"> <"\techo \"incomplete\" | tr -d \"\\\\012\" >>file &&\n"> <"\tGIT_AUTHOR_NAME=\"C\" GIT_AUTHOR_EMAIL=\"C@test.git\" \\\n"> <"\tgit commit -a -m \"Incomplete\"\n"> ) } ) (C {(test_expect_success)} {(SQ <"blame incomplete line">)} {(SQ <"\n"> <"\tcheck_count A 2 B 1 B1 2 B2 1 \"A U Thor\" 1 C 1\n">)} ) (C {(test_expect_success)} {(SQ <"setup edits">)} { (SQ <"\n"> <"\tmv file file.orig &&\n"> <"\t{\n"> <"\t\tcat file.orig &&\n"> <"\t\techo\n"> <"\t} | sed -e \"s/^3A/99/\" -e \"/^1A/d\" -e \"/^incomplete/d\" >file &&\n"> <"\techo \"incomplete\" | tr -d \"\\\\012\" >>file &&\n"> <"\tGIT_AUTHOR_NAME=\"D\" GIT_AUTHOR_EMAIL=\"D@test.git\" \\\n"> <"\tgit commit -a -m \"edit\"\n"> ) } ) (C {(test_expect_success)} {(SQ <"blame edits">)} {(SQ <"\n"> <"\tcheck_count A 1 B 1 B1 1 B2 1 \"A U Thor\" 1 C 1 D 1\n">)} ) (C {(test_expect_success)} {(SQ <"setup obfuscated email">)} { (SQ <"\n"> <"\techo \"No robots allowed\" >file.new &&\n"> <"\tcat file >>file.new &&\n"> <"\tmv file.new file &&\n"> <"\tGIT_AUTHOR_NAME=\"E\" GIT_AUTHOR_EMAIL=\"E at test dot git\" \\\n"> <"\tgit commit -a -m \"norobots\"\n"> ) } ) (C {(test_expect_success)} {(SQ <"blame obfuscated email">)} {(SQ <"\n"> <"\tcheck_count A 1 B 1 B1 1 B2 1 \"A U Thor\" 1 C 1 D 1 E 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L 1 (all)">)} {(SQ <"\n"> <"\tcheck_count -L1 A 1 B 1 B1 1 B2 1 \"A U Thor\" 1 C 1 D 1 E 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L , (all)">)} {(SQ <"\n"> <"\tcheck_count -L, A 1 B 1 B1 1 B2 1 \"A U Thor\" 1 C 1 D 1 E 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L X (X to end)">)} {(SQ <"\n"> <"\tcheck_count -L5 B1 1 C 1 D 1 \"A U Thor\" 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L X, (X to end)">)} {(SQ <"\n"> <"\tcheck_count -L5, B1 1 C 1 D 1 \"A U Thor\" 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L ,Y (up to Y)">)} {(SQ <"\n"> <"\tcheck_count -L,3 A 1 B2 1 E 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L X,X">)} {(SQ <"\n"> <"\tcheck_count -L3,3 B2 1\n">)}) (C {(test_expect_success)} {(SQ <"blame -L X,Y">)} {(SQ <"\n"> <"\tcheck_count -L3,6 B 1 B1 1 B2 1 D 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L Y,X (undocumented)">)} {(SQ <"\n"> <"\tcheck_count -L6,3 B 1 B1 1 B2 1 D 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L -X">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L-1 file\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L 0">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L0 file\n">)}) (C {(test_expect_success)} {(SQ <"blame -L ,0">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L,0 file\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L ,+0">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L,+0 file\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L X,+0">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L1,+0 file\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L X,+1">)} {(SQ <"\n"> <"\tcheck_count -L3,+1 B2 1\n">)}) (C {(test_expect_success)} {(SQ <"blame -L X,+N">)} {(SQ <"\n"> <"\tcheck_count -L3,+4 B 1 B1 1 B2 1 D 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L ,-0">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L,-0 file\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L X,-0">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L1,-0 file\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L X,-1">)} {(SQ <"\n"> <"\tcheck_count -L3,-1 B2 1\n">)}) (C {(test_expect_success)} {(SQ <"blame -L X,-N">)} {(SQ <"\n"> <"\tcheck_count -L6,-4 B 1 B1 1 B2 1 D 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L /RE/ (RE to end)">)} {(SQ <"\n"> <"\tcheck_count -L/evil/ C 1 \"A U Thor\" 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L /RE/,/RE2/">)} {(SQ <"\n"> <"\tcheck_count -L/robot/,/green/ A 1 B 1 B2 1 D 1 E 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L X,/RE/">)} {(SQ <"\n"> <"\tcheck_count -L5,/evil/ B1 1 D 1 \"A U Thor\" 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L /RE/,Y">)} {(SQ <"\n"> <"\tcheck_count -L/99/,7 B1 1 D 1 \"A U Thor\" 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L /RE/,+N">)} {(SQ <"\n"> <"\tcheck_count -L/99/,+3 B1 1 D 1 \"A U Thor\" 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L /RE/,-N">)} {(SQ <"\n"> <"\tcheck_count -L/99/,-3 B 1 B2 1 D 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L X (X == nlines)">)} {(SQ <"\n"> <"\tn=$(expr $(wc -l <"\tcheck_count -L$n C 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L X (X == nlines + 1)">)} {(SQ <"\n"> <"\tn=$(expr $(wc -l <"\ttest_must_fail $PROG -L$n file\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L X (X > nlines)">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L12345 file\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L ,Y (Y == nlines)">)} { (SQ <"\n"> <"\tn=$(expr $(wc -l <"\tcheck_count -L,$n A 1 B 1 B1 1 B2 1 \"A U Thor\" 1 C 1 D 1 E 1\n"> ) } ) (C {(test_expect_success)} {(SQ <"blame -L ,Y (Y == nlines + 1)">)} {(SQ <"\n"> <"\tn=$(expr $(wc -l <"\ttest_must_fail $PROG -L,$n file\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L ,Y (Y > nlines)">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L,12345 file\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L multiple (disjoint)">)} {(SQ <"\n"> <"\tcheck_count -L2,3 -L6,7 A 1 B1 1 B2 1 \"A U Thor\" 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L multiple (disjoint: unordered)">)} {(SQ <"\n"> <"\tcheck_count -L6,7 -L2,3 A 1 B1 1 B2 1 \"A U Thor\" 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L multiple (adjacent)">)} {(SQ <"\n"> <"\tcheck_count -L2,3 -L4,5 A 1 B 1 B2 1 D 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L multiple (adjacent: unordered)">)} {(SQ <"\n"> <"\tcheck_count -L4,5 -L2,3 A 1 B 1 B2 1 D 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L multiple (overlapping)">)} {(SQ <"\n"> <"\tcheck_count -L2,4 -L3,5 A 1 B 1 B2 1 D 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L multiple (overlapping: unordered)">)} {(SQ <"\n"> <"\tcheck_count -L3,5 -L2,4 A 1 B 1 B2 1 D 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L multiple (superset/subset)">)} {(SQ <"\n"> <"\tcheck_count -L2,8 -L3,5 A 1 B 1 B1 1 B2 1 C 1 D 1 \"A U Thor\" 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L multiple (superset/subset: unordered)">)} {(SQ <"\n"> <"\tcheck_count -L3,5 -L2,8 A 1 B 1 B1 1 B2 1 C 1 D 1 \"A U Thor\" 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L /RE/ (relative)">)} {(SQ <"\n"> <"\tcheck_count -L3,3 -L/fox/ B1 1 B2 1 C 1 D 1 \"A U Thor\" 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L /RE/ (relative: no preceding range)">)} {(SQ <"\n"> <"\tcheck_count -L/dog/ A 1 B 1 B1 1 B2 1 C 1 D 1 \"A U Thor\" 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L /RE/ (relative: adjacent)">)} {(SQ <"\n"> <"\tcheck_count -L1,1 -L/dog/,+1 A 1 E 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L /RE/ (relative: not found)">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L4,4 -L/dog/ file\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L /RE/ (relative: end-of-file)">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L, -L/$/ file\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L ^/RE/ (absolute)">)} {(SQ <"\n"> <"\tcheck_count -L3,3 -L^/dog/,+2 A 1 B2 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L ^/RE/ (absolute: no preceding range)">)} {(SQ <"\n"> <"\tcheck_count -L^/dog/,+2 A 1 B2 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L ^/RE/ (absolute: not found)">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L4,4 -L^/tambourine/ file\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L ^/RE/ (absolute: end-of-file)">)} { (SQ <"\n"> <"\tn=$(expr $(wc -l <"\tcheck_count -L$n -L^/$/,+2 A 1 C 1 E 1\n"> ) } ) (C {(test_expect_success)} {(SQ <"setup -L :regex">)} { (SQ <"\n"> <"\ttr Q \"\\\\t\" >hello.c <<-\\EOF &&\n"> <"\tint main(int argc, const char *argv[])\n"> <"\t{\n"> <"\tQputs(\"hello\");\n"> <"\t}\n"> <"\tEOF\n"> <"\tgit add hello.c &&\n"> <"\tGIT_AUTHOR_NAME=\"F\" GIT_AUTHOR_EMAIL=\"F@test.git\" \\\n"> <"\tgit commit -m \"hello\" &&\n"> <"\n"> <"\tmv hello.c hello.orig &&\n"> <"\tsed -e \"/}/ {x; s/$/Qputs(\\\"goodbye\\\");/; G;}\" <"\ttr Q \"\\\\t\" >hello.c &&\n"> <"\tGIT_AUTHOR_NAME=\"G\" GIT_AUTHOR_EMAIL=\"G@test.git\" \\\n"> <"\tgit commit -a -m \"goodbye\" &&\n"> <"\n"> <"\tmv hello.c hello.orig &&\n"> <"\techo \"#include \" >hello.c &&\n"> <"\tcat hello.orig >>hello.c &&\n"> <"\ttr Q \"\\\\t\" >>hello.c <<-\\EOF &&\n"> <"\tvoid mail()\n"> <"\t{\n"> <"\tQputs(\"mail\");\n"> <"\t}\n"> <"\tEOF\n"> <"\tGIT_AUTHOR_NAME=\"H\" GIT_AUTHOR_EMAIL=\"H@test.git\" \\\n"> <"\tgit commit -a -m \"mail\"\n"> ) } ) (C {(test_expect_success)} {(SQ <"blame -L :literal">)} {(SQ <"\n"> <"\tcheck_count -f hello.c -L:main F 4 G 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L :regex">)} {(SQ <"\n"> <"\tcheck_count -f hello.c \"-L:m[a-z][a-z]l\" H 4\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L :nomatch">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L:nomatch hello.c\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L :RE (relative)">)} {(SQ <"\n"> <"\tcheck_count -f hello.c -L3,3 -L:ma.. F 1 H 4\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L :RE (relative: no preceding range)">)} {(SQ <"\n"> <"\tcheck_count -f hello.c -L:ma.. F 4 G 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L :RE (relative: not found)">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L3,3 -L:tambourine hello.c\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L :RE (relative: end-of-file)">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L, -L:main hello.c\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L ^:RE (absolute)">)} {(SQ <"\n"> <"\tcheck_count -f hello.c -L3,3 -L^:ma.. F 4 G 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L ^:RE (absolute: no preceding range)">)} {(SQ <"\n"> <"\tcheck_count -f hello.c -L^:ma.. F 4 G 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L ^:RE (absolute: not found)">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L4,4 -L^:tambourine hello.c\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L ^:RE (absolute: end-of-file)">)} { (SQ <"\n"> <"\tn=$(printf \"%d\" $(wc -l <"\tcheck_count -f hello.c -L$n -L^:ma.. F 4 G 1 H 1\n"> ) } ) (C {(test_expect_success)} {(SQ <"setup incremental">)} { (SQ <"\n"> <"\t(\n"> <"\tGIT_AUTHOR_NAME=I &&\n"> <"\texport GIT_AUTHOR_NAME &&\n"> <"\tGIT_AUTHOR_EMAIL=I@test.git &&\n"> <"\texport GIT_AUTHOR_EMAIL &&\n"> <"\t>incremental &&\n"> <"\tgit add incremental &&\n"> <"\tgit commit -m \"step 0\" &&\n"> <"\tprintf \"partial\" >>incremental &&\n"> <"\tgit commit -a -m \"step 0.5\" &&\n"> <"\techo >>incremental &&\n"> <"\tgit commit -a -m \"step 1\"\n"> <"\t)\n"> ) } ) (C {(test_expect_success)} {(SQ <"blame empty">)} {(SQ <"\n"> <"\tcheck_count -h HEAD^^ -f incremental\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L 0 empty">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L0 incremental HEAD^^\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L 1 empty">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L1 incremental HEAD^^\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L 2 empty">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L2 incremental HEAD^^\n">)} ) (C {(test_expect_success)} {(SQ <"blame half">)} {(SQ <"\n"> <"\tcheck_count -h HEAD^ -f incremental I 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L 0 half">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L0 incremental HEAD^\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L 1 half">)} {(SQ <"\n"> <"\tcheck_count -h HEAD^ -f incremental -L1 I 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L 2 half">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L2 incremental HEAD^\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L 3 half">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L3 incremental HEAD^\n">)} ) (C {(test_expect_success)} {(SQ <"blame full">)} {(SQ <"\n"> <"\tcheck_count -f incremental I 1\n">)}) (C {(test_expect_success)} {(SQ <"blame -L 0 full">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L0 incremental\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L 1 full">)} {(SQ <"\n"> <"\tcheck_count -f incremental -L1 I 1\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L 2 full">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L2 incremental\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L 3 full">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L3 incremental\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L file\n">)}) (C {(test_expect_success)} {(SQ <"blame -L X,+">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L1,+ file\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L X,-">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L1,- file\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L X (non-numeric X)">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -LX file\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L X,Y (non-numeric Y)">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L1,Y file\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L X,+N (non-numeric N)">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L1,+N file\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L X,-N (non-numeric N)">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L1,-N file\n">)} ) (C {(test_expect_success)} {(SQ <"blame -L ,^/RE/">)} {(SQ <"\n"> <"\ttest_must_fail $PROG -L1,^/99/ file\n">)} ) ] )