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