Blob


1 #!/bin/sh
2 #
3 # Copyright (c) 2019 Stefan Sperling <stsp@openbsd.org>
4 #
5 # Permission to use, copy, modify, and distribute this software for any
6 # purpose with or without fee is hereby granted, provided that the above
7 # copyright notice and this permission notice appear in all copies.
8 #
9 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 . ./common.sh
19 blame_cmp() {
20 local testroot="$1"
21 local file="$2"
22 local xfail="$3"
24 (cd $testroot/wt && got blame "$file" | cut -d ' ' -f 2 \
25 > $testroot/${file}.blame.got)
26 (cd $testroot/repo && git reset --hard master > /dev/null)
27 (cd $testroot/repo && git blame "$file" | cut -d ' ' -f 1 \
28 > $testroot/${file}.blame.git)
30 cmp -s $testroot/${file}.blame.git $testroot/${file}.blame.got
31 ret=$?
32 if [ $ret -ne 0 -a "$xfail" = "" ]; then
33 diff -u $testroot/${file}.blame.git $testroot/${file}.blame.got
34 return 1
35 fi
36 return "$ret"
37 }
39 test_blame_basic() {
40 local testroot=`test_init blame_basic`
42 got checkout $testroot/repo $testroot/wt > /dev/null
43 ret=$?
44 if [ $ret -ne 0 ]; then
45 test_done "$testroot" "$ret"
46 return 1
47 fi
49 echo 1 > $testroot/wt/alpha
50 (cd $testroot/wt && got commit -m "change 1" > /dev/null)
51 local commit1=`git_show_head $testroot/repo`
53 echo 2 >> $testroot/wt/alpha
54 (cd $testroot/wt && got commit -m "change 2" > /dev/null)
55 local commit2=`git_show_head $testroot/repo`
57 echo 3 >> $testroot/wt/alpha
58 (cd $testroot/wt && got commit -m "change 3" > /dev/null)
59 local commit3=`git_show_head $testroot/repo`
60 local author_time=`git_show_author_time $testroot/repo`
62 (cd $testroot/wt && got blame alpha > $testroot/stdout)
64 local short_commit1=`trim_obj_id 32 $commit1`
65 local short_commit2=`trim_obj_id 32 $commit2`
66 local short_commit3=`trim_obj_id 32 $commit3`
68 d=`date -u -r $author_time +"%G-%m-%d"`
69 echo "1) $short_commit1 $d $GOT_AUTHOR_8 1" > $testroot/stdout.expected
70 echo "2) $short_commit2 $d $GOT_AUTHOR_8 2" >> $testroot/stdout.expected
71 echo "3) $short_commit3 $d $GOT_AUTHOR_8 3" >> $testroot/stdout.expected
73 cmp -s $testroot/stdout.expected $testroot/stdout
74 ret=$?
75 if [ $ret -ne 0 ]; then
76 diff -u $testroot/stdout.expected $testroot/stdout
77 test_done "$testroot" "$ret"
78 return 1
79 fi
81 blame_cmp "$testroot" "alpha"
82 ret=$?
83 test_done "$testroot" "$ret"
84 }
86 test_blame_tag() {
87 local testroot=`test_init blame_tag`
88 local tag=1.0.0
90 got checkout $testroot/repo $testroot/wt > /dev/null
91 ret=$?
92 if [ $ret -ne 0 ]; then
93 test_done "$testroot" "$ret"
94 return 1
95 fi
96 echo 1 > $testroot/wt/alpha
97 (cd $testroot/wt && got commit -m "change 1" > /dev/null)
98 local commit1=`git_show_head $testroot/repo`
100 echo 2 >> $testroot/wt/alpha
101 (cd $testroot/wt && got commit -m "change 2" > /dev/null)
102 local commit2=`git_show_head $testroot/repo`
104 (cd $testroot/repo && git tag -a -m "test" $tag)
106 echo 3 >> $testroot/wt/alpha
107 (cd $testroot/wt && got commit -m "change 3" > /dev/null)
108 local commit3=`git_show_head $testroot/repo`
109 local author_time=`git_show_author_time $testroot/repo`
111 (cd $testroot/wt && got blame -c $tag alpha > $testroot/stdout)
113 local short_commit1=`trim_obj_id 32 $commit1`
114 local short_commit2=`trim_obj_id 32 $commit2`
116 d=`date -u -r $author_time +"%G-%m-%d"`
117 echo "1) $short_commit1 $d $GOT_AUTHOR_8 1" > $testroot/stdout.expected
118 echo "2) $short_commit2 $d $GOT_AUTHOR_8 2" >> $testroot/stdout.expected
120 cmp -s $testroot/stdout.expected $testroot/stdout
121 ret=$?
122 if [ $ret -ne 0 ]; then
123 diff -u $testroot/stdout.expected $testroot/stdout
124 test_done "$testroot" "$ret"
125 return 1
126 fi
128 blame_cmp "$testroot" "alpha"
129 ret=$?
130 test_done "$testroot" "$ret"
133 test_blame_file_single_line() {
134 local testroot=`test_init blame_file_single_line`
136 got checkout $testroot/repo $testroot/wt > /dev/null
137 ret=$?
138 if [ $ret -ne 0 ]; then
139 test_done "$testroot" "$ret"
140 return 1
141 fi
143 echo 1 > $testroot/wt/alpha
144 (cd $testroot/wt && got commit -m "change 1" > /dev/null)
145 local commit1=`git_show_head $testroot/repo`
146 local author_time=`git_show_author_time $testroot/repo`
148 (cd $testroot/wt && got blame alpha > $testroot/stdout)
150 local short_commit1=`trim_obj_id 32 $commit1`
152 d=`date -u -r $author_time +"%G-%m-%d"`
153 echo "1) $short_commit1 $d $GOT_AUTHOR_8 1" > $testroot/stdout.expected
155 cmp -s $testroot/stdout.expected $testroot/stdout
156 ret=$?
157 if [ $ret -ne 0 ]; then
158 diff -u $testroot/stdout.expected $testroot/stdout
159 test_done "$testroot" "$ret"
160 return 1
161 fi
163 blame_cmp "$testroot" "alpha"
164 ret=$?
165 test_done "$testroot" "$ret"
168 test_blame_file_single_line_no_newline() {
169 local testroot=`test_init blame_file_single_line_no_newline`
171 got checkout $testroot/repo $testroot/wt > /dev/null
172 ret=$?
173 if [ $ret -ne 0 ]; then
174 test_done "$testroot" "$ret"
175 return 1
176 fi
178 echo -n 1 > $testroot/wt/alpha
179 (cd $testroot/wt && got commit -m "change 1" > /dev/null)
180 local commit1=`git_show_head $testroot/repo`
181 local author_time=`git_show_author_time $testroot/repo`
183 (cd $testroot/wt && got blame alpha > $testroot/stdout)
185 local short_commit1=`trim_obj_id 32 $commit1`
187 d=`date -u -r $author_time +"%G-%m-%d"`
188 echo "1) $short_commit1 $d $GOT_AUTHOR_8 1" > $testroot/stdout.expected
190 cmp -s $testroot/stdout.expected $testroot/stdout
191 ret=$?
192 if [ $ret -ne 0 ]; then
193 diff -u $testroot/stdout.expected $testroot/stdout
194 fi
195 test_done "$testroot" "$ret"
198 test_blame_all_lines_replaced() {
199 local testroot=`test_init blame_all_lines_replaced`
201 got checkout $testroot/repo $testroot/wt > /dev/null
202 ret=$?
203 if [ $ret -ne 0 ]; then
204 test_done "$testroot" "$ret"
205 return 1
206 fi
208 jot 8 > $testroot/wt/alpha
209 (cd $testroot/wt && got commit -m "change 1" > /dev/null)
210 local commit1=`git_show_head $testroot/repo`
211 local short_commit1=`trim_obj_id 32 $commit1`
212 local author_time=`git_show_author_time $testroot/repo`
214 (cd $testroot/wt && got blame alpha > $testroot/stdout)
216 d=`date -u -r $author_time +"%G-%m-%d"`
217 echo "1) $short_commit1 $d $GOT_AUTHOR_8 1" > $testroot/stdout.expected
218 echo "2) $short_commit1 $d $GOT_AUTHOR_8 2" >> $testroot/stdout.expected
219 echo "3) $short_commit1 $d $GOT_AUTHOR_8 3" >> $testroot/stdout.expected
220 echo "4) $short_commit1 $d $GOT_AUTHOR_8 4" >> $testroot/stdout.expected
221 echo "5) $short_commit1 $d $GOT_AUTHOR_8 5" >> $testroot/stdout.expected
222 echo "6) $short_commit1 $d $GOT_AUTHOR_8 6" >> $testroot/stdout.expected
223 echo "7) $short_commit1 $d $GOT_AUTHOR_8 7" >> $testroot/stdout.expected
224 echo "8) $short_commit1 $d $GOT_AUTHOR_8 8" >> $testroot/stdout.expected
226 cmp -s $testroot/stdout.expected $testroot/stdout
227 ret=$?
228 if [ $ret -ne 0 ]; then
229 diff -u $testroot/stdout.expected $testroot/stdout
230 fi
231 test_done "$testroot" "$ret"
235 test_blame_lines_shifted_up() {
236 local testroot=`test_init blame_lines_shifted_up`
238 got checkout $testroot/repo $testroot/wt > /dev/null
239 ret=$?
240 if [ $ret -ne 0 ]; then
241 test_done "$testroot" "$ret"
242 return 1
243 fi
245 jot 8 > $testroot/wt/alpha
246 (cd $testroot/wt && got commit -m "change 1" > /dev/null)
247 local commit1=`git_show_head $testroot/repo`
248 local short_commit1=`trim_obj_id 32 $commit1`
249 local author_time=`git_show_author_time $testroot/repo`
251 sed -i -e '/^[345]$/d' $testroot/wt/alpha
252 (cd $testroot/wt && got commit -m "change 2" > /dev/null)
253 local commit2=`git_show_head $testroot/repo`
254 local short_commit2=`trim_obj_id 32 $commit2`
256 jot 2 > $testroot/wt/alpha
257 echo foo >> $testroot/wt/alpha
258 echo bar >> $testroot/wt/alpha
259 echo baz >> $testroot/wt/alpha
260 jot 8 6 8 1 >> $testroot/wt/alpha
261 (cd $testroot/wt && got commit -m "change 3" > /dev/null)
262 local commit3=`git_show_head $testroot/repo`
263 local short_commit3=`trim_obj_id 32 $commit3`
264 local author_time=`git_show_author_time $testroot/repo`
266 (cd $testroot/wt && got blame alpha > $testroot/stdout)
268 d=`date -u -r $author_time +"%G-%m-%d"`
269 echo "1) $short_commit1 $d $GOT_AUTHOR_8 1" > $testroot/stdout.expected
270 echo "2) $short_commit1 $d $GOT_AUTHOR_8 2" >> $testroot/stdout.expected
271 echo "3) $short_commit3 $d $GOT_AUTHOR_8 foo" >> $testroot/stdout.expected
272 echo "4) $short_commit3 $d $GOT_AUTHOR_8 bar" >> $testroot/stdout.expected
273 echo "5) $short_commit3 $d $GOT_AUTHOR_8 baz" >> $testroot/stdout.expected
274 echo "6) $short_commit1 $d $GOT_AUTHOR_8 6" >> $testroot/stdout.expected
275 echo "7) $short_commit1 $d $GOT_AUTHOR_8 7" >> $testroot/stdout.expected
276 echo "8) $short_commit1 $d $GOT_AUTHOR_8 8" >> $testroot/stdout.expected
278 cmp -s $testroot/stdout.expected $testroot/stdout
279 ret=$?
280 if [ $ret -ne 0 ]; then
281 diff -u $testroot/stdout.expected $testroot/stdout
282 test_done "$testroot" "$ret"
283 return 1
284 fi
286 blame_cmp "$testroot" "alpha"
287 ret=$?
288 test_done "$testroot" "$ret"
291 test_blame_lines_shifted_down() {
292 local testroot=`test_init blame_lines_shifted_down`
294 got checkout $testroot/repo $testroot/wt > /dev/null
295 ret=$?
296 if [ $ret -ne 0 ]; then
297 test_done "$testroot" "$ret"
298 return 1
299 fi
301 jot 8 > $testroot/wt/alpha
302 (cd $testroot/wt && got commit -m "change 1" > /dev/null)
303 local commit1=`git_show_head $testroot/repo`
304 local short_commit1=`trim_obj_id 32 $commit1`
305 local author_time=`git_show_author_time $testroot/repo`
307 sed -i -e '/^8$/d' $testroot/wt/alpha
308 (cd $testroot/wt && got commit -m "change 2" > /dev/null)
309 local commit2=`git_show_head $testroot/repo`
310 local short_commit2=`trim_obj_id 32 $commit2`
312 jot 2 > $testroot/wt/alpha
313 echo foo >> $testroot/wt/alpha
314 echo bar >> $testroot/wt/alpha
315 echo baz >> $testroot/wt/alpha
316 jot 8 3 8 1 >> $testroot/wt/alpha
317 (cd $testroot/wt && got commit -m "change 3" > /dev/null)
318 local commit3=`git_show_head $testroot/repo`
319 local short_commit3=`trim_obj_id 32 $commit3`
320 local author_time=`git_show_author_time $testroot/repo`
322 (cd $testroot/wt && got blame alpha > $testroot/stdout)
324 d=`date -u -r $author_time +"%G-%m-%d"`
325 echo "01) $short_commit1 $d $GOT_AUTHOR_8 1" \
326 > $testroot/stdout.expected
327 echo "02) $short_commit1 $d $GOT_AUTHOR_8 2" \
328 >> $testroot/stdout.expected
329 echo "03) $short_commit3 $d $GOT_AUTHOR_8 foo" \
330 >> $testroot/stdout.expected
331 echo "04) $short_commit3 $d $GOT_AUTHOR_8 bar" \
332 >> $testroot/stdout.expected
333 echo "05) $short_commit3 $d $GOT_AUTHOR_8 baz" \
334 >> $testroot/stdout.expected
335 echo "06) $short_commit1 $d $GOT_AUTHOR_8 3" \
336 >> $testroot/stdout.expected
337 echo "07) $short_commit1 $d $GOT_AUTHOR_8 4" \
338 >> $testroot/stdout.expected
339 echo "08) $short_commit1 $d $GOT_AUTHOR_8 5" \
340 >> $testroot/stdout.expected
341 echo "09) $short_commit1 $d $GOT_AUTHOR_8 6" \
342 >> $testroot/stdout.expected
343 echo "10) $short_commit1 $d $GOT_AUTHOR_8 7" \
344 >> $testroot/stdout.expected
345 echo "11) $short_commit3 $d $GOT_AUTHOR_8 8" \
346 >> $testroot/stdout.expected
348 cmp -s $testroot/stdout.expected $testroot/stdout
349 ret=$?
350 if [ $ret -ne 0 ]; then
351 diff -u $testroot/stdout.expected $testroot/stdout
352 test_done "$testroot" "$ret"
353 return 1
354 fi
356 blame_cmp "$testroot" "alpha"
357 ret=$?
358 test_done "$testroot" "$ret"
361 test_blame_commit_subsumed() {
362 local testroot=`test_init blame_commit_subsumed`
364 got checkout $testroot/repo $testroot/wt > /dev/null
365 ret=$?
366 if [ $ret -ne 0 ]; then
367 test_done "$testroot" "$ret"
368 return 1
369 fi
371 cat > $testroot/wt/alpha <<EOF
372 SUBDIRS = ext modules codedocs docs
374 if WITH_PDNS_SERVER
375 SUBDIRS += pdns
376 endif
378 EXTRA_DIST =
379 INSTALL
380 NOTICE
381 README
382 .version
383 build-aux/gen-version
384 codedocs/doxygen.conf
385 contrib/powerdns.solaris.init.d
386 pdns/named.conf.parsertest
387 regression-tests/zones/unit.test
389 ACLOCAL_AMFLAGS = -I m4
391 dvi: # do nothing to build dvi
392 EOF
393 (cd $testroot/wt && got commit -m "change 1" > /dev/null)
394 local commit1=`git_show_head $testroot/repo`
395 local short_commit1=`trim_obj_id 32 $commit1`
396 local author_time1=`git_show_author_time $testroot/repo`
397 local d1=`date -u -r $author_time1 +"%G-%m-%d"`
399 cat > $testroot/wt/alpha <<EOF
400 SUBDIRS = ext modules codedocs docs
402 SUBDIRS += pdns
404 EXTRA_DIST =
405 INSTALL
406 NOTICE
407 README
408 .version
409 build-aux/gen-version
410 codedocs/doxygen.conf
411 contrib/powerdns.solaris.init.d
412 pdns/named.conf.parsertest
413 regression-tests/zones/unit.test
415 ACLOCAL_AMFLAGS = -I m4
417 dvi: # do nothing to build dvi
418 EOF
419 # all changes in this commit will be subsumed by later commits
420 (cd $testroot/wt && got commit -m "change 2" > /dev/null)
421 local commit2=`git_show_head $testroot/repo`
422 local short_commit2=`trim_obj_id 32 $commit2`
423 local author_time2=`git_show_author_time $testroot/repo`
424 local d2=`date -u -r $author_time2 +"%G-%m-%d"`
426 cat > $testroot/wt/alpha <<EOF
427 SUBDIRS = ext modules pdns codedocs docs
429 EXTRA_DIST =
430 INSTALL
431 NOTICE
432 README
433 .version
434 build-aux/gen-version
435 codedocs/doxygen.conf
436 contrib/powerdns.solaris.init.d
437 pdns/named.conf.parsertest
438 regression-tests/zones/unit.test
440 ACLOCAL_AMFLAGS = -I m4
442 dvi: # do nothing to build dvi
443 EOF
444 (cd $testroot/wt && got commit -m "change 3" > /dev/null)
445 local commit3=`git_show_head $testroot/repo`
446 local short_commit3=`trim_obj_id 32 $commit3`
447 local author_time3=`git_show_author_time $testroot/repo`
448 local d3=`date -u -r $author_time3 +"%G-%m-%d"`
450 cat > $testroot/wt/alpha <<EOF
451 SUBDIRS = ext modules pdns codedocs docs
453 EXTRA_DIST =
454 INSTALL
455 NOTICE
456 README
457 COPYING
458 codedocs/doxygen.conf
459 contrib/powerdns.solaris.init.d
460 pdns/named.conf.parsertest
461 regression-tests/zones/unit.test
462 builder-support/gen-version
464 ACLOCAL_AMFLAGS = -I m4
466 dvi: # do nothing to build dvi
467 EOF
468 (cd $testroot/wt && got commit -m "change 4" > /dev/null)
469 local commit4=`git_show_head $testroot/repo`
470 local short_commit4=`trim_obj_id 32 $commit4`
471 local author_time4=`git_show_author_time $testroot/repo`
472 local d4=`date -u -r $author_time4 +"%G-%m-%d"`
474 (cd $testroot/wt && got blame alpha > $testroot/stdout)
476 echo -n "01) $short_commit3 $d3 $GOT_AUTHOR_8 " \
477 > $testroot/stdout.expected
478 echo "SUBDIRS = ext modules pdns codedocs docs" \
479 >> $testroot/stdout.expected
480 echo "02) $short_commit1 $d1 $GOT_AUTHOR_8 " \
481 >> $testroot/stdout.expected
482 echo -n "03) $short_commit1 $d1 $GOT_AUTHOR_8 " \
483 >> $testroot/stdout.expected
484 echo 'EXTRA_DIST =' >> $testroot/stdout.expected
485 echo -n "04) $short_commit1 $d1 $GOT_AUTHOR_8 " \
486 >> $testroot/stdout.expected
487 printf "\tINSTALL\n" >> $testroot/stdout.expected
488 echo -n "05) $short_commit1 $d1 $GOT_AUTHOR_8 " \
489 >> $testroot/stdout.expected
490 printf "\tNOTICE\n" >> $testroot/stdout.expected
491 echo -n "06) $short_commit1 $d1 $GOT_AUTHOR_8 " \
492 >> $testroot/stdout.expected
493 printf "\tREADME\n" >> $testroot/stdout.expected
494 echo -n "07) $short_commit4 $d4 $GOT_AUTHOR_8 " \
495 >> $testroot/stdout.expected
496 printf "\tCOPYING\n" >> $testroot/stdout.expected
497 echo -n "08) $short_commit1 $d1 $GOT_AUTHOR_8 " \
498 >> $testroot/stdout.expected
499 printf "\tcodedocs/doxygen.conf\n" >> $testroot/stdout.expected
500 echo -n "09) $short_commit1 $d1 $GOT_AUTHOR_8 " \
501 >> $testroot/stdout.expected
502 printf "\tcontrib/powerdns.solaris.init.d\n" \
503 >> $testroot/stdout.expected
504 echo -n "10) $short_commit1 $d1 $GOT_AUTHOR_8 " \
505 >> $testroot/stdout.expected
506 printf "\tpdns/named.conf.parsertest\n" >> $testroot/stdout.expected
507 echo -n "11) $short_commit1 $d1 $GOT_AUTHOR_8 " \
508 >> $testroot/stdout.expected
509 printf "\tregression-tests/zones/unit.test\n" \
510 >> $testroot/stdout.expected
511 echo -n "12) $short_commit4 $d4 $GOT_AUTHOR_8 " \
512 >> $testroot/stdout.expected
513 printf "\tbuilder-support/gen-version\n" >> $testroot/stdout.expected
514 echo "13) $short_commit1 $d1 $GOT_AUTHOR_8 " \
515 >> $testroot/stdout.expected
516 echo -n "14) $short_commit1 $d1 $GOT_AUTHOR_8 " \
517 >> $testroot/stdout.expected
518 echo "ACLOCAL_AMFLAGS = -I m4" \
519 >> $testroot/stdout.expected
520 echo "15) $short_commit1 $d1 $GOT_AUTHOR_8 " \
521 >> $testroot/stdout.expected
522 echo -n "16) $short_commit1 $d1 $GOT_AUTHOR_8 " \
523 >> $testroot/stdout.expected
524 echo "dvi: # do nothing to build dvi" \
525 >> $testroot/stdout.expected
527 cmp -s $testroot/stdout.expected $testroot/stdout
528 ret=$?
529 if [ $ret -ne 0 ]; then
530 diff -u $testroot/stdout.expected $testroot/stdout
531 test_done "$testroot" "$ret"
532 return 1
533 fi
535 blame_cmp "$testroot" "alpha"
536 ret=$?
537 test_done "$testroot" "$ret"
540 test_blame_blame_h() {
541 local testroot=`test_init blame_blame_h`
543 got checkout $testroot/repo $testroot/wt > /dev/null
544 ret=$?
545 if [ $ret -ne 0 ]; then
546 test_done "$testroot" "$ret"
547 return 1
548 fi
550 cat > $testroot/wt/got_blame.h <<EOF
551 /*
552 * Copyright (c) 2018 Stefan Sperling <stsp@openbsd.org>
554 * Permission to use, copy, modify, and distribute this software for any
555 * purpose with or without fee is hereby granted, provided that the above
556 * copyright notice and this permission notice appear in all copies.
558 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
559 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
560 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
561 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
562 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
563 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
564 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
565 */
567 const struct got_error *got_blame(const char *, struct got_object_id *,
568 struct got_repository *, FILE *);
569 EOF
570 (cd $testroot/wt && got add got_blame.h > /dev/null)
571 (cd $testroot/wt && got commit -m "change 1" > /dev/null)
573 cat > $testroot/wt/blame-2.patch <<EOF
574 diff 63581804340e880bf611c6a4a59eda26c503799f 84451b3ef755f3226d0d79af367632e5f3a830e7
575 blob - b53ca469a18871cc2f6af334dab25028599c6488
576 blob + c787aadf05e2afab61bd34976f7349912252e6da
577 --- got_blame.h
578 +++ got_blame.h
579 @@ -14,5 +14,22 @@
580 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
581 */
583 +/*
584 + * Write an annotated version of a file at a given in-repository path,
585 + * as found in the commit specified by ID, to the specified output file.
586 + */
587 const struct got_error *got_blame(const char *, struct got_object_id *,
588 struct got_repository *, FILE *);
590 +/*
591 + * Like got_blame() but instead of generating an output file invoke
592 + * a callback whenever an annotation has been computed for a line.
593 + *
594 + * The callback receives the provided void * argument, the total number
595 + * of lines of the annotated file, a line number, and the ID of the commit
596 + * which last changed this line.
597 + */
598 +const struct got_error *got_blame_incremental(const char *,
599 + struct got_object_id *, struct got_repository *,
600 + const struct got_error *(*cb)(void *, int, int, struct got_object_id *),
601 + void *);
602 EOF
603 (cd $testroot/wt && patch < blame-2.patch > /dev/null)
604 (cd $testroot/wt && got commit -m "change 2" > /dev/null)
606 cat > $testroot/wt/blame-3.patch <<EOF
607 diff 75b7a700d9d14ef8eb902961255212acbedef164 d68a0a7de13af722c55099582019c03240e13320
608 blob - c787aadf05e2afab61bd34976f7349912252e6da
609 blob + 5255d076c915accf159940978b821d06803ff2f8
610 --- got_blame.h
611 +++ got_blame.h
612 @@ -28,6 +28,15 @@ const struct got_error *got_blame(const char *, struct
613 * The callback receives the provided void * argument, the total number
614 * of lines of the annotated file, a line number, and the ID of the commit
615 * which last changed this line.
616 + *
617 + * The callback is invoked for each commit as history is traversed.
618 + * If no changes to the file were made in a commit, line number -1 and
619 + * commit ID NULL will be reported.
620 + *
621 + * If the callback returns GOT_ERR_ITER_COMPLETED, the blame operation
622 + * will be aborted and this function returns NULL.
623 + * If the callback returns any other error, the blame operation will be
624 + * aborted and the callback's error is returned from this function.
625 */
626 const struct got_error *got_blame_incremental(const char *,
627 struct got_object_id *, struct got_repository *,
628 EOF
629 (cd $testroot/wt && patch < blame-3.patch > /dev/null)
630 (cd $testroot/wt && got commit -m "change 3" > /dev/null)
632 cat > $testroot/wt/blame-4.patch <<EOF
633 diff 3f60a8ef49086101685260fcb829f578cdf6d320 3bf198ba335fa30c8d16efb5c8e496200ac99c05
634 blob - 5255d076c915accf159940978b821d06803ff2f8
635 blob + 39623c468e733ee08abb50eafe29202b2b0a04ef
636 --- got_blame.h
637 +++ got_blame.h
638 @@ -30,8 +30,8 @@ const struct got_error *got_blame(const char *, struct
639 * which last changed this line.
641 * The callback is invoked for each commit as history is traversed.
642 - * If no changes to the file were made in a commit, line number -1 and
643 - * commit ID NULL will be reported.
644 + * If no changes to the file were made in a commit, line number -1 will
645 + * be reported.
647 * If the callback returns GOT_ERR_ITER_COMPLETED, the blame operation
648 * will be aborted and this function returns NULL.
649 EOF
650 (cd $testroot/wt && patch < blame-4.patch > /dev/null)
651 (cd $testroot/wt && got commit -m "change 4" > /dev/null)
653 cat > $testroot/wt/blame-5.patch <<EOF
654 diff 28315671b93d195163b0468fcb3879e29b25759c e27a7222faaa171dcb086ea0b566dc7bebb74a0b
655 blob - 39623c468e733ee08abb50eafe29202b2b0a04ef
656 blob + 6075cadbd177e1802679c7353515bf4ceebb51d0
657 --- got_blame.h
658 +++ got_blame.h
659 @@ -15,14 +15,7 @@
660 */
662 /*
663 - * Write an annotated version of a file at a given in-repository path,
664 - * as found in the commit specified by ID, to the specified output file.
665 - */
666 -const struct got_error *got_blame(const char *, struct got_object_id *,
667 - struct got_repository *, FILE *);
669 -/*
670 - * Like got_blame() but instead of generating an output file invoke
671 + * Blame the blob at the specified path in the specified commit and invoke
672 * a callback whenever an annotation has been computed for a line.
674 * The callback receives the provided void * argument, the total number
675 EOF
676 (cd $testroot/wt && patch < blame-5.patch > /dev/null)
677 (cd $testroot/wt && got commit -m "change 5" > /dev/null)
679 blame_cmp "$testroot" "got_blame.h"
680 ret=$?
681 test_done "$testroot" "$ret"
684 test_blame_added_on_branch() {
685 local testroot=`test_init blame_added_on_branch`
687 got branch -r $testroot/repo -c master newbranch
688 ret=$?
689 if [ $ret -ne 0 ]; then
690 test_done "$testroot" "$ret"
691 return 1
692 fi
694 got checkout -b newbranch $testroot/repo $testroot/wt > /dev/null
695 ret=$?
696 if [ $ret -ne 0 ]; then
697 test_done "$testroot" "$ret"
698 return 1
699 fi
701 echo 1 > $testroot/wt/new
702 (cd $testroot/wt && got add new > /dev/null)
703 (cd $testroot/wt && got commit -m "change 1" > /dev/null)
704 local commit1=`git_show_branch_head $testroot/repo newbranch`
706 echo 2 >> $testroot/wt/new
707 (cd $testroot/wt && got commit -m "change 2" > /dev/null)
708 local commit2=`git_show_branch_head $testroot/repo newbranch`
710 echo 3 >> $testroot/wt/new
711 (cd $testroot/wt && got commit -m "change 3" > /dev/null)
712 local commit3=`git_show_branch_head $testroot/repo newbranch`
713 local author_time=`git_show_author_time $testroot/repo`
715 (cd $testroot/wt && got blame new > $testroot/stdout)
717 local short_commit1=`trim_obj_id 32 $commit1`
718 local short_commit2=`trim_obj_id 32 $commit2`
719 local short_commit3=`trim_obj_id 32 $commit3`
721 d=`date -u -r $author_time +"%G-%m-%d"`
722 echo "1) $short_commit1 $d $GOT_AUTHOR_8 1" > $testroot/stdout.expected
723 echo "2) $short_commit2 $d $GOT_AUTHOR_8 2" >> $testroot/stdout.expected
724 echo "3) $short_commit3 $d $GOT_AUTHOR_8 3" >> $testroot/stdout.expected
726 cmp -s $testroot/stdout.expected $testroot/stdout
727 ret=$?
728 if [ $ret -ne 0 ]; then
729 diff -u $testroot/stdout.expected $testroot/stdout
730 fi
731 test_done "$testroot" "$ret"
734 test_blame_submodule() {
735 local testroot=`test_init blame_submodule`
736 local commit_id0=`git_show_head $testroot/repo`
737 local author_time=`git_show_author_time $testroot/repo`
739 make_single_file_repo $testroot/repo2 foo
741 (cd $testroot/repo && git -c protocol.file.allow=always \
742 submodule -q add ../repo2)
743 (cd $testroot/repo && git commit -q -m 'adding submodule')
745 # Attempt a (nonsensical) blame of a submodule.
746 got blame -r $testroot/repo repo2 \
747 > $testroot/stdout 2> $testroot/stderr
748 ret=$?
749 if [ $ret -eq 0 ]; then
750 echo "blame command succeeded unexpectedly" >&2
751 test_done "$testroot" "1"
752 return 1
753 fi
754 local submodule_id=$(got tree -r $testroot/repo -i | \
755 grep 'repo2\$$' | cut -d ' ' -f1)
756 echo "got: object $submodule_id not found" > $testroot/stderr.expected
758 cmp -s $testroot/stderr.expected $testroot/stderr
759 ret=$?
760 if [ $ret -ne 0 ]; then
761 diff -u $testroot/stderr.expected $testroot/stderr
762 fi
763 test_done "$testroot" "$ret"
766 test_blame_symlink() {
767 local testroot=`test_init blame_symlink`
768 local commit_id0=`git_show_head $testroot/repo`
769 local short_commit0=`trim_obj_id 32 $commit_id0`
771 (cd $testroot/repo && ln -s alpha alpha.link)
772 (cd $testroot/repo && ln -s epsilon epsilon.link)
773 (cd $testroot/repo && ln -s /etc/passwd passwd.link)
774 (cd $testroot/repo && ln -s ../beta epsilon/beta.link)
775 (cd $testroot/repo && ln -s nonexistent nonexistent.link)
776 (cd $testroot/repo && git add .)
777 git_commit $testroot/repo -m "add symlinks"
779 local commit_id1=`git_show_head $testroot/repo`
780 local short_commit1=`trim_obj_id 32 $commit_id1`
781 local author_time=`git_show_author_time $testroot/repo`
783 # got blame dereferences symlink to a regular file
784 got blame -r $testroot/repo alpha.link > $testroot/stdout
785 ret=$?
786 if [ $ret -ne 0 ]; then
787 echo "blame command failed unexpectedly" >&2
788 test_done "$testroot" "$ret"
789 return 1
790 fi
792 d=`date -u -r $author_time +"%G-%m-%d"`
793 echo "1) $short_commit0 $d $GOT_AUTHOR_8 alpha" \
794 > $testroot/stdout.expected
796 cmp -s $testroot/stdout.expected $testroot/stdout
797 ret=$?
798 if [ $ret -ne 0 -a "$xfail" = "" ]; then
799 diff -u $testroot/stdout.expected $testroot/stdout
800 test_done "$testroot" "1"
801 return 1
802 fi
804 # got blame dereferences symlink with relative path
805 got blame -r $testroot/repo epsilon/beta.link > $testroot/stdout
806 ret=$?
807 if [ $ret -ne 0 ]; then
808 echo "blame command failed unexpectedly" >&2
809 test_done "$testroot" "$ret"
810 return 1
811 fi
813 d=`date -u -r $author_time +"%G-%m-%d"`
814 echo "1) $short_commit0 $d $GOT_AUTHOR_8 beta" \
815 > $testroot/stdout.expected
817 cmp -s $testroot/stdout.expected $testroot/stdout
818 ret=$?
819 if [ $ret -ne 0 -a "$xfail" = "" ]; then
820 diff -u $testroot/stdout.expected $testroot/stdout
821 test_done "$testroot" "1"
822 return 1
823 fi
825 got blame -r $testroot/repo epsilon.link > $testroot/stdout \
826 2> $testroot/stderr
827 ret=$?
828 if [ $ret -eq 0 ]; then
829 echo "blame command succeeded unexpectedly" >&2
830 test_done "$testroot" "1"
831 return 1
832 fi
834 # blame dereferences symlink to a directory
835 echo "got: /epsilon: wrong type of object" > $testroot/stderr.expected
836 cmp -s $testroot/stderr.expected $testroot/stderr
837 ret=$?
838 if [ $ret -ne 0 ]; then
839 diff -u $testroot/stderr.expected $testroot/stderr
840 test_done "$testroot" "1"
841 return 1
842 fi
844 # got blame fails if symlink target does not exist in repo
845 got blame -r $testroot/repo passwd.link > $testroot/stdout \
846 2> $testroot/stderr
847 ret=$?
848 if [ $ret -eq 0 ]; then
849 echo "blame command succeeded unexpectedly" >&2
850 test_done "$testroot" "1"
851 return 1
852 fi
854 echo "got: /etc/passwd: no such entry found in tree" \
855 > $testroot/stderr.expected
856 cmp -s $testroot/stderr.expected $testroot/stderr
857 ret=$?
858 if [ $ret -ne 0 ]; then
859 diff -u $testroot/stderr.expected $testroot/stderr
860 test_done "$testroot" "1"
861 return 1
862 fi
864 got blame -r $testroot/repo nonexistent.link > $testroot/stdout \
865 2> $testroot/stderr
866 ret=$?
867 if [ $ret -eq 0 ]; then
868 echo "blame command succeeded unexpectedly" >&2
869 test_done "$testroot" "1"
870 return 1
871 fi
873 echo "got: /nonexistent: no such entry found in tree" \
874 > $testroot/stderr.expected
875 cmp -s $testroot/stderr.expected $testroot/stderr
876 ret=$?
877 if [ $ret -ne 0 ]; then
878 diff -u $testroot/stderr.expected $testroot/stderr
879 test_done "$testroot" "1"
880 return 1
881 fi
883 test_done "$testroot" "$ret"
886 test_blame_lines_shifted_skip() {
887 local testroot=`test_init blame_lines_shifted_skip`
889 got checkout $testroot/repo $testroot/wt > /dev/null
890 ret=$?
891 if [ $ret -ne 0 ]; then
892 test_done "$testroot" "$ret"
893 return 1
894 fi
896 cat > $testroot/wt/alpha <<EOF
901 EOF
902 (cd $testroot/wt && got commit -m "change 1" > /dev/null)
903 local commit1=`git_show_head $testroot/repo`
904 local short_commit1=`trim_obj_id 32 $commit1`
905 local author_time=`git_show_author_time $testroot/repo`
907 cat > $testroot/wt/alpha <<EOF
914 EOF
915 (cd $testroot/wt && got commit -m "change 2" > /dev/null)
916 local commit2=`git_show_head $testroot/repo`
917 local short_commit2=`trim_obj_id 32 $commit2`
919 cat > $testroot/wt/alpha <<EOF
927 EOF
928 (cd $testroot/wt && got commit -m "change 3" > /dev/null)
929 local commit3=`git_show_head $testroot/repo`
930 local short_commit3=`trim_obj_id 32 $commit3`
931 local author_time=`git_show_author_time $testroot/repo`
933 cat > $testroot/wt/alpha <<EOF
940 EOF
941 (cd $testroot/wt && got commit -m "change 4" > /dev/null)
942 local commit4=`git_show_head $testroot/repo`
943 local short_commit4=`trim_obj_id 32 $commit4`
944 local author_time=`git_show_author_time $testroot/repo`
946 cat > $testroot/wt/alpha <<EOF
954 EOF
955 (cd $testroot/wt && got commit -m "change 5" > /dev/null)
956 local commit5=`git_show_head $testroot/repo`
957 local short_commit5=`trim_obj_id 32 $commit5`
958 local author_time=`git_show_author_time $testroot/repo`
960 (cd $testroot/wt && got blame alpha > $testroot/stdout)
962 d=`date -u -r $author_time +"%G-%m-%d"`
963 echo "1) $short_commit5 $d $GOT_AUTHOR_8 X" > $testroot/stdout.expected
964 echo "2) $short_commit1 $d $GOT_AUTHOR_8 A" >> $testroot/stdout.expected
965 echo "3) $short_commit1 $d $GOT_AUTHOR_8 B" >> $testroot/stdout.expected
966 echo "4) $short_commit1 $d $GOT_AUTHOR_8 C" >> $testroot/stdout.expected
967 echo "5) $short_commit2 $d $GOT_AUTHOR_8 P" >> $testroot/stdout.expected
968 echo "6) $short_commit4 $d $GOT_AUTHOR_8 Y" >> $testroot/stdout.expected
969 echo "7) $short_commit2 $d $GOT_AUTHOR_8 Q" >> $testroot/stdout.expected
971 cmp -s $testroot/stdout.expected $testroot/stdout
972 ret=$?
973 if [ $ret -ne 0 ]; then
974 diff -u $testroot/stdout.expected $testroot/stdout
975 test_done "$testroot" "$ret"
976 return 1
977 fi
979 blame_cmp "$testroot" "alpha"
980 ret=$?
981 test_done "$testroot" "$ret"
984 test_parseargs "$@"
985 run_test test_blame_basic
986 run_test test_blame_tag
987 run_test test_blame_file_single_line
988 run_test test_blame_file_single_line_no_newline
989 run_test test_blame_all_lines_replaced
990 run_test test_blame_lines_shifted_up
991 run_test test_blame_lines_shifted_down
992 run_test test_blame_commit_subsumed
993 run_test test_blame_blame_h
994 run_test test_blame_added_on_branch
995 run_test test_blame_submodule
996 run_test test_blame_symlink
997 run_test test_blame_lines_shifted_skip