#!/bin/sh test_description='git blame ignore fuzzy heuristic' . ./test-lib.sh pick_author='s/^[0-9a-f^]* *(\([^ ]*\) .*/\1/' # Each test is composed of 4 variables: # titleN - the test name # aN - the initial content # bN - the final content # expectedN - the line numbers from aN that we expect git blame # on bN to identify, or "Final" if bN itself should # be identified as the origin of that line. # We start at test 2 because setup will show as test 1 title2="Regression test for partially overlapping search ranges" cat <<EOF >a2 1 2 3 abcdef 5 6 7 ijkl 9 10 11 pqrs 13 14 15 wxyz 17 18 19 EOF cat <<EOF >b2 abcde ijk pqr wxy EOF cat <<EOF >expected2 4 8 12 16 EOF title3="Combine 3 lines into 2" cat <<EOF >a3 if ((maxgrow==0) || ( single_line_field && (field->dcols < maxgrow)) || (!single_line_field && (field->drows < maxgrow))) EOF cat <<EOF >b3 if ((maxgrow == 0) || (single_line_field && (field->dcols < maxgrow)) || (!single_line_field && (field->drows < maxgrow))) { EOF cat <<EOF >expected3 2 3 EOF title4="Add curly brackets" cat <<EOF >a4 if (rows) *rows = field->rows; if (cols) *cols = field->cols; if (frow) *frow = field->frow; if (fcol) *fcol = field->fcol; EOF cat <<EOF >b4 if (rows) { *rows = field->rows; } if (cols) { *cols = field->cols; } if (frow) { *frow = field->frow; } if (fcol) { *fcol = field->fcol; } EOF cat <<EOF >expected4 1 1 Final 2 2 Final 3 3 Final 4 4 Final EOF title5="Combine many lines and change case" cat <<EOF >a5 for(row=0,pBuffer=field->buf; row<height; row++,pBuffer+=width ) { if ((len = (int)( After_End_Of_Data( pBuffer, width ) - pBuffer )) > 0) { wmove( win, row, 0 ); waddnstr( win, pBuffer, len ); EOF cat <<EOF >b5 for (Row = 0, PBuffer = field->buf; Row < Height; Row++, PBuffer += Width) { if ((Len = (int)(afterEndOfData(PBuffer, Width) - PBuffer)) > 0) { wmove(win, Row, 0); waddnstr(win, PBuffer, Len); EOF cat <<EOF >expected5 1 5 7 8 EOF title6="Rename and combine lines" cat <<EOF >a6 bool need_visual_update = ((form != (FORM *)0) && (form->status & _POSTED) && (form->current==field)); if (need_visual_update) Synchronize_Buffer(form); if (single_line_field) { growth = field->cols * amount; if (field->maxgrow) growth = Minimum(field->maxgrow - field->dcols,growth); field->dcols += growth; if (field->dcols == field->maxgrow) EOF cat <<EOF >b6 bool NeedVisualUpdate = ((Form != (FORM *)0) && (Form->status & _POSTED) && (Form->current == field)); if (NeedVisualUpdate) { synchronizeBuffer(Form); } if (SingleLineField) { Growth = field->cols * amount; if (field->maxgrow) { Growth = Minimum(field->maxgrow - field->dcols, Growth); } field->dcols += Growth; if (field->dcols == field->maxgrow) { EOF cat <<EOF >expected6 1 3 4 5 6 Final 7 8 10 11 12 Final 13 14 EOF # Both lines match identically so position must be used to tie-break. title7="Same line twice" cat <<EOF >a7 abc abc EOF cat <<EOF >b7 abcd abcd EOF cat <<EOF >expected7 1 2 EOF title8="Enforce line order" cat <<EOF >a8 abcdef ghijkl ab EOF cat <<EOF >b8 ghijk abcd EOF cat <<EOF >expected8 2 3 EOF title9="Expand lines and rename variables" cat <<EOF >a9 int myFunction(int ArgumentOne, Thing *ArgTwo, Blah XuglyBug) { Squiggle FabulousResult = squargle(ArgumentOne, *ArgTwo, XuglyBug) + EwwwGlobalWithAReallyLongNameYepTooLong; return FabulousResult * 42; } EOF cat <<EOF >b9 int myFunction(int argument_one, Thing *arg_asdfgh, Blah xugly_bug) { Squiggle fabulous_result = squargle(argument_one, *arg_asdfgh, xugly_bug) + g_ewww_global_with_a_really_long_name_yep_too_long; return fabulous_result * 42; } EOF cat <<EOF >expected9 1 1 2 3 3 4 5 EOF title10="Two close matches versus one less close match" cat <<EOF >a10 abcdef abcdef ghijkl EOF cat <<EOF >b10 gh abcdefx EOF cat <<EOF >expected10 Final 2 EOF # The first line of b matches best with the last line of a, but the overall # match is better if we match it with the the first line of a. title11="Piggy in the middle" cat <<EOF >a11 abcdefg ijklmn abcdefgh EOF cat <<EOF >b11 abcdefghx ijklm EOF cat <<EOF >expected11 1 2 EOF title12="No trailing newline" printf "abc\ndef" >a12 printf "abx\nstu" >b12 cat <<EOF >expected12 1 Final EOF title13="Reorder includes" cat <<EOF >a13 #include "c.h" #include "b.h" #include "a.h" #include "e.h" #include "d.h" EOF cat <<EOF >b13 #include "a.h" #include "b.h" #include "c.h" #include "d.h" #include "e.h" EOF cat <<EOF >expected13 3 2 1 5 4 EOF last_test=13 test_expect_success setup ' for i in $(test_seq 2 $last_test) do # Append each line in a separate commit to make it easy to # check which original line the blame output relates to. line_count=0 && while IFS= read line do line_count=$((line_count+1)) && echo "$line" >>"$i" && git add "$i" && test_tick && GIT_AUTHOR_NAME="$line_count" git commit -m "$line_count" done <"a$i" done && for i in $(test_seq 2 $last_test) do # Overwrite the files with the final content. cp b$i $i && git add $i done && test_tick && # Commit the final content all at once so it can all be # referred to with the same commit ID. GIT_AUTHOR_NAME=Final git commit -m Final && IGNOREME=$(git rev-parse HEAD) ' for i in $(test_seq 2 $last_test); do eval title="\$title$i" test_expect_success "$title" \ "git blame -M9 --ignore-rev $IGNOREME $i >output && sed -e \"$pick_author\" output >actual && test_cmp expected$i actual" done # This invoked a null pointer dereference when the chunk callback was called # with a zero length parent chunk and there were no more suspects. test_expect_success 'Diff chunks with no suspects' ' test_write_lines xy1 A B C xy1 >file && git add file && test_tick && GIT_AUTHOR_NAME=1 git commit -m 1 && test_write_lines xy2 A B xy2 C xy2 >file && git add file && test_tick && GIT_AUTHOR_NAME=2 git commit -m 2 && REV_2=$(git rev-parse HEAD) && test_write_lines xy3 A >file && git add file && test_tick && GIT_AUTHOR_NAME=3 git commit -m 3 && REV_3=$(git rev-parse HEAD) && test_write_lines 1 1 >expected && git blame --ignore-rev $REV_2 --ignore-rev $REV_3 file >output && sed -e "$pick_author" output >actual && test_cmp expected actual ' test_expect_success 'position matching' ' test_write_lines abc def >file2 && git add file2 && test_tick && GIT_AUTHOR_NAME=1 git commit -m 1 && test_write_lines abc def abc def >file2 && git add file2 && test_tick && GIT_AUTHOR_NAME=2 git commit -m 2 && test_write_lines abcx defx abcx defx >file2 && git add file2 && test_tick && GIT_AUTHOR_NAME=3 git commit -m 3 && REV_3=$(git rev-parse HEAD) && test_write_lines abcy defy abcx defx >file2 && git add file2 && test_tick && GIT_AUTHOR_NAME=4 git commit -m 4 && REV_4=$(git rev-parse HEAD) && test_write_lines 1 1 2 2 >expected && git blame --ignore-rev $REV_3 --ignore-rev $REV_4 file2 >output && sed -e "$pick_author" output >actual && test_cmp expected actual ' # This fails if each blame entry is processed independently instead of # processing each diff change in full. test_expect_success 'preserve order' ' test_write_lines bcde >file3 && git add file3 && test_tick && GIT_AUTHOR_NAME=1 git commit -m 1 && test_write_lines bcde fghij >file3 && git add file3 && test_tick && GIT_AUTHOR_NAME=2 git commit -m 2 && test_write_lines bcde fghij abcd >file3 && git add file3 && test_tick && GIT_AUTHOR_NAME=3 git commit -m 3 && test_write_lines abcdx fghijx bcdex >file3 && git add file3 && test_tick && GIT_AUTHOR_NAME=4 git commit -m 4 && REV_4=$(git rev-parse HEAD) && test_write_lines abcdx fghijy bcdex >file3 && git add file3 && test_tick && GIT_AUTHOR_NAME=5 git commit -m 5 && REV_5=$(git rev-parse HEAD) && test_write_lines 1 2 3 >expected && git blame --ignore-rev $REV_4 --ignore-rev $REV_5 file3 >output && sed -e "$pick_author" output >actual && test_cmp expected actual ' test_done