test-reach: create new test tool for ref_newer
authorDerrick Stolee <dstolee@microsoft.com>
Fri, 20 Jul 2018 16:33:15 +0000 (16:33 +0000)
committerJunio C Hamano <gitster@pobox.com>
Fri, 20 Jul 2018 22:38:55 +0000 (15:38 -0700)
As we prepare to change the behavior of the algorithms in
commit-reach.c, create a new test-tool subcommand 'reach' to test these
methods on interesting commit-graph shapes.

To use the new test-tool, use 'test-tool reach <method>' and provide
input to stdin that describes the inputs to the method. Currently, we
only implement the ref_newer method, which requires two commits. Use
lines "A:<committish>" and "B:<committish>" for the two inputs. We will
expand this input later to accommodate methods that take lists of
commits.

The test t6600-test-reach.sh creates a repo whose commits form a
two-dimensional grid. This grid makes it easy for us to determine
reachability because commit-A-B can reach commit-X-Y if and only if A is
at least X and B is at least Y. This helps create interesting test cases
for each result of the methods in commit-reach.c.

We test all methods in three different states of the commit-graph file:
Non-existent (no generation numbers), fully computed, and mixed (some
commits have generation numbers and others do not).

Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Makefile
t/helper/test-reach.c [new file with mode: 0644]
t/helper/test-tool.c
t/helper/test-tool.h
t/t6600-test-reach.sh [new file with mode: 0755]

index 59781f4..d69f9d4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -716,6 +716,7 @@ TEST_BUILTINS_OBJS += test-mktemp.o
 TEST_BUILTINS_OBJS += test-online-cpus.o
 TEST_BUILTINS_OBJS += test-path-utils.o
 TEST_BUILTINS_OBJS += test-prio-queue.o
+TEST_BUILTINS_OBJS += test-reach.o
 TEST_BUILTINS_OBJS += test-read-cache.o
 TEST_BUILTINS_OBJS += test-ref-store.o
 TEST_BUILTINS_OBJS += test-regex.o
diff --git a/t/helper/test-reach.c b/t/helper/test-reach.c
new file mode 100644 (file)
index 0000000..620bb46
--- /dev/null
@@ -0,0 +1,63 @@
+#include "test-tool.h"
+#include "cache.h"
+#include "commit.h"
+#include "commit-reach.h"
+#include "config.h"
+#include "parse-options.h"
+#include "tag.h"
+
+int cmd__reach(int ac, const char **av)
+{
+       struct object_id oid_A, oid_B;
+       struct strbuf buf = STRBUF_INIT;
+       struct repository *r = the_repository;
+
+       setup_git_directory();
+
+       if (ac < 2)
+               exit(1);
+
+
+       while (strbuf_getline(&buf, stdin) != EOF) {
+               struct object_id oid;
+               struct object *o;
+               struct commit *c;
+               if (buf.len < 3)
+                       continue;
+
+               if (get_oid_committish(buf.buf + 2, &oid))
+                       die("failed to resolve %s", buf.buf + 2);
+
+               o = parse_object(r, &oid);
+               o = deref_tag_noverify(o);
+
+               if (!o)
+                       die("failed to load commit for input %s resulting in oid %s\n",
+                           buf.buf, oid_to_hex(&oid));
+
+               c = object_as_type(r, o, OBJ_COMMIT, 0);
+
+               if (!c)
+                       die("failed to load commit for input %s resulting in oid %s\n",
+                           buf.buf, oid_to_hex(&oid));
+
+               switch (buf.buf[0]) {
+                       case 'A':
+                               oidcpy(&oid_A, &oid);
+                               break;
+
+                       case 'B':
+                               oidcpy(&oid_B, &oid);
+                               break;
+
+                       default:
+                               die("unexpected start of line: %c", buf.buf[0]);
+               }
+       }
+       strbuf_release(&buf);
+
+       if (!strcmp(av[1], "ref_newer"))
+               printf("%s(A,B):%d\n", av[1], ref_newer(&oid_A, &oid_B));
+
+       exit(0);
+}
index dafc91c..582d02a 100644 (file)
@@ -26,6 +26,7 @@ static struct test_cmd cmds[] = {
        { "online-cpus", cmd__online_cpus },
        { "path-utils", cmd__path_utils },
        { "prio-queue", cmd__prio_queue },
+       { "reach", cmd__reach },
        { "read-cache", cmd__read_cache },
        { "ref-store", cmd__ref_store },
        { "regex", cmd__regex },
index 80cbcf0..a7e53c4 100644 (file)
@@ -20,6 +20,7 @@ int cmd__mktemp(int argc, const char **argv);
 int cmd__online_cpus(int argc, const char **argv);
 int cmd__path_utils(int argc, const char **argv);
 int cmd__prio_queue(int argc, const char **argv);
+int cmd__reach(int argc, const char **argv);
 int cmd__read_cache(int argc, const char **argv);
 int cmd__ref_store(int argc, const char **argv);
 int cmd__regex(int argc, const char **argv);
diff --git a/t/t6600-test-reach.sh b/t/t6600-test-reach.sh
new file mode 100755 (executable)
index 0000000..966309c
--- /dev/null
@@ -0,0 +1,86 @@
+#!/bin/sh
+
+test_description='basic commit reachability tests'
+
+. ./test-lib.sh
+
+# Construct a grid-like commit graph with points (x,y)
+# with 1 <= x <= 10, 1 <= y <= 10, where (x,y) has
+# parents (x-1, y) and (x, y-1), keeping in mind that
+# we drop a parent if a coordinate is nonpositive.
+#
+#             (10,10)
+#            /       \
+#         (10,9)    (9,10)
+#        /     \   /      \
+#    (10,8)    (9,9)      (8,10)
+#   /     \    /   \      /    \
+#         ( continued...)
+#   \     /    \   /      \    /
+#    (3,1)     (2,2)      (1,3)
+#        \     /    \     /
+#         (2,1)      (2,1)
+#              \    /
+#              (1,1)
+#
+# We use branch 'commit-x-y' to refer to (x,y).
+# This grid allows interesting reachability and
+# non-reachability queries: (x,y) can reach (x',y')
+# if and only if x' <= x and y' <= y.
+test_expect_success 'setup' '
+       for i in $(test_seq 1 10)
+       do
+               test_commit "1-$i" &&
+               git branch -f commit-1-$i
+       done &&
+       for j in $(test_seq 1 9)
+       do
+               git reset --hard commit-$j-1 &&
+               x=$(($j + 1)) &&
+               test_commit "$x-1" &&
+               git branch -f commit-$x-1 &&
+
+               for i in $(test_seq 2 10)
+               do
+                       git merge commit-$j-$i -m "$x-$i" &&
+                       git branch -f commit-$x-$i
+               done
+       done &&
+       git commit-graph write --reachable &&
+       mv .git/objects/info/commit-graph commit-graph-full &&
+       git show-ref -s commit-5-5 | git commit-graph write --stdin-commits &&
+       mv .git/objects/info/commit-graph commit-graph-half &&
+       git config core.commitGraph true
+'
+
+test_three_modes () {
+       test_when_finished rm -rf .git/objects/info/commit-graph &&
+       test-tool reach $1 <input >actual &&
+       test_cmp expect actual &&
+       cp commit-graph-full .git/objects/info/commit-graph &&
+       test-tool reach $1 <input >actual &&
+       test_cmp expect actual &&
+       cp commit-graph-half .git/objects/info/commit-graph &&
+       test-tool reach $1 <input >actual &&
+       test_cmp expect actual
+}
+
+test_expect_success 'ref_newer:miss' '
+       cat >input <<-\EOF &&
+       A:commit-5-7
+       B:commit-4-9
+       EOF
+       echo "ref_newer(A,B):0" >expect &&
+       test_three_modes ref_newer
+'
+
+test_expect_success 'ref_newer:hit' '
+       cat >input <<-\EOF &&
+       A:commit-5-7
+       B:commit-2-3
+       EOF
+       echo "ref_newer(A,B):1" >expect &&
+       test_three_modes ref_newer
+'
+
+test_done