t: add tests for restore
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>
Thu, 25 Apr 2019 09:45:55 +0000 (16:45 +0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 7 May 2019 04:04:48 +0000 (13:04 +0900)
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
t/lib-patch-mode.sh
t/t2070-restore.sh [new file with mode: 0755]
t/t2071-restore-patch.sh [new file with mode: 0755]
index 06c3c9176207af6c27c924377f29cc2bd0c881e5..cfd76bf987bd902503cfcacd3e8ac1b9c4deb09c 100644 (file)
@@ -2,28 +2,40 @@
 
 . ./test-lib.sh
 
+# set_state <path> <worktree-content> <index-content>
+#
+# Prepare the content for path in worktree and the index as specified.
 set_state () {
        echo "$3" > "$1" &&
        git add "$1" &&
        echo "$2" > "$1"
 }
 
+# save_state <path>
+#
+# Save index/worktree content of <path> in the files _worktree_<path>
+# and _index_<path>
 save_state () {
        noslash="$(echo "$1" | tr / _)" &&
        cat "$1" > _worktree_"$noslash" &&
        git show :"$1" > _index_"$noslash"
 }
 
+# set_and_save_state <path> <worktree-content> <index-content>
 set_and_save_state () {
        set_state "$@" &&
        save_state "$1"
 }
 
+# verify_state <path> <expected-worktree-content> <expected-index-content>
 verify_state () {
        test "$(cat "$1")" = "$2" &&
        test "$(git show :"$1")" = "$3"
 }
 
+# verify_saved_state <path>
+#
+# Call verify_state with expected contents from the last save_state
 verify_saved_state () {
        noslash="$(echo "$1" | tr / _)" &&
        verify_state "$1" "$(cat _worktree_"$noslash")" "$(cat _index_"$noslash")"
diff --git a/t/t2070-restore.sh b/t/t2070-restore.sh
new file mode 100755 (executable)
index 0000000..73ea13e
--- /dev/null
@@ -0,0 +1,99 @@
+#!/bin/sh
+
+test_description='restore basic functionality'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       test_commit first &&
+       echo first-and-a-half >>first.t &&
+       git add first.t &&
+       test_commit second &&
+       echo one >one &&
+       echo two >two &&
+       echo untracked >untracked &&
+       echo ignored >ignored &&
+       echo /ignored >.gitignore &&
+       git add one two .gitignore &&
+       git update-ref refs/heads/one master
+'
+
+test_expect_success 'restore without pathspec is not ok' '
+       test_must_fail git restore &&
+       test_must_fail git restore --source=first
+'
+
+test_expect_success 'restore a file, ignoring branch of same name' '
+       cat one >expected &&
+       echo dirty >>one &&
+       git restore one &&
+       test_cmp expected one
+'
+
+test_expect_success 'restore a file on worktree from another ref' '
+       test_when_finished git reset --hard &&
+       git cat-file blob first:./first.t >expected &&
+       git restore --source=first first.t &&
+       test_cmp expected first.t &&
+       git cat-file blob HEAD:./first.t >expected &&
+       git show :first.t >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'restore a file in the index from another ref' '
+       test_when_finished git reset --hard &&
+       git cat-file blob first:./first.t >expected &&
+       git restore --source=first --staged first.t &&
+       git show :first.t >actual &&
+       test_cmp expected actual &&
+       git cat-file blob HEAD:./first.t >expected &&
+       test_cmp expected first.t
+'
+
+test_expect_success 'restore a file in both the index and worktree from another ref' '
+       test_when_finished git reset --hard &&
+       git cat-file blob first:./first.t >expected &&
+       git restore --source=first --staged --worktree first.t &&
+       git show :first.t >actual &&
+       test_cmp expected actual &&
+       test_cmp expected first.t
+'
+
+test_expect_success 'restore --staged uses HEAD as source' '
+       test_when_finished git reset --hard &&
+       git cat-file blob :./first.t >expected &&
+       echo index-dirty >>first.t &&
+       git add first.t &&
+       git restore --staged first.t &&
+       git cat-file blob :./first.t >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'restore --ignore-unmerged ignores unmerged entries' '
+       git init unmerged &&
+       (
+               cd unmerged &&
+               echo one >unmerged &&
+               echo one >common &&
+               git add unmerged common &&
+               git commit -m common &&
+               git switch -c first &&
+               echo first >unmerged &&
+               git commit -am first &&
+               git switch -c second master &&
+               echo second >unmerged &&
+               git commit -am second &&
+               test_must_fail git merge first &&
+
+               echo dirty >>common &&
+               test_must_fail git restore . &&
+
+               git restore --ignore-unmerged --quiet . >output 2>&1 &&
+               git diff common >diff-output &&
+               : >empty &&
+               test_cmp empty output &&
+               test_cmp empty diff-output
+       )
+'
+
+test_done
diff --git a/t/t2071-restore-patch.sh b/t/t2071-restore-patch.sh
new file mode 100755 (executable)
index 0000000..98b2476
--- /dev/null
@@ -0,0 +1,110 @@
+#!/bin/sh
+
+test_description='git restore --patch'
+
+. ./lib-patch-mode.sh
+
+test_expect_success PERL 'setup' '
+       mkdir dir &&
+       echo parent >dir/foo &&
+       echo dummy >bar &&
+       git add bar dir/foo &&
+       git commit -m initial &&
+       test_tick &&
+       test_commit second dir/foo head &&
+       set_and_save_state bar bar_work bar_index &&
+       save_head
+'
+
+test_expect_success PERL 'restore -p without pathspec is fine' '
+       echo q >cmd &&
+       git restore -p <cmd
+'
+
+# note: bar sorts before dir/foo, so the first 'n' is always to skip 'bar'
+
+test_expect_success PERL 'saying "n" does nothing' '
+       set_and_save_state dir/foo work head &&
+       test_write_lines n n | git restore -p &&
+       verify_saved_state bar &&
+       verify_saved_state dir/foo
+'
+
+test_expect_success PERL 'git restore -p' '
+       set_and_save_state dir/foo work head &&
+       test_write_lines n y | git restore -p &&
+       verify_saved_state bar &&
+       verify_state dir/foo head head
+'
+
+test_expect_success PERL 'git restore -p with staged changes' '
+       set_state dir/foo work index &&
+       test_write_lines n y | git restore -p &&
+       verify_saved_state bar &&
+       verify_state dir/foo index index
+'
+
+test_expect_success PERL 'git restore -p --source=HEAD' '
+       set_state dir/foo work index &&
+       # the third n is to get out in case it mistakenly does not apply
+       test_write_lines n y n | git restore -p --source=HEAD &&
+       verify_saved_state bar &&
+       verify_state dir/foo head index
+'
+
+test_expect_success PERL 'git restore -p --source=HEAD^' '
+       set_state dir/foo work index &&
+       # the third n is to get out in case it mistakenly does not apply
+       test_write_lines n y n | git restore -p --source=HEAD^ &&
+       verify_saved_state bar &&
+       verify_state dir/foo parent index
+'
+
+test_expect_success PERL 'git restore -p handles deletion' '
+       set_state dir/foo work index &&
+       rm dir/foo &&
+       test_write_lines n y | git restore -p &&
+       verify_saved_state bar &&
+       verify_state dir/foo index index
+'
+
+# The idea in the rest is that bar sorts first, so we always say 'y'
+# first and if the path limiter fails it'll apply to bar instead of
+# dir/foo.  There's always an extra 'n' to reject edits to dir/foo in
+# the failure case (and thus get out of the loop).
+
+test_expect_success PERL 'path limiting works: dir' '
+       set_state dir/foo work head &&
+       test_write_lines y n | git restore -p dir &&
+       verify_saved_state bar &&
+       verify_state dir/foo head head
+'
+
+test_expect_success PERL 'path limiting works: -- dir' '
+       set_state dir/foo work head &&
+       test_write_lines y n | git restore -p -- dir &&
+       verify_saved_state bar &&
+       verify_state dir/foo head head
+'
+
+test_expect_success PERL 'path limiting works: HEAD^ -- dir' '
+       set_state dir/foo work head &&
+       # the third n is to get out in case it mistakenly does not apply
+       test_write_lines y n n | git restore -p --source=HEAD^ -- dir &&
+       verify_saved_state bar &&
+       verify_state dir/foo parent head
+'
+
+test_expect_success PERL 'path limiting works: foo inside dir' '
+       set_state dir/foo work head &&
+       # the third n is to get out in case it mistakenly does not apply
+       test_write_lines y n n | (cd dir && git restore -p foo) &&
+       verify_saved_state bar &&
+       verify_state dir/foo head head
+'
+
+test_expect_success PERL 'none of this moved HEAD' '
+       verify_saved_head
+'
+
+test_done