0c51d6b4ae
Failures within `for` and `while` loops can go unnoticed if not detected and signaled manually since the loop itself does not abort when a contained command fails, nor will a failure necessarily be detected when the loop finishes since the loop returns the exit code of the last command it ran on the final iteration, which may not be the command which failed. Therefore, detect and signal failures manually within loops using the idiom `|| return 1` (or `|| exit 1` within subshells). Signed-off-by: Eric Sunshine <sunshine@sunshineco.com> Reviewed-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
438 lines
7.8 KiB
Bash
Executable File
438 lines
7.8 KiB
Bash
Executable File
#!/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 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" || return 1
|
|
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 || return 1
|
|
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
|