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