summaryrefslogtreecommitdiff
path: root/t/helper
diff options
context:
space:
mode:
Diffstat (limited to 't/helper')
-rw-r--r--t/helper/.gitignore2
-rw-r--r--t/helper/test-advise.c22
-rw-r--r--t/helper/test-bitmap.c32
-rw-r--r--t/helper/test-bloom.c97
-rw-r--r--t/helper/test-chmtime.c19
-rw-r--r--t/helper/test-config.c20
-rw-r--r--t/helper/test-crontab.c35
-rw-r--r--t/helper/test-csprng.c29
-rw-r--r--t/helper/test-date.c5
-rw-r--r--t/helper/test-drop-caches.c4
-rw-r--r--t/helper/test-dump-fsmonitor.c2
-rw-r--r--t/helper/test-dump-split-index.c2
-rw-r--r--t/helper/test-dump-untracked-cache.c6
-rw-r--r--t/helper/test-example-decorate.c6
-rw-r--r--t/helper/test-fast-rebase.c234
-rw-r--r--t/helper/test-fsmonitor-client.c222
-rw-r--r--t/helper/test-genzeros.c21
-rw-r--r--t/helper/test-getcwd.c26
-rw-r--r--t/helper/test-hash-speed.c2
-rw-r--r--t/helper/test-hash.c2
-rw-r--r--t/helper/test-hashmap.c9
-rw-r--r--t/helper/test-hexdump.c30
-rw-r--r--t/helper/test-line-buffer.c81
-rw-r--r--t/helper/test-match-trees.c2
-rw-r--r--t/helper/test-mergesort.c368
-rw-r--r--t/helper/test-oid-array.c (renamed from t/helper/test-sha1-array.c)15
-rw-r--r--t/helper/test-oidtree.c52
-rw-r--r--t/helper/test-pack-mtimes.c56
-rw-r--r--t/helper/test-parse-options.c10
-rw-r--r--t/helper/test-parse-pathspec-file.c33
-rw-r--r--t/helper/test-partial-clone.c43
-rw-r--r--t/helper/test-path-utils.c51
-rw-r--r--t/helper/test-pcre2-config.c12
-rw-r--r--t/helper/test-pkt-line.c41
-rw-r--r--t/helper/test-prio-queue.c2
-rw-r--r--t/helper/test-proc-receive.c202
-rw-r--r--t/helper/test-progress.c59
-rw-r--r--t/helper/test-reach.c8
-rw-r--r--t/helper/test-read-cache.c3
-rw-r--r--t/helper/test-read-graph.c39
-rw-r--r--t/helper/test-read-midx.c74
-rw-r--r--t/helper/test-ref-store.c108
-rw-r--r--t/helper/test-reftable.c22
-rw-r--r--t/helper/test-regex.c94
-rw-r--r--t/helper/test-repository.c14
-rw-r--r--t/helper/test-revision-walking.c1
-rw-r--r--t/helper/test-run-command.c102
-rw-r--r--t/helper/test-serve-v2.c14
-rw-r--r--t/helper/test-simple-ipc.c686
-rw-r--r--t/helper/test-submodule-nested-repo-config.c10
-rw-r--r--t/helper/test-subprocess.c2
-rw-r--r--t/helper/test-svn-fe.c52
-rw-r--r--t/helper/test-tool.c22
-rw-r--r--t/helper/test-tool.h21
-rw-r--r--t/helper/test-trace2.c41
-rw-r--r--t/helper/test-userdiff.c46
-rw-r--r--t/helper/test-windows-named-pipe.c2
57 files changed, 2844 insertions, 371 deletions
diff --git a/t/helper/.gitignore b/t/helper/.gitignore
index 48c7bb0..8c2ddcc 100644
--- a/t/helper/.gitignore
+++ b/t/helper/.gitignore
@@ -1,4 +1,2 @@
/test-tool
/test-fake-ssh
-/test-line-buffer
-/test-svn-fe
diff --git a/t/helper/test-advise.c b/t/helper/test-advise.c
new file mode 100644
index 0000000..cb88113
--- /dev/null
+++ b/t/helper/test-advise.c
@@ -0,0 +1,22 @@
+#include "test-tool.h"
+#include "cache.h"
+#include "advice.h"
+#include "config.h"
+
+int cmd__advise_if_enabled(int argc, const char **argv)
+{
+ if (argc != 2)
+ die("usage: %s <advice>", argv[0]);
+
+ setup_git_directory();
+ git_config(git_default_config, NULL);
+
+ /*
+ * Any advice type can be used for testing, but NESTED_TAG was
+ * selected here and in t0018 where this command is being
+ * executed.
+ */
+ advise_if_enabled(ADVICE_NESTED_TAG, "%s", argv[1]);
+
+ return 0;
+}
diff --git a/t/helper/test-bitmap.c b/t/helper/test-bitmap.c
new file mode 100644
index 0000000..ff35f59
--- /dev/null
+++ b/t/helper/test-bitmap.c
@@ -0,0 +1,32 @@
+#include "test-tool.h"
+#include "cache.h"
+#include "pack-bitmap.h"
+
+static int bitmap_list_commits(void)
+{
+ return test_bitmap_commits(the_repository);
+}
+
+static int bitmap_dump_hashes(void)
+{
+ return test_bitmap_hashes(the_repository);
+}
+
+int cmd__bitmap(int argc, const char **argv)
+{
+ setup_git_directory();
+
+ if (argc != 2)
+ goto usage;
+
+ if (!strcmp(argv[1], "list-commits"))
+ return bitmap_list_commits();
+ if (!strcmp(argv[1], "dump-hashes"))
+ return bitmap_dump_hashes();
+
+usage:
+ usage("\ttest-tool bitmap list-commits\n"
+ "\ttest-tool bitmap dump-hashes");
+
+ return -1;
+}
diff --git a/t/helper/test-bloom.c b/t/helper/test-bloom.c
new file mode 100644
index 0000000..ad3ef1c
--- /dev/null
+++ b/t/helper/test-bloom.c
@@ -0,0 +1,97 @@
+#include "git-compat-util.h"
+#include "bloom.h"
+#include "test-tool.h"
+#include "commit.h"
+
+static struct bloom_filter_settings settings = DEFAULT_BLOOM_FILTER_SETTINGS;
+
+static void add_string_to_filter(const char *data, struct bloom_filter *filter) {
+ struct bloom_key key;
+ int i;
+
+ fill_bloom_key(data, strlen(data), &key, &settings);
+ printf("Hashes:");
+ for (i = 0; i < settings.num_hashes; i++){
+ printf("0x%08x|", key.hashes[i]);
+ }
+ printf("\n");
+ add_key_to_filter(&key, filter, &settings);
+}
+
+static void print_bloom_filter(struct bloom_filter *filter) {
+ int i;
+
+ if (!filter) {
+ printf("No filter.\n");
+ return;
+ }
+ printf("Filter_Length:%d\n", (int)filter->len);
+ printf("Filter_Data:");
+ for (i = 0; i < filter->len; i++) {
+ printf("%02x|", filter->data[i]);
+ }
+ printf("\n");
+}
+
+static void get_bloom_filter_for_commit(const struct object_id *commit_oid)
+{
+ struct commit *c;
+ struct bloom_filter *filter;
+ setup_git_directory();
+ c = lookup_commit(the_repository, commit_oid);
+ filter = get_or_compute_bloom_filter(the_repository, c, 1,
+ &settings,
+ NULL);
+ print_bloom_filter(filter);
+}
+
+static const char *bloom_usage = "\n"
+" test-tool bloom get_murmur3 <string>\n"
+" test-tool bloom generate_filter <string> [<string>...]\n"
+" test-tool bloom get_filter_for_commit <commit-hex>\n";
+
+int cmd__bloom(int argc, const char **argv)
+{
+ setup_git_directory();
+
+ if (argc < 2)
+ usage(bloom_usage);
+
+ if (!strcmp(argv[1], "get_murmur3")) {
+ uint32_t hashed;
+ if (argc < 3)
+ usage(bloom_usage);
+ hashed = murmur3_seeded(0, argv[2], strlen(argv[2]));
+ printf("Murmur3 Hash with seed=0:0x%08x\n", hashed);
+ }
+
+ if (!strcmp(argv[1], "generate_filter")) {
+ struct bloom_filter filter;
+ int i = 2;
+ filter.len = (settings.bits_per_entry + BITS_PER_WORD - 1) / BITS_PER_WORD;
+ CALLOC_ARRAY(filter.data, filter.len);
+
+ if (argc - 1 < i)
+ usage(bloom_usage);
+
+ while (argv[i]) {
+ add_string_to_filter(argv[i], &filter);
+ i++;
+ }
+
+ print_bloom_filter(&filter);
+ }
+
+ if (!strcmp(argv[1], "get_filter_for_commit")) {
+ struct object_id oid;
+ const char *end;
+ if (argc < 3)
+ usage(bloom_usage);
+ if (parse_oid_hex(argv[2], &oid, &end))
+ die("cannot parse oid '%s'", argv[2]);
+ init_bloom_filters();
+ get_bloom_filter_for_commit(&oid);
+ }
+
+ return 0;
+}
diff --git a/t/helper/test-chmtime.c b/t/helper/test-chmtime.c
index aa22af4..dc28890 100644
--- a/t/helper/test-chmtime.c
+++ b/t/helper/test-chmtime.c
@@ -109,9 +109,9 @@ int cmd__chmtime(int argc, const char **argv)
uintmax_t mtime;
if (stat(argv[i], &sb) < 0) {
- fprintf(stderr, "Failed to stat %s: %s\n",
+ fprintf(stderr, "Failed to stat %s: %s. Skipping\n",
argv[i], strerror(errno));
- return 1;
+ continue;
}
#ifdef GIT_WINDOWS_NATIVE
@@ -134,6 +134,21 @@ int cmd__chmtime(int argc, const char **argv)
}
if (utb.modtime != sb.st_mtime && utime(argv[i], &utb) < 0) {
+#ifdef GIT_WINDOWS_NATIVE
+ if (S_ISDIR(sb.st_mode)) {
+ /*
+ * NEEDSWORK: The Windows version of `utime()`
+ * (aka `mingw_utime()`) does not correctly
+ * handle directory arguments, since it uses
+ * `_wopen()`. Ignore it for now since this
+ * is just a test.
+ */
+ fprintf(stderr,
+ ("Failed to modify time on directory %s. "
+ "Skipping\n"), argv[i]);
+ continue;
+ }
+#endif
fprintf(stderr, "Failed to modify time on %s: %s\n",
argv[i], strerror(errno));
return 1;
diff --git a/t/helper/test-config.c b/t/helper/test-config.c
index 214003d..a6e9367 100644
--- a/t/helper/test-config.c
+++ b/t/helper/test-config.c
@@ -37,21 +37,6 @@
*
*/
-static const char *scope_name(enum config_scope scope)
-{
- switch (scope) {
- case CONFIG_SCOPE_SYSTEM:
- return "system";
- case CONFIG_SCOPE_GLOBAL:
- return "global";
- case CONFIG_SCOPE_REPO:
- return "repo";
- case CONFIG_SCOPE_CMDLINE:
- return "cmdline";
- default:
- return "unknown";
- }
-}
static int iterate_cb(const char *var, const char *value, void *data)
{
static int nr;
@@ -63,7 +48,8 @@ static int iterate_cb(const char *var, const char *value, void *data)
printf("value=%s\n", value ? value : "(null)");
printf("origin=%s\n", current_config_origin_type());
printf("name=%s\n", current_config_name());
- printf("scope=%s\n", scope_name(current_config_scope()));
+ printf("lno=%d\n", current_config_line());
+ printf("scope=%s\n", config_scope_name(current_config_scope()));
return 0;
}
@@ -140,7 +126,7 @@ int cmd__config(int argc, const char **argv)
goto exit1;
}
} else if (argc == 3 && !strcmp(argv[1], "get_string")) {
- if (!git_config_get_string_const(argv[2], &v)) {
+ if (!git_config_get_string_tmp(argv[2], &v)) {
printf("%s\n", v);
goto exit0;
} else {
diff --git a/t/helper/test-crontab.c b/t/helper/test-crontab.c
new file mode 100644
index 0000000..e7c0137
--- /dev/null
+++ b/t/helper/test-crontab.c
@@ -0,0 +1,35 @@
+#include "test-tool.h"
+#include "cache.h"
+
+/*
+ * Usage: test-tool cron <file> [-l]
+ *
+ * If -l is specified, then write the contents of <file> to stdout.
+ * Otherwise, write from stdin into <file>.
+ */
+int cmd__crontab(int argc, const char **argv)
+{
+ int a;
+ FILE *from, *to;
+
+ if (argc == 3 && !strcmp(argv[2], "-l")) {
+ from = fopen(argv[1], "r");
+ if (!from)
+ return 0;
+ to = stdout;
+ } else if (argc == 2) {
+ from = stdin;
+ to = fopen(argv[1], "w");
+ } else
+ return error("unknown arguments");
+
+ while ((a = fgetc(from)) != EOF)
+ fputc(a, to);
+
+ if (argc == 3)
+ fclose(from);
+ else
+ fclose(to);
+
+ return 0;
+}
diff --git a/t/helper/test-csprng.c b/t/helper/test-csprng.c
new file mode 100644
index 0000000..65d1497
--- /dev/null
+++ b/t/helper/test-csprng.c
@@ -0,0 +1,29 @@
+#include "test-tool.h"
+#include "git-compat-util.h"
+
+
+int cmd__csprng(int argc, const char **argv)
+{
+ unsigned long count;
+ unsigned char buf[1024];
+
+ if (argc > 2) {
+ fprintf(stderr, "usage: %s [<size>]\n", argv[0]);
+ return 2;
+ }
+
+ count = (argc == 2) ? strtoul(argv[1], NULL, 0) : -1L;
+
+ while (count) {
+ unsigned long chunk = count < sizeof(buf) ? count : sizeof(buf);
+ if (csprng_bytes(buf, chunk) < 0) {
+ perror("failed to read");
+ return 5;
+ }
+ if (fwrite(buf, chunk, 1, stdout) != chunk)
+ return 1;
+ count -= chunk;
+ }
+
+ return 0;
+}
diff --git a/t/helper/test-date.c b/t/helper/test-date.c
index 099eff4..45951b1 100644
--- a/t/helper/test-date.c
+++ b/t/helper/test-date.c
@@ -1,5 +1,6 @@
#include "test-tool.h"
#include "cache.h"
+#include "date.h"
static const char *usage_msg = "\n"
" test-tool date relative [time_t]...\n"
@@ -34,7 +35,7 @@ static void show_human_dates(const char **argv)
static void show_dates(const char **argv, const char *format)
{
- struct date_mode mode;
+ struct date_mode mode = DATE_MODE_INIT;
parse_date_format(format, &mode);
for (; *argv; argv++) {
@@ -53,6 +54,8 @@ static void show_dates(const char **argv, const char *format)
printf("%s -> %s\n", *argv, show_date(t, tz, &mode));
}
+
+ date_mode_release(&mode);
}
static void parse_dates(const char **argv)
diff --git a/t/helper/test-drop-caches.c b/t/helper/test-drop-caches.c
index 7b42784..e37396d 100644
--- a/t/helper/test-drop-caches.c
+++ b/t/helper/test-drop-caches.c
@@ -3,6 +3,7 @@
#if defined(GIT_WINDOWS_NATIVE)
#include "lazyload.h"
+#include <winnt.h>
static int cmd_sync(void)
{
@@ -86,7 +87,8 @@ static int cmd_dropcaches(void)
{
HANDLE hProcess = GetCurrentProcess();
HANDLE hToken;
- DECLARE_PROC_ADDR(ntdll.dll, DWORD, NtSetSystemInformation, INT, PVOID, ULONG);
+ DECLARE_PROC_ADDR(ntdll.dll, DWORD, NTAPI, NtSetSystemInformation, INT, PVOID,
+ ULONG);
SYSTEM_MEMORY_LIST_COMMAND command;
int status;
diff --git a/t/helper/test-dump-fsmonitor.c b/t/helper/test-dump-fsmonitor.c
index 2786f47..975f0ac 100644
--- a/t/helper/test-dump-fsmonitor.c
+++ b/t/helper/test-dump-fsmonitor.c
@@ -13,7 +13,7 @@ int cmd__dump_fsmonitor(int ac, const char **av)
printf("no fsmonitor\n");
return 0;
}
- printf("fsmonitor last update %"PRIuMAX"\n", (uintmax_t)istate->fsmonitor_last_update);
+ printf("fsmonitor last update %s\n", istate->fsmonitor_last_update);
for (i = 0; i < istate->cache_nr; i++)
printf((istate->cache[i]->ce_flags & CE_FSMONITOR_VALID) ? "+" : "-");
diff --git a/t/helper/test-dump-split-index.c b/t/helper/test-dump-split-index.c
index 63c689d..a209880 100644
--- a/t/helper/test-dump-split-index.c
+++ b/t/helper/test-dump-split-index.c
@@ -13,6 +13,8 @@ int cmd__dump_split_index(int ac, const char **av)
struct split_index *si;
int i;
+ setup_git_directory();
+
do_read_index(&the_index, av[1], 1);
printf("own %s\n", oid_to_hex(&the_index.oid));
si = the_index.split_index;
diff --git a/t/helper/test-dump-untracked-cache.c b/t/helper/test-dump-untracked-cache.c
index cf0f2c7..9901061 100644
--- a/t/helper/test-dump-untracked-cache.c
+++ b/t/helper/test-dump-untracked-cache.c
@@ -45,8 +45,10 @@ int cmd__dump_untracked_cache(int ac, const char **av)
struct untracked_cache *uc;
struct strbuf base = STRBUF_INIT;
- /* Hack to avoid modifying the untracked cache when we read it */
- ignore_untracked_cache_config = 1;
+ /* Set core.untrackedCache=keep before setup_git_directory() */
+ xsetenv("GIT_CONFIG_COUNT", "1", 1);
+ xsetenv("GIT_CONFIG_KEY_0", "core.untrackedCache", 1);
+ xsetenv("GIT_CONFIG_VALUE_0", "keep", 1);
setup_git_directory();
if (read_cache() < 0)
diff --git a/t/helper/test-example-decorate.c b/t/helper/test-example-decorate.c
index c8a1cde..b9d1200 100644
--- a/t/helper/test-example-decorate.c
+++ b/t/helper/test-example-decorate.c
@@ -26,8 +26,8 @@ int cmd__example_decorate(int argc, const char **argv)
* Add 2 objects, one with a non-NULL decoration and one with a NULL
* decoration.
*/
- one = lookup_unknown_object(&one_oid);
- two = lookup_unknown_object(&two_oid);
+ one = lookup_unknown_object(the_repository, &one_oid);
+ two = lookup_unknown_object(the_repository, &two_oid);
ret = add_decoration(&n, one, &decoration_a);
if (ret)
BUG("when adding a brand-new object, NULL should be returned");
@@ -56,7 +56,7 @@ int cmd__example_decorate(int argc, const char **argv)
ret = lookup_decoration(&n, two);
if (ret != &decoration_b)
BUG("lookup should return added declaration");
- three = lookup_unknown_object(&three_oid);
+ three = lookup_unknown_object(the_repository, &three_oid);
ret = lookup_decoration(&n, three);
if (ret)
BUG("lookup for unknown object should return NULL");
diff --git a/t/helper/test-fast-rebase.c b/t/helper/test-fast-rebase.c
new file mode 100644
index 0000000..4e5553e
--- /dev/null
+++ b/t/helper/test-fast-rebase.c
@@ -0,0 +1,234 @@
+/*
+ * "git fast-rebase" builtin command
+ *
+ * FAST: Forking Any Subprocesses (is) Taboo
+ *
+ * This is meant SOLELY as a demo of what is possible. sequencer.c and
+ * rebase.c should be refactored to use the ideas here, rather than attempting
+ * to extend this file to replace those (unless Phillip or Dscho say that
+ * refactoring is too hard and we need a clean slate, but I'm guessing that
+ * refactoring is the better route).
+ */
+
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#include "test-tool.h"
+
+#include "cache-tree.h"
+#include "commit.h"
+#include "lockfile.h"
+#include "merge-ort.h"
+#include "refs.h"
+#include "revision.h"
+#include "sequencer.h"
+#include "strvec.h"
+#include "tree.h"
+
+static const char *short_commit_name(struct commit *commit)
+{
+ return find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV);
+}
+
+static struct commit *peel_committish(const char *name)
+{
+ struct object *obj;
+ struct object_id oid;
+
+ if (get_oid(name, &oid))
+ return NULL;
+ obj = parse_object(the_repository, &oid);
+ return (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT);
+}
+
+static char *get_author(const char *message)
+{
+ size_t len;
+ const char *a;
+
+ a = find_commit_header(message, "author", &len);
+ if (a)
+ return xmemdupz(a, len);
+
+ return NULL;
+}
+
+static struct commit *create_commit(struct tree *tree,
+ struct commit *based_on,
+ struct commit *parent)
+{
+ struct object_id ret;
+ struct object *obj;
+ struct commit_list *parents = NULL;
+ char *author;
+ char *sign_commit = NULL;
+ struct commit_extra_header *extra;
+ struct strbuf msg = STRBUF_INIT;
+ const char *out_enc = get_commit_output_encoding();
+ const char *message = logmsg_reencode(based_on, NULL, out_enc);
+ const char *orig_message = NULL;
+ const char *exclude_gpgsig[] = { "gpgsig", NULL };
+
+ commit_list_insert(parent, &parents);
+ extra = read_commit_extra_headers(based_on, exclude_gpgsig);
+ find_commit_subject(message, &orig_message);
+ strbuf_addstr(&msg, orig_message);
+ author = get_author(message);
+ reset_ident_date();
+ if (commit_tree_extended(msg.buf, msg.len, &tree->object.oid, parents,
+ &ret, author, NULL, sign_commit, extra)) {
+ error(_("failed to write commit object"));
+ return NULL;
+ }
+ free(author);
+ strbuf_release(&msg);
+
+ obj = parse_object(the_repository, &ret);
+ return (struct commit *)obj;
+}
+
+int cmd__fast_rebase(int argc, const char **argv)
+{
+ struct commit *onto;
+ struct commit *last_commit = NULL, *last_picked_commit = NULL;
+ struct object_id head;
+ struct lock_file lock = LOCK_INIT;
+ struct strvec rev_walk_args = STRVEC_INIT;
+ struct rev_info revs;
+ struct commit *commit;
+ struct merge_options merge_opt;
+ struct tree *next_tree, *base_tree, *head_tree;
+ struct merge_result result;
+ struct strbuf reflog_msg = STRBUF_INIT;
+ struct strbuf branch_name = STRBUF_INIT;
+ int ret = 0;
+
+ /*
+ * test-tool stuff doesn't set up the git directory by default; need to
+ * do that manually.
+ */
+ setup_git_directory();
+
+ if (argc == 2 && !strcmp(argv[1], "-h")) {
+ printf("Sorry, I am not a psychiatrist; I can not give you the help you need. Oh, you meant usage...\n");
+ exit(129);
+ }
+
+ if (argc != 5 || strcmp(argv[1], "--onto"))
+ die("usage: read the code, figure out how to use it, then do so");
+
+ onto = peel_committish(argv[2]);
+ strbuf_addf(&branch_name, "refs/heads/%s", argv[4]);
+
+ /* Sanity check */
+ if (get_oid("HEAD", &head))
+ die(_("Cannot read HEAD"));
+ assert(oideq(&onto->object.oid, &head));
+
+ hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
+ if (repo_read_index(the_repository) < 0)
+ BUG("Could not read index");
+
+ repo_init_revisions(the_repository, &revs, NULL);
+ revs.verbose_header = 1;
+ revs.max_parents = 1;
+ revs.cherry_mark = 1;
+ revs.limited = 1;
+ revs.reverse = 1;
+ revs.right_only = 1;
+ revs.sort_order = REV_SORT_IN_GRAPH_ORDER;
+ revs.topo_order = 1;
+ strvec_pushl(&rev_walk_args, "", argv[4], "--not", argv[3], NULL);
+
+ if (setup_revisions(rev_walk_args.nr, rev_walk_args.v, &revs, NULL) > 1) {
+ ret = error(_("unhandled options"));
+ goto cleanup;
+ }
+
+ strvec_clear(&rev_walk_args);
+
+ if (prepare_revision_walk(&revs) < 0) {
+ ret = error(_("error preparing revisions"));
+ goto cleanup;
+ }
+
+ init_merge_options(&merge_opt, the_repository);
+ memset(&result, 0, sizeof(result));
+ merge_opt.show_rename_progress = 1;
+ merge_opt.branch1 = "HEAD";
+ head_tree = get_commit_tree(onto);
+ result.tree = head_tree;
+ last_commit = onto;
+ while ((commit = get_revision(&revs))) {
+ struct commit *base;
+
+ fprintf(stderr, "Rebasing %s...\r",
+ oid_to_hex(&commit->object.oid));
+ assert(commit->parents && !commit->parents->next);
+ base = commit->parents->item;
+
+ next_tree = get_commit_tree(commit);
+ base_tree = get_commit_tree(base);
+
+ merge_opt.branch2 = short_commit_name(commit);
+ merge_opt.ancestor = xstrfmt("parent of %s", merge_opt.branch2);
+
+ merge_incore_nonrecursive(&merge_opt,
+ base_tree,
+ result.tree,
+ next_tree,
+ &result);
+
+ free((char*)merge_opt.ancestor);
+ merge_opt.ancestor = NULL;
+ if (!result.clean)
+ break;
+ last_picked_commit = commit;
+ last_commit = create_commit(result.tree, commit, last_commit);
+ }
+ /* TODO: There should be some kind of rev_info_free(&revs) call... */
+ memset(&revs, 0, sizeof(revs));
+
+ merge_switch_to_result(&merge_opt, head_tree, &result, 1, !result.clean);
+
+ if (result.clean < 0)
+ exit(128);
+
+ if (result.clean) {
+ fprintf(stderr, "\nDone.\n");
+ strbuf_addf(&reflog_msg, "finish rebase %s onto %s",
+ oid_to_hex(&last_picked_commit->object.oid),
+ oid_to_hex(&last_commit->object.oid));
+ if (update_ref(reflog_msg.buf, branch_name.buf,
+ &last_commit->object.oid,
+ &last_picked_commit->object.oid,
+ REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR)) {
+ error(_("could not update %s"), argv[4]);
+ die("Failed to update %s", argv[4]);
+ }
+ if (create_symref("HEAD", branch_name.buf, reflog_msg.buf) < 0)
+ die(_("unable to update HEAD"));
+
+ prime_cache_tree(the_repository, the_repository->index,
+ result.tree);
+ } else {
+ fprintf(stderr, "\nAborting: Hit a conflict.\n");
+ strbuf_addf(&reflog_msg, "rebase progress up to %s",
+ oid_to_hex(&last_picked_commit->object.oid));
+ if (update_ref(reflog_msg.buf, "HEAD",
+ &last_commit->object.oid,
+ &head,
+ REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR)) {
+ error(_("could not update %s"), argv[4]);
+ die("Failed to update %s", argv[4]);
+ }
+ }
+ if (write_locked_index(&the_index, &lock,
+ COMMIT_LOCK | SKIP_IF_UNCHANGED))
+ die(_("unable to write %s"), get_index_file());
+
+ ret = (result.clean == 0);
+cleanup:
+ strbuf_release(&reflog_msg);
+ strbuf_release(&branch_name);
+ release_revisions(&revs);
+ return ret;
+}
diff --git a/t/helper/test-fsmonitor-client.c b/t/helper/test-fsmonitor-client.c
new file mode 100644
index 0000000..54a4856
--- /dev/null
+++ b/t/helper/test-fsmonitor-client.c
@@ -0,0 +1,222 @@
+/*
+ * test-fsmonitor-client.c: client code to send commands/requests to
+ * a `git fsmonitor--daemon` daemon.
+ */
+
+#include "test-tool.h"
+#include "cache.h"
+#include "parse-options.h"
+#include "fsmonitor-ipc.h"
+#include "thread-utils.h"
+#include "trace2.h"
+
+#ifndef HAVE_FSMONITOR_DAEMON_BACKEND
+int cmd__fsmonitor_client(int argc, const char **argv)
+{
+ die("fsmonitor--daemon not available on this platform");
+}
+#else
+
+/*
+ * Read the `.git/index` to get the last token written to the
+ * FSMonitor Index Extension.
+ */
+static const char *get_token_from_index(void)
+{
+ struct index_state *istate = the_repository->index;
+
+ if (do_read_index(istate, the_repository->index_file, 0) < 0)
+ die("unable to read index file");
+ if (!istate->fsmonitor_last_update)
+ die("index file does not have fsmonitor extension");
+
+ return istate->fsmonitor_last_update;
+}
+
+/*
+ * Send an IPC query to a `git-fsmonitor--daemon` daemon and
+ * ask for the changes since the given token or from the last
+ * token in the index extension.
+ *
+ * This will implicitly start a daemon process if necessary. The
+ * daemon process will persist after we exit.
+ */
+static int do_send_query(const char *token)
+{
+ struct strbuf answer = STRBUF_INIT;
+ int ret;
+
+ if (!token || !*token)
+ token = get_token_from_index();
+
+ ret = fsmonitor_ipc__send_query(token, &answer);
+ if (ret < 0)
+ die("could not query fsmonitor--daemon");
+
+ write_in_full(1, answer.buf, answer.len);
+ strbuf_release(&answer);
+
+ return 0;
+}
+
+/*
+ * Send a "flush" command to the `git-fsmonitor--daemon` (if running)
+ * and tell it to flush its cache.
+ *
+ * This feature is primarily used by the test suite to simulate a loss of
+ * sync with the filesystem where we miss kernel events.
+ */
+static int do_send_flush(void)
+{
+ struct strbuf answer = STRBUF_INIT;
+ int ret;
+
+ ret = fsmonitor_ipc__send_command("flush", &answer);
+ if (ret)
+ return ret;
+
+ write_in_full(1, answer.buf, answer.len);
+ strbuf_release(&answer);
+
+ return 0;
+}
+
+struct hammer_thread_data
+{
+ pthread_t pthread_id;
+ int thread_nr;
+
+ int nr_requests;
+ const char *token;
+
+ int sum_successful;
+ int sum_errors;
+};
+
+static void *hammer_thread_proc(void *_hammer_thread_data)
+{
+ struct hammer_thread_data *data = _hammer_thread_data;
+ struct strbuf answer = STRBUF_INIT;
+ int k;
+ int ret;
+
+ trace2_thread_start("hammer");
+
+ for (k = 0; k < data->nr_requests; k++) {
+ strbuf_reset(&answer);
+
+ ret = fsmonitor_ipc__send_query(data->token, &answer);
+ if (ret < 0)
+ data->sum_errors++;
+ else
+ data->sum_successful++;
+ }
+
+ strbuf_release(&answer);
+ trace2_thread_exit();
+ return NULL;
+}
+
+/*
+ * Start a pool of client threads that will each send a series of
+ * commands to the daemon.
+ *
+ * The goal is to overload the daemon with a sustained series of
+ * concurrent requests.
+ */
+static int do_hammer(const char *token, int nr_threads, int nr_requests)
+{
+ struct hammer_thread_data *data = NULL;
+ int k;
+ int sum_join_errors = 0;
+ int sum_commands = 0;
+ int sum_errors = 0;
+
+ if (!token || !*token)
+ token = get_token_from_index();
+ if (nr_threads < 1)
+ nr_threads = 1;
+ if (nr_requests < 1)
+ nr_requests = 1;
+
+ CALLOC_ARRAY(data, nr_threads);
+
+ for (k = 0; k < nr_threads; k++) {
+ struct hammer_thread_data *p = &data[k];
+ p->thread_nr = k;
+ p->nr_requests = nr_requests;
+ p->token = token;
+
+ if (pthread_create(&p->pthread_id, NULL, hammer_thread_proc, p)) {
+ warning("failed to create thread[%d] skipping remainder", k);
+ nr_threads = k;
+ break;
+ }
+ }
+
+ for (k = 0; k < nr_threads; k++) {
+ struct hammer_thread_data *p = &data[k];
+
+ if (pthread_join(p->pthread_id, NULL))
+ sum_join_errors++;
+ sum_commands += p->sum_successful;
+ sum_errors += p->sum_errors;
+ }
+
+ fprintf(stderr, "HAMMER: [threads %d][requests %d] [ok %d][err %d][join %d]\n",
+ nr_threads, nr_requests, sum_commands, sum_errors, sum_join_errors);
+
+ free(data);
+
+ /*
+ * Return an error if any of the _send_query requests failed.
+ * We don't care about thread create/join errors.
+ */
+ return sum_errors > 0;
+}
+
+int cmd__fsmonitor_client(int argc, const char **argv)
+{
+ const char *subcmd;
+ const char *token = NULL;
+ int nr_threads = 1;
+ int nr_requests = 1;
+
+ const char * const fsmonitor_client_usage[] = {
+ "test-tool fsmonitor-client query [<token>]",
+ "test-tool fsmonitor-client flush",
+ "test-tool fsmonitor-client hammer [<token>] [<threads>] [<requests>]",
+ NULL,
+ };
+
+ struct option options[] = {
+ OPT_STRING(0, "token", &token, "token",
+ "command token to send to the server"),
+
+ OPT_INTEGER(0, "threads", &nr_threads, "number of client threads"),
+ OPT_INTEGER(0, "requests", &nr_requests, "number of requests per thread"),
+
+ OPT_END()
+ };
+
+ argc = parse_options(argc, argv, NULL, options, fsmonitor_client_usage, 0);
+
+ if (argc != 1)
+ usage_with_options(fsmonitor_client_usage, options);
+
+ subcmd = argv[0];
+
+ setup_git_directory();
+
+ if (!strcmp(subcmd, "query"))
+ return !!do_send_query(token);
+
+ if (!strcmp(subcmd, "flush"))
+ return !!do_send_flush();
+
+ if (!strcmp(subcmd, "hammer"))
+ return !!do_hammer(token, nr_threads, nr_requests);
+
+ die("Unhandled subcommand: '%s'", subcmd);
+}
+#endif
diff --git a/t/helper/test-genzeros.c b/t/helper/test-genzeros.c
index 9532f5b..8ca988d 100644
--- a/t/helper/test-genzeros.c
+++ b/t/helper/test-genzeros.c
@@ -3,18 +3,31 @@
int cmd__genzeros(int argc, const char **argv)
{
- long count;
+ /* static, so that it is NUL-initialized */
+ static const char zeros[256 * 1024];
+ intmax_t count;
+ ssize_t n;
if (argc > 2) {
fprintf(stderr, "usage: %s [<count>]\n", argv[0]);
return 1;
}
- count = argc > 1 ? strtol(argv[1], NULL, 0) : -1L;
+ count = argc > 1 ? strtoimax(argv[1], NULL, 0) : -1;
- while (count < 0 || count--) {
- if (putchar(0) == EOF)
+ /* Writing out individual NUL bytes is slow... */
+ while (count < 0)
+ if (write(1, zeros, ARRAY_SIZE(zeros)) < 0)
return -1;
+
+ while (count > 0) {
+ n = write(1, zeros, count < ARRAY_SIZE(zeros) ?
+ count : ARRAY_SIZE(zeros));
+
+ if (n < 0)
+ return -1;
+
+ count -= n;
}
return 0;
diff --git a/t/helper/test-getcwd.c b/t/helper/test-getcwd.c
new file mode 100644
index 0000000..d680038
--- /dev/null
+++ b/t/helper/test-getcwd.c
@@ -0,0 +1,26 @@
+#include "test-tool.h"
+#include "git-compat-util.h"
+#include "parse-options.h"
+
+static const char *getcwd_usage[] = {
+ "test-tool getcwd",
+ NULL
+};
+
+int cmd__getcwd(int argc, const char **argv)
+{
+ struct option options[] = {
+ OPT_END()
+ };
+ char *cwd;
+
+ argc = parse_options(argc, argv, "test-tools", options, getcwd_usage, 0);
+ if (argc > 0)
+ usage_with_options(getcwd_usage, options);
+
+ cwd = xgetcwd();
+ puts(cwd);
+ free(cwd);
+
+ return 0;
+}
diff --git a/t/helper/test-hash-speed.c b/t/helper/test-hash-speed.c
index 432233c..f40d9ad 100644
--- a/t/helper/test-hash-speed.c
+++ b/t/helper/test-hash-speed.c
@@ -57,5 +57,5 @@ int cmd__hash_speed(int ac, const char **av)
free(p);
}
- exit(0);
+ return 0;
}
diff --git a/t/helper/test-hash.c b/t/helper/test-hash.c
index 0a31de6..261c545 100644
--- a/t/helper/test-hash.c
+++ b/t/helper/test-hash.c
@@ -54,5 +54,5 @@ int cmd_hash_impl(int ac, const char **av, int algo)
fwrite(hash, 1, algop->rawsz, stdout);
else
puts(hash_to_hex_algop(hash, algop));
- exit(0);
+ return 0;
}
diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c
index f387062..36ff07b 100644
--- a/t/helper/test-hashmap.c
+++ b/t/helper/test-hashmap.c
@@ -110,7 +110,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)
hashmap_add(&map, &entries[i]->ent);
}
- hashmap_free(&map);
+ hashmap_clear(&map);
}
} else {
/* test map lookups */
@@ -130,7 +130,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)
}
}
- hashmap_free(&map);
+ hashmap_clear(&map);
}
}
@@ -151,12 +151,11 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)
int cmd__hashmap(int argc, const char **argv)
{
struct strbuf line = STRBUF_INIT;
- struct hashmap map;
int icase;
+ struct hashmap map = HASHMAP_INIT(test_entry_cmp, &icase);
/* init hash map */
icase = argc > 1 && !strcmp("ignorecase", argv[1]);
- hashmap_init(&map, test_entry_cmp, &icase, 0);
/* process commands from stdin */
while (strbuf_getline(&line, stdin) != EOF) {
@@ -262,6 +261,6 @@ int cmd__hashmap(int argc, const char **argv)
}
strbuf_release(&line);
- hashmap_free_entries(&map, struct test_entry, ent);
+ hashmap_clear_and_free(&map, struct test_entry, ent);
return 0;
}
diff --git a/t/helper/test-hexdump.c b/t/helper/test-hexdump.c
new file mode 100644
index 0000000..811e89c
--- /dev/null
+++ b/t/helper/test-hexdump.c
@@ -0,0 +1,30 @@
+#include "test-tool.h"
+#include "git-compat-util.h"
+
+/*
+ * Read stdin and print a hexdump to stdout.
+ */
+int cmd__hexdump(int argc, const char **argv)
+{
+ char buf[1024];
+ ssize_t i, len;
+ int have_data = 0;
+
+ for (;;) {
+ len = xread(0, buf, sizeof(buf));
+ if (len < 0)
+ die_errno("failure reading stdin");
+ if (!len)
+ break;
+
+ have_data = 1;
+
+ for (i = 0; i < len; i++)
+ printf("%02x ", (unsigned char)buf[i]);
+ }
+
+ if (have_data)
+ putchar('\n');
+
+ return 0;
+}
diff --git a/t/helper/test-line-buffer.c b/t/helper/test-line-buffer.c
deleted file mode 100644
index 078dd7e..0000000
--- a/t/helper/test-line-buffer.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * test-line-buffer.c: code to exercise the svn importer's input helper
- */
-
-#include "git-compat-util.h"
-#include "strbuf.h"
-#include "vcs-svn/line_buffer.h"
-
-static uint32_t strtouint32(const char *s)
-{
- char *end;
- uintmax_t n = strtoumax(s, &end, 10);
- if (*s == '\0' || *end != '\0')
- die("invalid count: %s", s);
- return (uint32_t) n;
-}
-
-static void handle_command(const char *command, const char *arg, struct line_buffer *buf)
-{
- if (starts_with(command, "binary ")) {
- struct strbuf sb = STRBUF_INIT;
- strbuf_addch(&sb, '>');
- buffer_read_binary(buf, &sb, strtouint32(arg));
- fwrite(sb.buf, 1, sb.len, stdout);
- strbuf_release(&sb);
- } else if (starts_with(command, "copy ")) {
- buffer_copy_bytes(buf, strtouint32(arg));
- } else if (starts_with(command, "skip ")) {
- buffer_skip_bytes(buf, strtouint32(arg));
- } else {
- die("unrecognized command: %s", command);
- }
-}
-
-static void handle_line(const char *line, struct line_buffer *stdin_buf)
-{
- const char *arg = strchr(line, ' ');
- if (!arg)
- die("no argument in line: %s", line);
- handle_command(line, arg + 1, stdin_buf);
-}
-
-int cmd_main(int argc, const char **argv)
-{
- struct line_buffer stdin_buf = LINE_BUFFER_INIT;
- struct line_buffer file_buf = LINE_BUFFER_INIT;
- struct line_buffer *input = &stdin_buf;
- const char *filename;
- char *s;
-
- if (argc == 1)
- filename = NULL;
- else if (argc == 2)
- filename = argv[1];
- else
- usage("test-line-buffer [file | &fd] < script");
-
- if (buffer_init(&stdin_buf, NULL))
- die_errno("open error");
- if (filename) {
- if (*filename == '&') {
- if (buffer_fdinit(&file_buf, strtouint32(filename + 1)))
- die_errno("error opening fd %s", filename + 1);
- } else {
- if (buffer_init(&file_buf, filename))
- die_errno("error opening %s", filename);
- }
- input = &file_buf;
- }
-
- while ((s = buffer_read_line(&stdin_buf)))
- handle_line(s, input);
-
- if (filename && buffer_deinit(&file_buf))
- die("error reading from %s", filename);
- if (buffer_deinit(&stdin_buf))
- die("input error");
- if (ferror(stdout))
- die("output error");
- return 0;
-}
diff --git a/t/helper/test-match-trees.c b/t/helper/test-match-trees.c
index b9fd427..4079fde 100644
--- a/t/helper/test-match-trees.c
+++ b/t/helper/test-match-trees.c
@@ -23,5 +23,5 @@ int cmd__match_trees(int ac, const char **av)
shift_tree(the_repository, &one->object.oid, &two->object.oid, &shifted, -1);
printf("shifted: %s\n", oid_to_hex(&shifted));
- exit(0);
+ return 0;
}
diff --git a/t/helper/test-mergesort.c b/t/helper/test-mergesort.c
index c5cffaa..ebf68f7 100644
--- a/t/helper/test-mergesort.c
+++ b/t/helper/test-mergesort.c
@@ -2,6 +2,12 @@
#include "cache.h"
#include "mergesort.h"
+static uint32_t minstd_rand(uint32_t *state)
+{
+ *state = (uint64_t)*state * 48271 % 2147483647;
+ return *state;
+}
+
struct line {
char *text;
struct line *next;
@@ -23,14 +29,12 @@ static int compare_strings(const void *a, const void *b)
return strcmp(x->text, y->text);
}
-int cmd__mergesort(int argc, const char **argv)
+static int sort_stdin(void)
{
struct line *line, *p = NULL, *lines = NULL;
struct strbuf sb = STRBUF_INIT;
- for (;;) {
- if (strbuf_getwholeline(&sb, stdin, '\n'))
- break;
+ while (!strbuf_getline(&sb, stdin)) {
line = xmalloc(sizeof(struct line));
line->text = strbuf_detach(&sb, NULL);
if (p) {
@@ -46,8 +50,362 @@ int cmd__mergesort(int argc, const char **argv)
lines = llist_mergesort(lines, get_next, set_next, compare_strings);
while (lines) {
- printf("%s", lines->text);
+ puts(lines->text);
lines = lines->next;
}
return 0;
}
+
+static void dist_sawtooth(int *arr, int n, int m)
+{
+ int i;
+ for (i = 0; i < n; i++)
+ arr[i] = i % m;
+}
+
+static void dist_rand(int *arr, int n, int m)
+{
+ int i;
+ uint32_t seed = 1;
+ for (i = 0; i < n; i++)
+ arr[i] = minstd_rand(&seed) % m;
+}
+
+static void dist_stagger(int *arr, int n, int m)
+{
+ int i;
+ for (i = 0; i < n; i++)
+ arr[i] = (i * m + i) % n;
+}
+
+static void dist_plateau(int *arr, int n, int m)
+{
+ int i;
+ for (i = 0; i < n; i++)
+ arr[i] = (i < m) ? i : m;
+}
+
+static void dist_shuffle(int *arr, int n, int m)
+{
+ int i, j, k;
+ uint32_t seed = 1;
+ for (i = j = 0, k = 1; i < n; i++)
+ arr[i] = minstd_rand(&seed) % m ? (j += 2) : (k += 2);
+}
+
+#define DIST(name) { #name, dist_##name }
+
+static struct dist {
+ const char *name;
+ void (*fn)(int *arr, int n, int m);
+} dist[] = {
+ DIST(sawtooth),
+ DIST(rand),
+ DIST(stagger),
+ DIST(plateau),
+ DIST(shuffle),
+};
+
+static const struct dist *get_dist_by_name(const char *name)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(dist); i++) {
+ if (!strcmp(dist[i].name, name))
+ return &dist[i];
+ }
+ return NULL;
+}
+
+static void mode_copy(int *arr, int n)
+{
+ /* nothing */
+}
+
+static void mode_reverse(int *arr, int n)
+{
+ int i, j;
+ for (i = 0, j = n - 1; i < j; i++, j--)
+ SWAP(arr[i], arr[j]);
+}
+
+static void mode_reverse_1st_half(int *arr, int n)
+{
+ mode_reverse(arr, n / 2);
+}
+
+static void mode_reverse_2nd_half(int *arr, int n)
+{
+ int half = n / 2;
+ mode_reverse(arr + half, n - half);
+}
+
+static int compare_ints(const void *av, const void *bv)
+{
+ const int *ap = av, *bp = bv;
+ int a = *ap, b = *bp;
+ return (a > b) - (a < b);
+}
+
+static void mode_sort(int *arr, int n)
+{
+ QSORT(arr, n, compare_ints);
+}
+
+static void mode_dither(int *arr, int n)
+{
+ int i;
+ for (i = 0; i < n; i++)
+ arr[i] += i % 5;
+}
+
+static void unriffle(int *arr, int n, int *tmp)
+{
+ int i, j;
+ COPY_ARRAY(tmp, arr, n);
+ for (i = j = 0; i < n; i += 2)
+ arr[j++] = tmp[i];
+ for (i = 1; i < n; i += 2)
+ arr[j++] = tmp[i];
+}
+
+static void unriffle_recursively(int *arr, int n, int *tmp)
+{
+ if (n > 1) {
+ int half = n / 2;
+ unriffle(arr, n, tmp);
+ unriffle_recursively(arr, half, tmp);
+ unriffle_recursively(arr + half, n - half, tmp);
+ }
+}
+
+static void mode_unriffle(int *arr, int n)
+{
+ int *tmp;
+ ALLOC_ARRAY(tmp, n);
+ unriffle_recursively(arr, n, tmp);
+ free(tmp);
+}
+
+static unsigned int prev_pow2(unsigned int n)
+{
+ unsigned int pow2 = 1;
+ while (pow2 * 2 < n)
+ pow2 *= 2;
+ return pow2;
+}
+
+static void unriffle_recursively_skewed(int *arr, int n, int *tmp)
+{
+ if (n > 1) {
+ int pow2 = prev_pow2(n);
+ int rest = n - pow2;
+ unriffle(arr + pow2 - rest, rest * 2, tmp);
+ unriffle_recursively_skewed(arr, pow2, tmp);
+ unriffle_recursively_skewed(arr + pow2, rest, tmp);
+ }
+}
+
+static void mode_unriffle_skewed(int *arr, int n)
+{
+ int *tmp;
+ ALLOC_ARRAY(tmp, n);
+ unriffle_recursively_skewed(arr, n, tmp);
+ free(tmp);
+}
+
+#define MODE(name) { #name, mode_##name }
+
+static struct mode {
+ const char *name;
+ void (*fn)(int *arr, int n);
+} mode[] = {
+ MODE(copy),
+ MODE(reverse),
+ MODE(reverse_1st_half),
+ MODE(reverse_2nd_half),
+ MODE(sort),
+ MODE(dither),
+ MODE(unriffle),
+ MODE(unriffle_skewed),
+};
+
+static const struct mode *get_mode_by_name(const char *name)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(mode); i++) {
+ if (!strcmp(mode[i].name, name))
+ return &mode[i];
+ }
+ return NULL;
+}
+
+static int generate(int argc, const char **argv)
+{
+ const struct dist *dist = NULL;
+ const struct mode *mode = NULL;
+ int i, n, m, *arr;
+
+ if (argc != 4)
+ return 1;
+
+ dist = get_dist_by_name(argv[0]);
+ mode = get_mode_by_name(argv[1]);
+ n = strtol(argv[2], NULL, 10);
+ m = strtol(argv[3], NULL, 10);
+ if (!dist || !mode)
+ return 1;
+
+ ALLOC_ARRAY(arr, n);
+ dist->fn(arr, n, m);
+ mode->fn(arr, n);
+ for (i = 0; i < n; i++)
+ printf("%08x\n", arr[i]);
+ free(arr);
+ return 0;
+}
+
+static struct stats {
+ int get_next, set_next, compare;
+} stats;
+
+struct number {
+ int value, rank;
+ struct number *next;
+};
+
+static void *get_next_number(const void *a)
+{
+ stats.get_next++;
+ return ((const struct number *)a)->next;
+}
+
+static void set_next_number(void *a, void *b)
+{
+ stats.set_next++;
+ ((struct number *)a)->next = b;
+}
+
+static int compare_numbers(const void *av, const void *bv)
+{
+ const struct number *an = av, *bn = bv;
+ int a = an->value, b = bn->value;
+ stats.compare++;
+ return (a > b) - (a < b);
+}
+
+static void clear_numbers(struct number *list)
+{
+ while (list) {
+ struct number *next = list->next;
+ free(list);
+ list = next;
+ }
+}
+
+static int test(const struct dist *dist, const struct mode *mode, int n, int m)
+{
+ int *arr;
+ size_t i;
+ struct number *curr, *list, **tail;
+ int is_sorted = 1;
+ int is_stable = 1;
+ const char *verdict;
+ int result = -1;
+
+ ALLOC_ARRAY(arr, n);
+ dist->fn(arr, n, m);
+ mode->fn(arr, n);
+ for (i = 0, tail = &list; i < n; i++) {
+ curr = xmalloc(sizeof(*curr));
+ curr->value = arr[i];
+ curr->rank = i;
+ *tail = curr;
+ tail = &curr->next;
+ }
+ *tail = NULL;
+
+ stats.get_next = stats.set_next = stats.compare = 0;
+ list = llist_mergesort(list, get_next_number, set_next_number,
+ compare_numbers);
+
+ QSORT(arr, n, compare_ints);
+ for (i = 0, curr = list; i < n && curr; i++, curr = curr->next) {
+ if (arr[i] != curr->value)
+ is_sorted = 0;
+ if (curr->next && curr->value == curr->next->value &&
+ curr->rank >= curr->next->rank)
+ is_stable = 0;
+ }
+ if (i < n) {
+ verdict = "too short";
+ } else if (curr) {
+ verdict = "too long";
+ } else if (!is_sorted) {
+ verdict = "not sorted";
+ } else if (!is_stable) {
+ verdict = "unstable";
+ } else {
+ verdict = "OK";
+ result = 0;
+ }
+
+ printf("%-9s %-16s %8d %8d %8d %8d %8d %s\n",
+ dist->name, mode->name, n, m, stats.get_next, stats.set_next,
+ stats.compare, verdict);
+
+ clear_numbers(list);
+ free(arr);
+
+ return result;
+}
+
+/*
+ * A version of the qsort certification program from "Engineering a Sort
+ * Function" by Bentley and McIlroy, Software—Practice and Experience,
+ * Volume 23, Issue 11, 1249–1265 (November 1993).
+ */
+static int run_tests(int argc, const char **argv)
+{
+ const char *argv_default[] = { "100", "1023", "1024", "1025" };
+ if (!argc)
+ return run_tests(ARRAY_SIZE(argv_default), argv_default);
+ printf("%-9s %-16s %8s %8s %8s %8s %8s %s\n",
+ "distribut", "mode", "n", "m", "get_next", "set_next",
+ "compare", "verdict");
+ while (argc--) {
+ int i, j, m, n = strtol(*argv++, NULL, 10);
+ for (i = 0; i < ARRAY_SIZE(dist); i++) {
+ for (j = 0; j < ARRAY_SIZE(mode); j++) {
+ for (m = 1; m < 2 * n; m *= 2) {
+ if (test(&dist[i], &mode[j], n, m))
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+int cmd__mergesort(int argc, const char **argv)
+{
+ int i;
+ const char *sep;
+
+ if (argc == 6 && !strcmp(argv[1], "generate"))
+ return generate(argc - 2, argv + 2);
+ if (argc == 2 && !strcmp(argv[1], "sort"))
+ return sort_stdin();
+ if (argc > 1 && !strcmp(argv[1], "test"))
+ return run_tests(argc - 2, argv + 2);
+ fprintf(stderr, "usage: test-tool mergesort generate <distribution> <mode> <n> <m>\n");
+ fprintf(stderr, " or: test-tool mergesort sort\n");
+ fprintf(stderr, " or: test-tool mergesort test [<n>...]\n");
+ fprintf(stderr, "\n");
+ for (i = 0, sep = "distributions: "; i < ARRAY_SIZE(dist); i++, sep = ", ")
+ fprintf(stderr, "%s%s", sep, dist[i].name);
+ fprintf(stderr, "\n");
+ for (i = 0, sep = "modes: "; i < ARRAY_SIZE(mode); i++, sep = ", ")
+ fprintf(stderr, "%s%s", sep, mode[i].name);
+ fprintf(stderr, "\n");
+ return 129;
+}
diff --git a/t/helper/test-sha1-array.c b/t/helper/test-oid-array.c
index ad5e69f..d1324d0 100644
--- a/t/helper/test-sha1-array.c
+++ b/t/helper/test-oid-array.c
@@ -1,6 +1,6 @@
#include "test-tool.h"
#include "cache.h"
-#include "sha1-array.h"
+#include "oid-array.h"
static int print_oid(const struct object_id *oid, void *data)
{
@@ -8,10 +8,13 @@ static int print_oid(const struct object_id *oid, void *data)
return 0;
}
-int cmd__sha1_array(int argc, const char **argv)
+int cmd__oid_array(int argc, const char **argv)
{
struct oid_array array = OID_ARRAY_INIT;
struct strbuf line = STRBUF_INIT;
+ int nongit_ok;
+
+ setup_git_directory_gently(&nongit_ok);
while (strbuf_getline(&line, stdin) != EOF) {
const char *arg;
@@ -19,11 +22,11 @@ int cmd__sha1_array(int argc, const char **argv)
if (skip_prefix(line.buf, "append ", &arg)) {
if (get_oid_hex(arg, &oid))
- die("not a hexadecimal SHA1: %s", arg);
+ die("not a hexadecimal oid: %s", arg);
oid_array_append(&array, &oid);
} else if (skip_prefix(line.buf, "lookup ", &arg)) {
if (get_oid_hex(arg, &oid))
- die("not a hexadecimal SHA1: %s", arg);
+ die("not a hexadecimal oid: %s", arg);
printf("%d\n", oid_array_lookup(&array, &oid));
} else if (!strcmp(line.buf, "clear"))
oid_array_clear(&array);
@@ -32,5 +35,9 @@ int cmd__sha1_array(int argc, const char **argv)
else
die("unknown command: %s", line.buf);
}
+
+ strbuf_release(&line);
+ oid_array_clear(&array);
+
return 0;
}
diff --git a/t/helper/test-oidtree.c b/t/helper/test-oidtree.c
new file mode 100644
index 0000000..d48a409
--- /dev/null
+++ b/t/helper/test-oidtree.c
@@ -0,0 +1,52 @@
+#include "test-tool.h"
+#include "cache.h"
+#include "oidtree.h"
+
+static enum cb_next print_oid(const struct object_id *oid, void *data)
+{
+ puts(oid_to_hex(oid));
+ return CB_CONTINUE;
+}
+
+int cmd__oidtree(int argc, const char **argv)
+{
+ struct oidtree ot;
+ struct strbuf line = STRBUF_INIT;
+ int nongit_ok;
+ int algo = GIT_HASH_UNKNOWN;
+
+ oidtree_init(&ot);
+ setup_git_directory_gently(&nongit_ok);
+
+ while (strbuf_getline(&line, stdin) != EOF) {
+ const char *arg;
+ struct object_id oid;
+
+ if (skip_prefix(line.buf, "insert ", &arg)) {
+ if (get_oid_hex_any(arg, &oid) == GIT_HASH_UNKNOWN)
+ die("insert not a hexadecimal oid: %s", arg);
+ algo = oid.algo;
+ oidtree_insert(&ot, &oid);
+ } else if (skip_prefix(line.buf, "contains ", &arg)) {
+ if (get_oid_hex(arg, &oid))
+ die("contains not a hexadecimal oid: %s", arg);
+ printf("%d\n", oidtree_contains(&ot, &oid));
+ } else if (skip_prefix(line.buf, "each ", &arg)) {
+ char buf[GIT_MAX_HEXSZ + 1] = { '0' };
+ memset(&oid, 0, sizeof(oid));
+ memcpy(buf, arg, strlen(arg));
+ buf[hash_algos[algo].hexsz] = '\0';
+ get_oid_hex_any(buf, &oid);
+ oid.algo = algo;
+ oidtree_each(&ot, &oid, strlen(arg), print_oid, NULL);
+ } else if (!strcmp(line.buf, "clear")) {
+ oidtree_clear(&ot);
+ } else {
+ die("unknown command: %s", line.buf);
+ }
+ }
+
+ strbuf_release(&line);
+
+ return 0;
+}
diff --git a/t/helper/test-pack-mtimes.c b/t/helper/test-pack-mtimes.c
new file mode 100644
index 0000000..f7b79da
--- /dev/null
+++ b/t/helper/test-pack-mtimes.c
@@ -0,0 +1,56 @@
+#include "git-compat-util.h"
+#include "test-tool.h"
+#include "strbuf.h"
+#include "object-store.h"
+#include "packfile.h"
+#include "pack-mtimes.h"
+
+static void dump_mtimes(struct packed_git *p)
+{
+ uint32_t i;
+ if (load_pack_mtimes(p) < 0)
+ die("could not load pack .mtimes");
+
+ for (i = 0; i < p->num_objects; i++) {
+ struct object_id oid;
+ if (nth_packed_object_id(&oid, p, i) < 0)
+ die("could not load object id at position %"PRIu32, i);
+
+ printf("%s %"PRIu32"\n",
+ oid_to_hex(&oid), nth_packed_mtime(p, i));
+ }
+}
+
+static const char *pack_mtimes_usage = "\n"
+" test-tool pack-mtimes <pack-name.mtimes>";
+
+int cmd__pack_mtimes(int argc, const char **argv)
+{
+ struct strbuf buf = STRBUF_INIT;
+ struct packed_git *p;
+
+ setup_git_directory();
+
+ if (argc != 2)
+ usage(pack_mtimes_usage);
+
+ for (p = get_all_packs(the_repository); p; p = p->next) {
+ strbuf_addstr(&buf, basename(p->pack_name));
+ strbuf_strip_suffix(&buf, ".pack");
+ strbuf_addstr(&buf, ".mtimes");
+
+ if (!strcmp(buf.buf, argv[1]))
+ break;
+
+ strbuf_reset(&buf);
+ }
+
+ strbuf_release(&buf);
+
+ if (!p)
+ die("could not find pack '%s'", argv[1]);
+
+ dump_mtimes(p);
+
+ return 0;
+}
diff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c
index af82db0..48d3cf6 100644
--- a/t/helper/test-parse-options.c
+++ b/t/helper/test-parse-options.c
@@ -14,7 +14,6 @@ static int dry_run = 0, quiet = 0;
static char *string = NULL;
static char *file = NULL;
static int ambiguous;
-static struct string_list list = STRING_LIST_INIT_NODUP;
static struct {
int called;
@@ -107,6 +106,8 @@ int cmd__parse_options(int argc, const char **argv)
NULL
};
struct string_list expect = STRING_LIST_INIT_NODUP;
+ struct string_list list = STRING_LIST_INIT_NODUP;
+
struct option options[] = {
OPT_BOOL(0, "yes", &boolean, "get a boolean"),
OPT_BOOL('D', "no-doubt", &boolean, "begins with 'no-'"),
@@ -121,6 +122,8 @@ int cmd__parse_options(int argc, const char **argv)
OPT_INTEGER('j', NULL, &integer, "get a integer, too"),
OPT_MAGNITUDE('m', "magnitude", &magnitude, "get a magnitude"),
OPT_SET_INT(0, "set23", &integer, "set integer to 23", 23),
+ OPT_CMDMODE(0, "mode1", &integer, "set integer to 1 (cmdmode option)", 1),
+ OPT_CMDMODE(0, "mode2", &integer, "set integer to 2 (cmdmode option)", 2),
OPT_CALLBACK('L', "length", &integer, "str",
"get length of <str>", length_callback),
OPT_FILENAME('F', "file", &file, "set file to <file>"),
@@ -132,7 +135,6 @@ int cmd__parse_options(int argc, const char **argv)
OPT_NOOP_NOARG(0, "obsolete"),
OPT_STRING_LIST(0, "list", &list, "str", "add str to list"),
OPT_GROUP("Magic arguments"),
- OPT_ARGUMENT("quux", NULL, "means --quux"),
OPT_NUMBER_CALLBACK(&integer, "set integer to NUM",
number_callback),
{ OPTION_COUNTUP, '+', NULL, &boolean, NULL, "same as -b",
@@ -184,5 +186,9 @@ int cmd__parse_options(int argc, const char **argv)
for (i = 0; i < argc; i++)
show(&expect, &ret, "arg %02d: %s", i, argv[i]);
+ expect.strdup_strings = 1;
+ string_list_clear(&expect, 0);
+ string_list_clear(&list, 0);
+
return ret;
}
diff --git a/t/helper/test-parse-pathspec-file.c b/t/helper/test-parse-pathspec-file.c
new file mode 100644
index 0000000..b3e08ce
--- /dev/null
+++ b/t/helper/test-parse-pathspec-file.c
@@ -0,0 +1,33 @@
+#include "test-tool.h"
+#include "parse-options.h"
+#include "pathspec.h"
+#include "gettext.h"
+
+int cmd__parse_pathspec_file(int argc, const char **argv)
+{
+ struct pathspec pathspec;
+ const char *pathspec_from_file = NULL;
+ int pathspec_file_nul = 0, i;
+
+ static const char *const usage[] = {
+ "test-tool parse-pathspec-file --pathspec-from-file [--pathspec-file-nul]",
+ NULL
+ };
+
+ struct option options[] = {
+ OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
+ OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
+ OPT_END()
+ };
+
+ parse_options(argc, argv, NULL, options, usage, 0);
+
+ parse_pathspec_file(&pathspec, 0, 0, NULL, pathspec_from_file,
+ pathspec_file_nul);
+
+ for (i = 0; i < pathspec.nr; i++)
+ printf("%s\n", pathspec.items[i].original);
+
+ clear_pathspec(&pathspec);
+ return 0;
+}
diff --git a/t/helper/test-partial-clone.c b/t/helper/test-partial-clone.c
new file mode 100644
index 0000000..3f102cf
--- /dev/null
+++ b/t/helper/test-partial-clone.c
@@ -0,0 +1,43 @@
+#include "cache.h"
+#include "test-tool.h"
+#include "repository.h"
+#include "object-store.h"
+
+/*
+ * Prints the size of the object corresponding to the given hash in a specific
+ * gitdir. This is similar to "git -C gitdir cat-file -s", except that this
+ * exercises the code that accesses the object of an arbitrary repository that
+ * is not the_repository. ("git -C gitdir" makes it so that the_repository is
+ * the one in gitdir.)
+ */
+static void object_info(const char *gitdir, const char *oid_hex)
+{
+ struct repository r;
+ struct object_id oid;
+ unsigned long size;
+ struct object_info oi = {.sizep = &size};
+ const char *p;
+
+ if (repo_init(&r, gitdir, NULL))
+ die("could not init repo");
+ if (parse_oid_hex(oid_hex, &oid, &p))
+ die("could not parse oid");
+ if (oid_object_info_extended(&r, &oid, &oi, 0))
+ die("could not obtain object info");
+ printf("%d\n", (int) size);
+}
+
+int cmd__partial_clone(int argc, const char **argv)
+{
+ setup_git_directory();
+
+ if (argc < 4)
+ die("too few arguments");
+
+ if (!strcmp(argv[1], "object-info"))
+ object_info(argv[2], argv[3]);
+ else
+ die("invalid argument '%s'", argv[1]);
+
+ return 0;
+}
diff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c
index 409034c..229ed41 100644
--- a/t/helper/test-path-utils.c
+++ b/t/helper/test-path-utils.c
@@ -172,9 +172,22 @@ static struct test_data dirname_data[] = {
{ NULL, NULL }
};
-static int is_dotgitmodules(const char *path)
+static int check_dotfile(const char *x, const char **argv,
+ int (*is_hfs)(const char *),
+ int (*is_ntfs)(const char *))
{
- return is_hfs_dotgitmodules(path) || is_ntfs_dotgitmodules(path);
+ int res = 0, expect = 1;
+ for (; *argv; argv++) {
+ if (!strcmp("--not", *argv))
+ expect = !expect;
+ else if (expect != (is_hfs(*argv) || is_ntfs(*argv)))
+ res = error("'%s' is %s.git%s", *argv,
+ expect ? "not " : "", x);
+ else
+ fprintf(stderr, "ok: '%s' is %s.git%s\n",
+ *argv, expect ? "" : "not ", x);
+ }
+ return !!res;
}
static int cmp_by_st_size(const void *a, const void *b)
@@ -290,11 +303,14 @@ int cmd__path_utils(int argc, const char **argv)
}
if (argc >= 2 && !strcmp(argv[1], "real_path")) {
+ struct strbuf realpath = STRBUF_INIT;
while (argc > 2) {
- puts(real_path(argv[2]));
+ strbuf_realpath(&realpath, argv[2], 1);
+ puts(realpath.buf);
argc--;
argv++;
}
+ strbuf_release(&realpath);
return 0;
}
@@ -379,17 +395,24 @@ int cmd__path_utils(int argc, const char **argv)
return test_function(dirname_data, posix_dirname, argv[1]);
if (argc > 2 && !strcmp(argv[1], "is_dotgitmodules")) {
- int res = 0, expect = 1, i;
- for (i = 2; i < argc; i++)
- if (!strcmp("--not", argv[i]))
- expect = !expect;
- else if (expect != is_dotgitmodules(argv[i]))
- res = error("'%s' is %s.gitmodules", argv[i],
- expect ? "not " : "");
- else
- fprintf(stderr, "ok: '%s' is %s.gitmodules\n",
- argv[i], expect ? "" : "not ");
- return !!res;
+ return check_dotfile("modules", argv + 2,
+ is_hfs_dotgitmodules,
+ is_ntfs_dotgitmodules);
+ }
+ if (argc > 2 && !strcmp(argv[1], "is_dotgitignore")) {
+ return check_dotfile("ignore", argv + 2,
+ is_hfs_dotgitignore,
+ is_ntfs_dotgitignore);
+ }
+ if (argc > 2 && !strcmp(argv[1], "is_dotgitattributes")) {
+ return check_dotfile("attributes", argv + 2,
+ is_hfs_dotgitattributes,
+ is_ntfs_dotgitattributes);
+ }
+ if (argc > 2 && !strcmp(argv[1], "is_dotmailmap")) {
+ return check_dotfile("mailmap", argv + 2,
+ is_hfs_dotmailmap,
+ is_ntfs_dotmailmap);
}
if (argc > 2 && !strcmp(argv[1], "file-size")) {
diff --git a/t/helper/test-pcre2-config.c b/t/helper/test-pcre2-config.c
new file mode 100644
index 0000000..5258fdd
--- /dev/null
+++ b/t/helper/test-pcre2-config.c
@@ -0,0 +1,12 @@
+#include "test-tool.h"
+#include "cache.h"
+#include "grep.h"
+
+int cmd__pcre2_config(int argc, const char **argv)
+{
+ if (argc == 2 && !strcmp(argv[1], "has-PCRE2_MATCH_INVALID_UTF")) {
+ int value = PCRE2_MATCH_INVALID_UTF;
+ return !value;
+ }
+ return 1;
+}
diff --git a/t/helper/test-pkt-line.c b/t/helper/test-pkt-line.c
index 282d536..c5e052e 100644
--- a/t/helper/test-pkt-line.c
+++ b/t/helper/test-pkt-line.c
@@ -26,6 +26,16 @@ static void pack(int argc, const char **argv)
}
}
+static void pack_raw_stdin(void)
+{
+ struct strbuf sb = STRBUF_INIT;
+
+ if (strbuf_read(&sb, 0, 0) < 0)
+ die_errno("failed to read from stdin");
+ packet_write(1, sb.buf, sb.len);
+ strbuf_release(&sb);
+}
+
static void unpack(void)
{
struct packet_reader reader;
@@ -46,6 +56,9 @@ static void unpack(void)
case PACKET_READ_DELIM:
printf("0001\n");
break;
+ case PACKET_READ_RESPONSE_END:
+ printf("0002\n");
+ break;
}
}
}
@@ -67,7 +80,7 @@ static void unpack_sideband(void)
case PACKET_READ_NORMAL:
band = reader.line[0] & 0xff;
if (band < 1 || band > 2)
- die("unexpected side band %d", band);
+ continue; /* skip non-sideband packets */
fd = band;
write_or_die(fd, reader.line + 1, reader.pktlen - 1);
@@ -75,11 +88,31 @@ static void unpack_sideband(void)
case PACKET_READ_FLUSH:
return;
case PACKET_READ_DELIM:
+ case PACKET_READ_RESPONSE_END:
break;
}
}
}
+static int send_split_sideband(void)
+{
+ const char *part1 = "Hello,";
+ const char *primary = "\001primary: regular output\n";
+ const char *part2 = " world!\n";
+
+ send_sideband(1, 2, part1, strlen(part1), LARGE_PACKET_MAX);
+ packet_write(1, primary, strlen(primary));
+ send_sideband(1, 2, part2, strlen(part2), LARGE_PACKET_MAX);
+ packet_response_end(1);
+
+ return 0;
+}
+
+static int receive_sideband(void)
+{
+ return recv_sideband("sideband", 0, 1);
+}
+
int cmd__pkt_line(int argc, const char **argv)
{
if (argc < 2)
@@ -87,10 +120,16 @@ int cmd__pkt_line(int argc, const char **argv)
if (!strcmp(argv[1], "pack"))
pack(argc - 2, argv + 2);
+ else if (!strcmp(argv[1], "pack-raw-stdin"))
+ pack_raw_stdin();
else if (!strcmp(argv[1], "unpack"))
unpack();
else if (!strcmp(argv[1], "unpack-sideband"))
unpack_sideband();
+ else if (!strcmp(argv[1], "send-split-sideband"))
+ send_split_sideband();
+ else if (!strcmp(argv[1], "receive-sideband"))
+ receive_sideband();
else
die("invalid argument '%s'", argv[1]);
diff --git a/t/helper/test-prio-queue.c b/t/helper/test-prio-queue.c
index f402844..133b5e6 100644
--- a/t/helper/test-prio-queue.c
+++ b/t/helper/test-prio-queue.c
@@ -46,5 +46,7 @@ int cmd__prio_queue(int argc, const char **argv)
}
}
+ clear_prio_queue(&pq);
+
return 0;
}
diff --git a/t/helper/test-proc-receive.c b/t/helper/test-proc-receive.c
new file mode 100644
index 0000000..cc08506
--- /dev/null
+++ b/t/helper/test-proc-receive.c
@@ -0,0 +1,202 @@
+#include "cache.h"
+#include "connect.h"
+#include "parse-options.h"
+#include "pkt-line.h"
+#include "sigchain.h"
+#include "test-tool.h"
+
+static const char *proc_receive_usage[] = {
+ "test-tool proc-receive [<options>...]",
+ NULL
+};
+
+static int die_read_version;
+static int die_write_version;
+static int die_read_commands;
+static int die_read_push_options;
+static int die_write_report;
+static int no_push_options;
+static int use_atomic;
+static int use_push_options;
+static int verbose;
+static int version = 1;
+static struct string_list returns = STRING_LIST_INIT_NODUP;
+
+struct command {
+ struct command *next;
+ const char *error_string;
+ unsigned int skip_update:1,
+ did_not_exist:1;
+ int index;
+ struct object_id old_oid;
+ struct object_id new_oid;
+ char ref_name[FLEX_ARRAY]; /* more */
+};
+
+static void proc_receive_verison(struct packet_reader *reader) {
+ int server_version = 0;
+
+ if (die_read_version)
+ die("die with the --die-read-version option");
+
+ for (;;) {
+ int linelen;
+
+ if (packet_reader_read(reader) != PACKET_READ_NORMAL)
+ break;
+
+ /* Ignore version negotiation for version 0 */
+ if (version == 0)
+ continue;
+
+ if (reader->pktlen > 8 && starts_with(reader->line, "version=")) {
+ server_version = atoi(reader->line+8);
+ if (server_version != 1)
+ die("bad protocol version: %d", server_version);
+ linelen = strlen(reader->line);
+ if (linelen < reader->pktlen) {
+ const char *feature_list = reader->line + linelen + 1;
+ if (parse_feature_request(feature_list, "atomic"))
+ use_atomic= 1;
+ if (parse_feature_request(feature_list, "push-options"))
+ use_push_options = 1;
+ }
+ }
+ }
+
+ if (die_write_version)
+ die("die with the --die-write-version option");
+
+ if (version != 0)
+ packet_write_fmt(1, "version=%d%c%s\n",
+ version, '\0',
+ use_push_options && !no_push_options ? "push-options": "");
+ packet_flush(1);
+}
+
+static void proc_receive_read_commands(struct packet_reader *reader,
+ struct command **commands)
+{
+ struct command **tail = commands;
+
+ for (;;) {
+ struct object_id old_oid, new_oid;
+ struct command *cmd;
+ const char *refname;
+ const char *p;
+
+ if (packet_reader_read(reader) != PACKET_READ_NORMAL)
+ break;
+
+ if (die_read_commands)
+ die("die with the --die-read-commands option");
+
+ if (parse_oid_hex(reader->line, &old_oid, &p) ||
+ *p++ != ' ' ||
+ parse_oid_hex(p, &new_oid, &p) ||
+ *p++ != ' ')
+ die("protocol error: expected 'old new ref', got '%s'",
+ reader->line);
+ refname = p;
+ FLEX_ALLOC_STR(cmd, ref_name, refname);
+ oidcpy(&cmd->old_oid, &old_oid);
+ oidcpy(&cmd->new_oid, &new_oid);
+
+ *tail = cmd;
+ tail = &cmd->next;
+ }
+}
+
+static void proc_receive_read_push_options(struct packet_reader *reader,
+ struct string_list *options)
+{
+
+ if (no_push_options || !use_push_options)
+ return;
+
+ if (die_read_push_options)
+ die("die with the --die-read-push-options option");
+
+ while (1) {
+ if (packet_reader_read(reader) != PACKET_READ_NORMAL)
+ break;
+
+ string_list_append(options, reader->line);
+ }
+}
+
+int cmd__proc_receive(int argc, const char **argv)
+{
+ int nongit_ok = 0;
+ struct packet_reader reader;
+ struct command *commands = NULL;
+ struct string_list push_options = STRING_LIST_INIT_DUP;
+ struct string_list_item *item;
+ struct option options[] = {
+ OPT_BOOL(0, "no-push-options", &no_push_options,
+ "disable push options"),
+ OPT_BOOL(0, "die-read-version", &die_read_version,
+ "die when reading version"),
+ OPT_BOOL(0, "die-write-version", &die_write_version,
+ "die when writing version"),
+ OPT_BOOL(0, "die-read-commands", &die_read_commands,
+ "die when reading commands"),
+ OPT_BOOL(0, "die-read-push-options", &die_read_push_options,
+ "die when reading push-options"),
+ OPT_BOOL(0, "die-write-report", &die_write_report,
+ "die when writing report"),
+ OPT_STRING_LIST('r', "return", &returns, "old/new/ref/status/msg",
+ "return of results"),
+ OPT__VERBOSE(&verbose, "be verbose"),
+ OPT_INTEGER('V', "version", &version,
+ "use this protocol version number"),
+ OPT_END()
+ };
+
+ setup_git_directory_gently(&nongit_ok);
+
+ argc = parse_options(argc, argv, "test-tools", options, proc_receive_usage, 0);
+ if (argc > 0)
+ usage_msg_opt("Too many arguments.", proc_receive_usage, options);
+ packet_reader_init(&reader, 0, NULL, 0,
+ PACKET_READ_CHOMP_NEWLINE |
+ PACKET_READ_GENTLE_ON_EOF);
+
+ sigchain_push(SIGPIPE, SIG_IGN);
+ proc_receive_verison(&reader);
+ proc_receive_read_commands(&reader, &commands);
+ proc_receive_read_push_options(&reader, &push_options);
+
+ if (verbose) {
+ struct command *cmd;
+
+ if (use_push_options || use_atomic)
+ fprintf(stderr, "proc-receive:%s%s\n",
+ use_atomic? " atomic": "",
+ use_push_options ? " push_options": "");
+
+ for (cmd = commands; cmd; cmd = cmd->next)
+ fprintf(stderr, "proc-receive< %s %s %s\n",
+ oid_to_hex(&cmd->old_oid),
+ oid_to_hex(&cmd->new_oid),
+ cmd->ref_name);
+
+ if (push_options.nr > 0)
+ for_each_string_list_item(item, &push_options)
+ fprintf(stderr, "proc-receive< %s\n", item->string);
+
+ if (returns.nr)
+ for_each_string_list_item(item, &returns)
+ fprintf(stderr, "proc-receive> %s\n", item->string);
+ }
+
+ if (die_write_report)
+ die("die with the --die-write-report option");
+ if (returns.nr)
+ for_each_string_list_item(item, &returns)
+ packet_write_fmt(1, "%s\n", item->string);
+ packet_flush(1);
+ sigchain_pop(SIGPIPE);
+
+ return 0;
+}
diff --git a/t/helper/test-progress.c b/t/helper/test-progress.c
index 42b96cb..6cc9735 100644
--- a/t/helper/test-progress.c
+++ b/t/helper/test-progress.c
@@ -3,6 +3,9 @@
*
* Reads instructions from standard input, one instruction per line:
*
+ * "start <total>[ <title>]" - Call start_progress(title, total),
+ * Uses the default title of "Working hard"
+ * if the " <title>" is omitted.
* "progress <items>" - Call display_progress() with the given item count
* as parameter.
* "throughput <bytes> <millis> - Call display_throughput() with the given
@@ -10,50 +13,60 @@
* specify the time elapsed since the
* start_progress() call.
* "update" - Set the 'progress_update' flag.
+ * "stop" - Call stop_progress().
*
* See 't0500-progress-display.sh' for examples.
*/
+#define GIT_TEST_PROGRESS_ONLY
#include "test-tool.h"
#include "gettext.h"
#include "parse-options.h"
#include "progress.h"
#include "strbuf.h"
-
-/*
- * These are defined in 'progress.c', but are not exposed in 'progress.h',
- * because they are exclusively for testing.
- */
-extern int progress_testing;
-extern uint64_t progress_test_ns;
-void progress_test_force_update(void);
+#include "string-list.h"
int cmd__progress(int argc, const char **argv)
{
- int total = 0;
- const char *title;
+ const char *const default_title = "Working hard";
+ struct string_list titles = STRING_LIST_INIT_DUP;
struct strbuf line = STRBUF_INIT;
- struct progress *progress;
+ struct progress *progress = NULL;
const char *usage[] = {
- "test-tool progress [--total=<n>] <progress-title>",
+ "test-tool progress <stdin",
NULL
};
struct option options[] = {
- OPT_INTEGER(0, "total", &total, "total number of items"),
OPT_END(),
};
argc = parse_options(argc, argv, NULL, options, usage, 0);
- if (argc != 1)
- die("need a title for the progress output");
- title = argv[0];
+ if (argc)
+ usage_with_options(usage, options);
progress_testing = 1;
- progress = start_progress(title, total);
while (strbuf_getline(&line, stdin) != EOF) {
char *end;
- if (skip_prefix(line.buf, "progress ", (const char **) &end)) {
+ if (skip_prefix(line.buf, "start ", (const char **) &end)) {
+ uint64_t total = strtoull(end, &end, 10);
+ const char *title;
+
+ /*
+ * We can't use "end + 1" as an argument to
+ * start_progress(), it doesn't xstrdup() its
+ * "title" argument. We need to hold onto a
+ * valid "char *" for it until the end.
+ */
+ if (!*end)
+ title = default_title;
+ else if (*end == ' ')
+ title = string_list_insert(&titles, end + 1)->string;
+ else
+ die("invalid input: '%s'\n", line.buf);
+
+ progress = start_progress(title, total);
+ } else if (skip_prefix(line.buf, "progress ", (const char **) &end)) {
uint64_t item_count = strtoull(end, &end, 10);
if (*end != '\0')
die("invalid input: '%s'\n", line.buf);
@@ -70,12 +83,16 @@ int cmd__progress(int argc, const char **argv)
die("invalid input: '%s'\n", line.buf);
progress_test_ns = test_ms * 1000 * 1000;
display_throughput(progress, byte_count);
- } else if (!strcmp(line.buf, "update"))
+ } else if (!strcmp(line.buf, "update")) {
progress_test_force_update();
- else
+ } else if (!strcmp(line.buf, "stop")) {
+ stop_progress(&progress);
+ } else {
die("invalid input: '%s'\n", line.buf);
+ }
}
- stop_progress(&progress);
+ strbuf_release(&line);
+ string_list_clear(&titles, 0);
return 0;
}
diff --git a/t/helper/test-reach.c b/t/helper/test-reach.c
index a027217..2f65c7f 100644
--- a/t/helper/test-reach.c
+++ b/t/helper/test-reach.c
@@ -67,7 +67,7 @@ int cmd__reach(int ac, const char **av)
die("failed to load commit for input %s resulting in oid %s\n",
buf.buf, oid_to_hex(&oid));
- c = object_as_type(r, peeled, OBJ_COMMIT, 0);
+ c = object_as_type(peeled, OBJ_COMMIT, 0);
if (!c)
die("failed to load commit for input %s resulting in oid %s\n",
@@ -107,8 +107,10 @@ int cmd__reach(int ac, const char **av)
printf("%s(A,B):%d\n", av[1], ref_newer(&oid_A, &oid_B));
else if (!strcmp(av[1], "in_merge_bases"))
printf("%s(A,B):%d\n", av[1], in_merge_bases(A, B));
+ else if (!strcmp(av[1], "in_merge_bases_many"))
+ printf("%s(A,X):%d\n", av[1], in_merge_bases_many(A, X_nr, X_array));
else if (!strcmp(av[1], "is_descendant_of"))
- printf("%s(A,X):%d\n", av[1], is_descendant_of(A, X));
+ printf("%s(A,X):%d\n", av[1], repo_is_descendant_of(r, A, X));
else if (!strcmp(av[1], "get_merge_bases_many")) {
struct commit_list *list = get_merge_bases_many(A, X_nr, X_array);
printf("%s(A,X):\n", av[1]);
@@ -164,5 +166,5 @@ int cmd__reach(int ac, const char **av)
print_sorted_commit_ids(list);
}
- exit(0);
+ return 0;
}
diff --git a/t/helper/test-read-cache.c b/t/helper/test-read-cache.c
index 244977a..b736ef1 100644
--- a/t/helper/test-read-cache.c
+++ b/t/helper/test-read-cache.c
@@ -7,6 +7,8 @@ int cmd__read_cache(int argc, const char **argv)
int i, cnt = 1;
const char *name = NULL;
+ initialize_the_repository();
+
if (argc > 1 && skip_prefix(argv[1], "--print-and-refresh=", &name)) {
argc--;
argv++;
@@ -16,6 +18,7 @@ int cmd__read_cache(int argc, const char **argv)
cnt = strtol(argv[1], NULL, 0);
setup_git_directory();
git_config(git_default_config, NULL);
+
for (i = 0; i < cnt; i++) {
read_cache();
if (name) {
diff --git a/t/helper/test-read-graph.c b/t/helper/test-read-graph.c
index d2884ef..98b73bb 100644
--- a/t/helper/test-read-graph.c
+++ b/t/helper/test-read-graph.c
@@ -3,31 +3,22 @@
#include "commit-graph.h"
#include "repository.h"
#include "object-store.h"
+#include "bloom.h"
int cmd__read_graph(int argc, const char **argv)
{
struct commit_graph *graph = NULL;
- char *graph_name;
- int open_ok;
- int fd;
- struct stat st;
- const char *object_dir;
+ struct object_directory *odb;
setup_git_directory();
- object_dir = get_object_directory();
+ odb = the_repository->objects->odb;
- graph_name = get_commit_graph_filename(object_dir);
+ prepare_repo_settings(the_repository);
- open_ok = open_commit_graph(graph_name, &fd, &st);
- if (!open_ok)
- die_errno(_("Could not open commit-graph '%s'"), graph_name);
-
- graph = load_commit_graph_one_fd_st(fd, &st);
+ graph = read_commit_graph_one(the_repository, odb);
if (!graph)
return 1;
- FREE_AND_NULL(graph_name);
-
printf("header: %08x %d %d %d %d\n",
ntohl(*(uint32_t*)graph->data),
*(unsigned char*)(graph->data + 4),
@@ -43,8 +34,28 @@ int cmd__read_graph(int argc, const char **argv)
printf(" oid_lookup");
if (graph->chunk_commit_data)
printf(" commit_metadata");
+ if (graph->chunk_generation_data)
+ printf(" generation_data");
+ if (graph->chunk_generation_data_overflow)
+ printf(" generation_data_overflow");
if (graph->chunk_extra_edges)
printf(" extra_edges");
+ if (graph->chunk_bloom_indexes)
+ printf(" bloom_indexes");
+ if (graph->chunk_bloom_data)
+ printf(" bloom_data");
+ printf("\n");
+
+ printf("options:");
+ if (graph->bloom_filter_settings)
+ printf(" bloom(%"PRIu32",%"PRIu32",%"PRIu32")",
+ graph->bloom_filter_settings->hash_version,
+ graph->bloom_filter_settings->bits_per_entry,
+ graph->bloom_filter_settings->num_hashes);
+ if (graph->read_generation_data)
+ printf(" read_generation_data");
+ if (graph->topo_levels)
+ printf(" topo_levels");
printf("\n");
UNLEAK(graph);
diff --git a/t/helper/test-read-midx.c b/t/helper/test-read-midx.c
index 831b586..27072ba 100644
--- a/t/helper/test-read-midx.c
+++ b/t/helper/test-read-midx.c
@@ -3,18 +3,23 @@
#include "midx.h"
#include "repository.h"
#include "object-store.h"
+#include "pack-bitmap.h"
-static int read_midx_file(const char *object_dir)
+static int read_midx_file(const char *object_dir, int show_objects)
{
uint32_t i;
- struct multi_pack_index *m = load_multi_pack_index(object_dir, 1);
+ struct multi_pack_index *m;
+
+ setup_git_directory();
+ m = load_multi_pack_index(object_dir, 1);
if (!m)
return 1;
- printf("header: %08x %d %d %d\n",
+ printf("header: %08x %d %d %d %d\n",
m->signature,
m->version,
+ m->hash_len,
m->num_chunks,
m->num_packs);
@@ -39,13 +44,70 @@ static int read_midx_file(const char *object_dir)
printf("object-dir: %s\n", m->object_dir);
+ if (show_objects) {
+ struct object_id oid;
+ struct pack_entry e;
+
+ for (i = 0; i < m->num_objects; i++) {
+ nth_midxed_object_oid(&oid, m, i);
+ fill_midx_entry(the_repository, &oid, &e, m);
+
+ printf("%s %"PRIu64"\t%s\n",
+ oid_to_hex(&oid), e.offset, e.p->pack_name);
+ }
+ }
+
+ close_midx(m);
+
+ return 0;
+}
+
+static int read_midx_checksum(const char *object_dir)
+{
+ struct multi_pack_index *m;
+
+ setup_git_directory();
+ m = load_multi_pack_index(object_dir, 1);
+ if (!m)
+ return 1;
+ printf("%s\n", hash_to_hex(get_midx_checksum(m)));
+ return 0;
+}
+
+static int read_midx_preferred_pack(const char *object_dir)
+{
+ struct multi_pack_index *midx = NULL;
+ struct bitmap_index *bitmap = NULL;
+
+ setup_git_directory();
+
+ midx = load_multi_pack_index(object_dir, 1);
+ if (!midx)
+ return 1;
+
+ bitmap = prepare_bitmap_git(the_repository);
+ if (!bitmap)
+ return 1;
+ if (!bitmap_is_midx(bitmap)) {
+ free_bitmap_index(bitmap);
+ return 1;
+ }
+
+ printf("%s\n", midx->pack_names[midx_preferred_pack(bitmap)]);
+ free_bitmap_index(bitmap);
return 0;
}
int cmd__read_midx(int argc, const char **argv)
{
- if (argc != 2)
- usage("read-midx <object-dir>");
+ if (!(argc == 2 || argc == 3))
+ usage("read-midx [--show-objects|--checksum|--preferred-pack] <object-dir>");
- return read_midx_file(argv[1]);
+ if (!strcmp(argv[1], "--show-objects"))
+ return read_midx_file(argv[2], 1);
+ else if (!strcmp(argv[1], "--checksum"))
+ return read_midx_checksum(argv[2]);
+ else if (!strcmp(argv[1], "--preferred-pack"))
+ return read_midx_preferred_pack(argv[2]);
+ return read_midx_file(argv[1], 0);
}
diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c
index 799fc00..9646d85 100644
--- a/t/helper/test-ref-store.c
+++ b/t/helper/test-ref-store.c
@@ -5,6 +5,48 @@
#include "object-store.h"
#include "repository.h"
+struct flag_definition {
+ const char *name;
+ uint64_t mask;
+};
+
+#define FLAG_DEF(x) \
+ { \
+#x, (x) \
+ }
+
+static unsigned int parse_flags(const char *str, struct flag_definition *defs)
+{
+ struct string_list masks = STRING_LIST_INIT_DUP;
+ int i = 0;
+ unsigned int result = 0;
+
+ if (!strcmp(str, "0"))
+ return 0;
+
+ string_list_split(&masks, str, ',', 64);
+ for (; i < masks.nr; i++) {
+ const char *name = masks.items[i].string;
+ struct flag_definition *def = defs;
+ int found = 0;
+ while (def->name) {
+ if (!strcmp(def->name, name)) {
+ result |= def->mask;
+ found = 1;
+ break;
+ }
+ def++;
+ }
+ if (!found)
+ die("unknown flag \"%s\"", name);
+ }
+
+ string_list_clear(&masks, 0);
+ return result;
+}
+
+static struct flag_definition empty_flags[] = { { NULL, 0 } };
+
static const char *notnull(const char *arg, const char *name)
{
if (!arg)
@@ -12,9 +54,10 @@ static const char *notnull(const char *arg, const char *name)
return arg;
}
-static unsigned int arg_flags(const char *arg, const char *name)
+static unsigned int arg_flags(const char *arg, const char *name,
+ struct flag_definition *defs)
{
- return atoi(notnull(arg, name));
+ return parse_flags(notnull(arg, name), defs);
}
static const char **get_store(const char **argv, struct ref_store **refs)
@@ -37,7 +80,7 @@ static const char **get_store(const char **argv, struct ref_store **refs)
*refs = get_submodule_ref_store(gitdir);
} else if (skip_prefix(argv[0], "worktree:", &gitdir)) {
- struct worktree **p, **worktrees = get_worktrees(0);
+ struct worktree **p, **worktrees = get_worktrees();
for (p = worktrees; *p; p++) {
struct worktree *wt = *p;
@@ -64,26 +107,17 @@ static const char **get_store(const char **argv, struct ref_store **refs)
return argv + 1;
}
+static struct flag_definition pack_flags[] = { FLAG_DEF(PACK_REFS_PRUNE),
+ FLAG_DEF(PACK_REFS_ALL),
+ { NULL, 0 } };
static int cmd_pack_refs(struct ref_store *refs, const char **argv)
{
- unsigned int flags = arg_flags(*argv++, "flags");
+ unsigned int flags = arg_flags(*argv++, "flags", pack_flags);
return refs_pack_refs(refs, flags);
}
-static int cmd_peel_ref(struct ref_store *refs, const char **argv)
-{
- const char *refname = notnull(*argv++, "refname");
- struct object_id oid;
- int ret;
-
- ret = refs_peel_ref(refs, refname, &oid);
- if (!ret)
- puts(oid_to_hex(&oid));
- return ret;
-}
-
static int cmd_create_symref(struct ref_store *refs, const char **argv)
{
const char *refname = notnull(*argv++, "refname");
@@ -93,16 +127,27 @@ static int cmd_create_symref(struct ref_store *refs, const char **argv)
return refs_create_symref(refs, refname, target, logmsg);
}
+static struct flag_definition transaction_flags[] = {
+ FLAG_DEF(REF_NO_DEREF),
+ FLAG_DEF(REF_FORCE_CREATE_REFLOG),
+ FLAG_DEF(REF_SKIP_OID_VERIFICATION),
+ FLAG_DEF(REF_SKIP_REFNAME_VERIFICATION),
+ { NULL, 0 }
+};
+
static int cmd_delete_refs(struct ref_store *refs, const char **argv)
{
- unsigned int flags = arg_flags(*argv++, "flags");
+ unsigned int flags = arg_flags(*argv++, "flags", transaction_flags);
const char *msg = *argv++;
struct string_list refnames = STRING_LIST_INIT_NODUP;
+ int result;
while (*argv)
string_list_append(&refnames, *argv++);
- return refs_delete_refs(refs, msg, &refnames, flags);
+ result = refs_delete_refs(refs, msg, &refnames, flags);
+ string_list_clear(&refnames, 0);
+ return result;
}
static int cmd_rename_ref(struct ref_store *refs, const char **argv)
@@ -130,9 +175,9 @@ static int cmd_for_each_ref(struct ref_store *refs, const char **argv)
static int cmd_resolve_ref(struct ref_store *refs, const char **argv)
{
- struct object_id oid;
+ struct object_id oid = *null_oid();
const char *refname = notnull(*argv++, "refname");
- int resolve_flags = arg_flags(*argv++, "resolve-flags");
+ int resolve_flags = arg_flags(*argv++, "resolve-flags", empty_flags);
int flags;
const char *ref;
@@ -163,9 +208,9 @@ static int each_reflog(struct object_id *old_oid, struct object_id *new_oid,
const char *committer, timestamp_t timestamp,
int tz, const char *msg, void *cb_data)
{
- printf("%s %s %s %"PRItime" %d %s\n",
- oid_to_hex(old_oid), oid_to_hex(new_oid),
- committer, timestamp, tz, msg);
+ printf("%s %s %s %" PRItime " %+05d%s%s", oid_to_hex(old_oid),
+ oid_to_hex(new_oid), committer, timestamp, tz,
+ *msg == '\n' ? "" : "\t", msg);
return 0;
}
@@ -193,11 +238,10 @@ static int cmd_reflog_exists(struct ref_store *refs, const char **argv)
static int cmd_create_reflog(struct ref_store *refs, const char **argv)
{
const char *refname = notnull(*argv++, "refname");
- int force_create = arg_flags(*argv++, "force-create");
struct strbuf err = STRBUF_INIT;
int ret;
- ret = refs_create_reflog(refs, refname, force_create, &err);
+ ret = refs_create_reflog(refs, refname, &err);
if (err.len)
puts(err.buf);
return ret;
@@ -220,11 +264,11 @@ static int cmd_delete_ref(struct ref_store *refs, const char **argv)
const char *msg = notnull(*argv++, "msg");
const char *refname = notnull(*argv++, "refname");
const char *sha1_buf = notnull(*argv++, "old-sha1");
- unsigned int flags = arg_flags(*argv++, "flags");
+ unsigned int flags = arg_flags(*argv++, "flags", transaction_flags);
struct object_id old_oid;
if (get_oid_hex(sha1_buf, &old_oid))
- die("not sha-1");
+ die("cannot parse %s as %s", sha1_buf, the_hash_algo->name);
return refs_delete_ref(refs, msg, refname, &old_oid, flags);
}
@@ -235,13 +279,14 @@ static int cmd_update_ref(struct ref_store *refs, const char **argv)
const char *refname = notnull(*argv++, "refname");
const char *new_sha1_buf = notnull(*argv++, "new-sha1");
const char *old_sha1_buf = notnull(*argv++, "old-sha1");
- unsigned int flags = arg_flags(*argv++, "flags");
+ unsigned int flags = arg_flags(*argv++, "flags", transaction_flags);
struct object_id old_oid;
struct object_id new_oid;
- if (get_oid_hex(old_sha1_buf, &old_oid) ||
- get_oid_hex(new_sha1_buf, &new_oid))
- die("not sha-1");
+ if (get_oid_hex(old_sha1_buf, &old_oid))
+ die("cannot parse %s as %s", old_sha1_buf, the_hash_algo->name);
+ if (get_oid_hex(new_sha1_buf, &new_oid))
+ die("cannot parse %s as %s", new_sha1_buf, the_hash_algo->name);
return refs_update_ref(refs, msg, refname,
&new_oid, &old_oid,
@@ -255,7 +300,6 @@ struct command {
static struct command commands[] = {
{ "pack-refs", cmd_pack_refs },
- { "peel-ref", cmd_peel_ref },
{ "create-symref", cmd_create_symref },
{ "delete-refs", cmd_delete_refs },
{ "rename-ref", cmd_rename_ref },
diff --git a/t/helper/test-reftable.c b/t/helper/test-reftable.c
new file mode 100644
index 0000000..1f0a28c
--- /dev/null
+++ b/t/helper/test-reftable.c
@@ -0,0 +1,22 @@
+#include "reftable/reftable-tests.h"
+#include "test-tool.h"
+
+int cmd__reftable(int argc, const char **argv)
+{
+ /* test from simple to complex. */
+ basics_test_main(argc, argv);
+ record_test_main(argc, argv);
+ block_test_main(argc, argv);
+ tree_test_main(argc, argv);
+ pq_test_main(argc, argv);
+ readwrite_test_main(argc, argv);
+ merged_test_main(argc, argv);
+ stack_test_main(argc, argv);
+ refname_test_main(argc, argv);
+ return 0;
+}
+
+int cmd__dump_reftable(int argc, const char **argv)
+{
+ return reftable_dump_main(argc, (char *const *)argv);
+}
diff --git a/t/helper/test-regex.c b/t/helper/test-regex.c
index 10284cc..d6f28ca 100644
--- a/t/helper/test-regex.c
+++ b/t/helper/test-regex.c
@@ -1,5 +1,4 @@
#include "test-tool.h"
-#include "git-compat-util.h"
#include "gettext.h"
struct reg_flag {
@@ -8,12 +7,13 @@ struct reg_flag {
};
static struct reg_flag reg_flags[] = {
- { "EXTENDED", REG_EXTENDED },
- { "NEWLINE", REG_NEWLINE },
- { "ICASE", REG_ICASE },
- { "NOTBOL", REG_NOTBOL },
+ { "EXTENDED", REG_EXTENDED },
+ { "NEWLINE", REG_NEWLINE },
+ { "ICASE", REG_ICASE },
+ { "NOTBOL", REG_NOTBOL },
+ { "NOTEOL", REG_NOTEOL },
#ifdef REG_STARTEND
- { "STARTEND", REG_STARTEND },
+ { "STARTEND", REG_STARTEND },
#endif
{ NULL, 0 }
};
@@ -41,36 +41,74 @@ int cmd__regex(int argc, const char **argv)
{
const char *pat;
const char *str;
- int flags = 0;
+ int ret, silent = 0, flags = 0;
regex_t r;
regmatch_t m[1];
-
- if (argc == 2 && !strcmp(argv[1], "--bug"))
- return test_regex_bug();
- else if (argc < 3)
- usage("test-tool regex --bug\n"
- "test-tool regex <pattern> <string> [<options>]");
+ char errbuf[64];
argv++;
- pat = *argv++;
- str = *argv++;
- while (*argv) {
- struct reg_flag *rf;
- for (rf = reg_flags; rf->name; rf++)
- if (!strcmp(*argv, rf->name)) {
- flags |= rf->flag;
- break;
- }
- if (!rf->name)
- die("do not recognize %s", *argv);
+ argc--;
+
+ if (!argc)
+ goto usage;
+
+ if (!strcmp(*argv, "--bug")) {
+ if (argc == 1)
+ return test_regex_bug();
+ else
+ goto usage;
+ }
+ if (!strcmp(*argv, "--silent")) {
+ silent = 1;
argv++;
+ argc--;
+ }
+ if (!argc)
+ goto usage;
+
+ pat = *argv++;
+ if (argc == 1)
+ str = NULL;
+ else {
+ str = *argv++;
+ while (*argv) {
+ struct reg_flag *rf;
+ for (rf = reg_flags; rf->name; rf++)
+ if (!strcmp(*argv, rf->name)) {
+ flags |= rf->flag;
+ break;
+ }
+ if (!rf->name)
+ die("do not recognize flag %s", *argv);
+ argv++;
+ }
}
git_setup_gettext();
- if (regcomp(&r, pat, flags))
- die("failed regcomp() for pattern '%s'", pat);
- if (regexec(&r, str, 1, m, 0))
- return 1;
+ ret = regcomp(&r, pat, flags);
+ if (ret) {
+ if (silent)
+ return ret;
+
+ regerror(ret, &r, errbuf, sizeof(errbuf));
+ die("failed regcomp() for pattern '%s' (%s)", pat, errbuf);
+ }
+ if (!str)
+ return 0;
+
+ ret = regexec(&r, str, 1, m, 0);
+ if (ret) {
+ if (silent || ret == REG_NOMATCH)
+ return ret;
+
+ regerror(ret, &r, errbuf, sizeof(errbuf));
+ die("failed regexec() for subject '%s' (%s)", str, errbuf);
+ }
return 0;
+usage:
+ usage("\ttest-tool regex --bug\n"
+ "\ttest-tool regex [--silent] <pattern>\n"
+ "\ttest-tool regex [--silent] <pattern> <string> [<options>]");
+ return -1;
}
diff --git a/t/helper/test-repository.c b/t/helper/test-repository.c
index f7f8618..56f0e3c 100644
--- a/t/helper/test-repository.c
+++ b/t/helper/test-repository.c
@@ -19,12 +19,11 @@ static void test_parse_commit_in_graph(const char *gitdir, const char *worktree,
memset(the_repository, 0, sizeof(*the_repository));
- /* TODO: Needed for temporary hack in hashcmp, see 183a638b7da. */
- repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
-
if (repo_init(&r, gitdir, worktree))
die("Couldn't init repo");
+ repo_set_hash_algo(the_repository, hash_algo_by_ptr(r.hash_algo));
+
c = lookup_commit(&r, commit_oid);
if (!parse_commit_in_graph(&r, c))
@@ -50,12 +49,11 @@ static void test_get_commit_tree_in_graph(const char *gitdir,
memset(the_repository, 0, sizeof(*the_repository));
- /* TODO: Needed for temporary hack in hashcmp, see 183a638b7da. */
- repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
-
if (repo_init(&r, gitdir, worktree))
die("Couldn't init repo");
+ repo_set_hash_algo(the_repository, hash_algo_by_ptr(r.hash_algo));
+
c = lookup_commit(&r, commit_oid);
/*
@@ -75,6 +73,10 @@ static void test_get_commit_tree_in_graph(const char *gitdir,
int cmd__repository(int argc, const char **argv)
{
+ int nongit_ok = 0;
+
+ setup_git_directory_gently(&nongit_ok);
+
if (argc < 2)
die("must have at least 2 arguments");
if (!strcmp(argv[1], "parse_commit_in_graph")) {
diff --git a/t/helper/test-revision-walking.c b/t/helper/test-revision-walking.c
index 625b2db..4a45d5b 100644
--- a/t/helper/test-revision-walking.c
+++ b/t/helper/test-revision-walking.c
@@ -43,6 +43,7 @@ static int run_revision_walk(void)
}
reset_revision_walk();
+ release_revisions(&rev);
return got_revision;
}
diff --git a/t/helper/test-run-command.c b/t/helper/test-run-command.c
index 1646aa2..c9283b4 100644
--- a/t/helper/test-run-command.c
+++ b/t/helper/test-run-command.c
@@ -12,14 +12,13 @@
#include "git-compat-util.h"
#include "cache.h"
#include "run-command.h"
-#include "argv-array.h"
+#include "strvec.h"
#include "strbuf.h"
#include "parse-options.h"
#include "string-list.h"
#include "thread-utils.h"
#include "wildmatch.h"
#include "gettext.h"
-#include "parse-options.h"
static int number_callbacks;
static int parallel_next(struct child_process *cp,
@@ -31,8 +30,12 @@ static int parallel_next(struct child_process *cp,
if (number_callbacks >= 4)
return 0;
- argv_array_pushv(&cp->args, d->argv);
- strbuf_addstr(err, "preloaded output of a child\n");
+ strvec_pushv(&cp->args, d->args.v);
+ if (err)
+ strbuf_addstr(err, "preloaded output of a child\n");
+ else
+ fprintf(stderr, "preloaded output of a child\n");
+
number_callbacks++;
return 1;
}
@@ -42,7 +45,10 @@ static int no_job(struct child_process *cp,
void *cb,
void **task_cb)
{
- strbuf_addstr(err, "no further jobs available\n");
+ if (err)
+ strbuf_addstr(err, "no further jobs available\n");
+ else
+ fprintf(stderr, "no further jobs available\n");
return 0;
}
@@ -51,7 +57,10 @@ static int task_finished(int result,
void *pp_cb,
void *pp_task_cb)
{
- strbuf_addstr(err, "asking for a quick stop\n");
+ if (err)
+ strbuf_addstr(err, "asking for a quick stop\n");
+ else
+ fprintf(stderr, "asking for a quick stop\n");
return 1;
}
@@ -60,8 +69,10 @@ struct testsuite {
int next;
int quiet, immediate, verbose, verbose_log, trace, write_junit_xml;
};
-#define TESTSUITE_INIT \
- { STRING_LIST_INIT_DUP, STRING_LIST_INIT_DUP, -1, 0, 0, 0, 0, 0, 0 }
+#define TESTSUITE_INIT { \
+ .tests = STRING_LIST_INIT_DUP, \
+ .failed = STRING_LIST_INIT_DUP, \
+}
static int next_test(struct child_process *cp, struct strbuf *err, void *cb,
void **task_cb)
@@ -72,19 +83,19 @@ static int next_test(struct child_process *cp, struct strbuf *err, void *cb,
return 0;
test = suite->tests.items[suite->next++].string;
- argv_array_pushl(&cp->args, "sh", test, NULL);
+ strvec_pushl(&cp->args, "sh", test, NULL);
if (suite->quiet)
- argv_array_push(&cp->args, "--quiet");
+ strvec_push(&cp->args, "--quiet");
if (suite->immediate)
- argv_array_push(&cp->args, "-i");
+ strvec_push(&cp->args, "-i");
if (suite->verbose)
- argv_array_push(&cp->args, "-v");
+ strvec_push(&cp->args, "-v");
if (suite->verbose_log)
- argv_array_push(&cp->args, "-V");
+ strvec_push(&cp->args, "-V");
if (suite->trace)
- argv_array_push(&cp->args, "-x");
+ strvec_push(&cp->args, "-x");
if (suite->write_junit_xml)
- argv_array_push(&cp->args, "--write-junit-xml");
+ strvec_push(&cp->args, "--write-junit-xml");
strbuf_addf(err, "Output of '%s':\n", test);
*task_cb = (void *)test;
@@ -142,9 +153,6 @@ static int testsuite(int argc, const char **argv)
OPT_END()
};
- memset(&suite, 0, sizeof(suite));
- suite.tests.strdup_strings = suite.failed.strdup_strings = 1;
-
argc = parse_options(argc, argv, NULL, options,
testsuite_usage, PARSE_OPT_STOP_AT_NON_OPTION);
@@ -181,15 +189,16 @@ static int testsuite(int argc, const char **argv)
if (max_jobs > suite.tests.nr)
max_jobs = suite.tests.nr;
- fprintf(stderr, "Running %d tests (%d at a time)\n",
- suite.tests.nr, max_jobs);
+ fprintf(stderr, "Running %"PRIuMAX" tests (%d at a time)\n",
+ (uintmax_t)suite.tests.nr, max_jobs);
ret = run_processes_parallel(max_jobs, next_test, test_failed,
test_finished, &suite);
if (suite.failed.nr > 0) {
ret = 1;
- fprintf(stderr, "%d tests failed:\n\n", suite.failed.nr);
+ fprintf(stderr, "%"PRIuMAX" tests failed:\n\n",
+ (uintmax_t)suite.failed.nr);
for (i = 0; i < suite.failed.nr; i++)
fprintf(stderr, "\t%s\n", suite.failed.items[i].string);
}
@@ -220,11 +229,11 @@ static int quote_stress_test(int argc, const char **argv)
char special[] = ".?*\\^_\"'`{}()[]<>@~&+:;$%"; // \t\r\n\a";
int i, j, k, trials = 100, skip = 0, msys2 = 0;
struct strbuf out = STRBUF_INIT;
- struct argv_array args = ARGV_ARRAY_INIT;
+ struct strvec args = STRVEC_INIT;
struct option options[] = {
- OPT_INTEGER('n', "trials", &trials, "Number of trials"),
- OPT_INTEGER('s', "skip", &skip, "Skip <n> trials"),
- OPT_BOOL('m', "msys2", &msys2, "Test quoting for MSYS2's sh"),
+ OPT_INTEGER('n', "trials", &trials, "number of trials"),
+ OPT_INTEGER('s', "skip", &skip, "skip <n> trials"),
+ OPT_BOOL('m', "msys2", &msys2, "test quoting for MSYS2's sh"),
OPT_END()
};
const char * const usage[] = {
@@ -241,20 +250,20 @@ static int quote_stress_test(int argc, const char **argv)
size_t arg_count, arg_offset;
int ret = 0;
- argv_array_clear(&args);
+ strvec_clear(&args);
if (msys2)
- argv_array_pushl(&args, "sh", "-c",
- "printf %s\\\\0 \"$@\"", "skip", NULL);
+ strvec_pushl(&args, "sh", "-c",
+ "printf %s\\\\0 \"$@\"", "skip", NULL);
else
- argv_array_pushl(&args, "test-tool", "run-command",
- "quote-echo", NULL);
- arg_offset = args.argc;
+ strvec_pushl(&args, "test-tool", "run-command",
+ "quote-echo", NULL);
+ arg_offset = args.nr;
if (argc > 0) {
trials = 1;
arg_count = argc;
for (j = 0; j < arg_count; j++)
- argv_array_push(&args, argv[j]);
+ strvec_push(&args, argv[j]);
} else {
arg_count = 1 + (my_random() % 5);
for (j = 0; j < arg_count; j++) {
@@ -268,20 +277,20 @@ static int quote_stress_test(int argc, const char **argv)
ARRAY_SIZE(special)];
buf[arg_len] = '\0';
- argv_array_push(&args, buf);
+ strvec_push(&args, buf);
}
}
if (i < skip)
continue;
- cp.argv = args.argv;
+ strvec_pushv(&cp.args, args.v);
strbuf_reset(&out);
if (pipe_command(&cp, NULL, 0, &out, 0, NULL, 0) < 0)
return error("Failed to spawn child process");
for (j = 0, k = 0; j < arg_count; j++) {
- const char *arg = args.argv[j + arg_offset];
+ const char *arg = args.v[j + arg_offset];
if (strcmp(arg, out.buf + k))
ret = error("incorrectly quoted arg: '%s', "
@@ -298,10 +307,10 @@ static int quote_stress_test(int argc, const char **argv)
fprintf(stderr, "Trial #%d failed. Arguments:\n", i);
for (j = 0; j < arg_count; j++)
fprintf(stderr, "arg #%d: '%s'\n",
- (int)j, args.argv[j + arg_offset]);
+ (int)j, args.v[j + arg_offset]);
strbuf_release(&out);
- argv_array_clear(&args);
+ strvec_clear(&args);
return ret;
}
@@ -311,7 +320,7 @@ static int quote_stress_test(int argc, const char **argv)
}
strbuf_release(&out);
- argv_array_clear(&args);
+ strvec_clear(&args);
return 0;
}
@@ -338,8 +347,8 @@ static int inherit_handle(const char *argv0)
xsnprintf(path, sizeof(path), "out-XXXXXX");
tmp = xmkstemp(path);
- argv_array_pushl(&cp.args,
- "test-tool", argv0, "inherited-handle-child", NULL);
+ strvec_pushl(&cp.args,
+ "test-tool", argv0, "inherited-handle-child", NULL);
cp.in = -1;
cp.no_stdout = cp.no_stderr = 1;
if (start_command(&cp) < 0)
@@ -391,13 +400,13 @@ int cmd__run_command(int argc, const char **argv)
while (!strcmp(argv[1], "env")) {
if (!argv[2])
die("env specifier without a value");
- argv_array_push(&proc.env_array, argv[2]);
+ strvec_push(&proc.env, argv[2]);
argv += 2;
argc -= 2;
}
if (argc < 3)
return 1;
- proc.argv = (const char **)argv + 2;
+ strvec_pushv(&proc.args, (const char **)argv + 2);
if (!strcmp(argv[1], "start-command-ENOENT")) {
if (start_command(&proc) < 0 && errno == ENOENT)
@@ -408,8 +417,15 @@ int cmd__run_command(int argc, const char **argv)
if (!strcmp(argv[1], "run-command"))
exit(run_command(&proc));
+ if (!strcmp(argv[1], "--ungroup")) {
+ argv += 1;
+ argc -= 1;
+ run_processes_parallel_ungroup = 1;
+ }
+
jobs = atoi(argv[2]);
- proc.argv = (const char **)argv + 3;
+ strvec_clear(&proc.args);
+ strvec_pushv(&proc.args, (const char **)argv + 3);
if (!strcmp(argv[1], "run-command-parallel"))
exit(run_processes_parallel(jobs, parallel_next,
diff --git a/t/helper/test-serve-v2.c b/t/helper/test-serve-v2.c
index aee35e5..28e905a 100644
--- a/t/helper/test-serve-v2.c
+++ b/t/helper/test-serve-v2.c
@@ -10,12 +10,12 @@ static char const * const serve_usage[] = {
int cmd__serve_v2(int argc, const char **argv)
{
- struct serve_options opts = SERVE_OPTIONS_INIT;
-
+ int stateless_rpc = 0;
+ int advertise_capabilities = 0;
struct option options[] = {
- OPT_BOOL(0, "stateless-rpc", &opts.stateless_rpc,
+ OPT_BOOL(0, "stateless-rpc", &stateless_rpc,
N_("quit after a single request/response exchange")),
- OPT_BOOL(0, "advertise-capabilities", &opts.advertise_capabilities,
+ OPT_BOOL(0, "advertise-capabilities", &advertise_capabilities,
N_("exit immediately after advertising capabilities")),
OPT_END()
};
@@ -25,7 +25,11 @@ int cmd__serve_v2(int argc, const char **argv)
argc = parse_options(argc, argv, prefix, options, serve_usage,
PARSE_OPT_KEEP_DASHDASH |
PARSE_OPT_KEEP_UNKNOWN);
- serve(&opts);
+
+ if (advertise_capabilities)
+ protocol_v2_advertise_capabilities();
+ else
+ protocol_v2_serve_loop(stateless_rpc);
return 0;
}
diff --git a/t/helper/test-simple-ipc.c b/t/helper/test-simple-ipc.c
new file mode 100644
index 0000000..28365ff
--- /dev/null
+++ b/t/helper/test-simple-ipc.c
@@ -0,0 +1,686 @@
+/*
+ * test-simple-ipc.c: verify that the Inter-Process Communication works.
+ */
+
+#include "test-tool.h"
+#include "cache.h"
+#include "strbuf.h"
+#include "simple-ipc.h"
+#include "parse-options.h"
+#include "thread-utils.h"
+#include "strvec.h"
+#include "run-command.h"
+
+#ifndef SUPPORTS_SIMPLE_IPC
+int cmd__simple_ipc(int argc, const char **argv)
+{
+ die("simple IPC not available on this platform");
+}
+#else
+
+/*
+ * The test daemon defines an "application callback" that supports a
+ * series of commands (see `test_app_cb()`).
+ *
+ * Unknown commands are caught here and we send an error message back
+ * to the client process.
+ */
+static int app__unhandled_command(const char *command,
+ ipc_server_reply_cb *reply_cb,
+ struct ipc_server_reply_data *reply_data)
+{
+ struct strbuf buf = STRBUF_INIT;
+ int ret;
+
+ strbuf_addf(&buf, "unhandled command: %s", command);
+ ret = reply_cb(reply_data, buf.buf, buf.len);
+ strbuf_release(&buf);
+
+ return ret;
+}
+
+/*
+ * Reply with a single very large buffer. This is to ensure that
+ * long response are properly handled -- whether the chunking occurs
+ * in the kernel or in the (probably pkt-line) layer.
+ */
+#define BIG_ROWS (10000)
+static int app__big_command(ipc_server_reply_cb *reply_cb,
+ struct ipc_server_reply_data *reply_data)
+{
+ struct strbuf buf = STRBUF_INIT;
+ int row;
+ int ret;
+
+ for (row = 0; row < BIG_ROWS; row++)
+ strbuf_addf(&buf, "big: %.75d\n", row);
+
+ ret = reply_cb(reply_data, buf.buf, buf.len);
+ strbuf_release(&buf);
+
+ return ret;
+}
+
+/*
+ * Reply with a series of lines. This is to ensure that we can incrementally
+ * compute the response and chunk it to the client.
+ */
+#define CHUNK_ROWS (10000)
+static int app__chunk_command(ipc_server_reply_cb *reply_cb,
+ struct ipc_server_reply_data *reply_data)
+{
+ struct strbuf buf = STRBUF_INIT;
+ int row;
+ int ret;
+
+ for (row = 0; row < CHUNK_ROWS; row++) {
+ strbuf_setlen(&buf, 0);
+ strbuf_addf(&buf, "big: %.75d\n", row);
+ ret = reply_cb(reply_data, buf.buf, buf.len);
+ }
+
+ strbuf_release(&buf);
+
+ return ret;
+}
+
+/*
+ * Slowly reply with a series of lines. This is to model an expensive to
+ * compute chunked response (which might happen if this callback is running
+ * in a thread and is fighting for a lock with other threads).
+ */
+#define SLOW_ROWS (1000)
+#define SLOW_DELAY_MS (10)
+static int app__slow_command(ipc_server_reply_cb *reply_cb,
+ struct ipc_server_reply_data *reply_data)
+{
+ struct strbuf buf = STRBUF_INIT;
+ int row;
+ int ret;
+
+ for (row = 0; row < SLOW_ROWS; row++) {
+ strbuf_setlen(&buf, 0);
+ strbuf_addf(&buf, "big: %.75d\n", row);
+ ret = reply_cb(reply_data, buf.buf, buf.len);
+ sleep_millisec(SLOW_DELAY_MS);
+ }
+
+ strbuf_release(&buf);
+
+ return ret;
+}
+
+/*
+ * The client sent a command followed by a (possibly very) large buffer.
+ */
+static int app__sendbytes_command(const char *received, size_t received_len,
+ ipc_server_reply_cb *reply_cb,
+ struct ipc_server_reply_data *reply_data)
+{
+ struct strbuf buf_resp = STRBUF_INIT;
+ const char *p = "?";
+ int len_ballast = 0;
+ int k;
+ int errs = 0;
+ int ret;
+
+ /*
+ * The test is setup to send:
+ * "sendbytes" SP <n * char>
+ */
+ if (received_len < strlen("sendbytes "))
+ BUG("received_len is short in app__sendbytes_command");
+
+ if (skip_prefix(received, "sendbytes ", &p))
+ len_ballast = strlen(p);
+
+ /*
+ * Verify that the ballast is n copies of a single letter.
+ * And that the multi-threaded IO layer didn't cross the streams.
+ */
+ for (k = 1; k < len_ballast; k++)
+ if (p[k] != p[0])
+ errs++;
+
+ if (errs)
+ strbuf_addf(&buf_resp, "errs:%d\n", errs);
+ else
+ strbuf_addf(&buf_resp, "rcvd:%c%08d\n", p[0], len_ballast);
+
+ ret = reply_cb(reply_data, buf_resp.buf, buf_resp.len);
+
+ strbuf_release(&buf_resp);
+
+ return ret;
+}
+
+/*
+ * An arbitrary fixed address to verify that the application instance
+ * data is handled properly.
+ */
+static int my_app_data = 42;
+
+static ipc_server_application_cb test_app_cb;
+
+/*
+ * This is the "application callback" that sits on top of the
+ * "ipc-server". It completely defines the set of commands supported
+ * by this application.
+ */
+static int test_app_cb(void *application_data,
+ const char *command, size_t command_len,
+ ipc_server_reply_cb *reply_cb,
+ struct ipc_server_reply_data *reply_data)
+{
+ /*
+ * Verify that we received the application-data that we passed
+ * when we started the ipc-server. (We have several layers of
+ * callbacks calling callbacks and it's easy to get things mixed
+ * up (especially when some are "void*").)
+ */
+ if (application_data != (void*)&my_app_data)
+ BUG("application_cb: application_data pointer wrong");
+
+ if (command_len == 4 && !strncmp(command, "quit", 4)) {
+ /*
+ * The client sent a "quit" command. This is an async
+ * request for the server to shutdown.
+ *
+ * We DO NOT send the client a response message
+ * (because we have nothing to say and the other
+ * server threads have not yet stopped).
+ *
+ * Tell the ipc-server layer to start shutting down.
+ * This includes: stop listening for new connections
+ * on the socket/pipe and telling all worker threads
+ * to finish/drain their outgoing responses to other
+ * clients.
+ *
+ * This DOES NOT force an immediate sync shutdown.
+ */
+ return SIMPLE_IPC_QUIT;
+ }
+
+ if (command_len == 4 && !strncmp(command, "ping", 4)) {
+ const char *answer = "pong";
+ return reply_cb(reply_data, answer, strlen(answer));
+ }
+
+ if (command_len == 3 && !strncmp(command, "big", 3))
+ return app__big_command(reply_cb, reply_data);
+
+ if (command_len == 5 && !strncmp(command, "chunk", 5))
+ return app__chunk_command(reply_cb, reply_data);
+
+ if (command_len == 4 && !strncmp(command, "slow", 4))
+ return app__slow_command(reply_cb, reply_data);
+
+ if (command_len >= 10 && starts_with(command, "sendbytes "))
+ return app__sendbytes_command(command, command_len,
+ reply_cb, reply_data);
+
+ return app__unhandled_command(command, reply_cb, reply_data);
+}
+
+struct cl_args
+{
+ const char *subcommand;
+ const char *path;
+ const char *token;
+
+ int nr_threads;
+ int max_wait_sec;
+ int bytecount;
+ int batchsize;
+
+ char bytevalue;
+};
+
+static struct cl_args cl_args = {
+ .subcommand = NULL,
+ .path = "ipc-test",
+ .token = NULL,
+
+ .nr_threads = 5,
+ .max_wait_sec = 60,
+ .bytecount = 1024,
+ .batchsize = 10,
+
+ .bytevalue = 'x',
+};
+
+/*
+ * This process will run as a simple-ipc server and listen for IPC commands
+ * from client processes.
+ */
+static int daemon__run_server(void)
+{
+ int ret;
+
+ struct ipc_server_opts opts = {
+ .nr_threads = cl_args.nr_threads,
+ };
+
+ /*
+ * Synchronously run the ipc-server. We don't need any application
+ * instance data, so pass an arbitrary pointer (that we'll later
+ * verify made the round trip).
+ */
+ ret = ipc_server_run(cl_args.path, &opts, test_app_cb, (void*)&my_app_data);
+ if (ret == -2)
+ error("socket/pipe already in use: '%s'", cl_args.path);
+ else if (ret == -1)
+ error_errno("could not start server on: '%s'", cl_args.path);
+
+ return ret;
+}
+
+static start_bg_wait_cb bg_wait_cb;
+
+static int bg_wait_cb(const struct child_process *cp, void *cb_data)
+{
+ int s = ipc_get_active_state(cl_args.path);
+
+ switch (s) {
+ case IPC_STATE__LISTENING:
+ /* child is "ready" */
+ return 0;
+
+ case IPC_STATE__NOT_LISTENING:
+ case IPC_STATE__PATH_NOT_FOUND:
+ /* give child more time */
+ return 1;
+
+ default:
+ case IPC_STATE__INVALID_PATH:
+ case IPC_STATE__OTHER_ERROR:
+ /* all the time in world won't help */
+ return -1;
+ }
+}
+
+static int daemon__start_server(void)
+{
+ struct child_process cp = CHILD_PROCESS_INIT;
+ enum start_bg_result sbgr;
+
+ strvec_push(&cp.args, "test-tool");
+ strvec_push(&cp.args, "simple-ipc");
+ strvec_push(&cp.args, "run-daemon");
+ strvec_pushf(&cp.args, "--name=%s", cl_args.path);
+ strvec_pushf(&cp.args, "--threads=%d", cl_args.nr_threads);
+
+ cp.no_stdin = 1;
+ cp.no_stdout = 1;
+ cp.no_stderr = 1;
+
+ sbgr = start_bg_command(&cp, bg_wait_cb, NULL, cl_args.max_wait_sec);
+
+ switch (sbgr) {
+ case SBGR_READY:
+ return 0;
+
+ default:
+ case SBGR_ERROR:
+ case SBGR_CB_ERROR:
+ return error("daemon failed to start");
+
+ case SBGR_TIMEOUT:
+ return error("daemon not online yet");
+
+ case SBGR_DIED:
+ return error("daemon terminated");
+ }
+}
+
+/*
+ * This process will run a quick probe to see if a simple-ipc server
+ * is active on this path.
+ *
+ * Returns 0 if the server is alive.
+ */
+static int client__probe_server(void)
+{
+ enum ipc_active_state s;
+
+ s = ipc_get_active_state(cl_args.path);
+ switch (s) {
+ case IPC_STATE__LISTENING:
+ return 0;
+
+ case IPC_STATE__NOT_LISTENING:
+ return error("no server listening at '%s'", cl_args.path);
+
+ case IPC_STATE__PATH_NOT_FOUND:
+ return error("path not found '%s'", cl_args.path);
+
+ case IPC_STATE__INVALID_PATH:
+ return error("invalid pipe/socket name '%s'", cl_args.path);
+
+ case IPC_STATE__OTHER_ERROR:
+ default:
+ return error("other error for '%s'", cl_args.path);
+ }
+}
+
+/*
+ * Send an IPC command token to an already-running server daemon and
+ * print the response.
+ *
+ * This is a simple 1 word command/token that `test_app_cb()` (in the
+ * daemon process) will understand.
+ */
+static int client__send_ipc(void)
+{
+ const char *command = "(no-command)";
+ struct strbuf buf = STRBUF_INIT;
+ struct ipc_client_connect_options options
+ = IPC_CLIENT_CONNECT_OPTIONS_INIT;
+
+ if (cl_args.token && *cl_args.token)
+ command = cl_args.token;
+
+ options.wait_if_busy = 1;
+ options.wait_if_not_found = 0;
+
+ if (!ipc_client_send_command(cl_args.path, &options,
+ command, strlen(command),
+ &buf)) {
+ if (buf.len) {
+ printf("%s\n", buf.buf);
+ fflush(stdout);
+ }
+ strbuf_release(&buf);
+
+ return 0;
+ }
+
+ return error("failed to send '%s' to '%s'", command, cl_args.path);
+}
+
+/*
+ * Send an IPC command to an already-running server and ask it to
+ * shutdown. "send quit" is an async request and queues a shutdown
+ * event in the server, so we spin and wait here for it to actually
+ * shutdown to make the unit tests a little easier to write.
+ */
+static int client__stop_server(void)
+{
+ int ret;
+ time_t time_limit, now;
+ enum ipc_active_state s;
+
+ time(&time_limit);
+ time_limit += cl_args.max_wait_sec;
+
+ cl_args.token = "quit";
+
+ ret = client__send_ipc();
+ if (ret)
+ return ret;
+
+ for (;;) {
+ sleep_millisec(100);
+
+ s = ipc_get_active_state(cl_args.path);
+
+ if (s != IPC_STATE__LISTENING) {
+ /*
+ * The socket/pipe is gone and/or has stopped
+ * responding. Lets assume that the daemon
+ * process has exited too.
+ */
+ return 0;
+ }
+
+ time(&now);
+ if (now > time_limit)
+ return error("daemon has not shutdown yet");
+ }
+}
+
+/*
+ * Send an IPC command followed by ballast to confirm that a large
+ * message can be sent and that the kernel or pkt-line layers will
+ * properly chunk it and that the daemon receives the entire message.
+ */
+static int do_sendbytes(int bytecount, char byte, const char *path,
+ const struct ipc_client_connect_options *options)
+{
+ struct strbuf buf_send = STRBUF_INIT;
+ struct strbuf buf_resp = STRBUF_INIT;
+
+ strbuf_addstr(&buf_send, "sendbytes ");
+ strbuf_addchars(&buf_send, byte, bytecount);
+
+ if (!ipc_client_send_command(path, options,
+ buf_send.buf, buf_send.len,
+ &buf_resp)) {
+ strbuf_rtrim(&buf_resp);
+ printf("sent:%c%08d %s\n", byte, bytecount, buf_resp.buf);
+ fflush(stdout);
+ strbuf_release(&buf_send);
+ strbuf_release(&buf_resp);
+
+ return 0;
+ }
+
+ return error("client failed to sendbytes(%d, '%c') to '%s'",
+ bytecount, byte, path);
+}
+
+/*
+ * Send an IPC command with ballast to an already-running server daemon.
+ */
+static int client__sendbytes(void)
+{
+ struct ipc_client_connect_options options
+ = IPC_CLIENT_CONNECT_OPTIONS_INIT;
+
+ options.wait_if_busy = 1;
+ options.wait_if_not_found = 0;
+ options.uds_disallow_chdir = 0;
+
+ return do_sendbytes(cl_args.bytecount, cl_args.bytevalue, cl_args.path,
+ &options);
+}
+
+struct multiple_thread_data {
+ pthread_t pthread_id;
+ struct multiple_thread_data *next;
+ const char *path;
+ int bytecount;
+ int batchsize;
+ int sum_errors;
+ int sum_good;
+ char letter;
+};
+
+static void *multiple_thread_proc(void *_multiple_thread_data)
+{
+ struct multiple_thread_data *d = _multiple_thread_data;
+ int k;
+ struct ipc_client_connect_options options
+ = IPC_CLIENT_CONNECT_OPTIONS_INIT;
+
+ options.wait_if_busy = 1;
+ options.wait_if_not_found = 0;
+ /*
+ * A multi-threaded client should not be randomly calling chdir().
+ * The test will pass without this restriction because the test is
+ * not otherwise accessing the filesystem, but it makes us honest.
+ */
+ options.uds_disallow_chdir = 1;
+
+ trace2_thread_start("multiple");
+
+ for (k = 0; k < d->batchsize; k++) {
+ if (do_sendbytes(d->bytecount + k, d->letter, d->path, &options))
+ d->sum_errors++;
+ else
+ d->sum_good++;
+ }
+
+ trace2_thread_exit();
+ return NULL;
+}
+
+/*
+ * Start a client-side thread pool. Each thread sends a series of
+ * IPC requests. Each request is on a new connection to the server.
+ */
+static int client__multiple(void)
+{
+ struct multiple_thread_data *list = NULL;
+ int k;
+ int sum_join_errors = 0;
+ int sum_thread_errors = 0;
+ int sum_good = 0;
+
+ for (k = 0; k < cl_args.nr_threads; k++) {
+ struct multiple_thread_data *d = xcalloc(1, sizeof(*d));
+ d->next = list;
+ d->path = cl_args.path;
+ d->bytecount = cl_args.bytecount + cl_args.batchsize*(k/26);
+ d->batchsize = cl_args.batchsize;
+ d->sum_errors = 0;
+ d->sum_good = 0;
+ d->letter = 'A' + (k % 26);
+
+ if (pthread_create(&d->pthread_id, NULL, multiple_thread_proc, d)) {
+ warning("failed to create thread[%d] skipping remainder", k);
+ free(d);
+ break;
+ }
+
+ list = d;
+ }
+
+ while (list) {
+ struct multiple_thread_data *d = list;
+
+ if (pthread_join(d->pthread_id, NULL))
+ sum_join_errors++;
+
+ sum_thread_errors += d->sum_errors;
+ sum_good += d->sum_good;
+
+ list = d->next;
+ free(d);
+ }
+
+ printf("client (good %d) (join %d), (errors %d)\n",
+ sum_good, sum_join_errors, sum_thread_errors);
+
+ return (sum_join_errors + sum_thread_errors) ? 1 : 0;
+}
+
+int cmd__simple_ipc(int argc, const char **argv)
+{
+ const char * const simple_ipc_usage[] = {
+ N_("test-helper simple-ipc is-active [<name>] [<options>]"),
+ N_("test-helper simple-ipc run-daemon [<name>] [<threads>]"),
+ N_("test-helper simple-ipc start-daemon [<name>] [<threads>] [<max-wait>]"),
+ N_("test-helper simple-ipc stop-daemon [<name>] [<max-wait>]"),
+ N_("test-helper simple-ipc send [<name>] [<token>]"),
+ N_("test-helper simple-ipc sendbytes [<name>] [<bytecount>] [<byte>]"),
+ N_("test-helper simple-ipc multiple [<name>] [<threads>] [<bytecount>] [<batchsize>]"),
+ NULL
+ };
+
+ const char *bytevalue = NULL;
+
+ struct option options[] = {
+#ifndef GIT_WINDOWS_NATIVE
+ OPT_STRING(0, "name", &cl_args.path, N_("name"), N_("name or pathname of unix domain socket")),
+#else
+ OPT_STRING(0, "name", &cl_args.path, N_("name"), N_("named-pipe name")),
+#endif
+ OPT_INTEGER(0, "threads", &cl_args.nr_threads, N_("number of threads in server thread pool")),
+ OPT_INTEGER(0, "max-wait", &cl_args.max_wait_sec, N_("seconds to wait for daemon to start or stop")),
+
+ OPT_INTEGER(0, "bytecount", &cl_args.bytecount, N_("number of bytes")),
+ OPT_INTEGER(0, "batchsize", &cl_args.batchsize, N_("number of requests per thread")),
+
+ OPT_STRING(0, "byte", &bytevalue, N_("byte"), N_("ballast character")),
+ OPT_STRING(0, "token", &cl_args.token, N_("token"), N_("command token to send to the server")),
+
+ OPT_END()
+ };
+
+ if (argc < 2)
+ usage_with_options(simple_ipc_usage, options);
+
+ if (argc == 2 && !strcmp(argv[1], "-h"))
+ usage_with_options(simple_ipc_usage, options);
+
+ if (argc == 2 && !strcmp(argv[1], "SUPPORTS_SIMPLE_IPC"))
+ return 0;
+
+ cl_args.subcommand = argv[1];
+
+ argc--;
+ argv++;
+
+ argc = parse_options(argc, argv, NULL, options, simple_ipc_usage, 0);
+
+ if (cl_args.nr_threads < 1)
+ cl_args.nr_threads = 1;
+ if (cl_args.max_wait_sec < 0)
+ cl_args.max_wait_sec = 0;
+ if (cl_args.bytecount < 1)
+ cl_args.bytecount = 1;
+ if (cl_args.batchsize < 1)
+ cl_args.batchsize = 1;
+
+ if (bytevalue && *bytevalue)
+ cl_args.bytevalue = bytevalue[0];
+
+ /*
+ * Use '!!' on all dispatch functions to map from `error()` style
+ * (returns -1) style to `test_must_fail` style (expects 1). This
+ * makes shell error messages less confusing.
+ */
+
+ if (!strcmp(cl_args.subcommand, "is-active"))
+ return !!client__probe_server();
+
+ if (!strcmp(cl_args.subcommand, "run-daemon"))
+ return !!daemon__run_server();
+
+ if (!strcmp(cl_args.subcommand, "start-daemon"))
+ return !!daemon__start_server();
+
+ /*
+ * Client commands follow. Ensure a server is running before
+ * sending any data. This might be overkill, but then again
+ * this is a test harness.
+ */
+
+ if (!strcmp(cl_args.subcommand, "stop-daemon")) {
+ if (client__probe_server())
+ return 1;
+ return !!client__stop_server();
+ }
+
+ if (!strcmp(cl_args.subcommand, "send")) {
+ if (client__probe_server())
+ return 1;
+ return !!client__send_ipc();
+ }
+
+ if (!strcmp(cl_args.subcommand, "sendbytes")) {
+ if (client__probe_server())
+ return 1;
+ return !!client__sendbytes();
+ }
+
+ if (!strcmp(cl_args.subcommand, "multiple")) {
+ if (client__probe_server())
+ return 1;
+ return !!client__multiple();
+ }
+
+ die("Unhandled subcommand: '%s'", cl_args.subcommand);
+}
+#endif
diff --git a/t/helper/test-submodule-nested-repo-config.c b/t/helper/test-submodule-nested-repo-config.c
index bc97929..dc1c14b 100644
--- a/t/helper/test-submodule-nested-repo-config.c
+++ b/t/helper/test-submodule-nested-repo-config.c
@@ -1,7 +1,7 @@
#include "test-tool.h"
#include "submodule-config.h"
-static void die_usage(int argc, const char **argv, const char *msg)
+static void die_usage(const char **argv, const char *msg)
{
fprintf(stderr, "%s\n", msg);
fprintf(stderr, "Usage: %s <submodulepath> <config name>\n", argv[0]);
@@ -11,16 +11,14 @@ static void die_usage(int argc, const char **argv, const char *msg)
int cmd__submodule_nested_repo_config(int argc, const char **argv)
{
struct repository subrepo;
- const struct submodule *sub;
if (argc < 3)
- die_usage(argc, argv, "Wrong number of arguments.");
+ die_usage(argv, "Wrong number of arguments.");
setup_git_directory();
- sub = submodule_from_path(the_repository, &null_oid, argv[1]);
- if (repo_submodule_init(&subrepo, the_repository, sub)) {
- die_usage(argc, argv, "Submodule not found.");
+ if (repo_submodule_init(&subrepo, the_repository, argv[1], null_oid())) {
+ die_usage(argv, "Submodule not found.");
}
/* Read the config of _child_ submodules. */
diff --git a/t/helper/test-subprocess.c b/t/helper/test-subprocess.c
index 92b69de..ff22f2f 100644
--- a/t/helper/test-subprocess.c
+++ b/t/helper/test-subprocess.c
@@ -15,6 +15,6 @@ int cmd__subprocess(int argc, const char **argv)
argv++;
}
cp.git_cmd = 1;
- cp.argv = (const char **)argv + 1;
+ strvec_pushv(&cp.args, (const char **)argv + 1);
return run_command(&cp);
}
diff --git a/t/helper/test-svn-fe.c b/t/helper/test-svn-fe.c
deleted file mode 100644
index 7667c08..0000000
--- a/t/helper/test-svn-fe.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * test-svn-fe: Code to exercise the svn import lib
- */
-
-#include "git-compat-util.h"
-#include "vcs-svn/svndump.h"
-#include "vcs-svn/svndiff.h"
-#include "vcs-svn/sliding_window.h"
-#include "vcs-svn/line_buffer.h"
-
-static const char test_svnfe_usage[] =
- "test-svn-fe (<dumpfile> | [-d] <preimage> <delta> <len>)";
-
-static int apply_delta(int argc, const char **argv)
-{
- struct line_buffer preimage = LINE_BUFFER_INIT;
- struct line_buffer delta = LINE_BUFFER_INIT;
- struct sliding_view preimage_view = SLIDING_VIEW_INIT(&preimage, -1);
-
- if (argc != 5)
- usage(test_svnfe_usage);
-
- if (buffer_init(&preimage, argv[2]))
- die_errno("cannot open preimage");
- if (buffer_init(&delta, argv[3]))
- die_errno("cannot open delta");
- if (svndiff0_apply(&delta, (off_t) strtoumax(argv[4], NULL, 0),
- &preimage_view, stdout))
- return 1;
- if (buffer_deinit(&preimage))
- die_errno("cannot close preimage");
- if (buffer_deinit(&delta))
- die_errno("cannot close delta");
- strbuf_release(&preimage_view.buf);
- return 0;
-}
-
-int cmd_main(int argc, const char **argv)
-{
- if (argc == 2) {
- if (svndump_init(argv[1]))
- return 1;
- svndump_read(NULL, "refs/heads/master", "refs/notes/svn/revs");
- svndump_deinit();
- svndump_reset();
- return 0;
- }
-
- if (argc >= 2 && !strcmp(argv[1], "-d"))
- return apply_delta(argc, argv);
- usage(test_svnfe_usage);
-}
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
index f20989d..318fdba 100644
--- a/t/helper/test-tool.c
+++ b/t/helper/test-tool.c
@@ -14,8 +14,13 @@ struct test_cmd {
};
static struct test_cmd cmds[] = {
+ { "advise", cmd__advise_if_enabled },
+ { "bitmap", cmd__bitmap },
+ { "bloom", cmd__bloom },
{ "chmtime", cmd__chmtime },
{ "config", cmd__config },
+ { "crontab", cmd__crontab },
+ { "csprng", cmd__csprng },
{ "ctype", cmd__ctype },
{ "date", cmd__date },
{ "delta", cmd__delta },
@@ -26,28 +31,41 @@ static struct test_cmd cmds[] = {
{ "dump-split-index", cmd__dump_split_index },
{ "dump-untracked-cache", cmd__dump_untracked_cache },
{ "example-decorate", cmd__example_decorate },
+ { "fast-rebase", cmd__fast_rebase },
+ { "fsmonitor-client", cmd__fsmonitor_client },
{ "genrandom", cmd__genrandom },
{ "genzeros", cmd__genzeros },
+ { "getcwd", cmd__getcwd },
{ "hashmap", cmd__hashmap },
{ "hash-speed", cmd__hash_speed },
+ { "hexdump", cmd__hexdump },
{ "index-version", cmd__index_version },
{ "json-writer", cmd__json_writer },
{ "lazy-init-name-hash", cmd__lazy_init_name_hash },
{ "match-trees", cmd__match_trees },
{ "mergesort", cmd__mergesort },
{ "mktemp", cmd__mktemp },
+ { "oid-array", cmd__oid_array },
{ "oidmap", cmd__oidmap },
+ { "oidtree", cmd__oidtree },
{ "online-cpus", cmd__online_cpus },
+ { "pack-mtimes", cmd__pack_mtimes },
{ "parse-options", cmd__parse_options },
+ { "parse-pathspec-file", cmd__parse_pathspec_file },
+ { "partial-clone", cmd__partial_clone },
{ "path-utils", cmd__path_utils },
+ { "pcre2-config", cmd__pcre2_config },
{ "pkt-line", cmd__pkt_line },
{ "prio-queue", cmd__prio_queue },
+ { "proc-receive", cmd__proc_receive },
{ "progress", cmd__progress },
{ "reach", cmd__reach },
{ "read-cache", cmd__read_cache },
{ "read-graph", cmd__read_graph },
{ "read-midx", cmd__read_midx },
{ "ref-store", cmd__ref_store },
+ { "reftable", cmd__reftable },
+ { "dump-reftable", cmd__dump_reftable },
{ "regex", cmd__regex },
{ "repository", cmd__repository },
{ "revision-walking", cmd__revision_walking },
@@ -55,15 +73,16 @@ static struct test_cmd cmds[] = {
{ "scrap-cache-tree", cmd__scrap_cache_tree },
{ "serve-v2", cmd__serve_v2 },
{ "sha1", cmd__sha1 },
- { "sha1-array", cmd__sha1_array },
{ "sha256", cmd__sha256 },
{ "sigchain", cmd__sigchain },
+ { "simple-ipc", cmd__simple_ipc },
{ "strcmp-offset", cmd__strcmp_offset },
{ "string-list", cmd__string_list },
{ "submodule-config", cmd__submodule_config },
{ "submodule-nested-repo-config", cmd__submodule_nested_repo_config },
{ "subprocess", cmd__subprocess },
{ "trace2", cmd__trace2 },
+ { "userdiff", cmd__userdiff },
{ "urlmatch-normalization", cmd__urlmatch_normalization },
{ "xml-encode", cmd__xml_encode },
{ "wildmatch", cmd__wildmatch },
@@ -110,6 +129,7 @@ int cmd_main(int argc, const char **argv)
argc--;
trace2_cmd_name(cmds[i].name);
trace2_cmd_list_config();
+ trace2_cmd_list_env_vars();
return cmds[i].fn(argc, argv);
}
}
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
index 8ed2af7..bb79927 100644
--- a/t/helper/test-tool.h
+++ b/t/helper/test-tool.h
@@ -4,8 +4,13 @@
#define USE_THE_INDEX_COMPATIBILITY_MACROS
#include "git-compat-util.h"
+int cmd__advise_if_enabled(int argc, const char **argv);
+int cmd__bitmap(int argc, const char **argv);
+int cmd__bloom(int argc, const char **argv);
int cmd__chmtime(int argc, const char **argv);
int cmd__config(int argc, const char **argv);
+int cmd__crontab(int argc, const char **argv);
+int cmd__csprng(int argc, const char **argv);
int cmd__ctype(int argc, const char **argv);
int cmd__date(int argc, const char **argv);
int cmd__delta(int argc, const char **argv);
@@ -15,11 +20,16 @@ int cmd__dump_cache_tree(int argc, const char **argv);
int cmd__dump_fsmonitor(int argc, const char **argv);
int cmd__dump_split_index(int argc, const char **argv);
int cmd__dump_untracked_cache(int argc, const char **argv);
+int cmd__dump_reftable(int argc, const char **argv);
int cmd__example_decorate(int argc, const char **argv);
+int cmd__fast_rebase(int argc, const char **argv);
+int cmd__fsmonitor_client(int argc, const char **argv);
int cmd__genrandom(int argc, const char **argv);
int cmd__genzeros(int argc, const char **argv);
+int cmd__getcwd(int argc, const char **argv);
int cmd__hashmap(int argc, const char **argv);
int cmd__hash_speed(int argc, const char **argv);
+int cmd__hexdump(int argc, const char **argv);
int cmd__index_version(int argc, const char **argv);
int cmd__json_writer(int argc, const char **argv);
int cmd__lazy_init_name_hash(int argc, const char **argv);
@@ -27,17 +37,24 @@ int cmd__match_trees(int argc, const char **argv);
int cmd__mergesort(int argc, const char **argv);
int cmd__mktemp(int argc, const char **argv);
int cmd__oidmap(int argc, const char **argv);
+int cmd__oidtree(int argc, const char **argv);
int cmd__online_cpus(int argc, const char **argv);
+int cmd__pack_mtimes(int argc, const char **argv);
int cmd__parse_options(int argc, const char **argv);
+int cmd__parse_pathspec_file(int argc, const char** argv);
+int cmd__partial_clone(int argc, const char **argv);
int cmd__path_utils(int argc, const char **argv);
+int cmd__pcre2_config(int argc, const char **argv);
int cmd__pkt_line(int argc, const char **argv);
int cmd__prio_queue(int argc, const char **argv);
+int cmd__proc_receive(int argc, const char **argv);
int cmd__progress(int argc, const char **argv);
int cmd__reach(int argc, const char **argv);
int cmd__read_cache(int argc, const char **argv);
int cmd__read_graph(int argc, const char **argv);
int cmd__read_midx(int argc, const char **argv);
int cmd__ref_store(int argc, const char **argv);
+int cmd__reftable(int argc, const char **argv);
int cmd__regex(int argc, const char **argv);
int cmd__repository(int argc, const char **argv);
int cmd__revision_walking(int argc, const char **argv);
@@ -45,15 +62,17 @@ int cmd__run_command(int argc, const char **argv);
int cmd__scrap_cache_tree(int argc, const char **argv);
int cmd__serve_v2(int argc, const char **argv);
int cmd__sha1(int argc, const char **argv);
-int cmd__sha1_array(int argc, const char **argv);
+int cmd__oid_array(int argc, const char **argv);
int cmd__sha256(int argc, const char **argv);
int cmd__sigchain(int argc, const char **argv);
+int cmd__simple_ipc(int argc, const char **argv);
int cmd__strcmp_offset(int argc, const char **argv);
int cmd__string_list(int argc, const char **argv);
int cmd__submodule_config(int argc, const char **argv);
int cmd__submodule_nested_repo_config(int argc, const char **argv);
int cmd__subprocess(int argc, const char **argv);
int cmd__trace2(int argc, const char **argv);
+int cmd__userdiff(int argc, const char **argv);
int cmd__urlmatch_normalization(int argc, const char **argv);
int cmd__xml_encode(int argc, const char **argv);
int cmd__wildmatch(int argc, const char **argv);
diff --git a/t/helper/test-trace2.c b/t/helper/test-trace2.c
index 197819c..a714130 100644
--- a/t/helper/test-trace2.c
+++ b/t/helper/test-trace2.c
@@ -1,6 +1,6 @@
#include "test-tool.h"
#include "cache.h"
-#include "argv-array.h"
+#include "strvec.h"
#include "run-command.h"
#include "exec-cmd.h"
#include "config.h"
@@ -198,6 +198,36 @@ static int ut_006data(int argc, const char **argv)
return 0;
}
+static int ut_007BUG(int argc, const char **argv)
+{
+ /*
+ * Exercise BUG() to ensure that the message is printed to trace2.
+ */
+ BUG("the bug message");
+}
+
+static int ut_008bug(int argc, const char **argv)
+{
+ bug("a bug message");
+ bug("another bug message");
+ BUG_if_bug("an explicit BUG_if_bug() following bug() call(s) is nice, but not required");
+ return 0;
+}
+
+static int ut_009bug_BUG(int argc, const char **argv)
+{
+ bug("a bug message");
+ bug("another bug message");
+ /* The BUG_if_bug(...) isn't here, but we'll spot bug() calls on exit()! */
+ return 0;
+}
+
+static int ut_010bug_BUG(int argc, const char **argv)
+{
+ bug("a %s message", "bug");
+ BUG("a %s message", "BUG");
+}
+
/*
* Usage:
* test-tool trace2 <ut_name_1> <ut_usage_1>
@@ -214,6 +244,10 @@ static struct unit_test ut_table[] = {
{ ut_004child, "004child", "[<child_command_line>]" },
{ ut_005exec, "005exec", "<git_command_args>" },
{ ut_006data, "006data", "[<category> <key> <value>]+" },
+ { ut_007BUG, "007bug", "" },
+ { ut_008bug, "008bug", "" },
+ { ut_009bug_BUG, "009bug_BUG","" },
+ { ut_010bug_BUG, "010bug_BUG","" },
};
/* clang-format on */
@@ -253,8 +287,9 @@ static int print_usage(void)
* [] the "cmd_name" event has been generated.
* [] this writes various "def_param" events for interesting config values.
*
- * We further assume that if we return (rather than exit()), trace2_cmd_exit()
- * will be called by test-tool.c:cmd_main().
+ * We return from here and let test-tool.c::cmd_main() pass the exit
+ * code to common-main.c::main(), which will use it to call
+ * trace2_cmd_exit().
*/
int cmd__trace2(int argc, const char **argv)
{
diff --git a/t/helper/test-userdiff.c b/t/helper/test-userdiff.c
new file mode 100644
index 0000000..f013f8a
--- /dev/null
+++ b/t/helper/test-userdiff.c
@@ -0,0 +1,46 @@
+#include "test-tool.h"
+#include "cache.h"
+#include "userdiff.h"
+#include "config.h"
+
+static int driver_cb(struct userdiff_driver *driver,
+ enum userdiff_driver_type type, void *priv)
+{
+ enum userdiff_driver_type *want_type = priv;
+ if (type & *want_type && driver->funcname.pattern)
+ puts(driver->name);
+ return 0;
+}
+
+static int cmd__userdiff_config(const char *var, const char *value, void *cb)
+{
+ if (userdiff_config(var, value) < 0)
+ return -1;
+ return 0;
+}
+
+int cmd__userdiff(int argc, const char **argv)
+{
+ enum userdiff_driver_type want = 0;
+ if (argc != 2)
+ return 1;
+
+ if (!strcmp(argv[1], "list-drivers"))
+ want = (USERDIFF_DRIVER_TYPE_BUILTIN |
+ USERDIFF_DRIVER_TYPE_CUSTOM);
+ else if (!strcmp(argv[1], "list-builtin-drivers"))
+ want = USERDIFF_DRIVER_TYPE_BUILTIN;
+ else if (!strcmp(argv[1], "list-custom-drivers"))
+ want = USERDIFF_DRIVER_TYPE_CUSTOM;
+ else
+ return error("unknown argument %s", argv[1]);
+
+ if (want & USERDIFF_DRIVER_TYPE_CUSTOM) {
+ setup_git_directory();
+ git_config(cmd__userdiff_config, NULL);
+ }
+
+ for_each_userdiff_driver(driver_cb, &want);
+
+ return 0;
+}
diff --git a/t/helper/test-windows-named-pipe.c b/t/helper/test-windows-named-pipe.c
index b4b752b..ae52183 100644
--- a/t/helper/test-windows-named-pipe.c
+++ b/t/helper/test-windows-named-pipe.c
@@ -19,7 +19,7 @@ int cmd__windows_named_pipe(int argc, const char **argv)
if (argc < 2)
goto print_usage;
filename = argv[1];
- if (strchr(filename, '/') || strchr(filename, '\\'))
+ if (strpbrk(filename, "/\\"))
goto print_usage;
strbuf_addf(&pathname, "//./pipe/%s", filename);