]> git.ipfire.org Git - thirdparty/git.git/blobdiff - t/t9300-fast-import.sh
The fifth batch
[thirdparty/git.git] / t / t9300-fast-import.sh
index 60e30fed3c2cfc22b2b4190655685a428ce36289..1e68426852f92c2fe4a7bb4eeea199e910df04dd 100755 (executable)
@@ -1059,30 +1059,33 @@ test_expect_success 'M: rename subdirectory to new subdirectory' '
        compare_diff_raw expect actual
 '
 
-test_expect_success 'M: rename root to subdirectory' '
-       cat >input <<-INPUT_END &&
-       commit refs/heads/M4
-       committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
-       data <<COMMIT
-       rename root
-       COMMIT
+for root in '""' ''
+do
+       test_expect_success "M: rename root ($root) to subdirectory" '
+               cat >input <<-INPUT_END &&
+               commit refs/heads/M4
+               committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+               data <<COMMIT
+               rename root
+               COMMIT
 
-       from refs/heads/M2^0
-       R "" sub
+               from refs/heads/M2^0
+               R $root sub
 
-       INPUT_END
+               INPUT_END
 
-       cat >expect <<-EOF &&
-       :100644 100644 $oldf $oldf R100 file2/oldf      sub/file2/oldf
-       :100755 100755 $f4id $f4id R100 file4   sub/file4
-       :100755 100755 $newf $newf R100 i/am/new/to/you sub/i/am/new/to/you
-       :100755 100755 $f6id $f6id R100 newdir/exec.sh  sub/newdir/exec.sh
-       :100644 100644 $f5id $f5id R100 newdir/interesting      sub/newdir/interesting
-       EOF
-       git fast-import <input &&
-       git diff-tree -M -r M4^ M4 >actual &&
-       compare_diff_raw expect actual
-'
+               cat >expect <<-EOF &&
+               :100644 100644 $oldf $oldf R100 file2/oldf      sub/file2/oldf
+               :100755 100755 $f4id $f4id R100 file4   sub/file4
+               :100755 100755 $newf $newf R100 i/am/new/to/you sub/i/am/new/to/you
+               :100755 100755 $f6id $f6id R100 newdir/exec.sh  sub/newdir/exec.sh
+               :100644 100644 $f5id $f5id R100 newdir/interesting      sub/newdir/interesting
+               EOF
+               git fast-import <input &&
+               git diff-tree -M -r M4^ M4 >actual &&
+               compare_diff_raw expect actual
+       '
+done
 
 ###
 ### series N
@@ -1259,49 +1262,52 @@ test_expect_success PIPE 'N: empty directory reads as missing' '
        test_cmp expect actual
 '
 
-test_expect_success 'N: copy root directory by tree hash' '
-       cat >expect <<-EOF &&
-       :100755 000000 $newf $zero D    file3/newf
-       :100644 000000 $oldf $zero D    file3/oldf
-       EOF
-       root=$(git rev-parse refs/heads/branch^0^{tree}) &&
-       cat >input <<-INPUT_END &&
-       commit refs/heads/N6
-       committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
-       data <<COMMIT
-       copy root directory by tree hash
-       COMMIT
-
-       from refs/heads/branch^0
-       M 040000 $root ""
-       INPUT_END
-       git fast-import <input &&
-       git diff-tree -C --find-copies-harder -r N4 N6 >actual &&
-       compare_diff_raw expect actual
-'
+for root in '""' ''
+do
+       test_expect_success "N: copy root ($root) by tree hash" '
+               cat >expect <<-EOF &&
+               :100755 000000 $newf $zero D    file3/newf
+               :100644 000000 $oldf $zero D    file3/oldf
+               EOF
+               root_tree=$(git rev-parse refs/heads/branch^0^{tree}) &&
+               cat >input <<-INPUT_END &&
+               commit refs/heads/N6
+               committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+               data <<COMMIT
+               copy root directory by tree hash
+               COMMIT
 
-test_expect_success 'N: copy root by path' '
-       cat >expect <<-EOF &&
-       :100755 100755 $newf $newf C100 file2/newf      oldroot/file2/newf
-       :100644 100644 $oldf $oldf C100 file2/oldf      oldroot/file2/oldf
-       :100755 100755 $f4id $f4id C100 file4   oldroot/file4
-       :100755 100755 $f6id $f6id C100 newdir/exec.sh  oldroot/newdir/exec.sh
-       :100644 100644 $f5id $f5id C100 newdir/interesting      oldroot/newdir/interesting
-       EOF
-       cat >input <<-INPUT_END &&
-       commit refs/heads/N-copy-root-path
-       committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
-       data <<COMMIT
-       copy root directory by (empty) path
-       COMMIT
+               from refs/heads/branch^0
+               M 040000 $root_tree $root
+               INPUT_END
+               git fast-import <input &&
+               git diff-tree -C --find-copies-harder -r N4 N6 >actual &&
+               compare_diff_raw expect actual
+       '
+
+       test_expect_success "N: copy root ($root) by path" '
+               cat >expect <<-EOF &&
+               :100755 100755 $newf $newf C100 file2/newf      oldroot/file2/newf
+               :100644 100644 $oldf $oldf C100 file2/oldf      oldroot/file2/oldf
+               :100755 100755 $f4id $f4id C100 file4   oldroot/file4
+               :100755 100755 $f6id $f6id C100 newdir/exec.sh  oldroot/newdir/exec.sh
+               :100644 100644 $f5id $f5id C100 newdir/interesting      oldroot/newdir/interesting
+               EOF
+               cat >input <<-INPUT_END &&
+               commit refs/heads/N-copy-root-path
+               committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+               data <<COMMIT
+               copy root directory by (empty) path
+               COMMIT
 
-       from refs/heads/branch^0
-       C "" oldroot
-       INPUT_END
-       git fast-import <input &&
-       git diff-tree -C --find-copies-harder -r branch N-copy-root-path >actual &&
-       compare_diff_raw expect actual
-'
+               from refs/heads/branch^0
+               C $root oldroot
+               INPUT_END
+               git fast-import <input &&
+               git diff-tree -C --find-copies-harder -r branch N-copy-root-path >actual &&
+               compare_diff_raw expect actual
+       '
+done
 
 test_expect_success 'N: delete directory by copying' '
        cat >expect <<-\EOF &&
@@ -1431,98 +1437,102 @@ test_expect_success 'N: reject foo/ syntax in ls argument' '
        INPUT_END
 '
 
-test_expect_success 'N: copy to root by id and modify' '
-       echo "hello, world" >expect.foo &&
-       echo hello >expect.bar &&
-       git fast-import <<-SETUP_END &&
-       commit refs/heads/N7
-       committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
-       data <<COMMIT
-       hello, tree
-       COMMIT
-
-       deleteall
-       M 644 inline foo/bar
-       data <<EOF
-       hello
-       EOF
-       SETUP_END
-
-       tree=$(git rev-parse --verify N7:) &&
-       git fast-import <<-INPUT_END &&
-       commit refs/heads/N8
-       committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
-       data <<COMMIT
-       copy to root by id and modify
-       COMMIT
+for root in '""' ''
+do
+       test_expect_success "N: copy to root ($root) by id and modify" '
+               echo "hello, world" >expect.foo &&
+               echo hello >expect.bar &&
+               git fast-import <<-SETUP_END &&
+               commit refs/heads/N7
+               committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+               data <<COMMIT
+               hello, tree
+               COMMIT
 
-       M 040000 $tree ""
-       M 644 inline foo/foo
-       data <<EOF
-       hello, world
-       EOF
-       INPUT_END
-       git show N8:foo/foo >actual.foo &&
-       git show N8:foo/bar >actual.bar &&
-       test_cmp expect.foo actual.foo &&
-       test_cmp expect.bar actual.bar
-'
+               deleteall
+               M 644 inline foo/bar
+               data <<EOF
+               hello
+               EOF
+               SETUP_END
 
-test_expect_success 'N: extract subtree' '
-       branch=$(git rev-parse --verify refs/heads/branch^{tree}) &&
-       cat >input <<-INPUT_END &&
-       commit refs/heads/N9
-       committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
-       data <<COMMIT
-       extract subtree branch:newdir
-       COMMIT
+               tree=$(git rev-parse --verify N7:) &&
+               git fast-import <<-INPUT_END &&
+               commit refs/heads/N8
+               committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+               data <<COMMIT
+               copy to root by id and modify
+               COMMIT
 
-       M 040000 $branch ""
-       C "newdir" ""
-       INPUT_END
-       git fast-import <input &&
-       git diff --exit-code branch:newdir N9
-'
+               M 040000 $tree $root
+               M 644 inline foo/foo
+               data <<EOF
+               hello, world
+               EOF
+               INPUT_END
+               git show N8:foo/foo >actual.foo &&
+               git show N8:foo/bar >actual.bar &&
+               test_cmp expect.foo actual.foo &&
+               test_cmp expect.bar actual.bar
+       '
+
+       test_expect_success "N: extract subtree to the root ($root)" '
+               branch=$(git rev-parse --verify refs/heads/branch^{tree}) &&
+               cat >input <<-INPUT_END &&
+               commit refs/heads/N9
+               committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+               data <<COMMIT
+               extract subtree branch:newdir
+               COMMIT
 
-test_expect_success 'N: modify subtree, extract it, and modify again' '
-       echo hello >expect.baz &&
-       echo hello, world >expect.qux &&
-       git fast-import <<-SETUP_END &&
-       commit refs/heads/N10
-       committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
-       data <<COMMIT
-       hello, tree
-       COMMIT
+               M 040000 $branch $root
+               C "newdir" $root
+               INPUT_END
+               git fast-import <input &&
+               git diff --exit-code branch:newdir N9
+       '
+
+       test_expect_success "N: modify subtree, extract it to the root ($root), and modify again" '
+               echo hello >expect.baz &&
+               echo hello, world >expect.qux &&
+               git fast-import <<-SETUP_END &&
+               commit refs/heads/N10
+               committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+               data <<COMMIT
+               hello, tree
+               COMMIT
 
-       deleteall
-       M 644 inline foo/bar/baz
-       data <<EOF
-       hello
-       EOF
-       SETUP_END
+               deleteall
+               M 644 inline foo/bar/baz
+               data <<EOF
+               hello
+               EOF
+               SETUP_END
 
-       tree=$(git rev-parse --verify N10:) &&
-       git fast-import <<-INPUT_END &&
-       commit refs/heads/N11
-       committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
-       data <<COMMIT
-       copy to root by id and modify
-       COMMIT
+               tree=$(git rev-parse --verify N10:) &&
+               git fast-import <<-INPUT_END &&
+               commit refs/heads/N11
+               committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+               data <<COMMIT
+               copy to root by id and modify
+               COMMIT
 
-       M 040000 $tree ""
-       M 100644 inline foo/bar/qux
-       data <<EOF
-       hello, world
-       EOF
-       R "foo" ""
-       C "bar/qux" "bar/quux"
-       INPUT_END
-       git show N11:bar/baz >actual.baz &&
-       git show N11:bar/qux >actual.qux &&
-       git show N11:bar/quux >actual.quux &&
-       test_cmp expect.baz actual.baz &&
-       test_cmp expect.qux actual.qux &&
-       test_cmp expect.qux actual.quux'
+               M 040000 $tree $root
+               M 100644 inline foo/bar/qux
+               data <<EOF
+               hello, world
+               EOF
+               R "foo" $root
+               C "bar/qux" "bar/quux"
+               INPUT_END
+               git show N11:bar/baz >actual.baz &&
+               git show N11:bar/qux >actual.qux &&
+               git show N11:bar/quux >actual.quux &&
+               test_cmp expect.baz actual.baz &&
+               test_cmp expect.qux actual.qux &&
+               test_cmp expect.qux actual.quux
+       '
+done
 
 ###
 ### series O
@@ -2142,6 +2152,7 @@ test_expect_success 'Q: deny note on empty branch' '
        EOF
        test_must_fail git fast-import <input
 '
+
 ###
 ### series R (feature and option)
 ###
@@ -2790,7 +2801,7 @@ test_expect_success 'R: blob appears only once' '
 '
 
 ###
-### series S
+### series S (mark and path parsing)
 ###
 #
 # Make sure missing spaces and EOLs after mark references
@@ -3060,21 +3071,283 @@ test_expect_success 'S: ls with garbage after sha1 must fail' '
        test_grep "space after tree-ish" err
 '
 
+#
+# Path parsing
+#
+# There are two sorts of ways a path can be parsed, depending on whether it is
+# the last field on the line. Additionally, ls without a <dataref> has a special
+# case. Test every occurrence of <path> in the grammar against every error case.
+# Paths for the root (empty strings) are tested elsewhere.
+#
+
+#
+# Valid paths at the end of a line: filemodify, filedelete, filecopy (dest),
+# filerename (dest), and ls.
+#
+# commit :301 from root -- modify hello.c (for setup)
+# commit :302 from :301 -- modify $path
+# commit :303 from :302 -- delete $path
+# commit :304 from :301 -- copy hello.c $path
+# commit :305 from :301 -- rename hello.c $path
+# ls :305 $path
+#
+test_path_eol_success () {
+       local test="$1" path="$2" unquoted_path="$3"
+       test_expect_success "S: paths at EOL with $test must work" '
+               test_when_finished "git branch -D S-path-eol" &&
+
+               git fast-import --export-marks=marks.out <<-EOF >out 2>err &&
+               blob
+               mark :401
+               data <<BLOB
+               hello world
+               BLOB
+
+               blob
+               mark :402
+               data <<BLOB
+               hallo welt
+               BLOB
+
+               commit refs/heads/S-path-eol
+               mark :301
+               committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+               data <<COMMIT
+               initial commit
+               COMMIT
+               M 100644 :401 hello.c
+
+               commit refs/heads/S-path-eol
+               mark :302
+               committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+               data <<COMMIT
+               commit filemodify
+               COMMIT
+               from :301
+               M 100644 :402 $path
+
+               commit refs/heads/S-path-eol
+               mark :303
+               committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+               data <<COMMIT
+               commit filedelete
+               COMMIT
+               from :302
+               D $path
+
+               commit refs/heads/S-path-eol
+               mark :304
+               committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+               data <<COMMIT
+               commit filecopy dest
+               COMMIT
+               from :301
+               C hello.c $path
+
+               commit refs/heads/S-path-eol
+               mark :305
+               committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+               data <<COMMIT
+               commit filerename dest
+               COMMIT
+               from :301
+               R hello.c $path
+
+               ls :305 $path
+               EOF
+
+               commit_m=$(grep :302 marks.out | cut -d\  -f2) &&
+               commit_d=$(grep :303 marks.out | cut -d\  -f2) &&
+               commit_c=$(grep :304 marks.out | cut -d\  -f2) &&
+               commit_r=$(grep :305 marks.out | cut -d\  -f2) &&
+               blob1=$(grep :401 marks.out | cut -d\  -f2) &&
+               blob2=$(grep :402 marks.out | cut -d\  -f2) &&
+
+               (
+                       printf "100644 blob $blob2\t$unquoted_path\n" &&
+                       printf "100644 blob $blob1\thello.c\n"
+               ) | sort >tree_m.exp &&
+               git ls-tree $commit_m | sort >tree_m.out &&
+               test_cmp tree_m.exp tree_m.out &&
+
+               printf "100644 blob $blob1\thello.c\n" >tree_d.exp &&
+               git ls-tree $commit_d >tree_d.out &&
+               test_cmp tree_d.exp tree_d.out &&
+
+               (
+                       printf "100644 blob $blob1\t$unquoted_path\n" &&
+                       printf "100644 blob $blob1\thello.c\n"
+               ) | sort >tree_c.exp &&
+               git ls-tree $commit_c | sort >tree_c.out &&
+               test_cmp tree_c.exp tree_c.out &&
+
+               printf "100644 blob $blob1\t$unquoted_path\n" >tree_r.exp &&
+               git ls-tree $commit_r >tree_r.out &&
+               test_cmp tree_r.exp tree_r.out &&
+
+               test_cmp out tree_r.exp
+       '
+}
+
+test_path_eol_success 'quoted spaces'   '" hello world.c "'  ' hello world.c '
+test_path_eol_success 'unquoted spaces' ' hello world.c '    ' hello world.c '
+test_path_eol_success 'octal escapes'   '"\150\151\056\143"' 'hi.c'
+
+#
+# Valid paths before a space: filecopy (source) and filerename (source).
+#
+# commit :301 from root -- modify $path (for setup)
+# commit :302 from :301 -- copy $path hello2.c
+# commit :303 from :301 -- rename $path hello2.c
+#
+test_path_space_success () {
+       local test="$1" path="$2" unquoted_path="$3"
+       test_expect_success "S: paths before space with $test must work" '
+               test_when_finished "git branch -D S-path-space" &&
+
+               git fast-import --export-marks=marks.out <<-EOF 2>err &&
+               blob
+               mark :401
+               data <<BLOB
+               hello world
+               BLOB
+
+               commit refs/heads/S-path-space
+               mark :301
+               committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+               data <<COMMIT
+               initial commit
+               COMMIT
+               M 100644 :401 $path
+
+               commit refs/heads/S-path-space
+               mark :302
+               committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+               data <<COMMIT
+               commit filecopy source
+               COMMIT
+               from :301
+               C $path hello2.c
+
+               commit refs/heads/S-path-space
+               mark :303
+               committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+               data <<COMMIT
+               commit filerename source
+               COMMIT
+               from :301
+               R $path hello2.c
+
+               EOF
+
+               commit_c=$(grep :302 marks.out | cut -d\  -f2) &&
+               commit_r=$(grep :303 marks.out | cut -d\  -f2) &&
+               blob=$(grep :401 marks.out | cut -d\  -f2) &&
+
+               (
+                       printf "100644 blob $blob\t$unquoted_path\n" &&
+                       printf "100644 blob $blob\thello2.c\n"
+               ) | sort >tree_c.exp &&
+               git ls-tree $commit_c | sort >tree_c.out &&
+               test_cmp tree_c.exp tree_c.out &&
+
+               printf "100644 blob $blob\thello2.c\n" >tree_r.exp &&
+               git ls-tree $commit_r >tree_r.out &&
+               test_cmp tree_r.exp tree_r.out
+       '
+}
+
+test_path_space_success 'quoted spaces'      '" hello world.c "'  ' hello world.c '
+test_path_space_success 'no unquoted spaces' 'hello_world.c'      'hello_world.c'
+test_path_space_success 'octal escapes'      '"\150\151\056\143"' 'hi.c'
+
+#
+# Test a single commit change with an invalid path. Run it with all occurrences
+# of <path> in the grammar against all error kinds.
+#
+test_path_fail () {
+       local change="$1" what="$2" prefix="$3" path="$4" suffix="$5" err_grep="$6"
+       test_expect_success "S: $change with $what must fail" '
+               test_must_fail git fast-import <<-EOF 2>err &&
+               blob
+               mark :1
+               data <<BLOB
+               hello world
+               BLOB
+
+               commit refs/heads/S-path-fail
+               mark :2
+               committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+               data <<COMMIT
+               commit setup
+               COMMIT
+               M 100644 :1 hello.c
+
+               commit refs/heads/S-path-fail
+               committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+               data <<COMMIT
+               commit with bad path
+               COMMIT
+               from :2
+               $prefix$path$suffix
+               EOF
+
+               test_grep "$err_grep" err
+       '
+}
+
+test_path_base_fail () {
+       local change="$1" prefix="$2" field="$3" suffix="$4"
+       test_path_fail "$change" 'unclosed " in '"$field"          "$prefix" '"hello.c'    "$suffix" "Invalid $field"
+       test_path_fail "$change" "invalid escape in quoted $field" "$prefix" '"hello\xff"' "$suffix" "Invalid $field"
+       test_path_fail "$change" "escaped NUL in quoted $field"    "$prefix" '"hello\000"' "$suffix" "NUL in $field"
+}
+test_path_eol_quoted_fail () {
+       local change="$1" prefix="$2" field="$3"
+       test_path_base_fail "$change" "$prefix" "$field" ''
+       test_path_fail "$change" "garbage after quoted $field" "$prefix" '"hello.c"' 'x' "Garbage after $field"
+       test_path_fail "$change" "space after quoted $field"   "$prefix" '"hello.c"' ' ' "Garbage after $field"
+}
+test_path_eol_fail () {
+       local change="$1" prefix="$2" field="$3"
+       test_path_eol_quoted_fail "$change" "$prefix" "$field"
+}
+test_path_space_fail () {
+       local change="$1" prefix="$2" field="$3"
+       test_path_base_fail "$change" "$prefix" "$field" ' world.c'
+       test_path_fail "$change" "missing space after quoted $field"   "$prefix" '"hello.c"' 'x world.c' "Missing space after $field"
+       test_path_fail "$change" "missing space after unquoted $field" "$prefix" 'hello.c'   ''          "Missing space after $field"
+}
+
+test_path_eol_fail   filemodify       'M 100644 :1 ' path
+test_path_eol_fail   filedelete       'D '           path
+test_path_space_fail filecopy         'C '           source
+test_path_eol_fail   filecopy         'C hello.c '   dest
+test_path_space_fail filerename       'R '           source
+test_path_eol_fail   filerename       'R hello.c '   dest
+test_path_eol_fail   'ls (in commit)' 'ls :2 '       path
+
+# When 'ls' has no <dataref>, the <path> must be quoted.
+test_path_eol_quoted_fail 'ls (without dataref in commit)' 'ls ' path
+
 ###
 ### series T (ls)
 ###
 # Setup is carried over from series S.
 
-test_expect_success 'T: ls root tree' '
-       sed -e "s/Z\$//" >expect <<-EOF &&
-       040000 tree $(git rev-parse S^{tree})   Z
-       EOF
-       sha1=$(git rev-parse --verify S) &&
-       git fast-import --import-marks=marks <<-EOF >actual &&
-       ls $sha1 ""
-       EOF
-       test_cmp expect actual
-'
+for root in '""' ''
+do
+       test_expect_success "T: ls root ($root) tree" '
+               sed -e "s/Z\$//" >expect <<-EOF &&
+               040000 tree $(git rev-parse S^{tree})   Z
+               EOF
+               sha1=$(git rev-parse --verify S) &&
+               git fast-import --import-marks=marks <<-EOF >actual &&
+               ls $sha1 $root
+               EOF
+               test_cmp expect actual
+       '
+done
 
 test_expect_success 'T: delete branch' '
        git branch to-delete &&
@@ -3176,30 +3449,33 @@ test_expect_success 'U: validate directory delete result' '
        compare_diff_raw expect actual
 '
 
-test_expect_success 'U: filedelete root succeeds' '
-       cat >input <<-INPUT_END &&
-       commit refs/heads/U
-       committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
-       data <<COMMIT
-       must succeed
-       COMMIT
-       from refs/heads/U^0
-       D ""
+for root in '""' ''
+do
+       test_expect_success "U: filedelete root ($root) succeeds" '
+               cat >input <<-INPUT_END &&
+               commit refs/heads/U-delete-root
+               committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+               data <<COMMIT
+               must succeed
+               COMMIT
+               from refs/heads/U^0
+               D $root
 
-       INPUT_END
+               INPUT_END
 
-       git fast-import <input
-'
+               git fast-import <input
+       '
 
-test_expect_success 'U: validate root delete result' '
-       cat >expect <<-EOF &&
-       :100644 000000 $f7id $ZERO_OID D        hello.c
-       EOF
+       test_expect_success "U: validate root ($root) delete result" '
+               cat >expect <<-EOF &&
+               :100644 000000 $f7id $ZERO_OID D        hello.c
+               EOF
 
-       git diff-tree -M -r U^1 U >actual &&
+               git diff-tree -M -r U U-delete-root >actual &&
 
-       compare_diff_raw expect actual
-'
+               compare_diff_raw expect actual
+       '
+done
 
 ###
 ### series V (checkpoint)