summaryrefslogtreecommitdiff
path: root/t
diff options
context:
space:
mode:
Diffstat (limited to 't')
-rw-r--r--t/.gitattributes1
-rw-r--r--t/README32
-rwxr-xr-xt/t0040-parse-options.sh116
-rwxr-xr-xt/t1400-update-ref.sh8
-rwxr-xr-xt/t1502-rev-parse-parseopt.sh4
-rwxr-xr-xt/t3800-mktag.sh4
-rwxr-xr-xt/t3903-stash.sh2
-rwxr-xr-xt/t4014-format-patch.sh6
-rwxr-xr-xt/t4015-diff-whitespace.sh8
-rwxr-xr-xt/t4016-diff-quote.sh14
-rwxr-xr-xt/t4109-apply-multifrag.sh132
-rw-r--r--t/t4109/patch1.patch28
-rw-r--r--t/t4109/patch2.patch30
-rw-r--r--t/t4109/patch3.patch31
-rw-r--r--t/t4109/patch4.patch30
-rwxr-xr-xt/t4119-apply-config.sh4
-rwxr-xr-xt/t4150-am.sh2
-rwxr-xr-xt/t5000-tar-tree.sh9
-rwxr-xr-xt/t5302-pack-index.sh14
-rwxr-xr-xt/t5303-pack-corruption-resilience.sh194
-rwxr-xr-xt/t5540-http-push.sh2
-rwxr-xr-xt/t5601-clone.sh22
-rwxr-xr-xt/t7502-commit.sh6
-rwxr-xr-xt/t7502-status.sh98
-rwxr-xr-xt/t9123-git-svn-rebuild-with-rewriteroot.sh32
-rwxr-xr-xt/t9301-fast-export.sh23
-rwxr-xr-xt/t9700-perl-git.sh39
-rwxr-xr-xt/t9700/test.pl100
-rw-r--r--t/test-lib.sh60
29 files changed, 891 insertions, 160 deletions
diff --git a/t/.gitattributes b/t/.gitattributes
index ab6edbf19e..1b97c5465b 100644
--- a/t/.gitattributes
+++ b/t/.gitattributes
@@ -1,2 +1 @@
-t[0-9][0-9][0-9][0-9]-*.sh -whitespace
t[0-9][0-9][0-9][0-9]/* -whitespace
diff --git a/t/README b/t/README
index 70841a4645..8f12d48fe8 100644
--- a/t/README
+++ b/t/README
@@ -54,6 +54,38 @@ You can pass --verbose (or -v), --debug (or -d), and --immediate
This causes the test to immediately exit upon the first
failed test.
+--long-tests::
+ This causes additional long-running tests to be run (where
+ available), for more exhaustive testing.
+
+
+Skipping Tests
+--------------
+
+In some environments, certain tests have no way of succeeding
+due to platform limitation, such as lack of 'unzip' program, or
+filesystem that do not allow arbitrary sequence of non-NUL bytes
+as pathnames.
+
+You should be able to say something like
+
+ $ GIT_SKIP_TESTS=t9200.8 sh ./t9200-git-cvsexport-commit.sh
+
+and even:
+
+ $ GIT_SKIP_TESTS='t[0-4]??? t91?? t9200.8' make
+
+to omit such tests. The value of the environment variable is a
+SP separated list of patterns that tells which tests to skip,
+and either can match the "t[0-9]{4}" part to skip the whole
+test, or t[0-9]{4} followed by ".$number" to say which
+particular test to skip.
+
+Note that some tests in the existing test suite rely on previous
+test item, so you cannot arbitrarily disable one and expect the
+remainder of test to check what the test originally was intended
+to check.
+
Naming Tests
------------
diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh
index 9965cfa1dc..6309aed451 100755
--- a/t/t0040-parse-options.sh
+++ b/t/t0040-parse-options.sh
@@ -11,23 +11,35 @@ cat > expect.err << EOF
usage: test-parse-options <options>
-b, --boolean get a boolean
+ -4, --or4 bitwise-or boolean with ...0100
+
-i, --integer <n> get a integer
-j <n> get a integer, too
+ --set23 set integer to 23
+ -t <time> get timestamp of <time>
+ -L, --length <str> get length of <str>
-string options
+String options
-s, --string <string>
get a string
--string2 <str> get another string
--st <st> get another string (pervert ordering)
-o <str> get another string
+ --default-string set string to default
-magic arguments
+Magic arguments
--quux means --quux
+Standard options
+ --abbrev[=<n>] use <n> digits to display SHA-1s
+ -v, --verbose be verbose
+ -n, --dry-run dry run
+ -q, --quiet be quiet
+
EOF
test_expect_success 'test help' '
- ! test-parse-options -h > output 2> output.err &&
+ test_must_fail test-parse-options -h > output 2> output.err &&
test ! -s output &&
test_cmp expect.err output.err
'
@@ -36,21 +48,31 @@ cat > expect << EOF
boolean: 2
integer: 1729
string: 123
+abbrev: 7
+verbose: 2
+quiet: no
+dry run: yes
EOF
test_expect_success 'short options' '
- test-parse-options -s123 -b -i 1729 -b > output 2> output.err &&
+ test-parse-options -s123 -b -i 1729 -b -vv -n > output 2> output.err &&
test_cmp expect output &&
test ! -s output.err
'
+
cat > expect << EOF
boolean: 2
integer: 1729
string: 321
+abbrev: 10
+verbose: 2
+quiet: no
+dry run: no
EOF
test_expect_success 'long options' '
test-parse-options --boolean --integer 1729 --boolean --string2=321 \
+ --verbose --verbose --no-dry-run --abbrev=10 \
> output 2> output.err &&
test ! -s output.err &&
test_cmp expect output
@@ -60,6 +82,10 @@ cat > expect << EOF
boolean: 1
integer: 13
string: 123
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
arg 00: a1
arg 01: b1
arg 02: --boolean
@@ -76,6 +102,10 @@ cat > expect << EOF
boolean: 0
integer: 2
string: (not set)
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
EOF
test_expect_success 'unambiguously abbreviated option' '
@@ -99,6 +129,10 @@ cat > expect << EOF
boolean: 0
integer: 0
string: 123
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
EOF
test_expect_success 'non ambiguous option (after two options it abbreviates)' '
@@ -107,20 +141,24 @@ test_expect_success 'non ambiguous option (after two options it abbreviates)' '
test_cmp expect output
'
-cat > expect.err << EOF
+cat > typo.err << EOF
error: did you mean \`--boolean\` (with two dashes ?)
EOF
test_expect_success 'detect possible typos' '
- ! test-parse-options -boolean > output 2> output.err &&
+ test_must_fail test-parse-options -boolean > output 2> output.err &&
test ! -s output &&
- test_cmp expect.err output.err
+ test_cmp typo.err output.err
'
cat > expect <<EOF
boolean: 0
integer: 0
string: (not set)
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
arg 00: --quux
EOF
@@ -130,4 +168,68 @@ test_expect_success 'keep some options as arguments' '
test_cmp expect output
'
+cat > expect <<EOF
+boolean: 0
+integer: 1
+string: default
+abbrev: 7
+verbose: 0
+quiet: yes
+dry run: no
+arg 00: foo
+EOF
+
+test_expect_success 'OPT_DATE() and OPT_SET_PTR() work' '
+ test-parse-options -t "1970-01-01 00:00:01 +0000" --default-string \
+ foo -q > output 2> output.err &&
+ test ! -s output.err &&
+ test_cmp expect output
+'
+
+cat > expect <<EOF
+Callback: "four", 0
+boolean: 5
+integer: 4
+string: (not set)
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
+EOF
+
+test_expect_success 'OPT_CALLBACK() and OPT_BIT() work' '
+ test-parse-options --length=four -b -4 > output 2> output.err &&
+ test ! -s output.err &&
+ test_cmp expect output
+'
+
+cat > expect <<EOF
+Callback: "not set", 1
+EOF
+
+test_expect_success 'OPT_CALLBACK() and callback errors work' '
+ test_must_fail test-parse-options --no-length > output 2> output.err &&
+ test_cmp expect output &&
+ test_cmp expect.err output.err
+'
+
+cat > expect <<EOF
+boolean: 1
+integer: 23
+string: (not set)
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
+EOF
+
+test_expect_success 'OPT_BIT() and OPT_SET_INT() work' '
+ test-parse-options --set23 -bbbbb --no-or4 > output 2> output.err &&
+ test ! -s output.err &&
+ test_cmp expect output
+'
+
+# --or4
+# --no-or4
+
test_done
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index b8b7ab4103..f387d46f1a 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -42,6 +42,14 @@ test_expect_success "delete $m" '
'
rm -f .git/$m
+test_expect_success "delete $m without oldvalue verification" "
+ git update-ref $m $A &&
+ test $A = \$(cat .git/$m) &&
+ git update-ref -d $m &&
+ ! test -f .git/$m
+"
+rm -f .git/$m
+
test_expect_success \
"fail to create $n" \
"touch .git/$n_dir
diff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh
index d24a47d114..997002d4c4 100755
--- a/t/t1502-rev-parse-parseopt.sh
+++ b/t/t1502-rev-parse-parseopt.sh
@@ -5,7 +5,7 @@ test_description='test git rev-parse --parseopt'
cat > expect.err <<EOF
usage: some-command [options] <args>...
-
+
some-command does foo and bar!
-h, --help show the help
@@ -13,7 +13,7 @@ usage: some-command [options] <args>...
--bar ... some cool option --bar with an argument
An option group Header
- -C [...] option C with an optional argument
+ -C[...] option C with an optional argument
Extras
--extra1 line above used to cause a segfault but no longer does
diff --git a/t/t3800-mktag.sh b/t/t3800-mktag.sh
index df1fd6f86f..c851db8ca9 100755
--- a/t/t3800-mktag.sh
+++ b/t/t3800-mktag.sh
@@ -241,11 +241,11 @@ check_verify_failure 'disallow spaces in tag email' \
############################################################
# 17. disallow missing tag timestamp
-cat >tag.sig <<EOF
+tr '_' ' ' >tag.sig <<EOF
object $head
type commit
tag mytag
-tagger T A Gger <tagger@example.com>
+tagger T A Gger <tagger@example.com>__
EOF
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 2d3ee3b78c..54d99ed0c3 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -41,7 +41,7 @@ test_expect_success 'apply needs clean working directory' '
echo 4 > other-file &&
git add other-file &&
echo 5 > other-file &&
- test_must_fail git stash apply
+ test_must_fail git stash apply
'
test_expect_success 'apply stashed changes' '
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 3583e68e92..7fe853c20d 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -98,7 +98,7 @@ test_expect_success 'extra headers' '
sed -e "/^$/q" patch2 > hdrs2 &&
grep "^To: R. E. Cipient <rcipient@example.com>$" hdrs2 &&
grep "^Cc: S. E. Cipient <scipient@example.com>$" hdrs2
-
+
'
test_expect_success 'extra headers without newlines' '
@@ -109,7 +109,7 @@ test_expect_success 'extra headers without newlines' '
sed -e "/^$/q" patch3 > hdrs3 &&
grep "^To: R. E. Cipient <rcipient@example.com>$" hdrs3 &&
grep "^Cc: S. E. Cipient <scipient@example.com>$" hdrs3
-
+
'
test_expect_success 'extra headers with multiple To:s' '
@@ -170,7 +170,7 @@ test_expect_success 'thread cover-letter' '
git checkout side &&
git format-patch --cover-letter --thread -o patches/ master &&
FIRST_MID=$(grep "Message-Id:" patches/0000-* | sed "s/^[^<]*\(<[^>]*>\).*$/\1/") &&
- for i in patches/0001-* patches/0002-* patches/0003-*
+ for i in patches/0001-* patches/0002-* patches/0003-*
do
grep "References: $FIRST_MID" $i &&
grep "In-Reply-To: $FIRST_MID" $i || break
diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh
index ca0302f41b..b7cc6b28e6 100755
--- a/t/t4015-diff-whitespace.sh
+++ b/t/t4015-diff-whitespace.sh
@@ -62,16 +62,16 @@ EOF
git update-index x
-cat << EOF > x
+tr '_' ' ' << EOF > x
whitespace at beginning
whitespace change
white space in the middle
-whitespace at end
+whitespace at end__
unchanged line
CR at end
EOF
-tr 'Q' '\015' << EOF > expect
+tr 'Q_' '\015 ' << EOF > expect
diff --git a/x b/x
index d99af23..8b32fb5 100644
--- a/x
@@ -84,7 +84,7 @@ index d99af23..8b32fb5 100644
+ whitespace at beginning
+whitespace change
+white space in the middle
-+whitespace at end
++whitespace at end__
unchanged line
-CR at endQ
+CR at end
diff --git a/t/t4016-diff-quote.sh b/t/t4016-diff-quote.sh
index 0950250c9b..f07035ab7e 100755
--- a/t/t4016-diff-quote.sh
+++ b/t/t4016-diff-quote.sh
@@ -53,13 +53,13 @@ test_expect_success 'git diff --summary -M HEAD' '
'
cat >expect <<\EOF
- pathname.1 => "Rpathname\twith HT.0" | 0
- pathname.3 => "Rpathname\nwith LF.0" | 0
- "pathname\twith HT.3" => "Rpathname\nwith LF.1" | 0
- pathname.2 => Rpathname with SP.0 | 0
- "pathname\twith HT.2" => Rpathname with SP.1 | 0
- pathname.0 => Rpathname.0 | 0
- "pathname\twith HT.0" => Rpathname.1 | 0
+ pathname.1 => "Rpathname\twith HT.0" | 0
+ pathname.3 => "Rpathname\nwith LF.0" | 0
+ "pathname\twith HT.3" => "Rpathname\nwith LF.1" | 0
+ pathname.2 => Rpathname with SP.0 | 0
+ "pathname\twith HT.2" => Rpathname with SP.1 | 0
+ pathname.0 => Rpathname.0 | 0
+ "pathname\twith HT.0" => Rpathname.1 | 0
7 files changed, 0 insertions(+), 0 deletions(-)
EOF
test_expect_success 'git diff --stat -M HEAD' '
diff --git a/t/t4109-apply-multifrag.sh b/t/t4109-apply-multifrag.sh
index bd40a218cd..ff5fdf35f9 100755
--- a/t/t4109-apply-multifrag.sh
+++ b/t/t4109-apply-multifrag.sh
@@ -9,134 +9,10 @@ test_description='git apply test patches with multiple fragments.
'
. ./test-lib.sh
-# setup
-
-cat > patch1.patch <<\EOF
-diff --git a/main.c b/main.c
-new file mode 100644
---- /dev/null
-+++ b/main.c
-@@ -0,0 +1,23 @@
-+#include <stdio.h>
-+
-+int func(int num);
-+void print_int(int num);
-+
-+int main() {
-+ int i;
-+
-+ for (i = 0; i < 10; i++) {
-+ print_int(func(i));
-+ }
-+
-+ return 0;
-+}
-+
-+int func(int num) {
-+ return num * num;
-+}
-+
-+void print_int(int num) {
-+ printf("%d", num);
-+}
-+
-EOF
-cat > patch2.patch <<\EOF
-diff --git a/main.c b/main.c
---- a/main.c
-+++ b/main.c
-@@ -1,7 +1,9 @@
-+#include <stdlib.h>
- #include <stdio.h>
-
- int func(int num);
- void print_int(int num);
-+void print_ln();
-
- int main() {
- int i;
-@@ -10,6 +12,8 @@
- print_int(func(i));
- }
-
-+ print_ln();
-+
- return 0;
- }
-
-@@ -21,3 +25,7 @@
- printf("%d", num);
- }
-
-+void print_ln() {
-+ printf("\n");
-+}
-+
-EOF
-cat > patch3.patch <<\EOF
-diff --git a/main.c b/main.c
---- a/main.c
-+++ b/main.c
-@@ -1,9 +1,7 @@
--#include <stdlib.h>
- #include <stdio.h>
-
- int func(int num);
- void print_int(int num);
--void print_ln();
-
- int main() {
- int i;
-@@ -12,8 +10,6 @@
- print_int(func(i));
- }
-
-- print_ln();
--
- return 0;
- }
-
-@@ -25,7 +21,3 @@
- printf("%d", num);
- }
-
--void print_ln() {
-- printf("\n");
--}
--
-EOF
-cat > patch4.patch <<\EOF
-diff --git a/main.c b/main.c
---- a/main.c
-+++ b/main.c
-@@ -1,13 +1,14 @@
- #include <stdio.h>
-
- int func(int num);
--void print_int(int num);
-+int func2(int num);
-
- int main() {
- int i;
-
- for (i = 0; i < 10; i++) {
-- print_int(func(i));
-+ printf("%d", func(i));
-+ printf("%d", func3(i));
- }
-
- return 0;
-@@ -17,7 +18,7 @@
- return num * num;
- }
-
--void print_int(int num) {
-- printf("%d", num);
-+int func2(int num) {
-+ return num * num * num;
- }
-
-EOF
+cp ../t4109/patch1.patch .
+cp ../t4109/patch2.patch .
+cp ../t4109/patch3.patch .
+cp ../t4109/patch4.patch .
test_expect_success "S = git apply (1)" \
'git apply patch1.patch patch2.patch'
diff --git a/t/t4109/patch1.patch b/t/t4109/patch1.patch
new file mode 100644
index 0000000000..1d411fc3cc
--- /dev/null
+++ b/t/t4109/patch1.patch
@@ -0,0 +1,28 @@
+diff --git a/main.c b/main.c
+new file mode 100644
+--- /dev/null
++++ b/main.c
+@@ -0,0 +1,23 @@
++#include <stdio.h>
++
++int func(int num);
++void print_int(int num);
++
++int main() {
++ int i;
++
++ for (i = 0; i < 10; i++) {
++ print_int(func(i));
++ }
++
++ return 0;
++}
++
++int func(int num) {
++ return num * num;
++}
++
++void print_int(int num) {
++ printf("%d", num);
++}
++
diff --git a/t/t4109/patch2.patch b/t/t4109/patch2.patch
new file mode 100644
index 0000000000..8c6b06d536
--- /dev/null
+++ b/t/t4109/patch2.patch
@@ -0,0 +1,30 @@
+diff --git a/main.c b/main.c
+--- a/main.c
++++ b/main.c
+@@ -1,7 +1,9 @@
++#include <stdlib.h>
+ #include <stdio.h>
+
+ int func(int num);
+ void print_int(int num);
++void print_ln();
+
+ int main() {
+ int i;
+@@ -10,6 +12,8 @@
+ print_int(func(i));
+ }
+
++ print_ln();
++
+ return 0;
+ }
+
+@@ -21,3 +25,7 @@
+ printf("%d", num);
+ }
+
++void print_ln() {
++ printf("\n");
++}
++
diff --git a/t/t4109/patch3.patch b/t/t4109/patch3.patch
new file mode 100644
index 0000000000..d696c55a75
--- /dev/null
+++ b/t/t4109/patch3.patch
@@ -0,0 +1,31 @@
+cat > patch3.patch <<\EOF
+diff --git a/main.c b/main.c
+--- a/main.c
++++ b/main.c
+@@ -1,9 +1,7 @@
+-#include <stdlib.h>
+ #include <stdio.h>
+
+ int func(int num);
+ void print_int(int num);
+-void print_ln();
+
+ int main() {
+ int i;
+@@ -12,8 +10,6 @@
+ print_int(func(i));
+ }
+
+- print_ln();
+-
+ return 0;
+ }
+
+@@ -25,7 +21,3 @@
+ printf("%d", num);
+ }
+
+-void print_ln() {
+- printf("\n");
+-}
+-
diff --git a/t/t4109/patch4.patch b/t/t4109/patch4.patch
new file mode 100644
index 0000000000..4b085909b1
--- /dev/null
+++ b/t/t4109/patch4.patch
@@ -0,0 +1,30 @@
+diff --git a/main.c b/main.c
+--- a/main.c
++++ b/main.c
+@@ -1,13 +1,14 @@
+ #include <stdio.h>
+
+ int func(int num);
+-void print_int(int num);
++int func2(int num);
+
+ int main() {
+ int i;
+
+ for (i = 0; i < 10; i++) {
+- print_int(func(i));
++ printf("%d", func(i));
++ printf("%d", func3(i));
+ }
+
+ return 0;
+@@ -17,7 +18,7 @@
+ return num * num;
+ }
+
+-void print_int(int num) {
+- printf("%d", num);
++int func2(int num) {
++ return num * num * num;
+ }
+
diff --git a/t/t4119-apply-config.sh b/t/t4119-apply-config.sh
index b540f7295a..3c73a783a7 100755
--- a/t/t4119-apply-config.sh
+++ b/t/t4119-apply-config.sh
@@ -19,12 +19,12 @@ test_expect_success setup '
'
# Also handcraft GNU diff output; note this has trailing whitespace.
-cat >gpatch.file <<\EOF &&
+tr '_' ' ' >gpatch.file <<\EOF &&
--- file1 2007-02-21 01:04:24.000000000 -0800
+++ file1+ 2007-02-21 01:07:44.000000000 -0800
@@ -1 +1 @@
-A
-+B
++B_
EOF
sed -e 's|file1|sub/&|' gpatch.file >gpatch-sub.file &&
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 722ae96cd5..bc982607d0 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -110,7 +110,7 @@ test_expect_success 'am applies patch correctly' '
GIT_AUTHOR_NAME="Another Thor"
GIT_AUTHOR_EMAIL="a.thor@example.com"
-GIT_COMMITTER_NAME="Co M Miter"
+GIT_COMMITTER_NAME="Co M Miter"
GIT_COMMITTER_EMAIL="c.miter@example.com"
export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index 9b0baac8db..3f1e25d921 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -45,6 +45,11 @@ test_expect_success \
(cd a && find .) | sort >a.lst'
test_expect_success \
+ 'add ignored file' \
+ 'echo ignore me >a/ignored &&
+ echo ignored export-ignore >.gitattributes'
+
+test_expect_success \
'add files to repository' \
'find a -type f | xargs git update-index --add &&
find a -type l | xargs git update-index --add &&
@@ -54,6 +59,10 @@ test_expect_success \
git commit-tree $treeid </dev/null)'
test_expect_success \
+ 'remove ignored file' \
+ 'rm a/ignored'
+
+test_expect_success \
'git archive' \
'git archive HEAD >b.tar'
diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh
index 09fd917672..ecec591634 100755
--- a/t/t5302-pack-index.sh
+++ b/t/t5302-pack-index.sh
@@ -162,4 +162,18 @@ test_expect_success \
'[index v2] 5) pack-objects refuses to reuse corrupted data' \
'! git pack-objects test-5 <obj-list'
+test_expect_success \
+ '[index v2] 6) verify-pack detects CRC mismatch' \
+ 'rm -f .git/objects/pack/* &&
+ git-index-pack --index-version=2 --stdin < "test-1-${pack1}.pack" &&
+ git verify-pack ".git/objects/pack/pack-${pack1}.pack" &&
+ chmod +w ".git/objects/pack/pack-${pack1}.idx" &&
+ dd if=/dev/zero of=".git/objects/pack/pack-${pack1}.idx" conv=notrunc \
+ bs=1 count=4 seek=$((8 + 256 * 4 + `wc -l <obj-list` * 20 + 0)) &&
+ ( while read obj
+ do git cat-file -p $obj >/dev/null || exit 1
+ done <obj-list ) &&
+ err=$(! git verify-pack ".git/objects/pack/pack-${pack1}.pack" 2>&1) &&
+ echo "$err" | grep "CRC mismatch"'
+
test_done
diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh
new file mode 100755
index 0000000000..b0f5693482
--- /dev/null
+++ b/t/t5303-pack-corruption-resilience.sh
@@ -0,0 +1,194 @@
+#!/bin/sh
+#
+# Copyright (c) 2008 Nicolas Pitre
+#
+
+test_description='resilience to pack corruptions with redundant objects'
+. ./test-lib.sh
+
+# Note: the test objects are created with knowledge of their pack encoding
+# to ensure good code path coverage, and to facilitate direct alteration
+# later on. The assumed characteristics are:
+#
+# 1) blob_2 is a delta with blob_1 for base and blob_3 is a delta with blob2
+# for base, such that blob_3 delta depth is 2;
+#
+# 2) the bulk of object data is uncompressible so the text part remains
+# visible;
+#
+# 3) object header is always 2 bytes.
+
+create_test_files() {
+ test-genrandom "foo" 2000 > file_1 &&
+ test-genrandom "foo" 1800 > file_2 &&
+ test-genrandom "foo" 1800 > file_3 &&
+ echo " base " >> file_1 &&
+ echo " delta1 " >> file_2 &&
+ echo " delta delta2 " >> file_3 &&
+ test-genrandom "bar" 150 >> file_2 &&
+ test-genrandom "baz" 100 >> file_3
+}
+
+create_new_pack() {
+ rm -rf .git &&
+ git init &&
+ blob_1=`git hash-object -t blob -w file_1` &&
+ blob_2=`git hash-object -t blob -w file_2` &&
+ blob_3=`git hash-object -t blob -w file_3` &&
+ pack=`printf "$blob_1\n$blob_2\n$blob_3\n" |
+ git pack-objects $@ .git/objects/pack/pack` &&
+ pack=".git/objects/pack/pack-${pack}" &&
+ git verify-pack -v ${pack}.pack
+}
+
+do_corrupt_object() {
+ ofs=`git show-index < ${pack}.idx | grep $1 | cut -f1 -d" "` &&
+ ofs=$(($ofs + $2)) &&
+ chmod +w ${pack}.pack &&
+ dd if=/dev/zero of=${pack}.pack count=1 bs=1 conv=notrunc seek=$ofs &&
+ test_must_fail git verify-pack ${pack}.pack
+}
+
+test_expect_success \
+ 'initial setup validation' \
+ 'create_test_files &&
+ create_new_pack &&
+ git prune-packed &&
+ git cat-file blob $blob_1 > /dev/null &&
+ git cat-file blob $blob_2 > /dev/null &&
+ git cat-file blob $blob_3 > /dev/null'
+
+test_expect_success \
+ 'create corruption in header of first object' \
+ 'do_corrupt_object $blob_1 0 &&
+ test_must_fail git cat-file blob $blob_1 > /dev/null &&
+ test_must_fail git cat-file blob $blob_2 > /dev/null &&
+ test_must_fail git cat-file blob $blob_3 > /dev/null'
+
+test_expect_success \
+ '... but having a loose copy allows for full recovery' \
+ 'mv ${pack}.idx tmp &&
+ git hash-object -t blob -w file_1 &&
+ mv tmp ${pack}.idx &&
+ git cat-file blob $blob_1 > /dev/null &&
+ git cat-file blob $blob_2 > /dev/null &&
+ git cat-file blob $blob_3 > /dev/null'
+
+test_expect_success \
+ '... and loose copy of first delta allows for partial recovery' \
+ 'git prune-packed &&
+ test_must_fail git cat-file blob $blob_2 > /dev/null &&
+ mv ${pack}.idx tmp &&
+ git hash-object -t blob -w file_2 &&
+ mv tmp ${pack}.idx &&
+ test_must_fail git cat-file blob $blob_1 > /dev/null &&
+ git cat-file blob $blob_2 > /dev/null &&
+ git cat-file blob $blob_3 > /dev/null'
+
+test_expect_success \
+ 'create corruption in data of first object' \
+ 'create_new_pack &&
+ git prune-packed &&
+ chmod +w ${pack}.pack &&
+ perl -i -pe "s/ base /abcdef/" ${pack}.pack &&
+ test_must_fail git cat-file blob $blob_1 > /dev/null &&
+ test_must_fail git cat-file blob $blob_2 > /dev/null &&
+ test_must_fail git cat-file blob $blob_3 > /dev/null'
+
+test_expect_success \
+ '... but having a loose copy allows for full recovery' \
+ 'mv ${pack}.idx tmp &&
+ git hash-object -t blob -w file_1 &&
+ mv tmp ${pack}.idx &&
+ git cat-file blob $blob_1 > /dev/null &&
+ git cat-file blob $blob_2 > /dev/null &&
+ git cat-file blob $blob_3 > /dev/null'
+
+test_expect_success \
+ '... and loose copy of second object allows for partial recovery' \
+ 'git prune-packed &&
+ test_must_fail git cat-file blob $blob_2 > /dev/null &&
+ mv ${pack}.idx tmp &&
+ git hash-object -t blob -w file_2 &&
+ mv tmp ${pack}.idx &&
+ test_must_fail git cat-file blob $blob_1 > /dev/null &&
+ git cat-file blob $blob_2 > /dev