Git fork
1#!/bin/sh
2
3test_description='git cat-file'
4
5. ./test-lib.sh
6. "$TEST_DIRECTORY/lib-loose.sh"
7
8test_cmdmode_usage () {
9 test_expect_code 129 "$@" 2>err &&
10 grep "^error: .* cannot be used together" err
11}
12
13for switches in \
14 '-e -p' \
15 '-p -t' \
16 '-t -s' \
17 '-s --textconv' \
18 '--textconv --filters' \
19 '--batch-all-objects -e'
20do
21 test_expect_success "usage: cmdmode $switches" '
22 test_cmdmode_usage git cat-file $switches
23 '
24done
25
26test_incompatible_usage () {
27 test_expect_code 129 "$@" 2>err &&
28 grep -E "^(fatal|error):.*(requires|incompatible with|needs)" err
29}
30
31for opt in --batch --batch-check
32do
33 test_expect_success "usage: incompatible options: --path with $opt" '
34 test_incompatible_usage git cat-file --path=foo $opt
35 '
36done
37
38test_missing_usage () {
39 test_expect_code 129 "$@" 2>err &&
40 grep -E "^fatal:.*required" err
41}
42
43short_modes="-e -p -t -s"
44cw_modes="--textconv --filters"
45
46for opt in $cw_modes
47do
48 test_expect_success "usage: $opt requires another option" '
49 test_missing_usage git cat-file $opt
50 '
51done
52
53for opt in $short_modes
54do
55 test_expect_success "usage: $opt requires another option" '
56 test_missing_usage git cat-file $opt
57 '
58
59 for opt2 in --batch \
60 --batch-check \
61 --follow-symlinks \
62 "--path=foo HEAD:some-path.txt"
63 do
64 test_expect_success "usage: incompatible options: $opt and $opt2" '
65 test_incompatible_usage git cat-file $opt $opt2
66 '
67 done
68done
69
70test_too_many_arguments () {
71 test_expect_code 129 "$@" 2>err &&
72 grep -E "^fatal: too many arguments$" err
73}
74
75for opt in $short_modes $cw_modes
76do
77 args="one two three"
78 test_expect_success "usage: too many arguments: $opt $args" '
79 test_too_many_arguments git cat-file $opt $args
80 '
81
82 for opt2 in --buffer --follow-symlinks
83 do
84 test_expect_success "usage: incompatible arguments: $opt with batch option $opt2" '
85 test_incompatible_usage git cat-file $opt $opt2
86 '
87 done
88done
89
90for opt in --buffer \
91 --follow-symlinks \
92 --batch-all-objects \
93 -z \
94 -Z
95do
96 test_expect_success "usage: bad option combination: $opt without batch mode" '
97 test_incompatible_usage git cat-file $opt &&
98 test_incompatible_usage git cat-file $opt commit HEAD
99 '
100done
101
102echo_without_newline () {
103 printf '%s' "$*"
104}
105
106echo_without_newline_nul () {
107 echo_without_newline "$@" | tr '\n' '\0'
108}
109
110strlen () {
111 echo_without_newline "$1" | wc -c | sed -e 's/^ *//'
112}
113
114run_tests () {
115 type=$1
116 object_name="$2"
117 mode=$3
118 size=$4
119 content=$5
120 pretty_content=$6
121 oid=${7:-"$object_name"}
122
123 batch_output="$oid $type $size
124$content"
125
126 test_expect_success "$type exists" '
127 git cat-file -e "$object_name"
128 '
129
130 test_expect_success "Type of $type is correct" '
131 echo $type >expect &&
132 git cat-file -t "$object_name" >actual &&
133 test_cmp expect actual
134 '
135
136 test_expect_success "Size of $type is correct" '
137 echo $size >expect &&
138 git cat-file -s "$object_name" >actual &&
139 test_cmp expect actual
140 '
141
142 test -z "$content" ||
143 test_expect_success "Content of $type is correct" '
144 echo_without_newline "$content" >expect &&
145 git cat-file $type "$object_name" >actual &&
146 test_cmp expect actual
147 '
148
149 test_expect_success "Pretty content of $type is correct" '
150 echo_without_newline "$pretty_content" >expect &&
151 git cat-file -p "$object_name" >actual &&
152 test_cmp expect actual
153 '
154
155 test -z "$content" ||
156 test_expect_success "--batch output of $type is correct" '
157 echo "$batch_output" >expect &&
158 echo "$object_name" | git cat-file --batch >actual &&
159 test_cmp expect actual
160 '
161
162 test_expect_success "--batch-check output of $type is correct" '
163 echo "$oid $type $size" >expect &&
164 echo_without_newline "$object_name" | git cat-file --batch-check >actual &&
165 test_cmp expect actual
166 '
167
168 for opt in --buffer --no-buffer
169 do
170 test -z "$content" ||
171 test_expect_success "--batch-command $opt output of $type content is correct" '
172 echo "$batch_output" >expect &&
173 test_write_lines "contents $object_name" | git cat-file --batch-command $opt >actual &&
174 test_cmp expect actual
175 '
176
177 test_expect_success "--batch-command $opt output of $type info is correct" '
178 echo "$oid $type $size" >expect &&
179 test_write_lines "info $object_name" |
180 git cat-file --batch-command $opt >actual &&
181 test_cmp expect actual
182 '
183 done
184
185 test_expect_success "custom --batch-check format" '
186 echo "$type $oid" >expect &&
187 echo "$object_name" | git cat-file --batch-check="%(objecttype) %(objectname)" >actual &&
188 test_cmp expect actual
189 '
190
191 test_expect_success "custom --batch-command format" '
192 echo "$type $oid" >expect &&
193 echo "info $object_name" | git cat-file --batch-command="%(objecttype) %(objectname)" >actual &&
194 test_cmp expect actual
195 '
196
197 # FIXME: %(rest) is incompatible with object names that include whitespace,
198 # e.g. HEAD:path/to/a/file with spaces. Use the resolved OID as input to
199 # test this instead of the raw object name.
200 if echo "$object_name" | grep -q " "; then
201 test_rest=test_expect_failure
202 else
203 test_rest=test_expect_success
204 fi
205
206 $test_rest '--batch-check with %(rest)' '
207 echo "$type this is some extra content" >expect &&
208 echo "$object_name this is some extra content" |
209 git cat-file --batch-check="%(objecttype) %(rest)" >actual &&
210 test_cmp expect actual
211 '
212
213 test_expect_success '--batch-check with %(objectmode)' '
214 echo "$mode $oid" >expect &&
215 echo $object_name | git cat-file --batch-check="%(objectmode) %(objectname)" >actual &&
216 test_cmp expect actual
217 '
218
219 test -z "$content" ||
220 test_expect_success "--batch without type ($type)" '
221 {
222 echo "$size" &&
223 echo "$content"
224 } >expect &&
225 echo "$object_name" | git cat-file --batch="%(objectsize)" >actual &&
226 test_cmp expect actual
227 '
228
229 test -z "$content" ||
230 test_expect_success "--batch without size ($type)" '
231 {
232 echo "$type" &&
233 echo "$content"
234 } >expect &&
235 echo "$object_name" | git cat-file --batch="%(objecttype)" >actual &&
236 test_cmp expect actual
237 '
238}
239
240hello_content="Hello World"
241hello_size=$(strlen "$hello_content")
242hello_oid=$(echo_without_newline "$hello_content" | git hash-object --stdin)
243
244test_expect_success "setup" '
245 git config core.repositoryformatversion 1 &&
246 git config extensions.objectformat $test_hash_algo &&
247 git config extensions.compatobjectformat $test_compat_hash_algo &&
248 echo_without_newline "$hello_content" > hello &&
249 git update-index --add hello &&
250 echo_without_newline "$hello_content" > "path with spaces" &&
251 git update-index --add --chmod=+x "path with spaces" &&
252 git commit -m "add hello file"
253'
254
255run_blob_tests () {
256 oid=$1
257 run_tests 'blob' $oid "" $hello_size "$hello_content" "$hello_content"
258
259 test_expect_success '--batch-command --buffer with flush for blob info' '
260 echo "$oid blob $hello_size" >expect &&
261 test_write_lines "info $oid" "flush" |
262 GIT_TEST_CAT_FILE_NO_FLUSH_ON_EXIT=1 \
263 git cat-file --batch-command --buffer >actual &&
264 test_cmp expect actual
265 '
266
267 test_expect_success '--batch-command --buffer without flush for blob info' '
268 touch output &&
269 test_write_lines "info $oid" |
270 GIT_TEST_CAT_FILE_NO_FLUSH_ON_EXIT=1 \
271 git cat-file --batch-command --buffer >>output &&
272 test_must_be_empty output
273 '
274}
275
276hello_compat_oid=$(git rev-parse --output-object-format=$test_compat_hash_algo $hello_oid)
277run_blob_tests $hello_oid
278run_blob_tests $hello_compat_oid
279
280test_expect_success '--batch-check without %(rest) considers whole line' '
281 echo "$hello_oid blob $hello_size" >expect &&
282 git update-index --add --cacheinfo 100644 $hello_oid "white space" &&
283 test_when_finished "git update-index --remove \"white space\"" &&
284 echo ":white space" | git cat-file --batch-check >actual &&
285 test_cmp expect actual
286'
287
288tree_oid=$(git write-tree)
289tree_compat_oid=$(git rev-parse --output-object-format=$test_compat_hash_algo $tree_oid)
290tree_size=$((2 * $(test_oid rawsz) + 13 + 24))
291tree_compat_size=$((2 * $(test_oid --hash=compat rawsz) + 13 + 24))
292tree_pretty_content="100644 blob $hello_oid hello${LF}100755 blob $hello_oid path with spaces${LF}"
293tree_compat_pretty_content="100644 blob $hello_compat_oid hello${LF}100755 blob $hello_compat_oid path with spaces${LF}"
294
295run_tests 'tree' $tree_oid "" $tree_size "" "$tree_pretty_content"
296run_tests 'tree' $tree_compat_oid "" $tree_compat_size "" "$tree_compat_pretty_content"
297run_tests 'blob' "$tree_oid:hello" "100644" $hello_size "" "$hello_content" $hello_oid
298run_tests 'blob' "$tree_compat_oid:hello" "100644" $hello_size "" "$hello_content" $hello_compat_oid
299run_tests 'blob' "$tree_oid:path with spaces" "100755" $hello_size "" "$hello_content" $hello_oid
300run_tests 'blob' "$tree_compat_oid:path with spaces" "100755" $hello_size "" "$hello_content" $hello_compat_oid
301
302commit_message="Initial commit"
303commit_oid=$(echo_without_newline "$commit_message" | git commit-tree $tree_oid)
304commit_compat_oid=$(git rev-parse --output-object-format=$test_compat_hash_algo $commit_oid)
305commit_size=$(($(test_oid hexsz) + 137))
306commit_compat_size=$(($(test_oid --hash=compat hexsz) + 137))
307commit_content="tree $tree_oid
308author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE
309committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
310
311$commit_message"
312
313commit_compat_content="tree $tree_compat_oid
314author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE
315committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
316
317$commit_message"
318
319run_tests 'commit' $commit_oid "" $commit_size "$commit_content" "$commit_content"
320run_tests 'commit' $commit_compat_oid "" $commit_compat_size "$commit_compat_content" "$commit_compat_content"
321
322tag_header_without_oid="type blob
323tag hellotag
324tagger $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
325tag_header_without_timestamp="object $hello_oid
326$tag_header_without_oid"
327tag_compat_header_without_timestamp="object $hello_compat_oid
328$tag_header_without_oid"
329tag_description="This is a tag"
330tag_content="$tag_header_without_timestamp 0 +0000
331
332$tag_description"
333tag_compat_content="$tag_compat_header_without_timestamp 0 +0000
334
335$tag_description"
336
337tag_oid=$(echo_without_newline "$tag_content" | git hash-object -t tag --stdin -w)
338tag_size=$(strlen "$tag_content")
339
340tag_compat_oid=$(git rev-parse --output-object-format=$test_compat_hash_algo $tag_oid)
341tag_compat_size=$(strlen "$tag_compat_content")
342
343run_tests 'tag' $tag_oid "" $tag_size "$tag_content" "$tag_content"
344run_tests 'tag' $tag_compat_oid "" $tag_compat_size "$tag_compat_content" "$tag_compat_content"
345
346test_expect_success "Reach a blob from a tag pointing to it" '
347 echo_without_newline "$hello_content" >expect &&
348 git cat-file blob $tag_oid >actual &&
349 test_cmp expect actual
350'
351
352for oid in $hello_oid $hello_compat_oid
353do
354 for batch in batch batch-check batch-command
355 do
356 for opt in t s e p
357 do
358 test_expect_success "Passing -$opt with --$batch fails" '
359 test_must_fail git cat-file --$batch -$opt $oid
360 '
361
362 test_expect_success "Passing --$batch with -$opt fails" '
363 test_must_fail git cat-file -$opt --$batch $oid
364 '
365 done
366
367 test_expect_success "Passing <type> with --$batch fails" '
368 test_must_fail git cat-file --$batch blob $oid
369 '
370
371 test_expect_success "Passing --$batch with <type> fails" '
372 test_must_fail git cat-file blob --$batch $oid
373 '
374
375 test_expect_success "Passing oid with --$batch fails" '
376 test_must_fail git cat-file --$batch $oid
377 '
378 done
379done
380
381for oid in $hello_oid $hello_compat_oid
382do
383 for opt in t s e p
384 do
385 test_expect_success "Passing -$opt with --follow-symlinks fails" '
386 test_must_fail git cat-file --follow-symlinks -$opt $oid
387 '
388 done
389done
390
391test_expect_success "--batch-check for a non-existent named object" '
392 cat >expect <<-EOF &&
393 foobar42 missing
394 foobar84 missing
395 EOF
396
397 printf "foobar42\nfoobar84" >in &&
398 git cat-file --batch-check <in >actual &&
399 test_cmp expect actual
400'
401
402test_expect_success "--batch-check for a non-existent hash" '
403 cat >expect <<-EOF &&
404 0000000000000000000000000000000000000042 missing
405 0000000000000000000000000000000000000084 missing
406 EOF
407
408 printf "0000000000000000000000000000000000000042\n0000000000000000000000000000000000000084" >in &&
409 git cat-file --batch-check <in >actual &&
410 test_cmp expect actual
411'
412
413test_expect_success "--batch for an existent and a non-existent hash" '
414 cat >expect <<-EOF &&
415 $tag_oid tag $tag_size
416 $tag_content
417 0000000000000000000000000000000000000000 missing
418 EOF
419
420 printf "$tag_oid\n0000000000000000000000000000000000000000" >in &&
421 git cat-file --batch <in >actual &&
422 test_cmp expect actual
423'
424
425test_expect_success "--batch-check for an empty line" '
426 cat >expect <<-EOF &&
427 missing
428 EOF
429
430 echo >in &&
431 git cat-file --batch-check <in >actual &&
432 test_cmp expect actual
433'
434
435test_expect_success 'empty --batch-check notices missing object' '
436 echo "$ZERO_OID missing" >expect &&
437 echo "$ZERO_OID" | git cat-file --batch-check="" >actual &&
438 test_cmp expect actual
439'
440
441batch_tests () {
442 boid=$1
443 loid=$2
444 lsize=$3
445 coid=$4
446 csize=$5
447 ccontent=$6
448 toid=$7
449 tsize=$8
450 tcontent=$9
451
452 batch_input="$boid
453$coid
454$toid
455deadbeef
456
457"
458
459 printf "%s\0" \
460 "$boid blob $hello_size" \
461 "$hello_content" \
462 "$coid commit $csize" \
463 "$ccontent" \
464 "$toid tag $tsize" \
465 "$tcontent" \
466 "deadbeef missing" \
467 " missing" >batch_output
468
469 test_expect_success '--batch with multiple oids gives correct format' '
470 tr "\0" "\n" <batch_output >expect &&
471 echo_without_newline "$batch_input" >in &&
472 git cat-file --batch <in >actual &&
473 test_cmp expect actual
474 '
475
476 test_expect_success '--batch, -z with multiple oids gives correct format' '
477 echo_without_newline_nul "$batch_input" >in &&
478 tr "\0" "\n" <batch_output >expect &&
479 git cat-file --batch -z <in >actual &&
480 test_cmp expect actual
481 '
482
483 test_expect_success '--batch, -Z with multiple oids gives correct format' '
484 echo_without_newline_nul "$batch_input" >in &&
485 git cat-file --batch -Z <in >actual &&
486 test_cmp batch_output actual
487 '
488
489batch_check_input="$boid
490$loid
491$coid
492$toid
493deadbeef
494
495"
496
497 printf "%s\0" \
498 "$boid blob $hello_size" \
499 "$loid tree $lsize" \
500 "$coid commit $csize" \
501 "$toid tag $tsize" \
502 "deadbeef missing" \
503 " missing" >batch_check_output
504
505 test_expect_success "--batch-check with multiple oids gives correct format" '
506 tr "\0" "\n" <batch_check_output >expect &&
507 echo_without_newline "$batch_check_input" >in &&
508 git cat-file --batch-check <in >actual &&
509 test_cmp expect actual
510 '
511
512 test_expect_success "--batch-check, -z with multiple oids gives correct format" '
513 tr "\0" "\n" <batch_check_output >expect &&
514 echo_without_newline_nul "$batch_check_input" >in &&
515 git cat-file --batch-check -z <in >actual &&
516 test_cmp expect actual
517 '
518
519 test_expect_success "--batch-check, -Z with multiple oids gives correct format" '
520 echo_without_newline_nul "$batch_check_input" >in &&
521 git cat-file --batch-check -Z <in >actual &&
522 test_cmp batch_check_output actual
523 '
524
525batch_command_multiple_info="info $boid
526info $loid
527info $coid
528info $toid
529info deadbeef"
530
531 test_expect_success '--batch-command with multiple info calls gives correct format' '
532 cat >expect <<-EOF &&
533 $boid blob $hello_size
534 $loid tree $lsize
535 $coid commit $csize
536 $toid tag $tsize
537 deadbeef missing
538 EOF
539
540 echo "$batch_command_multiple_info" >in &&
541 git cat-file --batch-command --buffer <in >actual &&
542
543 test_cmp expect actual &&
544
545 echo "$batch_command_multiple_info" | tr "\n" "\0" >in &&
546 git cat-file --batch-command --buffer -z <in >actual &&
547
548 test_cmp expect actual &&
549
550 echo "$batch_command_multiple_info" | tr "\n" "\0" >in &&
551 tr "\n" "\0" <expect >expect_nul &&
552 git cat-file --batch-command --buffer -Z <in >actual &&
553
554 test_cmp expect_nul actual
555 '
556
557batch_command_multiple_contents="contents $boid
558contents $coid
559contents $toid
560contents deadbeef
561flush"
562
563 test_expect_success '--batch-command with multiple command calls gives correct format' '
564 printf "%s\0" \
565 "$boid blob $hello_size" \
566 "$hello_content" \
567 "$coid commit $csize" \
568 "$ccontent" \
569 "$toid tag $tsize" \
570 "$tcontent" \
571 "deadbeef missing" >expect_nul &&
572 tr "\0" "\n" <expect_nul >expect &&
573
574 echo "$batch_command_multiple_contents" >in &&
575 git cat-file --batch-command --buffer <in >actual &&
576
577 test_cmp expect actual &&
578
579 echo "$batch_command_multiple_contents" | tr "\n" "\0" >in &&
580 git cat-file --batch-command --buffer -z <in >actual &&
581
582 test_cmp expect actual &&
583
584 echo "$batch_command_multiple_contents" | tr "\n" "\0" >in &&
585 git cat-file --batch-command --buffer -Z <in >actual &&
586
587 test_cmp expect_nul actual
588 '
589
590}
591
592batch_tests $hello_oid $tree_oid $tree_size $commit_oid $commit_size "$commit_content" $tag_oid $tag_size "$tag_content"
593batch_tests $hello_compat_oid $tree_compat_oid $tree_compat_size $commit_compat_oid $commit_compat_size "$commit_compat_content" $tag_compat_oid $tag_compat_size "$tag_compat_content"
594
595
596test_expect_success FUNNYNAMES 'setup with newline in input' '
597 touch -- "newline${LF}embedded" &&
598 git add -- "newline${LF}embedded" &&
599 git commit -m "file with newline embedded" &&
600 test_tick &&
601
602 printf "HEAD:newline${LF}embedded" >in
603'
604
605test_expect_success FUNNYNAMES '--batch-check, -z with newline in input' '
606 git cat-file --batch-check -z <in >actual &&
607 echo "$(git rev-parse "HEAD:newline${LF}embedded") blob 0" >expect &&
608 test_cmp expect actual
609'
610
611test_expect_success FUNNYNAMES '--batch-check, -Z with newline in input' '
612 git cat-file --batch-check -Z <in >actual &&
613 printf "%s\0" "$(git rev-parse "HEAD:newline${LF}embedded") blob 0" >expect &&
614 test_cmp expect actual
615'
616
617test_expect_success 'setup with curly braches in input' '
618 git branch "foo{bar" HEAD &&
619 git branch "foo@" HEAD
620'
621
622test_expect_success 'object reference with curly brace' '
623 git cat-file -p "foo{bar:hello" >actual &&
624 git cat-file -p HEAD:hello >expect &&
625 test_cmp expect actual
626'
627
628test_expect_success 'object reference with at-sign' '
629 git cat-file -p "foo@@{0}:hello" >actual &&
630 git cat-file -p HEAD:hello >expect &&
631 test_cmp expect actual
632'
633
634test_expect_success 'setup with commit with colon' '
635 git commit-tree -m "testing: just a bunch of junk" HEAD^{tree} >out &&
636 git branch other $(cat out)
637'
638
639test_expect_success 'object reference via commit text search' '
640 git cat-file -p "other^{/testing:}:hello" >actual &&
641 git cat-file -p HEAD:hello >expect &&
642 test_cmp expect actual
643'
644
645test_expect_success 'setup blobs which are likely to delta' '
646 test-tool genrandom foo 10240 >foo &&
647 { cat foo && echo plus; } >foo-plus &&
648 git add foo foo-plus &&
649 git commit -m foo &&
650 cat >blobs <<-\EOF
651 HEAD:foo
652 HEAD:foo-plus
653 EOF
654'
655
656test_expect_success 'confirm that neither loose blob is a delta' '
657 cat >expect <<-EOF &&
658 $ZERO_OID
659 $ZERO_OID
660 EOF
661 git cat-file --batch-check="%(deltabase)" <blobs >actual &&
662 test_cmp expect actual
663'
664
665# To avoid relying too much on the current delta heuristics,
666# we will check only that one of the two objects is a delta
667# against the other, but not the order. We can do so by just
668# asking for the base of both, and checking whether either
669# oid appears in the output.
670test_expect_success '%(deltabase) reports packed delta bases' '
671 git repack -ad &&
672 git cat-file --batch-check="%(deltabase)" <blobs >actual &&
673 {
674 grep "$(git rev-parse HEAD:foo)" actual ||
675 grep "$(git rev-parse HEAD:foo-plus)" actual
676 }
677'
678
679test_expect_success 'setup bogus data' '
680 bogus_short_type="bogus" &&
681 bogus_short_content="bogus" &&
682 bogus_short_size=$(strlen "$bogus_short_content") &&
683 bogus_short_oid=$(echo_without_newline "$bogus_short_content" | loose_obj .git/objects $bogus_short_type) &&
684
685 bogus_long_type="abcdefghijklmnopqrstuvwxyz1234679" &&
686 bogus_long_content="bogus" &&
687 bogus_long_size=$(strlen "$bogus_long_content") &&
688 bogus_long_oid=$(echo_without_newline "$bogus_long_content" | loose_obj .git/objects $bogus_long_type)
689'
690
691for arg1 in -s -t -p
692do
693 test_expect_success "cat-file $arg1 error on bogus short OID" '
694 cat >expect <<-\EOF &&
695 fatal: invalid object type
696 EOF
697
698 test_must_fail git cat-file $arg1 $bogus_short_oid >out 2>actual &&
699 test_must_be_empty out &&
700 test_cmp expect actual
701 '
702
703 test_expect_success "cat-file $arg1 error on bogus full OID" '
704 if test "$arg1" = "-p"
705 then
706 cat >expect <<-EOF
707 error: header for $bogus_long_oid too long, exceeds 32 bytes
708 fatal: Not a valid object name $bogus_long_oid
709 EOF
710 else
711 cat >expect <<-EOF
712 error: header for $bogus_long_oid too long, exceeds 32 bytes
713 fatal: git cat-file: could not get object info
714 EOF
715 fi &&
716
717 test_must_fail git cat-file $arg1 $bogus_long_oid >out 2>actual &&
718 test_must_be_empty out &&
719 test_cmp expect actual
720 '
721
722 test_expect_success "cat-file $arg1 error on missing short OID" '
723 cat >expect.err <<-EOF &&
724 fatal: Not a valid object name $(test_oid deadbeef_short)
725 EOF
726 test_must_fail git cat-file $arg1 $(test_oid deadbeef_short) >out 2>err.actual &&
727 test_must_be_empty out &&
728 test_cmp expect.err err.actual
729 '
730
731 test_expect_success "cat-file $arg1 error on missing full OID" '
732 if test "$arg1" = "-p"
733 then
734 cat >expect.err <<-EOF
735 fatal: Not a valid object name $(test_oid deadbeef)
736 EOF
737 else
738 cat >expect.err <<-\EOF
739 fatal: git cat-file: could not get object info
740 EOF
741 fi &&
742 test_must_fail git cat-file $arg1 $(test_oid deadbeef) >out 2>err.actual &&
743 test_must_be_empty out &&
744 test_cmp expect.err err.actual
745 '
746done
747
748test_expect_success '-e is OK with a broken object' '
749 git cat-file -e $bogus_short_oid
750'
751
752test_expect_success '<type> <hash> does not work with objects of broken types' '
753 cat >err.expect <<-\EOF &&
754 fatal: invalid object type "bogus"
755 EOF
756 test_must_fail git cat-file $bogus_short_type $bogus_short_oid 2>err.actual &&
757 test_cmp err.expect err.actual
758'
759
760test_expect_success 'broken types combined with --batch and --batch-check' '
761 echo $bogus_short_oid >bogus-oid &&
762
763 cat >err.expect <<-\EOF &&
764 fatal: invalid object type
765 EOF
766
767 test_must_fail git cat-file --batch <bogus-oid 2>err.actual &&
768 test_cmp err.expect err.actual &&
769
770 test_must_fail git cat-file --batch-check <bogus-oid 2>err.actual &&
771 test_cmp err.expect err.actual
772'
773
774test_expect_success 'clean up broken objects' '
775 rm .git/objects/$(test_oid_to_path $bogus_short_oid) &&
776 rm .git/objects/$(test_oid_to_path $bogus_long_oid)
777'
778
779test_expect_success 'cat-file -t and -s on corrupt loose object' '
780 git init --bare corrupt-loose.git &&
781 (
782 cd corrupt-loose.git &&
783
784 # Setup and create the empty blob and its path
785 empty_path=$(git rev-parse --git-path objects/$(test_oid_to_path "$EMPTY_BLOB")) &&
786 empty_blob=$(git hash-object -w --stdin </dev/null) &&
787
788 # Create another blob and its path
789 echo other >other.blob &&
790 other_blob=$(git hash-object -w --stdin <other.blob) &&
791 other_path=$(git rev-parse --git-path objects/$(test_oid_to_path "$other_blob")) &&
792
793 # Before the swap the size is 0
794 cat >out.expect <<-EOF &&
795 0
796 EOF
797 git cat-file -s "$EMPTY_BLOB" >out.actual 2>err.actual &&
798 test_must_be_empty err.actual &&
799 test_cmp out.expect out.actual &&
800
801 # Swap the two to corrupt the repository
802 mv -f "$other_path" "$empty_path" &&
803 test_must_fail git fsck 2>err.fsck &&
804 grep "hash-path mismatch" err.fsck &&
805
806 # confirm that cat-file is reading the new swapped-in
807 # blob...
808 cat >out.expect <<-EOF &&
809 blob
810 EOF
811 git cat-file -t "$EMPTY_BLOB" >out.actual 2>err.actual &&
812 test_must_be_empty err.actual &&
813 test_cmp out.expect out.actual &&
814
815 # ... since it has a different size now.
816 cat >out.expect <<-EOF &&
817 6
818 EOF
819 git cat-file -s "$EMPTY_BLOB" >out.actual 2>err.actual &&
820 test_must_be_empty err.actual &&
821 test_cmp out.expect out.actual &&
822
823 # So far "cat-file" has been happy to spew the found
824 # content out as-is. Try to make it zlib-invalid.
825 mv -f other.blob "$empty_path" &&
826 test_must_fail git fsck 2>err.fsck &&
827 cat >expect <<-EOF &&
828 error: inflate: data stream error (incorrect header check)
829 error: unable to unpack header of ./$empty_path
830 error: $empty_blob: object corrupt or missing: ./$empty_path
831 EOF
832 grep "^error: " err.fsck >actual &&
833 test_cmp expect actual
834 )
835'
836
837test_expect_success 'object reading handles zlib dictionary' - <<\EOT
838 echo 'content that will be recompressed' >file &&
839 blob=$(git hash-object -w file) &&
840 objpath=.git/objects/$(test_oid_to_path "$blob") &&
841
842 # Recompress a loose object using a precomputed zlib dictionary.
843 # This was originally done with:
844 #
845 # perl -MCompress::Raw::Zlib -e '
846 # binmode STDIN;
847 # binmode STDOUT;
848 # my $data = do { local $/; <STDIN> };
849 # my $in = new Compress::Raw::Zlib::Inflate;
850 # my $de = new Compress::Raw::Zlib::Deflate(
851 # -Dictionary => "anything"
852 # );
853 # $in->inflate($data, $raw);
854 # $de->deflate($raw, $out);
855 # print $out;
856 # ' <obj.bak >$objpath
857 #
858 # but we do not want to require the perl module for all test runs (nor
859 # carry a custom t/helper program that uses zlib features we don't
860 # otherwise care about).
861 mv "$objpath" obj.bak &&
862 test_when_finished 'mv obj.bak "$objpath"' &&
863 printf '\170\273\017\112\003\143' >$objpath &&
864
865 test_must_fail git cat-file blob $blob 2>err &&
866 test_grep ! 'too long' err &&
867 test_grep 'error: unable to unpack' err &&
868 test_grep 'error: inflate: needs dictionary' err
869EOT
870
871# Tests for git cat-file --follow-symlinks
872test_expect_success 'prep for symlink tests' '
873 echo_without_newline "$hello_content" >morx &&
874 test_ln_s_add morx same-dir-link &&
875 test_ln_s_add dir link-to-dir &&
876 test_ln_s_add ../fleem out-of-repo-link &&
877 test_ln_s_add .. out-of-repo-link-dir &&
878 test_ln_s_add same-dir-link link-to-link &&
879 test_ln_s_add nope broken-same-dir-link &&
880 mkdir dir &&
881 test_ln_s_add ../morx dir/parent-dir-link &&
882 test_ln_s_add .. dir/link-dir &&
883 test_ln_s_add ../../escape dir/out-of-repo-link &&
884 test_ln_s_add ../.. dir/out-of-repo-link-dir &&
885 test_ln_s_add nope dir/broken-link-in-dir &&
886 mkdir dir/subdir &&
887 test_ln_s_add ../../morx dir/subdir/grandparent-dir-link &&
888 test_ln_s_add ../../../great-escape dir/subdir/out-of-repo-link &&
889 test_ln_s_add ../../.. dir/subdir/out-of-repo-link-dir &&
890 test_ln_s_add ../../../ dir/subdir/out-of-repo-link-dir-trailing &&
891 test_ln_s_add ../parent-dir-link dir/subdir/parent-dir-link-to-link &&
892 echo_without_newline "$hello_content" >dir/subdir/ind2 &&
893 echo_without_newline "$hello_content" >dir/ind1 &&
894 test_ln_s_add dir dirlink &&
895 test_ln_s_add dir/subdir subdirlink &&
896 test_ln_s_add subdir/ind2 dir/link-to-child &&
897 test_ln_s_add dir/link-to-child link-to-down-link &&
898 test_ln_s_add dir/.. up-down &&
899 test_ln_s_add dir/../ up-down-trailing &&
900 test_ln_s_add dir/../morx up-down-file &&
901 test_ln_s_add dir/../../morx up-up-down-file &&
902 test_ln_s_add subdirlink/../../morx up-two-down-file &&
903 test_ln_s_add loop1 loop2 &&
904 test_ln_s_add loop2 loop1 &&
905 git add morx dir/subdir/ind2 dir/ind1 &&
906 git commit -am "test" &&
907 echo $hello_oid blob $hello_size >found
908'
909
910test_expect_success 'git cat-file --batch-check --follow-symlinks works for non-links' '
911 echo HEAD:morx | git cat-file --batch-check --follow-symlinks >actual &&
912 test_cmp found actual &&
913 echo HEAD:nope missing >expect &&
914 echo HEAD:nope | git cat-file --batch-check --follow-symlinks >actual &&
915 test_cmp expect actual
916'
917
918test_expect_success 'git cat-file --batch-check --follow-symlinks works for in-repo, same-dir links' '
919 echo HEAD:same-dir-link | git cat-file --batch-check --follow-symlinks >actual &&
920 test_cmp found actual
921'
922
923test_expect_success 'git cat-file --batch-check --follow-symlinks works for in-repo, links to dirs' '
924 echo HEAD:link-to-dir/ind1 | git cat-file --batch-check --follow-symlinks >actual &&
925 test_cmp found actual
926'
927
928
929test_expect_success 'git cat-file --batch-check --follow-symlinks works for broken in-repo, same-dir links' '
930 echo dangling 25 >expect &&
931 echo HEAD:broken-same-dir-link >>expect &&
932 echo HEAD:broken-same-dir-link | git cat-file --batch-check --follow-symlinks >actual &&
933 test_cmp expect actual
934'
935
936test_expect_success 'git cat-file --batch-check --follow-symlinks -Z works for broken in-repo, same-dir links' '
937 printf "HEAD:broken-same-dir-link\0" >in &&
938 printf "dangling 25\0HEAD:broken-same-dir-link\0" >expect &&
939 git cat-file --batch-check --follow-symlinks -Z <in >actual &&
940 test_cmp expect actual
941'
942
943test_expect_success 'git cat-file --batch-check --follow-symlinks works for same-dir links-to-links' '
944 echo HEAD:link-to-link | git cat-file --batch-check --follow-symlinks >actual &&
945 test_cmp found actual
946'
947
948test_expect_success 'git cat-file --batch-check --follow-symlinks works for parent-dir links' '
949 echo HEAD:dir/parent-dir-link | git cat-file --batch-check --follow-symlinks >actual &&
950 test_cmp found actual &&
951 echo notdir 29 >expect &&
952 echo HEAD:dir/parent-dir-link/nope >>expect &&
953 echo HEAD:dir/parent-dir-link/nope | git cat-file --batch-check --follow-symlinks >actual &&
954 test_cmp expect actual
955'
956
957test_expect_success 'git cat-file --batch-check --follow-symlinks -Z works for parent-dir links' '
958 echo HEAD:dir/parent-dir-link | git cat-file --batch-check --follow-symlinks >actual &&
959 test_cmp found actual &&
960 printf "notdir 29\0HEAD:dir/parent-dir-link/nope\0" >expect &&
961 printf "HEAD:dir/parent-dir-link/nope\0" >in &&
962 git cat-file --batch-check --follow-symlinks -Z <in >actual &&
963 test_cmp expect actual
964'
965
966test_expect_success 'git cat-file --batch-check --follow-symlinks works for .. links' '
967 echo dangling 22 >expect &&
968 echo HEAD:dir/link-dir/nope >>expect &&
969 echo HEAD:dir/link-dir/nope | git cat-file --batch-check --follow-symlinks >actual &&
970 test_cmp expect actual &&
971 echo HEAD:dir/link-dir/morx | git cat-file --batch-check --follow-symlinks >actual &&
972 test_cmp found actual &&
973 echo dangling 27 >expect &&
974 echo HEAD:dir/broken-link-in-dir >>expect &&
975 echo HEAD:dir/broken-link-in-dir | git cat-file --batch-check --follow-symlinks >actual &&
976 test_cmp expect actual
977'
978
979test_expect_success 'git cat-file --batch-check --follow-symlinks works for ../.. links' '
980 echo notdir 41 >expect &&
981 echo HEAD:dir/subdir/grandparent-dir-link/nope >>expect &&
982 echo HEAD:dir/subdir/grandparent-dir-link/nope | git cat-file --batch-check --follow-symlinks >actual &&
983 test_cmp expect actual &&
984 echo HEAD:dir/subdir/grandparent-dir-link | git cat-file --batch-check --follow-symlinks >actual &&
985 test_cmp found actual &&
986 echo HEAD:dir/subdir/parent-dir-link-to-link | git cat-file --batch-check --follow-symlinks >actual &&
987 test_cmp found actual
988'
989
990test_expect_success 'git cat-file --batch-check --follow-symlinks works for dir/ links' '
991 echo dangling 17 >expect &&
992 echo HEAD:dirlink/morx >>expect &&
993 echo HEAD:dirlink/morx | git cat-file --batch-check --follow-symlinks >actual &&
994 test_cmp expect actual &&
995 echo $hello_oid blob $hello_size >expect &&
996 echo HEAD:dirlink/ind1 | git cat-file --batch-check --follow-symlinks >actual &&
997 test_cmp expect actual
998'
999
1000test_expect_success 'git cat-file --batch-check --follow-symlinks works for dir/subdir links' '
1001 echo dangling 20 >expect &&
1002 echo HEAD:subdirlink/morx >>expect &&
1003 echo HEAD:subdirlink/morx | git cat-file --batch-check --follow-symlinks >actual &&
1004 test_cmp expect actual &&
1005 echo HEAD:subdirlink/ind2 | git cat-file --batch-check --follow-symlinks >actual &&
1006 test_cmp found actual
1007'
1008
1009test_expect_success 'git cat-file --batch-check --follow-symlinks works for dir ->subdir links' '
1010 echo notdir 27 >expect &&
1011 echo HEAD:dir/link-to-child/morx >>expect &&
1012 echo HEAD:dir/link-to-child/morx | git cat-file --batch-check --follow-symlinks >actual &&
1013 test_cmp expect actual &&
1014 echo HEAD:dir/link-to-child | git cat-file --batch-check --follow-symlinks >actual &&
1015 test_cmp found actual &&
1016 echo HEAD:link-to-down-link | git cat-file --batch-check --follow-symlinks >actual &&
1017 test_cmp found actual
1018'
1019
1020test_expect_success 'git cat-file --batch-check --follow-symlinks works for out-of-repo symlinks' '
1021 echo symlink 8 >expect &&
1022 echo ../fleem >>expect &&
1023 echo HEAD:out-of-repo-link | git cat-file --batch-check --follow-symlinks >actual &&
1024 test_cmp expect actual &&
1025 echo symlink 2 >expect &&
1026 echo .. >>expect &&
1027 echo HEAD:out-of-repo-link-dir | git cat-file --batch-check --follow-symlinks >actual &&
1028 test_cmp expect actual
1029'
1030
1031test_expect_success 'git cat-file --batch-check --follow-symlinks works for out-of-repo symlinks in dirs' '
1032 echo symlink 9 >expect &&
1033 echo ../escape >>expect &&
1034 echo HEAD:dir/out-of-repo-link | git cat-file --batch-check --follow-symlinks >actual &&
1035 test_cmp expect actual &&
1036 echo symlink 2 >expect &&
1037 echo .. >>expect &&
1038 echo HEAD:dir/out-of-repo-link-dir | git cat-file --batch-check --follow-symlinks >actual &&
1039 test_cmp expect actual
1040'
1041
1042test_expect_success 'git cat-file --batch-check --follow-symlinks works for out-of-repo symlinks in subdirs' '
1043 echo symlink 15 >expect &&
1044 echo ../great-escape >>expect &&
1045 echo HEAD:dir/subdir/out-of-repo-link | git cat-file --batch-check --follow-symlinks >actual &&
1046 test_cmp expect actual &&
1047 echo symlink 2 >expect &&
1048 echo .. >>expect &&
1049 echo HEAD:dir/subdir/out-of-repo-link-dir | git cat-file --batch-check --follow-symlinks >actual &&
1050 test_cmp expect actual &&
1051 echo symlink 3 >expect &&
1052 echo ../ >>expect &&
1053 echo HEAD:dir/subdir/out-of-repo-link-dir-trailing | git cat-file --batch-check --follow-symlinks >actual &&
1054 test_cmp expect actual
1055'
1056
1057test_expect_success 'git cat-file --batch-check --follow-symlinks works for symlinks with internal ..' '
1058 echo HEAD: | git cat-file --batch-check >expect &&
1059 echo HEAD:up-down | git cat-file --batch-check --follow-symlinks >actual &&
1060 test_cmp expect actual &&
1061 echo HEAD:up-down-trailing | git cat-file --batch-check --follow-symlinks >actual &&
1062 test_cmp expect actual &&
1063 echo HEAD:up-down-file | git cat-file --batch-check --follow-symlinks >actual &&
1064 test_cmp found actual &&
1065 echo symlink 7 >expect &&
1066 echo ../morx >>expect &&
1067 echo HEAD:up-up-down-file | git cat-file --batch-check --follow-symlinks >actual &&
1068 test_cmp expect actual &&
1069 echo HEAD:up-two-down-file | git cat-file --batch-check --follow-symlinks >actual &&
1070 test_cmp found actual
1071'
1072
1073test_expect_success 'git cat-file --batch-check --follow-symlink breaks loops' '
1074 echo loop 10 >expect &&
1075 echo HEAD:loop1 >>expect &&
1076 echo HEAD:loop1 | git cat-file --batch-check --follow-symlinks >actual &&
1077 test_cmp expect actual
1078'
1079
1080test_expect_success 'git cat-file --batch-check --follow-symlink -Z breaks loops' '
1081 printf "loop 10\0HEAD:loop1\0" >expect &&
1082 printf "HEAD:loop1\0" >in &&
1083 git cat-file --batch-check --follow-symlinks -Z <in >actual &&
1084 test_cmp expect actual
1085'
1086
1087test_expect_success 'git cat-file --batch --follow-symlink returns correct sha and mode' '
1088 echo HEAD:morx | git cat-file --batch >expect &&
1089 echo HEAD:morx | git cat-file --batch --follow-symlinks >actual &&
1090 test_cmp expect actual
1091'
1092
1093test_expect_success 'cat-file --batch-all-objects shows all objects' '
1094 # make new repos so we know the full set of objects; we will
1095 # also make sure that there are some packed and some loose
1096 # objects, some referenced and some not, some duplicates, and that
1097 # there are some available only via alternates.
1098 git init all-one &&
1099 (
1100 cd all-one &&
1101 echo content >file &&
1102 git add file &&
1103 git commit -qm base &&
1104 git rev-parse HEAD HEAD^{tree} HEAD:file &&
1105 git repack -ad &&
1106 echo not-cloned | git hash-object -w --stdin
1107 ) >expect.unsorted &&
1108 git clone -s all-one all-two &&
1109 (
1110 cd all-two &&
1111 echo local-unref | git hash-object -w --stdin
1112 ) >>expect.unsorted &&
1113 git -C all-two rev-parse HEAD:file |
1114 git -C all-two pack-objects .git/objects/pack/pack &&
1115 sort <expect.unsorted >expect &&
1116 git -C all-two cat-file --batch-all-objects \
1117 --batch-check="%(objectname)" >actual &&
1118 test_cmp expect actual
1119'
1120
1121# The only user-visible difference is that the objects are no longer sorted,
1122# and the resulting sort order is undefined. So we can only check that it
1123# produces the same objects as the ordered case, but that at least exercises
1124# the code.
1125test_expect_success 'cat-file --unordered works' '
1126 git -C all-two cat-file --batch-all-objects --unordered \
1127 --batch-check="%(objectname)" >actual.unsorted &&
1128 sort <actual.unsorted >actual &&
1129 test_cmp expect actual
1130'
1131
1132test_expect_success 'set up object list for --batch-all-objects tests' '
1133 git -C all-two cat-file --batch-all-objects --batch-check="%(objectname)" >objects
1134'
1135
1136test_expect_success 'cat-file --batch="%(objectname)" with --batch-all-objects will work' '
1137 git -C all-two cat-file --batch="%(objectname)" <objects >expect &&
1138 git -C all-two cat-file --batch-all-objects --batch="%(objectname)" >actual &&
1139 cmp expect actual
1140'
1141
1142test_expect_success 'cat-file --batch="%(rest)" with --batch-all-objects will work' '
1143 git -C all-two cat-file --batch="%(rest)" <objects >expect &&
1144 git -C all-two cat-file --batch-all-objects --batch="%(rest)" >actual &&
1145 cmp expect actual
1146'
1147
1148test_expect_success 'cat-file --batch="batman" with --batch-all-objects will work' '
1149 git -C all-two cat-file --batch="batman" <objects >expect &&
1150 git -C all-two cat-file --batch-all-objects --batch="batman" >actual &&
1151 cmp expect actual
1152'
1153
1154test_expect_success 'cat-file %(objectsize:disk) with --batch-all-objects' '
1155 # our state has both loose and packed objects,
1156 # so find both for our expected output
1157 {
1158 find .git/objects/?? -type f |
1159 awk -F/ "{ print \$0, \$3\$4 }" |
1160 while read path oid
1161 do
1162 size=$(test_file_size "$path") &&
1163 echo "$oid $size" ||
1164 return 1
1165 done &&
1166 rawsz=$(test_oid rawsz) &&
1167 find .git/objects/pack -name "*.idx" |
1168 while read idx
1169 do
1170 git show-index <"$idx" >idx.raw &&
1171 sort -nr <idx.raw >idx.sorted &&
1172 packsz=$(test_file_size "${idx%.idx}.pack") &&
1173 end=$((packsz - rawsz)) &&
1174 while read start oid rest
1175 do
1176 size=$((end - start)) &&
1177 end=$start &&
1178 echo "$oid $size" ||
1179 return 1
1180 done <idx.sorted ||
1181 return 1
1182 done
1183 } >expect.raw &&
1184 sort <expect.raw >expect &&
1185 git cat-file --batch-all-objects \
1186 --batch-check="%(objectname) %(objectsize:disk)" >actual &&
1187 test_cmp expect actual
1188'
1189
1190test_expect_success 'set up replacement object' '
1191 orig=$(git rev-parse HEAD) &&
1192 git cat-file commit $orig >orig &&
1193 {
1194 cat orig &&
1195 echo extra
1196 } >fake &&
1197 fake=$(git hash-object -t commit -w fake) &&
1198 orig_size=$(git cat-file -s $orig) &&
1199 fake_size=$(git cat-file -s $fake) &&
1200 git replace $orig $fake
1201'
1202
1203test_expect_success 'cat-file --batch respects replace objects' '
1204 git cat-file --batch >actual <<-EOF &&
1205 $orig
1206 EOF
1207 {
1208 echo "$orig commit $fake_size" &&
1209 cat fake &&
1210 echo
1211 } >expect &&
1212 test_cmp expect actual
1213'
1214
1215test_expect_success 'cat-file --batch-check respects replace objects' '
1216 git cat-file --batch-check >actual <<-EOF &&
1217 $orig
1218 EOF
1219 echo "$orig commit $fake_size" >expect &&
1220 test_cmp expect actual
1221'
1222
1223test_expect_success 'batch-check with a submodule' '
1224 # FIXME: this call to mktree is incompatible with compatObjectFormat
1225 # because the submodule OID cannot be mapped to the compat hash algo.
1226 test_unconfig extensions.compatobjectformat &&
1227 printf "160000 commit $(test_oid deadbeef)\tsub\n" >tree-with-sub &&
1228 tree=$(git mktree <tree-with-sub) &&
1229 test_config extensions.compatobjectformat $test_compat_hash_algo &&
1230
1231 git cat-file --batch-check >actual <<-EOF &&
1232 $tree:sub
1233 EOF
1234 printf "$(test_oid deadbeef) submodule\n" >expect &&
1235 test_cmp expect actual
1236'
1237
1238test_expect_success 'batch-check with a submodule, object exists' '
1239 printf "160000 commit $commit_oid\tsub\n" >tree-with-sub &&
1240 tree=$(git mktree <tree-with-sub) &&
1241 git cat-file --batch-check >actual <<-EOF &&
1242 $tree:sub
1243 EOF
1244 printf "$commit_oid commit $commit_size\n" >expect &&
1245 test_cmp expect actual
1246'
1247
1248# Pull the entry for object with oid "$1" out of the output of
1249# "cat-file --batch", including its object content (which requires
1250# parsing and reading a set amount of bytes, hence perl).
1251extract_batch_output () {
1252 perl -ne '
1253 BEGIN { $oid = shift }
1254 if (/^$oid \S+ (\d+)$/) {
1255 print;
1256 read STDIN, my $buf, $1;
1257 print $buf;
1258 print "\n";
1259 }
1260 ' "$@"
1261}
1262
1263test_expect_success PERL_TEST_HELPERS 'cat-file --batch-all-objects --batch ignores replace' '
1264 git cat-file --batch-all-objects --batch >actual.raw &&
1265 extract_batch_output $orig <actual.raw >actual &&
1266 {
1267 echo "$orig commit $orig_size" &&
1268 cat orig &&
1269 echo
1270 } >expect &&
1271 test_cmp expect actual
1272'
1273
1274test_expect_success 'cat-file --batch-all-objects --batch-check ignores replace' '
1275 git cat-file --batch-all-objects --batch-check >actual.raw &&
1276 grep ^$orig actual.raw >actual &&
1277 echo "$orig commit $orig_size" >expect &&
1278 test_cmp expect actual
1279'
1280test_expect_success 'batch-command empty command' '
1281 echo "" >cmd &&
1282 test_expect_code 128 git cat-file --batch-command <cmd 2>err &&
1283 grep "^fatal:.*empty command in input.*" err
1284'
1285
1286test_expect_success 'batch-command whitespace before command' '
1287 echo " info deadbeef" >cmd &&
1288 test_expect_code 128 git cat-file --batch-command <cmd 2>err &&
1289 grep "^fatal:.*whitespace before command.*" err
1290'
1291
1292test_expect_success 'batch-command unknown command' '
1293 echo unknown_command >cmd &&
1294 test_expect_code 128 git cat-file --batch-command <cmd 2>err &&
1295 grep "^fatal:.*unknown command.*" err
1296'
1297
1298test_expect_success 'batch-command missing arguments' '
1299 echo "info" >cmd &&
1300 test_expect_code 128 git cat-file --batch-command <cmd 2>err &&
1301 grep "^fatal:.*info requires arguments.*" err
1302'
1303
1304test_expect_success 'batch-command flush with arguments' '
1305 echo "flush arg" >cmd &&
1306 test_expect_code 128 git cat-file --batch-command --buffer <cmd 2>err &&
1307 grep "^fatal:.*flush takes no arguments.*" err
1308'
1309
1310test_expect_success 'batch-command flush without --buffer' '
1311 echo "flush" >cmd &&
1312 test_expect_code 128 git cat-file --batch-command <cmd 2>err &&
1313 grep "^fatal:.*flush is only for --buffer mode.*" err
1314'
1315
1316perl_script='
1317use warnings;
1318use strict;
1319use IPC::Open2;
1320my ($opt, $oid, $expect, @pfx) = @ARGV;
1321my @cmd = (qw(git cat-file), $opt);
1322my $pid = open2(my $out, my $in, @cmd) or die "open2: @cmd";
1323print $in @pfx, $oid, "\n" or die "print $!";
1324my $rvec = "";
1325vec($rvec, fileno($out), 1) = 1;
1326select($rvec, undef, undef, 30) or die "no response to `@pfx $oid` from @cmd";
1327my $info = <$out>;
1328chop($info) eq "\n" or die "no LF";
1329$info eq $expect or die "`$info` != `$expect`";
1330close $in or die "close in $!";
1331close $out or die "close out $!";
1332waitpid $pid, 0;
1333$? == 0 or die "\$?=$?";
1334'
1335
1336expect="$hello_oid blob $hello_size"
1337
1338test_lazy_prereq PERL_IPC_OPEN2 '
1339 perl -MIPC::Open2 -e "exit 0"
1340'
1341
1342test_expect_success PERL_IPC_OPEN2 '--batch-check is unbuffered by default' '
1343 perl -e "$perl_script" -- --batch-check $hello_oid "$expect"
1344'
1345
1346test_expect_success PERL_IPC_OPEN2 '--batch-command info is unbuffered by default' '
1347 perl -e "$perl_script" -- --batch-command $hello_oid "$expect" "info "
1348'
1349
1350test_expect_success 'setup for objects filter' '
1351 git init repo &&
1352 (
1353 # Seed the repository with four different sets of objects:
1354 #
1355 # - The first set is fully packed and has a bitmap.
1356 # - The second set is packed, but has no bitmap.
1357 # - The third set is loose.
1358 # - The fourth set is loose and contains big objects.
1359 #
1360 # This ensures that we cover all these types as expected.
1361 cd repo &&
1362 test_commit first &&
1363 git repack -Adb &&
1364 test_commit second &&
1365 git repack -d &&
1366 test_commit third &&
1367
1368 for n in 1000 10000
1369 do
1370 printf "%"$n"s" X >large.$n || return 1
1371 done &&
1372 git add large.* &&
1373 git commit -m fourth
1374 )
1375'
1376
1377test_expect_success 'objects filter with unknown option' '
1378 cat >expect <<-EOF &&
1379 fatal: invalid filter-spec ${SQ}unknown${SQ}
1380 EOF
1381 test_must_fail git -C repo cat-file --filter=unknown 2>err &&
1382 test_cmp expect err
1383'
1384
1385for option in sparse:oid=1234 tree:1 sparse:path=x
1386do
1387 test_expect_success "objects filter with unsupported option $option" '
1388 case "$option" in
1389 tree:1)
1390 echo "usage: objects filter not supported: ${SQ}tree${SQ}" >expect
1391 ;;
1392 sparse:path=x)
1393 echo "fatal: sparse:path filters support has been dropped" >expect
1394 ;;
1395 *)
1396 option_name=$(echo "$option" | cut -d= -f1) &&
1397 printf "usage: objects filter not supported: ${SQ}%s${SQ}\n" "$option_name" >expect
1398 ;;
1399 esac &&
1400 test_must_fail git -C repo cat-file --filter=$option 2>err &&
1401 test_cmp expect err
1402 '
1403done
1404
1405test_expect_success 'objects filter: disabled' '
1406 git -C repo cat-file --batch-check="%(objectname)" --batch-all-objects --no-filter >actual &&
1407 sort actual >actual.sorted &&
1408 git -C repo rev-list --objects --no-object-names --all >expect &&
1409 sort expect >expect.sorted &&
1410 test_cmp expect.sorted actual.sorted
1411'
1412
1413test_objects_filter () {
1414 filter="$1"
1415
1416 test_expect_success "objects filter: $filter" '
1417 git -C repo cat-file --batch-check="%(objectname)" --batch-all-objects --filter="$filter" >actual &&
1418 sort actual >actual.sorted &&
1419 git -C repo rev-list --objects --no-object-names --all --filter="$filter" --filter-provided-objects >expect &&
1420 sort expect >expect.sorted &&
1421 test_cmp expect.sorted actual.sorted
1422 '
1423
1424 test_expect_success "objects filter prints excluded objects: $filter" '
1425 # Find all objects that would be excluded by the current filter.
1426 git -C repo rev-list --objects --no-object-names --all >all &&
1427 git -C repo rev-list --objects --no-object-names --all --filter="$filter" --filter-provided-objects >filtered &&
1428 sort all >all.sorted &&
1429 sort filtered >filtered.sorted &&
1430 comm -23 all.sorted filtered.sorted >expected.excluded &&
1431 test_line_count -gt 0 expected.excluded &&
1432
1433 git -C repo cat-file --batch-check="%(objectname)" --filter="$filter" <expected.excluded >actual &&
1434 awk "/excluded/{ print \$1 }" actual | sort >actual.excluded &&
1435 test_cmp expected.excluded actual.excluded
1436 '
1437}
1438
1439test_objects_filter "blob:none"
1440test_objects_filter "blob:limit=1"
1441test_objects_filter "blob:limit=500"
1442test_objects_filter "blob:limit=1000"
1443test_objects_filter "blob:limit=1k"
1444test_objects_filter "object:type=blob"
1445test_objects_filter "object:type=commit"
1446test_objects_filter "object:type=tag"
1447test_objects_filter "object:type=tree"
1448
1449test_done