| 1 | #!/bin/sh |
| 2 | |
| 3 | test_description='git blame ignore fuzzy heuristic' |
| 4 | |
| 5 | . ./test-lib.sh |
| 6 | |
| 7 | pick_author='s/^[0-9a-f^]* *(\([^ ]*\) .*/\1/' |
| 8 | |
| 9 | # Each test is composed of 4 variables: |
| 10 | # titleN - the test name |
| 11 | # aN - the initial content |
| 12 | # bN - the final content |
| 13 | # expectedN - the line numbers from aN that we expect git blame |
| 14 | # on bN to identify, or "Final" if bN itself should |
| 15 | # be identified as the origin of that line. |
| 16 | |
| 17 | # We start at test 2 because setup will show as test 1 |
| 18 | title2="Regression test for partially overlapping search ranges" |
| 19 | cat <<EOF >a2 |
| 20 | 1 |
| 21 | 2 |
| 22 | 3 |
| 23 | abcdef |
| 24 | 5 |
| 25 | 6 |
| 26 | 7 |
| 27 | ijkl |
| 28 | 9 |
| 29 | 10 |
| 30 | 11 |
| 31 | pqrs |
| 32 | 13 |
| 33 | 14 |
| 34 | 15 |
| 35 | wxyz |
| 36 | 17 |
| 37 | 18 |
| 38 | 19 |
| 39 | EOF |
| 40 | cat <<EOF >b2 |
| 41 | abcde |
| 42 | ijk |
| 43 | pqr |
| 44 | wxy |
| 45 | EOF |
| 46 | cat <<EOF >expected2 |
| 47 | 4 |
| 48 | 8 |
| 49 | 12 |
| 50 | 16 |
| 51 | EOF |
| 52 | |
| 53 | title3="Combine 3 lines into 2" |
| 54 | cat <<EOF >a3 |
| 55 | if ((maxgrow==0) || |
| 56 | ( single_line_field && (field->dcols < maxgrow)) || |
| 57 | (!single_line_field && (field->drows < maxgrow))) |
| 58 | EOF |
| 59 | cat <<EOF >b3 |
| 60 | if ((maxgrow == 0) || (single_line_field && (field->dcols < maxgrow)) || |
| 61 | (!single_line_field && (field->drows < maxgrow))) { |
| 62 | EOF |
| 63 | cat <<EOF >expected3 |
| 64 | 2 |
| 65 | 3 |
| 66 | EOF |
| 67 | |
| 68 | title4="Add curly brackets" |
| 69 | cat <<EOF >a4 |
| 70 | if (rows) *rows = field->rows; |
| 71 | if (cols) *cols = field->cols; |
| 72 | if (frow) *frow = field->frow; |
| 73 | if (fcol) *fcol = field->fcol; |
| 74 | EOF |
| 75 | cat <<EOF >b4 |
| 76 | if (rows) { |
| 77 | *rows = field->rows; |
| 78 | } |
| 79 | if (cols) { |
| 80 | *cols = field->cols; |
| 81 | } |
| 82 | if (frow) { |
| 83 | *frow = field->frow; |
| 84 | } |
| 85 | if (fcol) { |
| 86 | *fcol = field->fcol; |
| 87 | } |
| 88 | EOF |
| 89 | cat <<EOF >expected4 |
| 90 | 1 |
| 91 | 1 |
| 92 | Final |
| 93 | 2 |
| 94 | 2 |
| 95 | Final |
| 96 | 3 |
| 97 | 3 |
| 98 | Final |
| 99 | 4 |
| 100 | 4 |
| 101 | Final |
| 102 | EOF |
| 103 | |
| 104 | |
| 105 | title5="Combine many lines and change case" |
| 106 | cat <<EOF >a5 |
| 107 | for(row=0,pBuffer=field->buf; |
| 108 | row<height; |
| 109 | row++,pBuffer+=width ) |
| 110 | { |
| 111 | if ((len = (int)( After_End_Of_Data( pBuffer, width ) - pBuffer )) > 0) |
| 112 | { |
| 113 | wmove( win, row, 0 ); |
| 114 | waddnstr( win, pBuffer, len ); |
| 115 | EOF |
| 116 | cat <<EOF >b5 |
| 117 | for (Row = 0, PBuffer = field->buf; Row < Height; Row++, PBuffer += Width) { |
| 118 | if ((Len = (int)(afterEndOfData(PBuffer, Width) - PBuffer)) > 0) { |
| 119 | wmove(win, Row, 0); |
| 120 | waddnstr(win, PBuffer, Len); |
| 121 | EOF |
| 122 | cat <<EOF >expected5 |
| 123 | 1 |
| 124 | 5 |
| 125 | 7 |
| 126 | 8 |
| 127 | EOF |
| 128 | |
| 129 | title6="Rename and combine lines" |
| 130 | cat <<EOF >a6 |
| 131 | bool need_visual_update = ((form != (FORM *)0) && |
| 132 | (form->status & _POSTED) && |
| 133 | (form->current==field)); |
| 134 | |
| 135 | if (need_visual_update) |
| 136 | Synchronize_Buffer(form); |
| 137 | |
| 138 | if (single_line_field) |
| 139 | { |
| 140 | growth = field->cols * amount; |
| 141 | if (field->maxgrow) |
| 142 | growth = Minimum(field->maxgrow - field->dcols,growth); |
| 143 | field->dcols += growth; |
| 144 | if (field->dcols == field->maxgrow) |
| 145 | EOF |
| 146 | cat <<EOF >b6 |
| 147 | bool NeedVisualUpdate = ((Form != (FORM *)0) && (Form->status & _POSTED) && |
| 148 | (Form->current == field)); |
| 149 | |
| 150 | if (NeedVisualUpdate) { |
| 151 | synchronizeBuffer(Form); |
| 152 | } |
| 153 | |
| 154 | if (SingleLineField) { |
| 155 | Growth = field->cols * amount; |
| 156 | if (field->maxgrow) { |
| 157 | Growth = Minimum(field->maxgrow - field->dcols, Growth); |
| 158 | } |
| 159 | field->dcols += Growth; |
| 160 | if (field->dcols == field->maxgrow) { |
| 161 | EOF |
| 162 | cat <<EOF >expected6 |
| 163 | 1 |
| 164 | 3 |
| 165 | 4 |
| 166 | 5 |
| 167 | 6 |
| 168 | Final |
| 169 | 7 |
| 170 | 8 |
| 171 | 10 |
| 172 | 11 |
| 173 | 12 |
| 174 | Final |
| 175 | 13 |
| 176 | 14 |
| 177 | EOF |
| 178 | |
| 179 | # Both lines match identically so position must be used to tie-break. |
| 180 | title7="Same line twice" |
| 181 | cat <<EOF >a7 |
| 182 | abc |
| 183 | abc |
| 184 | EOF |
| 185 | cat <<EOF >b7 |
| 186 | abcd |
| 187 | abcd |
| 188 | EOF |
| 189 | cat <<EOF >expected7 |
| 190 | 1 |
| 191 | 2 |
| 192 | EOF |
| 193 | |
| 194 | title8="Enforce line order" |
| 195 | cat <<EOF >a8 |
| 196 | abcdef |
| 197 | ghijkl |
| 198 | ab |
| 199 | EOF |
| 200 | cat <<EOF >b8 |
| 201 | ghijk |
| 202 | abcd |
| 203 | EOF |
| 204 | cat <<EOF >expected8 |
| 205 | 2 |
| 206 | 3 |
| 207 | EOF |
| 208 | |
| 209 | title9="Expand lines and rename variables" |
| 210 | cat <<EOF >a9 |
| 211 | int myFunction(int ArgumentOne, Thing *ArgTwo, Blah XuglyBug) { |
| 212 | Squiggle FabulousResult = squargle(ArgumentOne, *ArgTwo, |
| 213 | XuglyBug) + EwwwGlobalWithAReallyLongNameYepTooLong; |
| 214 | return FabulousResult * 42; |
| 215 | } |
| 216 | EOF |
| 217 | cat <<EOF >b9 |
| 218 | int myFunction(int argument_one, Thing *arg_asdfgh, |
| 219 | Blah xugly_bug) { |
| 220 | Squiggle fabulous_result = squargle(argument_one, |
| 221 | *arg_asdfgh, xugly_bug) |
| 222 | + g_ewww_global_with_a_really_long_name_yep_too_long; |
| 223 | return fabulous_result * 42; |
| 224 | } |
| 225 | EOF |
| 226 | cat <<EOF >expected9 |
| 227 | 1 |
| 228 | 1 |
| 229 | 2 |
| 230 | 3 |
| 231 | 3 |
| 232 | 4 |
| 233 | 5 |
| 234 | EOF |
| 235 | |
| 236 | title10="Two close matches versus one less close match" |
| 237 | cat <<EOF >a10 |
| 238 | abcdef |
| 239 | abcdef |
| 240 | ghijkl |
| 241 | EOF |
| 242 | cat <<EOF >b10 |
| 243 | gh |
| 244 | abcdefx |
| 245 | EOF |
| 246 | cat <<EOF >expected10 |
| 247 | Final |
| 248 | 2 |
| 249 | EOF |
| 250 | |
| 251 | # The first line of b matches best with the last line of a, but the overall |
| 252 | # match is better if we match it with the first line of a. |
| 253 | title11="Piggy in the middle" |
| 254 | cat <<EOF >a11 |
| 255 | abcdefg |
| 256 | ijklmn |
| 257 | abcdefgh |
| 258 | EOF |
| 259 | cat <<EOF >b11 |
| 260 | abcdefghx |
| 261 | ijklm |
| 262 | EOF |
| 263 | cat <<EOF >expected11 |
| 264 | 1 |
| 265 | 2 |
| 266 | EOF |
| 267 | |
| 268 | title12="No trailing newline" |
| 269 | printf "abc\ndef" >a12 |
| 270 | printf "abx\nstu" >b12 |
| 271 | cat <<EOF >expected12 |
| 272 | 1 |
| 273 | Final |
| 274 | EOF |
| 275 | |
| 276 | title13="Reorder includes" |
| 277 | cat <<EOF >a13 |
| 278 | #include "c.h" |
| 279 | #include "b.h" |
| 280 | #include "a.h" |
| 281 | #include "e.h" |
| 282 | #include "d.h" |
| 283 | EOF |
| 284 | cat <<EOF >b13 |
| 285 | #include "a.h" |
| 286 | #include "b.h" |
| 287 | #include "c.h" |
| 288 | #include "d.h" |
| 289 | #include "e.h" |
| 290 | EOF |
| 291 | cat <<EOF >expected13 |
| 292 | 3 |
| 293 | 2 |
| 294 | 1 |
| 295 | 5 |
| 296 | 4 |
| 297 | EOF |
| 298 | |
| 299 | last_test=13 |
| 300 | |
| 301 | test_expect_success setup ' |
| 302 | for i in $(test_seq 2 $last_test) |
| 303 | do |
| 304 | # Append each line in a separate commit to make it easy to |
| 305 | # check which original line the blame output relates to. |
| 306 | |
| 307 | line_count=0 && |
| 308 | while IFS= read line |
| 309 | do |
| 310 | line_count=$((line_count+1)) && |
| 311 | echo "$line" >>"$i" && |
| 312 | git add "$i" && |
| 313 | test_tick && |
| 314 | GIT_AUTHOR_NAME="$line_count" git commit -m "$line_count" || return 1 |
| 315 | done <"a$i" |
| 316 | done && |
| 317 | |
| 318 | for i in $(test_seq 2 $last_test) |
| 319 | do |
| 320 | # Overwrite the files with the final content. |
| 321 | cp b$i $i && |
| 322 | git add $i || return 1 |
| 323 | done && |
| 324 | test_tick && |
| 325 | |
| 326 | # Commit the final content all at once so it can all be |
| 327 | # referred to with the same commit ID. |
| 328 | GIT_AUTHOR_NAME=Final git commit -m Final && |
| 329 | |
| 330 | IGNOREME=$(git rev-parse HEAD) |
| 331 | ' |
| 332 | |
| 333 | for i in $(test_seq 2 $last_test); do |
| 334 | eval title="\$title$i" |
| 335 | test_expect_success "$title" \ |
| 336 | "git blame -M9 --ignore-rev $IGNOREME $i >output && |
| 337 | sed -e \"$pick_author\" output >actual && |
| 338 | test_cmp expected$i actual" |
| 339 | done |
| 340 | |
| 341 | # This invoked a null pointer dereference when the chunk callback was called |
| 342 | # with a zero length parent chunk and there were no more suspects. |
| 343 | test_expect_success 'Diff chunks with no suspects' ' |
| 344 | test_write_lines xy1 A B C xy1 >file && |
| 345 | git add file && |
| 346 | test_tick && |
| 347 | GIT_AUTHOR_NAME=1 git commit -m 1 && |
| 348 | |
| 349 | test_write_lines xy2 A B xy2 C xy2 >file && |
| 350 | git add file && |
| 351 | test_tick && |
| 352 | GIT_AUTHOR_NAME=2 git commit -m 2 && |
| 353 | REV_2=$(git rev-parse HEAD) && |
| 354 | |
| 355 | test_write_lines xy3 A >file && |
| 356 | git add file && |
| 357 | test_tick && |
| 358 | GIT_AUTHOR_NAME=3 git commit -m 3 && |
| 359 | REV_3=$(git rev-parse HEAD) && |
| 360 | |
| 361 | test_write_lines 1 1 >expected && |
| 362 | |
| 363 | git blame --ignore-rev $REV_2 --ignore-rev $REV_3 file >output && |
| 364 | sed -e "$pick_author" output >actual && |
| 365 | |
| 366 | test_cmp expected actual |
| 367 | ' |
| 368 | |
| 369 | test_expect_success 'position matching' ' |
| 370 | test_write_lines abc def >file2 && |
| 371 | git add file2 && |
| 372 | test_tick && |
| 373 | GIT_AUTHOR_NAME=1 git commit -m 1 && |
| 374 | |
| 375 | test_write_lines abc def abc def >file2 && |
| 376 | git add file2 && |
| 377 | test_tick && |
| 378 | GIT_AUTHOR_NAME=2 git commit -m 2 && |
| 379 | |
| 380 | test_write_lines abcx defx abcx defx >file2 && |
| 381 | git add file2 && |
| 382 | test_tick && |
| 383 | GIT_AUTHOR_NAME=3 git commit -m 3 && |
| 384 | REV_3=$(git rev-parse HEAD) && |
| 385 | |
| 386 | test_write_lines abcy defy abcx defx >file2 && |
| 387 | git add file2 && |
| 388 | test_tick && |
| 389 | GIT_AUTHOR_NAME=4 git commit -m 4 && |
| 390 | REV_4=$(git rev-parse HEAD) && |
| 391 | |
| 392 | test_write_lines 1 1 2 2 >expected && |
| 393 | |
| 394 | git blame --ignore-rev $REV_3 --ignore-rev $REV_4 file2 >output && |
| 395 | sed -e "$pick_author" output >actual && |
| 396 | |
| 397 | test_cmp expected actual |
| 398 | ' |
| 399 | |
| 400 | # This fails if each blame entry is processed independently instead of |
| 401 | # processing each diff change in full. |
| 402 | test_expect_success 'preserve order' ' |
| 403 | test_write_lines bcde >file3 && |
| 404 | git add file3 && |
| 405 | test_tick && |
| 406 | GIT_AUTHOR_NAME=1 git commit -m 1 && |
| 407 | |
| 408 | test_write_lines bcde fghij >file3 && |
| 409 | git add file3 && |
| 410 | test_tick && |
| 411 | GIT_AUTHOR_NAME=2 git commit -m 2 && |
| 412 | |
| 413 | test_write_lines bcde fghij abcd >file3 && |
| 414 | git add file3 && |
| 415 | test_tick && |
| 416 | GIT_AUTHOR_NAME=3 git commit -m 3 && |
| 417 | |
| 418 | test_write_lines abcdx fghijx bcdex >file3 && |
| 419 | git add file3 && |
| 420 | test_tick && |
| 421 | GIT_AUTHOR_NAME=4 git commit -m 4 && |
| 422 | REV_4=$(git rev-parse HEAD) && |
| 423 | |
| 424 | test_write_lines abcdx fghijy bcdex >file3 && |
| 425 | git add file3 && |
| 426 | test_tick && |
| 427 | GIT_AUTHOR_NAME=5 git commit -m 5 && |
| 428 | REV_5=$(git rev-parse HEAD) && |
| 429 | |
| 430 | test_write_lines 1 2 3 >expected && |
| 431 | |
| 432 | git blame --ignore-rev $REV_4 --ignore-rev $REV_5 file3 >output && |
| 433 | sed -e "$pick_author" output >actual && |
| 434 | |
| 435 | test_cmp expected actual |
| 436 | ' |
| 437 | |
| 438 | test_done |