t7063: tests for untracked cache
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>
Sun, 8 Mar 2015 10:12:44 +0000 (17:12 +0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 12 Mar 2015 20:45:18 +0000 (13:45 -0700)
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
.gitignore
Makefile
t/t7063-status-untracked-cache.sh [new file with mode: 0755]
test-dump-untracked-cache.c [new file with mode: 0644]
index a05241916c9c9a3760a6e98670a7f6427d553d77..422c5382c1acfde24223fda6236dd3586456a263 100644 (file)
 /test-delta
 /test-dump-cache-tree
 /test-dump-split-index
+/test-dump-untracked-cache
 /test-scrap-cache-tree
 /test-genrandom
 /test-hashmap
index 44f1dd10ff508c03d10704f497c32868762243ce..e63538a2e7ab2732d7f8c7605226ee61e9e25007 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -570,6 +570,7 @@ TEST_PROGRAMS_NEED_X += test-date
 TEST_PROGRAMS_NEED_X += test-delta
 TEST_PROGRAMS_NEED_X += test-dump-cache-tree
 TEST_PROGRAMS_NEED_X += test-dump-split-index
+TEST_PROGRAMS_NEED_X += test-dump-untracked-cache
 TEST_PROGRAMS_NEED_X += test-genrandom
 TEST_PROGRAMS_NEED_X += test-hashmap
 TEST_PROGRAMS_NEED_X += test-index-version
diff --git a/t/t7063-status-untracked-cache.sh b/t/t7063-status-untracked-cache.sh
new file mode 100755 (executable)
index 0000000..2b2ffd7
--- /dev/null
@@ -0,0 +1,353 @@
+#!/bin/sh
+
+test_description='test untracked cache'
+
+. ./test-lib.sh
+
+avoid_racy() {
+       sleep 1
+}
+
+git update-index --untracked-cache
+# It's fine if git update-index returns an error code other than one,
+# it'll be caught in the first test.
+if test $? -eq 1; then
+       skip_all='This system does not support untracked cache'
+       test_done
+fi
+
+test_expect_success 'setup' '
+       git init worktree &&
+       cd worktree &&
+       mkdir done dtwo dthree &&
+       touch one two three done/one dtwo/two dthree/three &&
+       git add one two done/one &&
+       : >.git/info/exclude &&
+       git update-index --untracked-cache
+'
+
+test_expect_success 'untracked cache is empty' '
+       test-dump-untracked-cache >../actual &&
+       cat >../expect <<EOF &&
+info/exclude 0000000000000000000000000000000000000000
+core.excludesfile 0000000000000000000000000000000000000000
+exclude_per_dir .gitignore
+flags 00000006
+EOF
+       test_cmp ../expect ../actual
+'
+
+cat >../status.expect <<EOF &&
+A  done/one
+A  one
+A  two
+?? dthree/
+?? dtwo/
+?? three
+EOF
+
+cat >../dump.expect <<EOF &&
+info/exclude e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
+core.excludesfile 0000000000000000000000000000000000000000
+exclude_per_dir .gitignore
+flags 00000006
+/ 0000000000000000000000000000000000000000 recurse valid
+dthree/
+dtwo/
+three
+/done/ 0000000000000000000000000000000000000000 recurse valid
+/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
+three
+/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
+two
+EOF
+
+test_expect_success 'status first time (empty cache)' '
+       avoid_racy &&
+       : >../trace &&
+       GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
+       git status --porcelain >../actual &&
+       test_cmp ../status.expect ../actual &&
+       cat >../trace.expect <<EOF &&
+node creation: 3
+gitignore invalidation: 1
+directory invalidation: 0
+opendir: 4
+EOF
+       test_cmp ../trace.expect ../trace
+'
+
+test_expect_success 'untracked cache after first status' '
+       test-dump-untracked-cache >../actual &&
+       test_cmp ../dump.expect ../actual
+'
+
+test_expect_success 'status second time (fully populated cache)' '
+       avoid_racy &&
+       : >../trace &&
+       GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
+       git status --porcelain >../actual &&
+       test_cmp ../status.expect ../actual &&
+       cat >../trace.expect <<EOF &&
+node creation: 0
+gitignore invalidation: 0
+directory invalidation: 0
+opendir: 0
+EOF
+       test_cmp ../trace.expect ../trace
+'
+
+test_expect_success 'untracked cache after second status' '
+       test-dump-untracked-cache >../actual &&
+       test_cmp ../dump.expect ../actual
+'
+
+test_expect_success 'modify in root directory, one dir invalidation' '
+       avoid_racy &&
+       : >four &&
+       : >../trace &&
+       GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
+       git status --porcelain >../actual &&
+       cat >../status.expect <<EOF &&
+A  done/one
+A  one
+A  two
+?? dthree/
+?? dtwo/
+?? four
+?? three
+EOF
+       test_cmp ../status.expect ../actual &&
+       cat >../trace.expect <<EOF &&
+node creation: 0
+gitignore invalidation: 0
+directory invalidation: 1
+opendir: 1
+EOF
+       test_cmp ../trace.expect ../trace
+
+'
+
+test_expect_success 'verify untracked cache dump' '
+       test-dump-untracked-cache >../actual &&
+       cat >../expect <<EOF &&
+info/exclude e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
+core.excludesfile 0000000000000000000000000000000000000000
+exclude_per_dir .gitignore
+flags 00000006
+/ 0000000000000000000000000000000000000000 recurse valid
+dthree/
+dtwo/
+four
+three
+/done/ 0000000000000000000000000000000000000000 recurse valid
+/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
+three
+/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
+two
+EOF
+       test_cmp ../expect ../actual
+'
+
+test_expect_success 'new .gitignore invalidates recursively' '
+       avoid_racy &&
+       echo four >.gitignore &&
+       : >../trace &&
+       GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
+       git status --porcelain >../actual &&
+       cat >../status.expect <<EOF &&
+A  done/one
+A  one
+A  two
+?? .gitignore
+?? dthree/
+?? dtwo/
+?? three
+EOF
+       test_cmp ../status.expect ../actual &&
+       cat >../trace.expect <<EOF &&
+node creation: 0
+gitignore invalidation: 1
+directory invalidation: 1
+opendir: 4
+EOF
+       test_cmp ../trace.expect ../trace
+
+'
+
+test_expect_success 'verify untracked cache dump' '
+       test-dump-untracked-cache >../actual &&
+       cat >../expect <<EOF &&
+info/exclude e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
+core.excludesfile 0000000000000000000000000000000000000000
+exclude_per_dir .gitignore
+flags 00000006
+/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
+.gitignore
+dthree/
+dtwo/
+three
+/done/ 0000000000000000000000000000000000000000 recurse valid
+/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
+three
+/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
+two
+EOF
+       test_cmp ../expect ../actual
+'
+
+test_expect_success 'new info/exclude invalidates everything' '
+       avoid_racy &&
+       echo three >>.git/info/exclude &&
+       : >../trace &&
+       GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
+       git status --porcelain >../actual &&
+       cat >../status.expect <<EOF &&
+A  done/one
+A  one
+A  two
+?? .gitignore
+?? dtwo/
+EOF
+       test_cmp ../status.expect ../actual &&
+       cat >../trace.expect <<EOF &&
+node creation: 0
+gitignore invalidation: 1
+directory invalidation: 0
+opendir: 4
+EOF
+       test_cmp ../trace.expect ../trace
+'
+
+test_expect_success 'verify untracked cache dump' '
+       test-dump-untracked-cache >../actual &&
+       cat >../expect <<EOF &&
+info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
+core.excludesfile 0000000000000000000000000000000000000000
+exclude_per_dir .gitignore
+flags 00000006
+/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
+.gitignore
+dtwo/
+/done/ 0000000000000000000000000000000000000000 recurse valid
+/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
+/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
+two
+EOF
+       test_cmp ../expect ../actual
+'
+
+test_expect_success 'move two from tracked to untracked' '
+       git rm --cached two &&
+       test-dump-untracked-cache >../actual &&
+       cat >../expect <<EOF &&
+info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
+core.excludesfile 0000000000000000000000000000000000000000
+exclude_per_dir .gitignore
+flags 00000006
+/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse
+/done/ 0000000000000000000000000000000000000000 recurse valid
+/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
+/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
+two
+EOF
+       test_cmp ../expect ../actual
+'
+
+test_expect_success 'status after the move' '
+       : >../trace &&
+       GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
+       git status --porcelain >../actual &&
+       cat >../status.expect <<EOF &&
+A  done/one
+A  one
+?? .gitignore
+?? dtwo/
+?? two
+EOF
+       test_cmp ../status.expect ../actual &&
+       cat >../trace.expect <<EOF &&
+node creation: 0
+gitignore invalidation: 0
+directory invalidation: 0
+opendir: 1
+EOF
+       test_cmp ../trace.expect ../trace
+'
+
+test_expect_success 'verify untracked cache dump' '
+       test-dump-untracked-cache >../actual &&
+       cat >../expect <<EOF &&
+info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
+core.excludesfile 0000000000000000000000000000000000000000
+exclude_per_dir .gitignore
+flags 00000006
+/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
+.gitignore
+dtwo/
+two
+/done/ 0000000000000000000000000000000000000000 recurse valid
+/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
+/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
+two
+EOF
+       test_cmp ../expect ../actual
+'
+
+test_expect_success 'move two from untracked to tracked' '
+       git add two &&
+       test-dump-untracked-cache >../actual &&
+       cat >../expect <<EOF &&
+info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
+core.excludesfile 0000000000000000000000000000000000000000
+exclude_per_dir .gitignore
+flags 00000006
+/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse
+/done/ 0000000000000000000000000000000000000000 recurse valid
+/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
+/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
+two
+EOF
+       test_cmp ../expect ../actual
+'
+
+test_expect_success 'status after the move' '
+       : >../trace &&
+       GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \
+       git status --porcelain >../actual &&
+       cat >../status.expect <<EOF &&
+A  done/one
+A  one
+A  two
+?? .gitignore
+?? dtwo/
+EOF
+       test_cmp ../status.expect ../actual &&
+       cat >../trace.expect <<EOF &&
+node creation: 0
+gitignore invalidation: 0
+directory invalidation: 0
+opendir: 1
+EOF
+       test_cmp ../trace.expect ../trace
+'
+
+test_expect_success 'verify untracked cache dump' '
+       test-dump-untracked-cache >../actual &&
+       cat >../expect <<EOF &&
+info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
+core.excludesfile 0000000000000000000000000000000000000000
+exclude_per_dir .gitignore
+flags 00000006
+/ e6fcc8f2ee31bae321d66afd183fcb7237afae6e recurse valid
+.gitignore
+dtwo/
+/done/ 0000000000000000000000000000000000000000 recurse valid
+/dthree/ 0000000000000000000000000000000000000000 recurse check_only valid
+/dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
+two
+EOF
+       test_cmp ../expect ../actual
+'
+
+test_done
diff --git a/test-dump-untracked-cache.c b/test-dump-untracked-cache.c
new file mode 100644 (file)
index 0000000..710441e
--- /dev/null
@@ -0,0 +1,61 @@
+#include "cache.h"
+#include "dir.h"
+
+static int compare_untracked(const void *a_, const void *b_)
+{
+       const char *const *a = a_;
+       const char *const *b = b_;
+       return strcmp(*a, *b);
+}
+
+static int compare_dir(const void *a_, const void *b_)
+{
+       const struct untracked_cache_dir *const *a = a_;
+       const struct untracked_cache_dir *const *b = b_;
+       return strcmp((*a)->name, (*b)->name);
+}
+
+static void dump(struct untracked_cache_dir *ucd, struct strbuf *base)
+{
+       int i, len;
+       qsort(ucd->untracked, ucd->untracked_nr, sizeof(*ucd->untracked),
+             compare_untracked);
+       qsort(ucd->dirs, ucd->dirs_nr, sizeof(*ucd->dirs),
+             compare_dir);
+       len = base->len;
+       strbuf_addf(base, "%s/", ucd->name);
+       printf("%s %s", base->buf,
+              sha1_to_hex(ucd->exclude_sha1));
+       if (ucd->recurse)
+               fputs(" recurse", stdout);
+       if (ucd->check_only)
+               fputs(" check_only", stdout);
+       if (ucd->valid)
+               fputs(" valid", stdout);
+       printf("\n");
+       for (i = 0; i < ucd->untracked_nr; i++)
+               printf("%s\n", ucd->untracked[i]);
+       for (i = 0; i < ucd->dirs_nr; i++)
+               dump(ucd->dirs[i], base);
+       strbuf_setlen(base, len);
+}
+
+int main(int ac, char **av)
+{
+       struct untracked_cache *uc;
+       struct strbuf base = STRBUF_INIT;
+       if (read_cache() < 0)
+               die("unable to read index file");
+       uc = the_index.untracked;
+       if (!uc) {
+               printf("no untracked cache\n");
+               return 0;
+       }
+       printf("info/exclude %s\n", sha1_to_hex(uc->ss_info_exclude.sha1));
+       printf("core.excludesfile %s\n", sha1_to_hex(uc->ss_excludes_file.sha1));
+       printf("exclude_per_dir %s\n", uc->exclude_per_dir);
+       printf("flags %08x\n", uc->dir_flags);
+       if (uc->root)
+               dump(uc->root, &base);
+       return 0;
+}