aboutsummaryrefslogtreecommitdiffstats
path: root/t/helper
diff options
context:
space:
mode:
Diffstat (limited to 't/helper')
-rw-r--r--t/helper/test-bloom.c2
-rw-r--r--t/helper/test-config.c2
-rw-r--r--t/helper/test-crontab.c23
-rw-r--r--t/helper/test-delta.c21
-rw-r--r--t/helper/test-dump-cache-tree.c7
-rw-r--r--t/helper/test-fast-rebase.c2
-rw-r--r--t/helper/test-hash.c1
-rw-r--r--t/helper/test-json-writer.c16
-rw-r--r--t/helper/test-mergesort.c74
-rw-r--r--t/helper/test-parse-options.c128
-rw-r--r--t/helper/test-path-utils.c11
-rw-r--r--t/helper/test-ref-store.c5
-rw-r--r--t/helper/test-regex.c9
-rw-r--r--t/helper/test-rot13-filter.c382
-rw-r--r--t/helper/test-scrap-cache-tree.c1
-rw-r--r--t/helper/test-serve-v2.c2
-rw-r--r--t/helper/test-submodule-config.c11
-rw-r--r--t/helper/test-submodule.c146
-rw-r--r--t/helper/test-tool-utils.h9
-rw-r--r--t/helper/test-tool.c10
-rw-r--r--t/helper/test-tool.h4
-rw-r--r--t/helper/test-urlmatch-normalization.c11
-rw-r--r--t/helper/test-userdiff.c2
23 files changed, 785 insertions, 94 deletions
diff --git a/t/helper/test-bloom.c b/t/helper/test-bloom.c
index ad3ef1cd77..6c900ca668 100644
--- a/t/helper/test-bloom.c
+++ b/t/helper/test-bloom.c
@@ -16,6 +16,7 @@ static void add_string_to_filter(const char *data, struct bloom_filter *filter)
}
printf("\n");
add_key_to_filter(&key, filter, &settings);
+ clear_bloom_key(&key);
}
static void print_bloom_filter(struct bloom_filter *filter) {
@@ -80,6 +81,7 @@ int cmd__bloom(int argc, const char **argv)
}
print_bloom_filter(&filter);
+ free(filter.data);
}
if (!strcmp(argv[1], "get_filter_for_commit")) {
diff --git a/t/helper/test-config.c b/t/helper/test-config.c
index a6e936721f..4ba9eb6560 100644
--- a/t/helper/test-config.c
+++ b/t/helper/test-config.c
@@ -37,7 +37,7 @@
*
*/
-static int iterate_cb(const char *var, const char *value, void *data)
+static int iterate_cb(const char *var, const char *value, void *data UNUSED)
{
static int nr;
diff --git a/t/helper/test-crontab.c b/t/helper/test-crontab.c
index e7c0137a47..e6c1b1e22b 100644
--- a/t/helper/test-crontab.c
+++ b/t/helper/test-crontab.c
@@ -2,33 +2,34 @@
#include "cache.h"
/*
- * Usage: test-tool cron <file> [-l]
+ * Usage: test-tool crontab <file> -l|<input>
*
* If -l is specified, then write the contents of <file> to stdout.
- * Otherwise, write from stdin into <file>.
+ * Otherwise, copy the contents of <input> into <file>.
*/
int cmd__crontab(int argc, const char **argv)
{
int a;
FILE *from, *to;
- if (argc == 3 && !strcmp(argv[2], "-l")) {
+ if (argc != 3)
+ usage("test-tool crontab <file> -l|<input>");
+
+ if (!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");
+ } else {
+ from = xfopen(argv[2], "r");
+ to = xfopen(argv[1], "w");
+ }
while ((a = fgetc(from)) != EOF)
fputc(a, to);
- if (argc == 3)
- fclose(from);
- else
+ fclose(from);
+ if (to != stdout)
fclose(to);
return 0;
diff --git a/t/helper/test-delta.c b/t/helper/test-delta.c
index e749a49c88..b15481ea59 100644
--- a/t/helper/test-delta.c
+++ b/t/helper/test-delta.c
@@ -20,8 +20,9 @@ int cmd__delta(int argc, const char **argv)
{
int fd;
struct stat st;
- void *from_buf, *data_buf, *out_buf;
+ void *from_buf = NULL, *data_buf = NULL, *out_buf = NULL;
unsigned long from_size, data_size, out_size;
+ int ret = 1;
if (argc != 5 || (strcmp(argv[1], "-d") && strcmp(argv[1], "-p"))) {
fprintf(stderr, "usage: %s\n", usage_str);
@@ -38,21 +39,21 @@ int cmd__delta(int argc, const char **argv)
if (read_in_full(fd, from_buf, from_size) < 0) {
perror(argv[2]);
close(fd);
- return 1;
+ goto cleanup;
}
close(fd);
fd = open(argv[3], O_RDONLY);
if (fd < 0 || fstat(fd, &st)) {
perror(argv[3]);
- return 1;
+ goto cleanup;
}
data_size = st.st_size;
data_buf = xmalloc(data_size);
if (read_in_full(fd, data_buf, data_size) < 0) {
perror(argv[3]);
close(fd);
- return 1;
+ goto cleanup;
}
close(fd);
@@ -66,14 +67,20 @@ int cmd__delta(int argc, const char **argv)
&out_size);
if (!out_buf) {
fprintf(stderr, "delta operation failed (returned NULL)\n");
- return 1;
+ goto cleanup;
}
fd = open (argv[4], O_WRONLY|O_CREAT|O_TRUNC, 0666);
if (fd < 0 || write_in_full(fd, out_buf, out_size) < 0) {
perror(argv[4]);
- return 1;
+ goto cleanup;
}
- return 0;
+ ret = 0;
+cleanup:
+ free(from_buf);
+ free(data_buf);
+ free(out_buf);
+
+ return ret;
}
diff --git a/t/helper/test-dump-cache-tree.c b/t/helper/test-dump-cache-tree.c
index 6a3f88f5f5..0d6d7f1ecb 100644
--- a/t/helper/test-dump-cache-tree.c
+++ b/t/helper/test-dump-cache-tree.c
@@ -59,11 +59,16 @@ int cmd__dump_cache_tree(int ac, const char **av)
{
struct index_state istate;
struct cache_tree *another = cache_tree();
+ int ret;
+
setup_git_directory();
if (read_cache() < 0)
die("unable to read index file");
istate = the_index;
istate.cache_tree = another;
cache_tree_update(&istate, WRITE_TREE_DRY_RUN);
- return dump_cache_tree(active_cache_tree, another, "");
+ ret = dump_cache_tree(active_cache_tree, another, "");
+ cache_tree_free(&another);
+
+ return ret;
}
diff --git a/t/helper/test-fast-rebase.c b/t/helper/test-fast-rebase.c
index 4e5553e202..45665ec19a 100644
--- a/t/helper/test-fast-rebase.c
+++ b/t/helper/test-fast-rebase.c
@@ -184,8 +184,6 @@ int cmd__fast_rebase(int argc, const char **argv)
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);
diff --git a/t/helper/test-hash.c b/t/helper/test-hash.c
index 261c545b9d..5860dab0ff 100644
--- a/t/helper/test-hash.c
+++ b/t/helper/test-hash.c
@@ -54,5 +54,6 @@ 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));
+ free(buffer);
return 0;
}
diff --git a/t/helper/test-json-writer.c b/t/helper/test-json-writer.c
index 37c452535f..8c3edacc00 100644
--- a/t/helper/test-json-writer.c
+++ b/t/helper/test-json-writer.c
@@ -181,12 +181,18 @@ static struct json_writer nest1 = JSON_WRITER_INIT;
static void make_nest1(int pretty)
{
+ make_obj1(0);
+ make_arr1(0);
+
jw_object_begin(&nest1, pretty);
{
jw_object_sub_jw(&nest1, "obj1", &obj1);
jw_object_sub_jw(&nest1, "arr1", &arr1);
}
jw_end(&nest1);
+
+ jw_release(&obj1);
+ jw_release(&arr1);
}
static char *expect_inline1 =
@@ -313,6 +319,9 @@ static void make_mixed1(int pretty)
jw_object_sub_jw(&mixed1, "arr1", &arr1);
}
jw_end(&mixed1);
+
+ jw_release(&obj1);
+ jw_release(&arr1);
}
static void cmp(const char *test, const struct json_writer *jw, const char *exp)
@@ -325,8 +334,8 @@ static void cmp(const char *test, const struct json_writer *jw, const char *exp)
exit(1);
}
-#define t(v) do { make_##v(0); cmp(#v, &v, expect_##v); } while (0)
-#define p(v) do { make_##v(1); cmp(#v, &v, pretty_##v); } while (0)
+#define t(v) do { make_##v(0); cmp(#v, &v, expect_##v); jw_release(&v); } while (0)
+#define p(v) do { make_##v(1); cmp(#v, &v, pretty_##v); jw_release(&v); } while (0)
/*
* Run some basic regression tests with some known patterns.
@@ -381,7 +390,6 @@ static int unit_tests(void)
/* mixed forms */
t(mixed1);
- jw_init(&mixed1);
p(mixed1);
return 0;
@@ -544,7 +552,7 @@ static int scripted(void)
printf("%s\n", jw.json.buf);
- strbuf_release(&jw.json);
+ jw_release(&jw);
return 0;
}
diff --git a/t/helper/test-mergesort.c b/t/helper/test-mergesort.c
index ebf68f7de8..335e5bb3a9 100644
--- a/t/helper/test-mergesort.c
+++ b/t/helper/test-mergesort.c
@@ -13,41 +13,46 @@ struct line {
struct line *next;
};
-static void *get_next(const void *a)
-{
- return ((const struct line *)a)->next;
-}
+DEFINE_LIST_SORT(static, sort_lines, struct line, next);
-static void set_next(void *a, void *b)
+static int compare_strings(const struct line *x, const struct line *y)
{
- ((struct line *)a)->next = b;
-}
-
-static int compare_strings(const void *a, const void *b)
-{
- const struct line *x = a, *y = b;
return strcmp(x->text, y->text);
}
static int sort_stdin(void)
{
- struct line *line, *p = NULL, *lines = NULL;
+ struct line *lines;
+ struct line **tail = &lines;
struct strbuf sb = STRBUF_INIT;
-
- while (!strbuf_getline(&sb, stdin)) {
- line = xmalloc(sizeof(struct line));
- line->text = strbuf_detach(&sb, NULL);
- if (p) {
- line->next = p->next;
- p->next = line;
- } else {
- line->next = NULL;
- lines = line;
- }
- p = line;
+ struct mem_pool lines_pool;
+ char *p;
+
+ strbuf_read(&sb, 0, 0);
+
+ /*
+ * Split by newline, but don't create an item
+ * for the empty string after the last separator.
+ */
+ if (sb.len && sb.buf[sb.len - 1] == '\n')
+ strbuf_setlen(&sb, sb.len - 1);
+
+ mem_pool_init(&lines_pool, 0);
+ p = sb.buf;
+ for (;;) {
+ char *eol = strchr(p, '\n');
+ struct line *line = mem_pool_alloc(&lines_pool, sizeof(*line));
+ line->text = p;
+ *tail = line;
+ tail = &line->next;
+ if (!eol)
+ break;
+ *eol = '\0';
+ p = eol + 1;
}
+ *tail = NULL;
- lines = llist_mergesort(lines, get_next, set_next, compare_strings);
+ sort_lines(&lines, compare_strings);
while (lines) {
puts(lines->text);
@@ -273,21 +278,11 @@ struct number {
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;
-}
+DEFINE_LIST_SORT_DEBUG(static, sort_numbers, struct number, next,
+ stats.get_next++, stats.set_next++);
-static int compare_numbers(const void *av, const void *bv)
+static int compare_numbers(const struct number *an, const struct number *bn)
{
- const struct number *an = av, *bn = bv;
int a = an->value, b = bn->value;
stats.compare++;
return (a > b) - (a < b);
@@ -325,8 +320,7 @@ static int test(const struct dist *dist, const struct mode *mode, int n, int m)
*tail = NULL;
stats.get_next = stats.set_next = stats.compare = 0;
- list = llist_mergesort(list, get_next_number, set_next_number,
- compare_numbers);
+ sort_numbers(&list, compare_numbers);
QSORT(arr, n, compare_ints);
for (i = 0, curr = list; i < n && curr; i++, curr = curr->next) {
diff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c
index 48d3cf6692..506835521a 100644
--- a/t/helper/test-parse-options.c
+++ b/t/helper/test-parse-options.c
@@ -192,3 +192,131 @@ int cmd__parse_options(int argc, const char **argv)
return ret;
}
+
+static void print_args(int argc, const char **argv)
+{
+ int i;
+ for (i = 0; i < argc; i++)
+ printf("arg %02d: %s\n", i, argv[i]);
+}
+
+static int parse_options_flags__cmd(int argc, const char **argv,
+ enum parse_opt_flags test_flags)
+{
+ const char *usage[] = {
+ "<...> cmd [options]",
+ NULL
+ };
+ int opt = 0;
+ const struct option options[] = {
+ OPT_INTEGER('o', "opt", &opt, "an integer option"),
+ OPT_END()
+ };
+
+ argc = parse_options(argc, argv, NULL, options, usage, test_flags);
+
+ printf("opt: %d\n", opt);
+ print_args(argc, argv);
+
+ return 0;
+}
+
+static enum parse_opt_flags test_flags = 0;
+static const struct option test_flag_options[] = {
+ OPT_GROUP("flag-options:"),
+ OPT_BIT(0, "keep-dashdash", &test_flags,
+ "pass PARSE_OPT_KEEP_DASHDASH to parse_options()",
+ PARSE_OPT_KEEP_DASHDASH),
+ OPT_BIT(0, "stop-at-non-option", &test_flags,
+ "pass PARSE_OPT_STOP_AT_NON_OPTION to parse_options()",
+ PARSE_OPT_STOP_AT_NON_OPTION),
+ OPT_BIT(0, "keep-argv0", &test_flags,
+ "pass PARSE_OPT_KEEP_ARGV0 to parse_options()",
+ PARSE_OPT_KEEP_ARGV0),
+ OPT_BIT(0, "keep-unknown-opt", &test_flags,
+ "pass PARSE_OPT_KEEP_UNKNOWN_OPT to parse_options()",
+ PARSE_OPT_KEEP_UNKNOWN_OPT),
+ OPT_BIT(0, "no-internal-help", &test_flags,
+ "pass PARSE_OPT_NO_INTERNAL_HELP to parse_options()",
+ PARSE_OPT_NO_INTERNAL_HELP),
+ OPT_BIT(0, "subcommand-optional", &test_flags,
+ "pass PARSE_OPT_SUBCOMMAND_OPTIONAL to parse_options()",
+ PARSE_OPT_SUBCOMMAND_OPTIONAL),
+ OPT_END()
+};
+
+int cmd__parse_options_flags(int argc, const char **argv)
+{
+ const char *usage[] = {
+ "test-tool parse-options-flags [flag-options] cmd [options]",
+ NULL
+ };
+
+ argc = parse_options(argc, argv, NULL, test_flag_options, usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+
+ if (!argc || strcmp(argv[0], "cmd")) {
+ error("'cmd' is mandatory");
+ usage_with_options(usage, test_flag_options);
+ }
+
+ return parse_options_flags__cmd(argc, argv, test_flags);
+}
+
+static int subcmd_one(int argc, const char **argv, const char *prefix)
+{
+ printf("fn: subcmd_one\n");
+ print_args(argc, argv);
+ return 0;
+}
+
+static int subcmd_two(int argc, const char **argv, const char *prefix)
+{
+ printf("fn: subcmd_two\n");
+ print_args(argc, argv);
+ return 0;
+}
+
+static int parse_subcommand__cmd(int argc, const char **argv,
+ enum parse_opt_flags test_flags)
+{
+ const char *usage[] = {
+ "<...> cmd subcmd-one",
+ "<...> cmd subcmd-two",
+ NULL
+ };
+ parse_opt_subcommand_fn *fn = NULL;
+ int opt = 0;
+ struct option options[] = {
+ OPT_SUBCOMMAND("subcmd-one", &fn, subcmd_one),
+ OPT_SUBCOMMAND("subcmd-two", &fn, subcmd_two),
+ OPT_INTEGER('o', "opt", &opt, "an integer option"),
+ OPT_END()
+ };
+
+ if (test_flags & PARSE_OPT_SUBCOMMAND_OPTIONAL)
+ fn = subcmd_one;
+ argc = parse_options(argc, argv, NULL, options, usage, test_flags);
+
+ printf("opt: %d\n", opt);
+
+ return fn(argc, argv, NULL);
+}
+
+int cmd__parse_subcommand(int argc, const char **argv)
+{
+ const char *usage[] = {
+ "test-tool parse-subcommand [flag-options] cmd <subcommand>",
+ NULL
+ };
+
+ argc = parse_options(argc, argv, NULL, test_flag_options, usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+
+ if (!argc || strcmp(argv[0], "cmd")) {
+ error("'cmd' is mandatory");
+ usage_with_options(usage, test_flag_options);
+ }
+
+ return parse_subcommand__cmd(argc, argv, test_flags);
+}
diff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c
index 229ed416b0..d20e1b7a18 100644
--- a/t/helper/test-path-utils.c
+++ b/t/helper/test-path-utils.c
@@ -296,9 +296,8 @@ int cmd__path_utils(int argc, const char **argv)
if (argc == 3 && !strcmp(argv[1], "normalize_path_copy")) {
char *buf = xmallocz(strlen(argv[2]));
int rv = normalize_path_copy(buf, argv[2]);
- if (rv)
- buf = "++failed++";
- puts(buf);
+ puts(rv ? "++failed++" : buf);
+ free(buf);
return 0;
}
@@ -356,7 +355,10 @@ int cmd__path_utils(int argc, const char **argv)
int nongit_ok;
setup_git_directory_gently(&nongit_ok);
while (argc > 3) {
- puts(prefix_path(prefix, prefix_len, argv[3]));
+ char *pfx = prefix_path(prefix, prefix_len, argv[3]);
+
+ puts(pfx);
+ free(pfx);
argc--;
argv++;
}
@@ -366,6 +368,7 @@ int cmd__path_utils(int argc, const char **argv)
if (argc == 4 && !strcmp(argv[1], "strip_path_suffix")) {
char *prefix = strip_path_suffix(argv[2], argv[3]);
printf("%s\n", prefix ? prefix : "(null)");
+ free(prefix);
return 0;
}
diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c
index 9646d85fc8..ae8a5648da 100644
--- a/t/helper/test-ref-store.c
+++ b/t/helper/test-ref-store.c
@@ -96,6 +96,7 @@ static const char **get_store(const char **argv, struct ref_store **refs)
die("no such worktree: %s", gitdir);
*refs = get_worktree_ref_store(*p);
+ free_worktrees(worktrees);
} else
die("unknown backend %s", argv[0]);
@@ -160,7 +161,7 @@ static int cmd_rename_ref(struct ref_store *refs, const char **argv)
}
static int each_ref(const char *refname, const struct object_id *oid,
- int flags, void *cb_data)
+ int flags, void *cb_data UNUSED)
{
printf("%s %s 0x%x\n", oid_to_hex(oid), refname, flags);
return 0;
@@ -206,7 +207,7 @@ static int cmd_for_each_reflog(struct ref_store *refs, const char **argv)
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)
+ int tz, const char *msg, void *cb_data UNUSED)
{
printf("%s %s %s %" PRItime " %+05d%s%s", oid_to_hex(old_oid),
oid_to_hex(new_oid), committer, timestamp, tz,
diff --git a/t/helper/test-regex.c b/t/helper/test-regex.c
index d6f28ca8d1..bd871a735b 100644
--- a/t/helper/test-regex.c
+++ b/t/helper/test-regex.c
@@ -34,6 +34,7 @@ static int test_regex_bug(void)
if (m[0].rm_so == 3) /* matches '\n' when it should not */
die("regex bug confirmed: re-build git with NO_REGEX=1");
+ regfree(&r);
return 0;
}
@@ -94,18 +95,20 @@ int cmd__regex(int argc, const char **argv)
die("failed regcomp() for pattern '%s' (%s)", pat, errbuf);
}
if (!str)
- return 0;
+ goto cleanup;
ret = regexec(&r, str, 1, m, 0);
if (ret) {
if (silent || ret == REG_NOMATCH)
- return ret;
+ goto cleanup;
regerror(ret, &r, errbuf, sizeof(errbuf));
die("failed regexec() for subject '%s' (%s)", str, errbuf);
}
- return 0;
+cleanup:
+ regfree(&r);
+ return ret;
usage:
usage("\ttest-tool regex --bug\n"
"\ttest-tool regex [--silent] <pattern>\n"
diff --git a/t/helper/test-rot13-filter.c b/t/helper/test-rot13-filter.c
new file mode 100644
index 0000000000..f8d564c622
--- /dev/null
+++ b/t/helper/test-rot13-filter.c
@@ -0,0 +1,382 @@
+/*
+ * Example implementation for the Git filter protocol version 2
+ * See Documentation/gitattributes.txt, section "Filter Protocol"
+ *
+ * Usage: test-tool rot13-filter [--always-delay] --log=<path> <capabilities>
+ *
+ * Log path defines a debug log file that the script writes to. The
+ * subsequent arguments define a list of supported protocol capabilities
+ * ("clean", "smudge", etc).
+ *
+ * When --always-delay is given all pathnames with the "can-delay" flag
+ * that don't appear on the list bellow are delayed with a count of 1
+ * (see more below).
+ *
+ * This implementation supports special test cases:
+ * (1) If data with the pathname "clean-write-fail.r" is processed with
+ * a "clean" operation then the write operation will die.
+ * (2) If data with the pathname "smudge-write-fail.r" is processed with
+ * a "smudge" operation then the write operation will die.
+ * (3) If data with the pathname "error.r" is processed with any
+ * operation then the filter signals that it cannot or does not want
+ * to process the file.
+ * (4) If data with the pathname "abort.r" is processed with any
+ * operation then the filter signals that it cannot or does not want
+ * to process the file and any file after that is processed with the
+ * same command.
+ * (5) If data with a pathname that is a key in the delay hash is
+ * requested (e.g. "test-delay10.a") then the filter responds with
+ * a "delay" status and sets the "requested" field in the delay hash.
+ * The filter will signal the availability of this object after
+ * "count" (field in delay hash) "list_available_blobs" commands.
+ * (6) If data with the pathname "missing-delay.a" is processed that the
+ * filter will drop the path from the "list_available_blobs" response.
+ * (7) If data with the pathname "invalid-delay.a" is processed that the
+ * filter will add the path "unfiltered" which was not delayed before
+ * to the "list_available_blobs" response.
+ */
+
+#include "test-tool.h"
+#include "pkt-line.h"
+#include "string-list.h"
+#include "strmap.h"
+#include "parse-options.h"
+
+static FILE *logfile;
+static int always_delay, has_clean_cap, has_smudge_cap;
+static struct strmap delay = STRMAP_INIT;
+
+static inline const char *str_or_null(const char *str)
+{
+ return str ? str : "(null)";
+}
+
+static char *rot13(char *str)
+{
+ char *c;
+ for (c = str; *c; c++)
+ if (isalpha(*c))
+ *c += tolower(*c) < 'n' ? 13 : -13;
+ return str;
+}
+
+static char *get_value(char *buf, const char *key)
+{
+ const char *orig_buf = buf;
+ if (!buf ||
+ !skip_prefix((const char *)buf, key, (const char **)&buf) ||
+ !skip_prefix((const char *)buf, "=", (const char **)&buf) ||
+ !*buf)
+ die("expected key '%s', got '%s'", key, str_or_null(orig_buf));
+ return buf;
+}
+
+/*
+ * Read a text packet, expecting that it is in the form "key=value" for
+ * the given key. An EOF does not trigger any error and is reported
+ * back to the caller with NULL. Die if the "key" part of "key=value" does
+ * not match the given key, or the value part is empty.
+ */
+static char *packet_key_val_read(const char *key)
+{
+ char *buf;
+ if (packet_read_line_gently(0, NULL, &buf) < 0)
+ return NULL;
+ return xstrdup(get_value(buf, key));
+}
+
+static inline void assert_remote_capability(struct strset *caps, const char *cap)
+{
+ if (!strset_contains(caps, cap))
+ die("required '%s' capability not available from remote", cap);
+}
+
+static void read_capabilities(struct strset *remote_caps)
+{
+ for (;;) {
+ char *buf = packet_read_line(0, NULL);
+ if (!buf)
+ break;
+ strset_add(remote_caps, get_value(buf, "capability"));
+ }
+
+ assert_remote_capability(remote_caps, "clean");
+ assert_remote_capability(remote_caps, "smudge");
+ assert_remote_capability(remote_caps, "delay");
+}
+
+static void check_and_write_capabilities(struct strset *remote_caps,
+ const char **caps, int nr_caps)
+{
+ int i;
+ for (i = 0; i < nr_caps; i++) {
+ if (!strset_contains(remote_caps, caps[i]))
+ die("our capability '%s' is not available from remote",
+ caps[i]);
+ packet_write_fmt(1, "capability=%s\n", caps[i]);
+ }
+ packet_flush(1);
+}
+
+struct delay_entry {
+ int requested, count;
+ char *output;
+};
+
+static void free_delay_entries(void)
+{
+ struct hashmap_iter iter;
+ struct strmap_entry *ent;
+
+ strmap_for_each_entry(&delay, &iter, ent) {
+ struct delay_entry *delay_entry = ent->value;
+ free(delay_entry->output);
+ free(delay_entry);
+ }
+ strmap_clear(&delay, 0);
+}
+
+static void add_delay_entry(char *pathname, int count, int requested)
+{
+ struct delay_entry *entry = xcalloc(1, sizeof(*entry));
+ entry->count = count;
+ entry->requested = requested;
+ if (strmap_put(&delay, pathname, entry))
+ BUG("adding the same path twice to delay hash?");
+}
+
+static void reply_list_available_blobs_cmd(void)
+{
+ struct hashmap_iter iter;
+ struct strmap_entry *ent;
+ struct string_list_item *str_item;
+ struct string_list paths = STRING_LIST_INIT_NODUP;
+
+ /* flush */
+ if (packet_read_line(0, NULL))
+ die("bad list_available_blobs end");
+
+ strmap_for_each_entry(&delay, &iter, ent) {
+ struct delay_entry *delay_entry = ent->value;
+ if (!delay_entry->requested)
+ continue;
+ delay_entry->count--;
+ if (!strcmp(ent->key, "invalid-delay.a")) {
+ /* Send Git a pathname that was not delayed earlier */
+ packet_write_fmt(1, "pathname=unfiltered");
+ }
+ if (!strcmp(ent->key, "missing-delay.a")) {
+ /* Do not signal Git that this file is available */
+ } else if (!delay_entry->count) {
+ string_list_append(&paths, ent->key);
+ packet_write_fmt(1, "pathname=%s", ent->key);
+ }
+ }
+
+ /* Print paths in sorted order. */
+ string_list_sort(&paths);
+ for_each_string_list_item(str_item, &paths)
+ fprintf(logfile, " %s", str_item->string);
+ string_list_clear(&paths, 0);
+
+ packet_flush(1);
+
+ fprintf(logfile, " [OK]\n");
+ packet_write_fmt(1, "status=success");
+ packet_flush(1);
+}
+
+static void command_loop(void)
+{
+ for (;;) {
+ char *buf, *output;
+ char *pathname;
+ struct delay_entry *entry;
+ struct strbuf input = STRBUF_INIT;
+ char *command = packet_key_val_read("command");
+
+ if (!command) {
+ fprintf(logfile, "STOP\n");
+ break;
+ }
+ fprintf(logfile, "IN: %s", command);
+
+ if (!strcmp(command, "list_available_blobs")) {
+ reply_list_available_blobs_cmd();
+ free(command);
+ continue;
+ }
+
+ pathname = packet_key_val_read("pathname");
+ if (!pathname)
+ die("unexpected EOF while expecting pathname");
+ fprintf(logfile, " %s", pathname);
+
+ /* Read until flush */
+ while ((buf = packet_read_line(0, NULL))) {
+ if (!strcmp(buf, "can-delay=1")) {
+ entry = strmap_get(&delay, pathname);
+ if (entry && !entry->requested)
+ entry->requested = 1;
+ else if (!entry && always_delay)
+ add_delay_entry(pathname, 1, 1);
+ } else if (starts_with(buf, "ref=") ||
+ starts_with(buf, "treeish=") ||
+ starts_with(buf, "blob=")) {
+ fprintf(logfile, " %s", buf);
+ } else {
+ /*
+ * In general, filters need to be graceful about
+ * new metadata, since it's documented that we
+ * can pass any key-value pairs, but for tests,
+ * let's be a little stricter.
+ */
+ die("Unknown message '%s'", buf);
+ }
+ }
+
+ read_packetized_to_strbuf(0, &input, 0);
+ fprintf(logfile, " %"PRIuMAX" [OK] -- ", (uintmax_t)input.len);
+
+ entry = strmap_get(&delay, pathname);
+ if (entry && entry->output) {
+ output = entry->output;
+ } else if (!strcmp(pathname, "error.r") || !strcmp(pathname, "abort.r")) {
+ output = "";
+ } else if (!strcmp(command, "clean") && has_clean_cap) {
+ output = rot13(input.buf);
+ } else if (!strcmp(command, "smudge") && has_smudge_cap) {
+ output = rot13(input.buf);
+ } else {
+ die("bad command '%s'", command);
+ }
+
+ if (!strcmp(pathname, "error.r")) {
+ fprintf(logfile, "[ERROR]\n");
+ packet_write_fmt(1, "status=error");
+ packet_flush(1);
+ } else if (!strcmp(pathname, "abort.r")) {
+ fprintf(logfile, "[ABORT]\n");
+ packet_write_fmt(1, "status=abort");
+ packet_flush(1);
+ } else if (!strcmp(command, "smudge") &&
+ (entry = strmap_get(&delay, pathname)) &&
+ entry->requested == 1) {
+ fprintf(logfile, "[DELAYED]\n");
+ packet_write_fmt(1, "status=delayed");
+ packet_flush(1);
+ entry->requested = 2;
+ if (entry->output != output) {
+ free(entry->output);
+ entry->output = xstrdup(output);
+ }
+ } else {
+ int i, nr_packets = 0;
+ size_t output_len;
+ const char *p;
+ packet_write_fmt(1, "status=success");
+ packet_flush(1);
+
+ if (skip_prefix(pathname, command, &p) &&
+ !strcmp(p, "-write-fail.r")) {
+ fprintf(logfile, "[WRITE FAIL]\n");
+ die("%s write error", command);
+ }
+
+ output_len = strlen(output);
+ fprintf(logfile, "OUT: %"PRIuMAX" ", (uintmax_t)output_len);
+
+ if (write_packetized_from_buf_no_flush_count(output,
+ output_len, 1, &nr_packets))
+ die("failed to write buffer to stdout");
+ packet_flush(1);
+
+ for (i = 0; i < nr_packets; i++)
+ fprintf(logfile, ".");
+ fprintf(logfile, " [OK]\n");
+
+ packet_flush(1);
+ }
+ free(pathname);
+ strbuf_release(&input);
+ free(command);
+ }
+}
+
+static void packet_initialize(void)
+{
+ char *pkt_buf = packet_read_line(0, NULL);
+
+ if (!pkt_buf || strcmp(pkt_buf, "git-filter-client"))
+ die("bad initialize: '%s'", str_or_null(pkt_buf));
+
+ pkt_buf = packet_read_line(0, NULL);
+ if (!pkt_buf || strcmp(pkt_buf, "version=2"))
+ die("bad version: '%s'", str_or_null(pkt_buf));
+
+ pkt_buf = packet_read_line(0, NULL);
+ if (pkt_buf)
+ die("bad version end: '%s'", pkt_buf);
+
+ packet_write_fmt(1, "git-filter-server");
+ packet_write_fmt(1, "version=2");
+ packet_flush(1);
+}
+
+static const char *rot13_usage[] = {
+ "test-tool rot13-filter [--always-delay] --log=<path> <capabilities>",
+ NULL
+};
+
+int cmd__rot13_filter(int argc, const char **argv)
+{
+ int i, nr_caps;
+ struct strset remote_caps = STRSET_INIT;
+ const char *log_path = NULL;
+
+ struct option options[] = {
+ OPT_BOOL(0, "always-delay", &always_delay,
+ "delay all paths with the can-delay flag"),
+ OPT_STRING(0, "log", &log_path, "path",
+ "path to the debug log file"),
+ OPT_END()
+ };
+ nr_caps = parse_options(argc, argv, NULL, options, rot13_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+
+ if (!log_path || !nr_caps)
+ usage_with_options(rot13_usage, options);
+
+ logfile = fopen(log_path, "a");
+ if (!logfile)
+ die_errno("failed to open log file");
+
+ for (i = 0; i < nr_caps; i++) {
+ if (!strcmp(argv[i], "smudge"))
+ has_smudge_cap = 1;
+ if (!strcmp(argv[i], "clean"))
+ has_clean_cap = 1;
+ }
+
+ add_delay_entry("test-delay10.a", 1, 0);
+ add_delay_entry("test-delay11.a", 1, 0);
+ add_delay_entry("test-delay20.a", 2, 0);
+ add_delay_entry("test-delay10.b", 1, 0);
+ add_delay_entry("missing-delay.a", 1, 0);
+ add_delay_entry("invalid-delay.a", 1, 0);
+
+ fprintf(logfile, "START\n");
+ packet_initialize();
+
+ read_capabilities(&remote_caps);
+ check_and_write_capabilities(&remote_caps, argv, nr_caps);
+ fprintf(logfile, "init handshake complete\n");
+ strset_clear(&remote_caps);
+
+ command_loop();
+
+ if (fclose(logfile))
+ die_errno("error closing logfile");
+ free_delay_entries();
+ return 0;
+}
diff --git a/t/helper/test-scrap-cache-tree.c b/t/helper/test-scrap-cache-tree.c
index 393f1604ff..026c802479 100644
--- a/t/helper/test-scrap-cache-tree.c
+++ b/t/helper/test-scrap-cache-tree.c
@@ -12,6 +12,7 @@ int cmd__scrap_cache_tree(int ac, const char **av)
hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR);
if (read_cache() < 0)
die("unable to read index file");
+ cache_tree_free(&active_cache_tree);
active_cache_tree = NULL;
if (write_locked_index(&the_index, &index_lock, COMMIT_LOCK))
die("unable to write index file");
diff --git a/t/helper/test-serve-v2.c b/t/helper/test-serve-v2.c
index 28e905afc3..824e5c0a95 100644
--- a/t/helper/test-serve-v2.c
+++ b/t/helper/test-serve-v2.c
@@ -24,7 +24,7 @@ int cmd__serve_v2(int argc, const char **argv)
/* ignore all unknown cmdline switches for now */
argc = parse_options(argc, argv, prefix, options, serve_usage,
PARSE_OPT_KEEP_DASHDASH |
- PARSE_OPT_KEEP_UNKNOWN);
+ PARSE_OPT_KEEP_UNKNOWN_OPT);
if (advertise_capabilities)
protocol_v2_advertise_capabilities();
diff --git a/t/helper/test-submodule-config.c b/t/helper/test-submodule-config.c
index e2692746df..22a41c4092 100644
--- a/t/helper/test-submodule-config.c
+++ b/t/helper/test-submodule-config.c
@@ -15,14 +15,11 @@ int cmd__submodule_config(int argc, const char **argv)
{
const char **arg = argv;
int my_argc = argc;
- int output_url = 0;
int lookup_name = 0;
arg++;
my_argc--;
while (arg[0] && starts_with(arg[0], "--")) {
- if (!strcmp(arg[0], "--url"))
- output_url = 1;
if (!strcmp(arg[0], "--name"))
lookup_name = 1;
arg++;
@@ -57,12 +54,8 @@ int cmd__submodule_config(int argc, const char **argv)
if (!submodule)
die_usage(argc, argv, "Submodule not found.");
- if (output_url)
- printf("Submodule url: '%s' for path '%s'\n",
- submodule->url, submodule->path);
- else
- printf("Submodule name: '%s' for path '%s'\n",
- submodule->name, submodule->path);
+ printf("Submodule name: '%s' for path '%s'\n", submodule->name,
+ submodule->path);
arg += 2;
}
diff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c
new file mode 100644
index 0000000000..e0e0c53d38
--- /dev/null
+++ b/t/helper/test-submodule.c
@@ -0,0 +1,146 @@
+#include "test-tool.h"
+#include "test-tool-utils.h"
+#include "cache.h"
+#include "parse-options.h"
+#include "remote.h"
+#include "submodule-config.h"
+#include "submodule.h"
+
+#define TEST_TOOL_CHECK_NAME_USAGE \
+ "test-tool submodule check-name <name>"
+static const char *submodule_check_name_usage[] = {
+ TEST_TOOL_CHECK_NAME_USAGE,
+ NULL
+};
+
+#define TEST_TOOL_IS_ACTIVE_USAGE \
+ "test-tool submodule is-active <name>"
+static const char *submodule_is_active_usage[] = {
+ TEST_TOOL_IS_ACTIVE_USAGE,
+ NULL
+};
+
+#define TEST_TOOL_RESOLVE_RELATIVE_URL_USAGE \
+ "test-tool submodule resolve-relative-url <up_path> <remoteurl> <url>"
+static const char *submodule_resolve_relative_url_usage[] = {
+ TEST_TOOL_RESOLVE_RELATIVE_URL_USAGE,
+ NULL,
+};
+
+static const char *submodule_usage[] = {
+ TEST_TOOL_CHECK_NAME_USAGE,
+ TEST_TOOL_IS_ACTIVE_USAGE,
+ TEST_TOOL_RESOLVE_RELATIVE_URL_USAGE,
+ NULL
+};
+
+/*
+ * Exit non-zero if any of the submodule names given on the command line is
+ * invalid. If no names are given, filter stdin to print only valid names
+ * (which is primarily intended for testing).
+ */
+static int check_name(int argc, const char **argv)
+{
+ if (argc > 1) {
+ while (*++argv) {
+ if (check_submodule_name(*argv) < 0)
+ return 1;
+ }
+ } else {
+ struct strbuf buf = STRBUF_INIT;
+ while (strbuf_getline(&buf, stdin) != EOF) {
+ if (!check_submodule_name(buf.buf))
+ printf("%s\n", buf.buf);
+ }
+ strbuf_release(&buf);
+ }
+ return 0;
+}
+
+static int cmd__submodule_check_name(int argc, const char **argv)
+{
+ struct option options[] = {
+ OPT_END()
+ };
+ argc = parse_options(argc, argv, "test-tools", options,
+ submodule_check_name_usage, 0);
+ if (argc)
+ usage_with_options(submodule_check_name_usage, options);
+
+ return check_name(argc, argv);
+}
+
+static int cmd__submodule_is_active(int argc, const char **argv)
+{
+ struct option options[] = {
+ OPT_END()
+ };
+ argc = parse_options(argc, argv, "test-tools", options,
+ submodule_is_active_usage, 0);
+ if (argc != 1)
+ usage_with_options(submodule_is_active_usage, options);
+
+ setup_git_directory();
+
+ return !is_submodule_active(the_repository, argv[0]);
+}
+
+static int resolve_relative_url(int argc, const char **argv)
+{
+ char *remoteurl, *res;
+ const char *up_path, *url;
+
+ up_path = argv[0];
+ remoteurl = xstrdup(argv[1]);
+ url = argv[2];
+
+ if (!strcmp(up_path, "(null)"))
+ up_path = NULL;
+
+ res = relative_url(remoteurl, url, up_path);
+ puts(res);
+ free(res);
+ free(remoteurl);
+ return 0;
+}
+
+static int cmd__submodule_resolve_relative_url(int argc, const char **argv)
+{
+ struct option options[] = {
+ OPT_END()
+ };
+ argc = parse_options(argc, argv, "test-tools", options,
+ submodule_resolve_relative_url_usage, 0);
+ if (argc != 3)
+ usage_with_options(submodule_resolve_relative_url_usage, options);
+
+ return resolve_relative_url(argc, argv);
+}
+
+static struct test_cmd cmds[] = {
+ { "check-name", cmd__submodule_check_name },
+ { "is-active", cmd__submodule_is_active },
+ { "resolve-relative-url", cmd__submodule_resolve_relative_url},
+};
+
+int cmd__submodule(int argc, const char **argv)
+{
+ struct option options[] = {
+ OPT_END()
+ };
+ size_t i;
+
+ argc = parse_options(argc, argv, "test-tools", options, submodule_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+ if (argc < 1)
+ usage_with_options(submodule_usage, options);
+
+ for (i = 0; i < ARRAY_SIZE(cmds); i++)
+ if (!strcmp(cmds[i].name, argv[0]))
+ return cmds[i].fn(argc, argv);
+
+ usage_msg_optf("unknown subcommand '%s'", submodule_usage, options,
+ argv[0]);
+
+ return 0;
+}
diff --git a/t/helper/test-tool-utils.h b/t/helper/test-tool-utils.h
new file mode 100644
index 0000000000..6a0e5e0074
--- /dev/null
+++ b/t/helper/test-tool-utils.h
@@ -0,0 +1,9 @@
+#ifndef TEST_TOOL_UTILS_H
+#define TEST_TOOL_UTILS_H
+
+struct test_cmd {
+ const char *name;
+ int (*fn)(int argc, const char **argv);
+};
+
+#endif
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
index 318fdbab0c..d1d013bcd9 100644
--- a/t/helper/test-tool.c
+++ b/t/helper/test-tool.c
@@ -1,5 +1,6 @@
#include "git-compat-util.h"
#include "test-tool.h"
+#include "test-tool-utils.h"
#include "trace2.h"
#include "parse-options.h"
@@ -8,11 +9,6 @@ static const char * const test_tool_usage[] = {
NULL
};
-struct test_cmd {
- const char *name;
- int (*fn)(int argc, const char **argv);
-};
-
static struct test_cmd cmds[] = {
{ "advise", cmd__advise_if_enabled },
{ "bitmap", cmd__bitmap },
@@ -51,7 +47,9 @@ static struct test_cmd cmds[] = {
{ "online-cpus", cmd__online_cpus },
{ "pack-mtimes", cmd__pack_mtimes },
{ "parse-options", cmd__parse_options },
+ { "parse-options-flags", cmd__parse_options_flags },
{ "parse-pathspec-file", cmd__parse_pathspec_file },
+ { "parse-subcommand", cmd__parse_subcommand },
{ "partial-clone", cmd__partial_clone },
{ "path-utils", cmd__path_utils },
{ "pcre2-config", cmd__pcre2_config },
@@ -65,6 +63,7 @@ static struct test_cmd cmds[] = {
{ "read-midx", cmd__read_midx },
{ "ref-store", cmd__ref_store },
{ "reftable", cmd__reftable },
+ { "rot13-filter", cmd__rot13_filter },
{ "dump-reftable", cmd__dump_reftable },
{ "regex", cmd__regex },
{ "repository", cmd__repository },
@@ -78,6 +77,7 @@ static struct test_cmd cmds[] = {
{ "simple-ipc", cmd__simple_ipc },
{ "strcmp-offset", cmd__strcmp_offset },
{ "string-list", cmd__string_list },
+ { "submodule", cmd__submodule },
{ "submodule-config", cmd__submodule_config },
{ "submodule-nested-repo-config", cmd__submodule_nested_repo_config },
{ "subprocess", cmd__subprocess },
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
index bb79927163..6b46b6444b 100644
--- a/t/helper/test-tool.h
+++ b/t/helper/test-tool.h
@@ -41,7 +41,9 @@ 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_options_flags(int argc, const char **argv);
int cmd__parse_pathspec_file(int argc, const char** argv);
+int cmd__parse_subcommand(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);
@@ -54,6 +56,7 @@ 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__rot13_filter(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);
@@ -68,6 +71,7 @@ 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(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);
diff --git a/t/helper/test-urlmatch-normalization.c b/t/helper/test-urlmatch-normalization.c
index 8f4d67e646..86edd454f5 100644
--- a/t/helper/test-urlmatch-normalization.c
+++ b/t/helper/test-urlmatch-normalization.c
@@ -5,8 +5,9 @@
int cmd__urlmatch_normalization(int argc, const char **argv)
{
const char usage[] = "test-tool urlmatch-normalization [-p | -l] <url1> | <url1> <url2>";
- char *url1, *url2;
+ char *url1 = NULL, *url2 = NULL;
int opt_p = 0, opt_l = 0;
+ int ret = 0;
/*
* For one url, succeed if url_normalize succeeds on it, fail otherwise.
@@ -39,7 +40,7 @@ int cmd__urlmatch_normalization(int argc, const char **argv)
printf("%s\n", url1);
if (opt_l)
printf("%u\n", (unsigned)info.url_len);
- return 0;
+ goto cleanup;
}
if (opt_p || opt_l)
@@ -47,5 +48,9 @@ int cmd__urlmatch_normalization(int argc, const char **argv)
url1 = url_normalize(argv[1], NULL);
url2 = url_normalize(argv[2], NULL);
- return (url1 && url2 && !strcmp(url1, url2)) ? 0 : 1;
+ ret = (url1 && url2 && !strcmp(url1, url2)) ? 0 : 1;
+cleanup:
+ free(url1);
+ free(url2);
+ return ret;
}
diff --git a/t/helper/test-userdiff.c b/t/helper/test-userdiff.c
index f013f8a31e..a2b56b9cae 100644
--- a/t/helper/test-userdiff.c
+++ b/t/helper/test-userdiff.c
@@ -12,7 +12,7 @@ static int driver_cb(struct userdiff_driver *driver,
return 0;
}
-static int cmd__userdiff_config(const char *var, const char *value, void *cb)
+static int cmd__userdiff_config(const char *var, const char *value, void *cb UNUSED)
{
if (userdiff_config(var, value) < 0)
return -1;