Merge branch 'jt/submodule-tests-cleanup'
[gitweb.git] / t / lib-submodule-update.sh
index bb94c2320958eb1d1a319899697ecefc881e3043..38dadd2c2902f3621d54168d32a54d7863497968 100755 (executable)
@@ -554,6 +554,10 @@ test_submodule_switch_common() {
 #  - if succeeds, once "git submodule update" is invoked, the contents of
 #    submodule directories are updated
 #
+# If the command under test is known to not work with submodules in certain
+# conditions, set the appropriate KNOWN_FAILURE_* variable used in the tests
+# below to 1.
+#
 # Use as follows:
 #
 # my_func () {
@@ -622,19 +626,11 @@ test_submodule_forced_switch () {
 # - Removing a submodule with a git directory absorbs the submodules
 #   git directory first into the superproject.
 
-test_submodule_switch_recursing_with_args () {
-       cmd_args="$1"
-       command="git $cmd_args --recurse-submodules"
-       RESULTDS=success
-       if test "$KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS" = 1
-       then
-               RESULTDS=failure
-       fi
-       RESULTOI=success
-       if test "$KNOWN_FAILURE_SUBMODULE_OVERWRITE_IGNORED_UNTRACKED" = 1
-       then
-               RESULTOI=failure
-       fi
+# Internal function; use test_submodule_switch_recursing_with_args() or
+# test_submodule_forced_switch_recursing_with_args() instead.
+test_submodule_recursing_with_args_common() {
+       command="$1"
+
        ######################### Appearing submodule #########################
        # Switching to a commit letting a submodule appear checks it out ...
        test_expect_success "$command: added submodule is checked out" '
@@ -648,7 +644,7 @@ test_submodule_switch_recursing_with_args () {
                        test_submodule_content sub1 origin/add_sub1
                )
        '
-       # ... ignoring an empty existing directory ...
+       # ... ignoring an empty existing directory.
        test_expect_success "$command: added submodule is checked out in empty dir" '
                prolog &&
                reset_work_tree_to_interested no_submodule &&
@@ -661,34 +657,23 @@ test_submodule_switch_recursing_with_args () {
                        test_submodule_content sub1 origin/add_sub1
                )
        '
-       # ... unless there is an untracked file in its place.
-       test_expect_success "$command: added submodule doesn't remove untracked file with same name" '
-               prolog &&
-               reset_work_tree_to_interested no_submodule &&
-               (
-                       cd submodule_update &&
-                       git branch -t add_sub1 origin/add_sub1 &&
-                       : >sub1 &&
-                       test_must_fail $command add_sub1 &&
-                       test_superproject_content origin/no_submodule &&
-                       test_must_be_empty sub1
-               )
-       '
-       # ... but an ignored file is fine.
-       test_expect_$RESULTOI "$command: added submodule removes an untracked ignored file" '
-               test_when_finished "rm submodule_update/.git/info/exclude" &&
+       test_expect_success "$command: submodule branch is not changed, detach HEAD instead" '
                prolog &&
-               reset_work_tree_to_interested no_submodule &&
+               reset_work_tree_to_interested add_sub1 &&
                (
                        cd submodule_update &&
-                       git branch -t add_sub1 origin/add_sub1 &&
-                       : >sub1 &&
-                       echo sub1 >.git/info/exclude
-                       $command add_sub1 &&
-                       test_superproject_content origin/add_sub1 &&
-                       test_submodule_content sub1 origin/add_sub1
+                       git -C sub1 checkout -b keep_branch &&
+                       git -C sub1 rev-parse HEAD >expect &&
+                       git branch -t check-keep origin/modify_sub1 &&
+                       $command check-keep &&
+                       test_superproject_content origin/modify_sub1 &&
+                       test_submodule_content sub1 origin/modify_sub1 &&
+                       git -C sub1 rev-parse keep_branch >actual &&
+                       test_cmp expect actual &&
+                       test_must_fail git -C sub1 symbolic-ref HEAD
                )
        '
+
        # Replacing a tracked file with a submodule produces a checked out submodule
        test_expect_success "$command: replace tracked file with submodule checks out submodule" '
                prolog &&
@@ -742,33 +727,6 @@ test_submodule_switch_recursing_with_args () {
                        test_git_directory_exists sub1
                )
        '
-       # Replacing a submodule with files in a directory must succeeds
-       # when the submodule is clean
-       test_expect_$RESULTDS "$command: replace submodule with a directory" '
-               prolog &&
-               reset_work_tree_to_interested add_sub1 &&
-               (
-                       cd submodule_update &&
-                       git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
-                       $command replace_sub1_with_directory &&
-                       test_superproject_content origin/replace_sub1_with_directory &&
-                       test_submodule_content sub1 origin/replace_sub1_with_directory
-               )
-       '
-       # ... absorbing a .git directory.
-       test_expect_$RESULTDS "$command: replace submodule containing a .git directory with a directory must absorb the git dir" '
-               prolog &&
-               reset_work_tree_to_interested add_sub1 &&
-               (
-                       cd submodule_update &&
-                       git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
-                       replace_gitfile_with_git_dir sub1 &&
-                       rm -rf .git/modules &&
-                       $command replace_sub1_with_directory &&
-                       test_superproject_content origin/replace_sub1_with_directory &&
-                       test_git_directory_exists sub1
-               )
-       '
 
        # Replacing it with a file ...
        test_expect_success "$command: replace submodule with a file" '
@@ -782,7 +740,11 @@ test_submodule_switch_recursing_with_args () {
                        test -f sub1
                )
        '
-
+       RESULTDS=success
+       if test "$KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS" = 1
+       then
+               RESULTDS=failure
+       fi
        # ... must check its local work tree for untracked files
        test_expect_$RESULTDS "$command: replace submodule with a file must fail with untracked files" '
                prolog &&
@@ -794,21 +756,7 @@ test_submodule_switch_recursing_with_args () {
                        test_must_fail $command replace_sub1_with_file &&
                        test_superproject_content origin/add_sub1 &&
                        test_submodule_content sub1 origin/add_sub1
-               )
-       '
-
-       # ... and ignored files are ignored
-       test_expect_success "$command: replace submodule with a file works ignores ignored files in submodule" '
-               test_when_finished "rm submodule_update/.git/modules/sub1/info/exclude" &&
-               prolog &&
-               reset_work_tree_to_interested add_sub1 &&
-               (
-                       cd submodule_update &&
-                       git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
-                       : >sub1/ignored &&
-                       $command replace_sub1_with_file &&
-                       test_superproject_content origin/replace_sub1_with_file &&
-                       test -f sub1
+                       test -f sub1/untracked_file
                )
        '
 
@@ -825,19 +773,6 @@ test_submodule_switch_recursing_with_args () {
                        test_submodule_content sub1 origin/modify_sub1
                )
        '
-
-       test_expect_success "git -c submodule.recurse=true $cmd_args: modified submodule updates submodule work tree" '
-               prolog &&
-               reset_work_tree_to_interested add_sub1 &&
-               (
-                       cd submodule_update &&
-                       git branch -t modify_sub1 origin/modify_sub1 &&
-                       git -c submodule.recurse=true $cmd_args modify_sub1 &&
-                       test_superproject_content origin/modify_sub1 &&
-                       test_submodule_content sub1 origin/modify_sub1
-               )
-       '
-
        # Updating a submodule to an invalid sha1 doesn't update the
        # superproject nor the submodule's work tree.
        test_expect_success "$command: updating to a missing submodule commit fails" '
@@ -851,126 +786,166 @@ test_submodule_switch_recursing_with_args () {
                        test_submodule_content sub1 origin/add_sub1
                )
        '
-
-       # recursing deeper than one level doesn't work yet.
-       test_expect_success "$command: modified submodule updates submodule recursively" '
-               prolog &&
-               reset_work_tree_to_interested add_nested_sub &&
-               (
-                       cd submodule_update &&
-                       git branch -t modify_sub1_recursively origin/modify_sub1_recursively &&
-                       $command modify_sub1_recursively &&
-                       test_superproject_content origin/modify_sub1_recursively &&
-                       test_submodule_content sub1 origin/modify_sub1_recursively &&
-                       test_submodule_content -C sub1 sub2 origin/modify_sub1_recursively
-               )
-       '
 }
 
-# Test that submodule contents are updated when switching between commits
-# that change a submodule, but throwing away local changes in
-# the superproject as well as the submodule is allowed.
-test_submodule_forced_switch_recursing_with_args () {
+# Declares and invokes several tests that, in various situations, checks that
+# the provided Git command, when invoked with --recurse-submodules:
+#  - succeeds in updating the worktree and index of a superproject to a target
+#    commit, or fails atomically (depending on the test situation)
+#  - if succeeds, the contents of submodule directories are updated
+#
+# Specify the Git command so that "git $GIT_COMMAND --recurse-submodules"
+# works.
+#
+# If the command under test is known to not work with submodules in certain
+# conditions, set the appropriate KNOWN_FAILURE_* variable used in the tests
+# below to 1.
+#
+# Use as follows:
+#
+# test_submodule_switch_recursing_with_args "$GIT_COMMAND"
+test_submodule_switch_recursing_with_args () {
        cmd_args="$1"
        command="git $cmd_args --recurse-submodules"
-       RESULT=success
+       test_submodule_recursing_with_args_common "$command"
+
+       RESULTDS=success
        if test "$KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS" = 1
        then
-               RESULT=failure
+               RESULTDS=failure
        fi
-       ######################### Appearing submodule #########################
-       # Switching to a commit letting a submodule appear creates empty dir ...
-       test_expect_success "$command: added submodule is checked out" '
+       RESULTOI=success
+       if test "$KNOWN_FAILURE_SUBMODULE_OVERWRITE_IGNORED_UNTRACKED" = 1
+       then
+               RESULTOI=failure
+       fi
+       # Switching to a commit letting a submodule appear cannot override an
+       # untracked file.
+       test_expect_success "$command: added submodule doesn't remove untracked file with same name" '
                prolog &&
                reset_work_tree_to_interested no_submodule &&
                (
                        cd submodule_update &&
                        git branch -t add_sub1 origin/add_sub1 &&
-                       $command add_sub1 &&
-                       test_superproject_content origin/add_sub1 &&
-                       test_submodule_content sub1 origin/add_sub1
+                       : >sub1 &&
+                       test_must_fail $command add_sub1 &&
+                       test_superproject_content origin/no_submodule &&
+                       test_must_be_empty sub1
                )
        '
-       # ... and doesn't care if it already exists ...
-       test_expect_success "$command: added submodule ignores empty directory" '
+       # ... but an ignored file is fine.
+       test_expect_$RESULTOI "$command: added submodule removes an untracked ignored file" '
+               test_when_finished "rm submodule_update/.git/info/exclude" &&
                prolog &&
                reset_work_tree_to_interested no_submodule &&
                (
                        cd submodule_update &&
                        git branch -t add_sub1 origin/add_sub1 &&
-                       mkdir sub1 &&
+                       : >sub1 &&
+                       echo sub1 >.git/info/exclude
                        $command add_sub1 &&
                        test_superproject_content origin/add_sub1 &&
                        test_submodule_content sub1 origin/add_sub1
                )
        '
-       # ... not caring about an untracked file either
-       test_expect_success "$command: added submodule does remove untracked unignored file with same name when forced" '
+
+       # Replacing a submodule with files in a directory must succeeds
+       # when the submodule is clean
+       test_expect_$RESULTDS "$command: replace submodule with a directory" '
                prolog &&
-               reset_work_tree_to_interested no_submodule &&
+               reset_work_tree_to_interested add_sub1 &&
                (
                        cd submodule_update &&
-                       git branch -t add_sub1 origin/add_sub1 &&
-                       >sub1 &&
-                       $command add_sub1 &&
-                       test_superproject_content origin/add_sub1 &&
-                       test_submodule_content sub1 origin/add_sub1
+                       git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
+                       $command replace_sub1_with_directory &&
+                       test_superproject_content origin/replace_sub1_with_directory &&
+                       test_submodule_content sub1 origin/replace_sub1_with_directory
                )
        '
-       # Replacing a tracked file with a submodule checks out the submodule
-       test_expect_success "$command: replace tracked file with submodule populates the submodule" '
+       # ... absorbing a .git directory.
+       test_expect_$RESULTDS "$command: replace submodule containing a .git directory with a directory must absorb the git dir" '
                prolog &&
-               reset_work_tree_to_interested replace_sub1_with_file &&
+               reset_work_tree_to_interested add_sub1 &&
                (
                        cd submodule_update &&
-                       git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&
-                       $command replace_file_with_sub1 &&
-                       test_superproject_content origin/replace_file_with_sub1 &&
-                       test_submodule_content sub1 origin/replace_file_with_sub1
+                       git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
+                       replace_gitfile_with_git_dir sub1 &&
+                       rm -rf .git/modules &&
+                       $command replace_sub1_with_directory &&
+                       test_superproject_content origin/replace_sub1_with_directory &&
+                       test_git_directory_exists sub1
                )
        '
-       # ... as does removing a directory with tracked files with a
-       # submodule.
-       test_expect_success "$command: replace directory with submodule" '
+
+       # ... and ignored files are ignored
+       test_expect_success "$command: replace submodule with a file works ignores ignored files in submodule" '
+               test_when_finished "rm submodule_update/.git/modules/sub1/info/exclude" &&
                prolog &&
-               reset_work_tree_to_interested replace_sub1_with_directory &&
+               reset_work_tree_to_interested add_sub1 &&
                (
                        cd submodule_update &&
-                       git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
-                       $command replace_directory_with_sub1 &&
-                       test_superproject_content origin/replace_directory_with_sub1 &&
-                       test_submodule_content sub1 origin/replace_directory_with_sub1
+                       git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
+                       : >sub1/ignored &&
+                       $command replace_sub1_with_file &&
+                       test_superproject_content origin/replace_sub1_with_file &&
+                       test -f sub1
                )
        '
 
-       ######################## Disappearing submodule #######################
-       # Removing a submodule doesn't remove its work tree ...
-       test_expect_success "$command: removed submodule leaves submodule directory and its contents in place" '
+       test_expect_success "git -c submodule.recurse=true $cmd_args: modified submodule updates submodule work tree" '
                prolog &&
                reset_work_tree_to_interested add_sub1 &&
                (
                        cd submodule_update &&
-                       git branch -t remove_sub1 origin/remove_sub1 &&
-                       $command remove_sub1 &&
-                       test_superproject_content origin/remove_sub1 &&
-                       ! test -e sub1
+                       git branch -t modify_sub1 origin/modify_sub1 &&
+                       git -c submodule.recurse=true $cmd_args modify_sub1 &&
+                       test_superproject_content origin/modify_sub1 &&
+                       test_submodule_content sub1 origin/modify_sub1
                )
        '
-       # ... especially when it contains a .git directory.
-       test_expect_success "$command: removed submodule leaves submodule containing a .git directory alone" '
+
+       # recursing deeper than one level doesn't work yet.
+       test_expect_success "$command: modified submodule updates submodule recursively" '
                prolog &&
-               reset_work_tree_to_interested add_sub1 &&
+               reset_work_tree_to_interested add_nested_sub &&
                (
                        cd submodule_update &&
-                       git branch -t remove_sub1 origin/remove_sub1 &&
-                       replace_gitfile_with_git_dir sub1 &&
-                       rm -rf .git/modules/sub1 &&
-                       $command remove_sub1 &&
-                       test_superproject_content origin/remove_sub1 &&
-                       test_git_directory_exists sub1 &&
-                       ! test -e sub1
+                       git branch -t modify_sub1_recursively origin/modify_sub1_recursively &&
+                       $command modify_sub1_recursively &&
+                       test_superproject_content origin/modify_sub1_recursively &&
+                       test_submodule_content sub1 origin/modify_sub1_recursively &&
+                       test_submodule_content -C sub1 sub2 origin/modify_sub1_recursively
+               )
+       '
+}
+
+# Same as test_submodule_switch_recursing_with_args(), except that throwing
+# away local changes in the superproject is allowed.
+test_submodule_forced_switch_recursing_with_args () {
+       cmd_args="$1"
+       command="git $cmd_args --recurse-submodules"
+       test_submodule_recursing_with_args_common "$command"
+
+       RESULT=success
+       if test "$KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS" = 1
+       then
+               RESULT=failure
+       fi
+       # Switching to a commit letting a submodule appear does not care about
+       # an untracked file.
+       test_expect_success "$command: added submodule does remove untracked unignored file with same name when forced" '
+               prolog &&
+               reset_work_tree_to_interested no_submodule &&
+               (
+                       cd submodule_update &&
+                       git branch -t add_sub1 origin/add_sub1 &&
+                       >sub1 &&
+                       $command add_sub1 &&
+                       test_superproject_content origin/add_sub1 &&
+                       test_submodule_content sub1 origin/add_sub1
                )
        '
+
        # Replacing a submodule with files in a directory ...
        test_expect_success "$command: replace submodule with a directory" '
                prolog &&
@@ -997,17 +972,6 @@ test_submodule_forced_switch_recursing_with_args () {
                        test_git_directory_exists sub1
                )
        '
-       # Replacing it with a file
-       test_expect_success "$command: replace submodule with a file" '
-               prolog &&
-               reset_work_tree_to_interested add_sub1 &&
-               (
-                       cd submodule_update &&
-                       git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
-                       $command replace_sub1_with_file &&
-                       test_superproject_content origin/replace_sub1_with_file
-               )
-       '
 
        # ... even if the submodule contains ignored files
        test_expect_success "$command: replace submodule with a file ignoring ignored files" '
@@ -1022,46 +986,6 @@ test_submodule_forced_switch_recursing_with_args () {
                )
        '
 
-       # ... but stops for untracked files that would be lost
-       test_expect_$RESULT "$command: replace submodule with a file stops for untracked files" '
-               prolog &&
-               reset_work_tree_to_interested add_sub1 &&
-               (
-                       cd submodule_update &&
-                       git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
-                       : >sub1/untracked_file &&
-                       test_must_fail $command replace_sub1_with_file &&
-                       test_superproject_content origin/add_sub1 &&
-                       test -f sub1/untracked_file
-               )
-       '
-
-       ########################## Modified submodule #########################
-       # Updating a submodule sha1 updates the submodule's work tree
-       test_expect_success "$command: modified submodule updates submodule work tree" '
-               prolog &&
-               reset_work_tree_to_interested add_sub1 &&
-               (
-                       cd submodule_update &&
-                       git branch -t modify_sub1 origin/modify_sub1 &&
-                       $command modify_sub1 &&
-                       test_superproject_content origin/modify_sub1 &&
-                       test_submodule_content sub1 origin/modify_sub1
-               )
-       '
-       # Updating a submodule to an invalid sha1 doesn't update the
-       # submodule's work tree, subsequent update will fail
-       test_expect_success "$command: modified submodule does not update submodule work tree to invalid commit" '
-               prolog &&
-               reset_work_tree_to_interested add_sub1 &&
-               (
-                       cd submodule_update &&
-                       git branch -t invalid_sub1 origin/invalid_sub1 &&
-                       test_must_fail $command invalid_sub1 &&
-                       test_superproject_content origin/add_sub1 &&
-                       test_submodule_content sub1 origin/add_sub1
-               )
-       '
        # Updating a submodule from an invalid sha1 updates
        test_expect_success "$command: modified submodule does update submodule work tree from invalid commit" '
                prolog &&