---
 Makefile              |   1 +
 t/helper/test-reach.c | 123 ++++++++++++++++++++++++++++++++++++++++++
 t/helper/test-tool.c  |   1 +
 t/helper/test-tool.h  |   1 +
 t/t6600-test-reach.sh |  81 ++++++++++++++++++++++++++++
 5 files changed, 207 insertions(+)
 create mode 100644 t/helper/test-reach.c
 create mode 100755 t/t6600-test-reach.sh

diff --git a/Makefile b/Makefile
index 89ad873ce0..c2a2c6457e 100644
--- 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
index 0000000000..d57660af45
--- /dev/null
+++ b/t/helper/test-reach.c
@@ -0,0 +1,123 @@
+#include "test-tool.h"
+#include "cache.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 commit *A, *B;
+       struct commit **X, **Y;
+       int nr_X, alloc_X, nr_Y, alloc_Y;
+       struct commit_list *list_X, *list_Y;
+       struct strbuf buf = STRBUF_INIT;
+
+       setup_git_directory();
+       get_git_config(default_git_config, 0);
+
+       if (argc < 2)
+               exit(1);
+
+       /* load input data */
+       A = B = NULL;
+       list_X = list_Y = NULL;
+       nr_X = nr_Y = 0;
+       alloc_X = alloc_Y = 16;
+       ALLOC_ARRAY(X, alloc_X);
+       ALLOC_ARRAY(Y, alloc_Y);
+
+       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(&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(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);
+                               A = c;
+                               break;
+
+                       case 'B':
+                               oidcpy(&oid_B, &oid);
+                               B = c;
+                               break;
+
+                       case 'X':
+                               ALLOC_GROW(X, nr_X + 1, alloc_X);
+                               X[nr_X++] = c;
+                               commit_list_insert(c, &list_X);
+                               break;
+
+                       case 'Y':
+                               ALLOC_GROW(Y, nr_Y + 1, alloc_Y);
+                               Y[nr_Y++] = c;
+                               commit_list_insert(c, &list_Y);
+                               break;
+
+                       default:
+                               die("unexpected start of line: %c", buf.buf[0]);
+               }
+       }
+       strbuf_release(&buf);
+
+       if (ac > 2 && !strcmp(av[2], "graph:off"))
+               core_commit_graph = 0;
+       if (ac > 2 && !strcmp(av[2], "graph:on"))
+               core_commit_graph = 1;
+
+       if (!strcmp(av[1], "ref_newer"))
+               printf("%s:%d\n", av[1], ref_newer(&oid_A, &oid_B));
+       else if (!strcmp(av[1], "in_merge_base"))
+               printf("%s:%d\n", av[1], in_merge_bases(A, B));
+       else if (!strcmp(av[1], "get_merge_bases_many")) {
+               struct commit_list *list = get_merge_bases_many(A, nr_X, X);
+               printf("%s(A,X):\n", av[1]);
+               while (list) {
+                       printf("%s\n", oid_to_hex(&list->item->object.oid));
+                       list = list->next;
+               }
+
+               list = get_merge_bases_many(B, nr_Y, Y);
+               printf("%s(B,Y):\n", av[1]);
+               while (list) {
+                       printf("%s\n", oid_to_hex(&list->item->object.oid));
+                       list = list->next;
+               }
+       } else if (!strcmp(av[1], "reduce_heads")) {
+               struct commit_list *list = reduce_heads(list_X);
+               printf("%s(X):\n", av[1]);
+               while (list) {
+                       printf("%s\n", oid_to_hex(&list->item->object.oid));
+                       list = list->next;
+               }
+
+               list = reduce_heads(list_Y);
+               printf("%s(Y):\n", av[1]);
+               while (list) {
+                       printf("%s\n", oid_to_hex(&list->item->object.oid));
+                       list = list->next;
+               }
+       }
+
+       exit(0);
+}
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
index 805a45de9c..64d250b602 100644
--- a/t/helper/test-tool.c
+++ b/t/helper/test-tool.c
@@ -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 },
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
index 7116ddfb94..0b1d3534b5 100644
--- a/t/helper/test-tool.h
+++ b/t/helper/test-tool.h
@@ -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
index 0000000000..c9337b6b46
--- /dev/null
+++ b/t/t6600-test-reach.sh
@@ -0,0 +1,81 @@
+#!/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 'comit-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
+'
+
+test_reach_two_modes() {
+       test-tool reach $1 graph:off <input >output &&
+       test_cmp output expect &&
+       test-tool reach $1 graph:on <input >output &&
+       test_cmp output expect
+}
+
+test_expect_success 'ref_newer:miss' '
+       cat >input <<- EOF &&
+       A:commit-5-7
+       B:commit-4-9
+       EOF
+       cat >expect <<- EOF &&
+       ref_newer:0
+       EOF
+       test_reach_two_modes "ref_newer"
+'
+
+test_expect_success 'ref_newer:miss' '
+       cat >input <<- EOF &&
+       A:commit-5-7
+       B:commit-2-3
+       EOF
+       cat >expect <<- EOF &&
+       ref_newer:1
+       EOF
+       test_reach_two_modes "ref_newer"
+'
+
+test_done
-- 
2.18.0.118.gd4f65b8d14

Reply via email to