diff options
Diffstat (limited to 't')
86 files changed, 2154 insertions, 331 deletions
diff --git a/t/helper/test-advise.c b/t/helper/test-advise.c index 8a3fd0009a..6967c8e25c 100644 --- a/t/helper/test-advise.c +++ b/t/helper/test-advise.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "advice.h" #include "config.h" diff --git a/t/helper/test-config.c b/t/helper/test-config.c index ed444ca4c2..e193079ed5 100644 --- a/t/helper/test-config.c +++ b/t/helper/test-config.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "config.h" #include "setup.h" diff --git a/t/helper/test-example-tap.c b/t/helper/test-example-tap.c index 914af88e0a..229d495ecf 100644 --- a/t/helper/test-example-tap.c +++ b/t/helper/test-example-tap.c @@ -70,7 +70,7 @@ static void t_empty(void) ; /* empty */ } -int cmd__example_tap(int argc, const char **argv) +int cmd__example_tap(int argc UNUSED, const char **argv UNUSED) { check(1); diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c index 195e6278be..7782ae585e 100644 --- a/t/helper/test-hashmap.c +++ b/t/helper/test-hashmap.c @@ -138,7 +138,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds) * * perfhashmap method rounds -> test hashmap.[ch] performance */ -int cmd__hashmap(int argc, const char **argv) +int cmd__hashmap(int argc UNUSED, const char **argv UNUSED) { struct string_list parts = STRING_LIST_INIT_NODUP; struct strbuf line = STRBUF_INIT; diff --git a/t/helper/test-mergesort.c b/t/helper/test-mergesort.c index 42ccc87051..328bfe2977 100644 --- a/t/helper/test-mergesort.c +++ b/t/helper/test-mergesort.c @@ -122,7 +122,7 @@ static const struct dist *get_dist_by_name(const char *name) return NULL; } -static void mode_copy(int *arr, int n) +static void mode_copy(int *arr UNUSED, int n UNUSED) { /* nothing */ } diff --git a/t/helper/test-reach.c b/t/helper/test-reach.c index 5dd374379c..7314f6c0d8 100644 --- a/t/helper/test-reach.c +++ b/t/helper/test-reach.c @@ -116,6 +116,8 @@ int cmd__reach(int ac, const char **av) repo_in_merge_bases_many(the_repository, A, X_nr, X_array, 0)); else if (!strcmp(av[1], "is_descendant_of")) printf("%s(A,X):%d\n", av[1], repo_is_descendant_of(r, A, X)); + else if (!strcmp(av[1], "get_branch_base_for_tip")) + printf("%s(A,X):%d\n", av[1], get_branch_base_for_tip(r, A, X_array, X_nr)); else if (!strcmp(av[1], "get_merge_bases_many")) { struct commit_list *list = NULL; if (repo_get_merge_bases_many(the_repository, diff --git a/t/helper/test-reftable.c b/t/helper/test-reftable.c index 7bdd18430b..3cd3314f07 100644 --- a/t/helper/test-reftable.c +++ b/t/helper/test-reftable.c @@ -1,16 +1,202 @@ +#include "git-compat-util.h" +#include "hash.h" +#include "hex.h" #include "reftable/system.h" +#include "reftable/reftable-error.h" +#include "reftable/reftable-merged.h" +#include "reftable/reftable-reader.h" +#include "reftable/reftable-stack.h" #include "reftable/reftable-tests.h" #include "test-tool.h" int cmd__reftable(int argc, const char **argv) { /* test from simple to complex. */ - readwrite_test_main(argc, argv); stack_test_main(argc, argv); return 0; } +static void print_help(void) +{ + printf("usage: dump [-st] arg\n\n" + "options: \n" + " -b dump blocks\n" + " -t dump table\n" + " -s dump stack\n" + " -6 sha256 hash format\n" + " -h this help\n" + "\n"); +} + +static int dump_table(struct reftable_merged_table *mt) +{ + struct reftable_iterator it = { NULL }; + struct reftable_ref_record ref = { NULL }; + struct reftable_log_record log = { NULL }; + const struct git_hash_algo *algop; + int err; + + reftable_merged_table_init_ref_iterator(mt, &it); + err = reftable_iterator_seek_ref(&it, ""); + if (err < 0) + return err; + + algop = &hash_algos[hash_algo_by_id(reftable_merged_table_hash_id(mt))]; + + while (1) { + err = reftable_iterator_next_ref(&it, &ref); + if (err > 0) + break; + if (err < 0) + return err; + + printf("ref{%s(%" PRIu64 ") ", ref.refname, ref.update_index); + switch (ref.value_type) { + case REFTABLE_REF_SYMREF: + printf("=> %s", ref.value.symref); + break; + case REFTABLE_REF_VAL2: + printf("val 2 %s", hash_to_hex_algop(ref.value.val2.value, algop)); + printf("(T %s)", hash_to_hex_algop(ref.value.val2.target_value, algop)); + break; + case REFTABLE_REF_VAL1: + printf("val 1 %s", hash_to_hex_algop(ref.value.val1, algop)); + break; + case REFTABLE_REF_DELETION: + printf("delete"); + break; + } + printf("}\n"); + } + reftable_iterator_destroy(&it); + reftable_ref_record_release(&ref); + + reftable_merged_table_init_log_iterator(mt, &it); + err = reftable_iterator_seek_log(&it, ""); + if (err < 0) + return err; + + while (1) { + err = reftable_iterator_next_log(&it, &log); + if (err > 0) + break; + if (err < 0) + return err; + + switch (log.value_type) { + case REFTABLE_LOG_DELETION: + printf("log{%s(%" PRIu64 ") delete\n", log.refname, + log.update_index); + break; + case REFTABLE_LOG_UPDATE: + printf("log{%s(%" PRIu64 ") %s <%s> %" PRIu64 " %04d\n", + log.refname, log.update_index, + log.value.update.name ? log.value.update.name : "", + log.value.update.email ? log.value.update.email : "", + log.value.update.time, + log.value.update.tz_offset); + printf("%s => ", hash_to_hex_algop(log.value.update.old_hash, algop)); + printf("%s\n\n%s\n}\n", hash_to_hex_algop(log.value.update.new_hash, algop), + log.value.update.message ? log.value.update.message : ""); + break; + } + } + reftable_iterator_destroy(&it); + reftable_log_record_release(&log); + return 0; +} + +static int dump_stack(const char *stackdir, uint32_t hash_id) +{ + struct reftable_stack *stack = NULL; + struct reftable_write_options opts = { .hash_id = hash_id }; + struct reftable_merged_table *merged = NULL; + + int err = reftable_new_stack(&stack, stackdir, &opts); + if (err < 0) + goto done; + + merged = reftable_stack_merged_table(stack); + err = dump_table(merged); +done: + if (stack) + reftable_stack_destroy(stack); + return err; +} + +static int dump_reftable(const char *tablename) +{ + struct reftable_block_source src = { 0 }; + struct reftable_merged_table *mt = NULL; + struct reftable_reader *r = NULL; + int err; + + err = reftable_block_source_from_file(&src, tablename); + if (err < 0) + goto done; + + err = reftable_new_reader(&r, &src, tablename); + if (err < 0) + goto done; + + err = reftable_merged_table_new(&mt, &r, 1, + reftable_reader_hash_id(r)); + if (err < 0) + goto done; + + err = dump_table(mt); + +done: + reftable_merged_table_free(mt); + reftable_reader_free(r); + return err; +} + int cmd__dump_reftable(int argc, const char **argv) { - return reftable_dump_main(argc, (char *const *)argv); + int err = 0; + int opt_dump_blocks = 0; + int opt_dump_table = 0; + int opt_dump_stack = 0; + uint32_t opt_hash_id = GIT_SHA1_FORMAT_ID; + const char *arg = NULL, *argv0 = argv[0]; + + for (; argc > 1; argv++, argc--) + if (*argv[1] != '-') + break; + else if (!strcmp("-b", argv[1])) + opt_dump_blocks = 1; + else if (!strcmp("-t", argv[1])) + opt_dump_table = 1; + else if (!strcmp("-6", argv[1])) + opt_hash_id = GIT_SHA256_FORMAT_ID; + else if (!strcmp("-s", argv[1])) + opt_dump_stack = 1; + else if (!strcmp("-?", argv[1]) || !strcmp("-h", argv[1])) { + print_help(); + return 2; + } + + if (argc != 2) { + fprintf(stderr, "need argument\n"); + print_help(); + return 2; + } + + arg = argv[1]; + + if (opt_dump_blocks) { + err = reftable_reader_print_blocks(arg); + } else if (opt_dump_table) { + err = dump_reftable(arg); + } else if (opt_dump_stack) { + err = dump_stack(arg, opt_hash_id); + } + + if (err < 0) { + fprintf(stderr, "%s: %s: %s\n", argv0, arg, + reftable_error_str(err)); + return 1; + } + return 0; } diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c index da3e69128a..f8a67df7de 100644 --- a/t/helper/test-tool.c +++ b/t/helper/test-tool.c @@ -83,7 +83,6 @@ static struct test_cmd cmds[] = { { "trace2", cmd__trace2 }, { "truncate", cmd__truncate }, { "userdiff", cmd__userdiff }, - { "urlmatch-normalization", cmd__urlmatch_normalization }, { "xml-encode", cmd__xml_encode }, { "wildmatch", cmd__wildmatch }, #ifdef GIT_WINDOWS_NATIVE diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h index 642a34578c..e74bc0ffd4 100644 --- a/t/helper/test-tool.h +++ b/t/helper/test-tool.h @@ -76,7 +76,6 @@ int cmd__subprocess(int argc, const char **argv); int cmd__trace2(int argc, const char **argv); int cmd__truncate(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); #ifdef GIT_WINDOWS_NATIVE diff --git a/t/helper/test-urlmatch-normalization.c b/t/helper/test-urlmatch-normalization.c deleted file mode 100644 index 86edd454f5..0000000000 --- a/t/helper/test-urlmatch-normalization.c +++ /dev/null @@ -1,56 +0,0 @@ -#include "test-tool.h" -#include "git-compat-util.h" -#include "urlmatch.h" - -int cmd__urlmatch_normalization(int argc, const char **argv) -{ - const char usage[] = "test-tool urlmatch-normalization [-p | -l] <url1> | <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. - * For two urls, succeed only if url_normalize succeeds on both and - * the results compare equal with strcmp. If -p is given (one url only) - * and url_normalize succeeds, print the result followed by "\n". If - * -l is given (one url only) and url_normalize succeeds, print the - * returned length in decimal followed by "\n". - */ - - if (argc > 1 && !strcmp(argv[1], "-p")) { - opt_p = 1; - argc--; - argv++; - } else if (argc > 1 && !strcmp(argv[1], "-l")) { - opt_l = 1; - argc--; - argv++; - } - - if (argc < 2 || argc > 3) - die("%s", usage); - - if (argc == 2) { - struct url_info info; - url1 = url_normalize(argv[1], &info); - if (!url1) - return 1; - if (opt_p) - printf("%s\n", url1); - if (opt_l) - printf("%u\n", (unsigned)info.url_len); - goto cleanup; - } - - if (opt_p || opt_l) - die("%s", usage); - - url1 = url_normalize(argv[1], NULL); - url2 = url_normalize(argv[2], NULL); - 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 0ce31ce59f..94c48ababb 100644 --- a/t/helper/test-userdiff.c +++ b/t/helper/test-userdiff.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "setup.h" #include "userdiff.h" diff --git a/t/perf/p1500-graph-walks.sh b/t/perf/p1500-graph-walks.sh index e14e7620cc..5b23ce5db9 100755 --- a/t/perf/p1500-graph-walks.sh +++ b/t/perf/p1500-graph-walks.sh @@ -20,6 +20,21 @@ test_expect_success 'setup' ' echo tag-$ref || return 1 done >tags && + + echo "A:HEAD" >test-tool-refs && + for line in $(cat refs) + do + echo "X:$line" >>test-tool-refs || return 1 + done && + echo "A:HEAD" >test-tool-tags && + for line in $(cat tags) + do + echo "X:$line" >>test-tool-tags || return 1 + done && + + commit=$(git commit-tree $(git rev-parse HEAD^{tree})) && + git update-ref refs/heads/disjoint-base $commit && + git commit-graph write --reachable ' @@ -47,4 +62,20 @@ test_perf 'contains: git tag --merged' ' xargs git tag --merged=HEAD <tags ' +test_perf 'is-base check: test-tool reach (refs)' ' + test-tool reach get_branch_base_for_tip <test-tool-refs +' + +test_perf 'is-base check: test-tool reach (tags)' ' + test-tool reach get_branch_base_for_tip <test-tool-tags +' + +test_perf 'is-base check: git for-each-ref' ' + git for-each-ref --format="%(is-base:HEAD)" --stdin <refs +' + +test_perf 'is-base check: git for-each-ref (disjoint-base)' ' + git for-each-ref --format="%(is-base:refs/heads/disjoint-base)" --stdin <refs +' + test_done diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 49e9bf77c6..0178aa62a4 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -500,6 +500,7 @@ test_expect_success 're-init from a linked worktree' ' ' test_expect_success 'init honors GIT_DEFAULT_HASH' ' + test_when_finished "rm -rf sha1 sha256" && GIT_DEFAULT_HASH=sha1 git init sha1 && git -C sha1 rev-parse --show-object-format >actual && echo sha1 >expected && @@ -511,6 +512,7 @@ test_expect_success 'init honors GIT_DEFAULT_HASH' ' ' test_expect_success 'init honors --object-format' ' + test_when_finished "rm -rf explicit-sha1 explicit-sha256" && git init --object-format=sha1 explicit-sha1 && git -C explicit-sha1 rev-parse --show-object-format >actual && echo sha1 >expected && @@ -521,7 +523,58 @@ test_expect_success 'init honors --object-format' ' test_cmp expected actual ' +test_expect_success 'init honors init.defaultObjectFormat' ' + test_when_finished "rm -rf sha1 sha256" && + + test_config_global init.defaultObjectFormat sha1 && + ( + sane_unset GIT_DEFAULT_HASH && + git init sha1 && + git -C sha1 rev-parse --show-object-format >actual && + echo sha1 >expected && + test_cmp expected actual + ) && + + test_config_global init.defaultObjectFormat sha256 && + ( + sane_unset GIT_DEFAULT_HASH && + git init sha256 && + git -C sha256 rev-parse --show-object-format >actual && + echo sha256 >expected && + test_cmp expected actual + ) +' + +test_expect_success 'init warns about invalid init.defaultObjectFormat' ' + test_when_finished "rm -rf repo" && + test_config_global init.defaultObjectFormat garbage && + + echo "warning: unknown hash algorithm ${SQ}garbage${SQ}" >expect && + git init repo 2>err && + test_cmp expect err && + + git -C repo rev-parse --show-object-format >actual && + echo $GIT_DEFAULT_HASH >expected && + test_cmp expected actual +' + +test_expect_success '--object-format overrides GIT_DEFAULT_HASH' ' + test_when_finished "rm -rf repo" && + GIT_DEFAULT_HASH=sha1 git init --object-format=sha256 repo && + git -C repo rev-parse --show-object-format >actual && + echo sha256 >expected +' + +test_expect_success 'GIT_DEFAULT_HASH overrides init.defaultObjectFormat' ' + test_when_finished "rm -rf repo" && + test_config_global init.defaultObjectFormat sha1 && + GIT_DEFAULT_HASH=sha256 git init repo && + git -C repo rev-parse --show-object-format >actual && + echo sha256 >expected +' + test_expect_success 'extensions.objectFormat is not allowed with repo version 0' ' + test_when_finished "rm -rf explicit-v0" && git init --object-format=sha256 explicit-v0 && git -C explicit-v0 config core.repositoryformatversion 0 && test_must_fail git -C explicit-v0 rev-parse --show-object-format @@ -558,15 +611,6 @@ test_expect_success DEFAULT_REPO_FORMAT 'extensions.refStorage with unknown back grep "invalid value for ${SQ}extensions.refstorage${SQ}: ${SQ}garbage${SQ}" err ' -test_expect_success DEFAULT_REPO_FORMAT 'init with GIT_DEFAULT_REF_FORMAT=files' ' - test_when_finished "rm -rf refformat" && - GIT_DEFAULT_REF_FORMAT=files git init refformat && - echo 0 >expect && - git -C refformat config core.repositoryformatversion >actual && - test_cmp expect actual && - test_must_fail git -C refformat config extensions.refstorage -' - test_expect_success 'init with GIT_DEFAULT_REF_FORMAT=garbage' ' test_when_finished "rm -rf refformat" && cat >expect <<-EOF && @@ -576,15 +620,90 @@ test_expect_success 'init with GIT_DEFAULT_REF_FORMAT=garbage' ' test_cmp expect err ' -test_expect_success 'init with --ref-format=files' ' +test_expect_success 'init warns about invalid init.defaultRefFormat' ' + test_when_finished "rm -rf repo" && + test_config_global init.defaultRefFormat garbage && + + echo "warning: unknown ref storage format ${SQ}garbage${SQ}" >expect && + git init repo 2>err && + test_cmp expect err && + + git -C repo rev-parse --show-ref-format >actual && + echo $GIT_DEFAULT_REF_FORMAT >expected && + test_cmp expected actual +' + +backends="files reftable" +for format in $backends +do + test_expect_success DEFAULT_REPO_FORMAT "init with GIT_DEFAULT_REF_FORMAT=$format" ' + test_when_finished "rm -rf refformat" && + GIT_DEFAULT_REF_FORMAT=$format git init refformat && + + if test $format = files + then + test_must_fail git -C refformat config extensions.refstorage && + echo 0 >expect + else + git -C refformat config extensions.refstorage && + echo 1 >expect + fi && + git -C refformat config core.repositoryformatversion >actual && + test_cmp expect actual && + + echo $format >expect && + git -C refformat rev-parse --show-ref-format >actual && + test_cmp expect actual + ' + + test_expect_success "init with --ref-format=$format" ' + test_when_finished "rm -rf refformat" && + git init --ref-format=$format refformat && + echo $format >expect && + git -C refformat rev-parse --show-ref-format >actual && + test_cmp expect actual + ' + + test_expect_success "init with init.defaultRefFormat=$format" ' + test_when_finished "rm -rf refformat" && + test_config_global init.defaultRefFormat $format && + ( + sane_unset GIT_DEFAULT_REF_FORMAT && + git init refformat + ) && + + echo $format >expect && + git -C refformat rev-parse --show-ref-format >actual && + test_cmp expect actual + ' + + test_expect_success "--ref-format=$format overrides GIT_DEFAULT_REF_FORMAT" ' + test_when_finished "rm -rf refformat" && + GIT_DEFAULT_REF_FORMAT=garbage git init --ref-format=$format refformat && + echo $format >expect && + git -C refformat rev-parse --show-ref-format >actual && + test_cmp expect actual + ' +done + +test_expect_success "--ref-format= overrides GIT_DEFAULT_REF_FORMAT" ' test_when_finished "rm -rf refformat" && - git init --ref-format=files refformat && - echo files >expect && + GIT_DEFAULT_REF_FORMAT=files git init --ref-format=reftable refformat && + echo reftable >expect && + git -C refformat rev-parse --show-ref-format >actual && + test_cmp expect actual +' + +test_expect_success "GIT_DEFAULT_REF_FORMAT= overrides init.defaultRefFormat" ' + test_when_finished "rm -rf refformat" && + test_config_global init.defaultRefFormat files && + + GIT_DEFAULT_REF_FORMAT=reftable git init refformat && + echo reftable >expect && git -C refformat rev-parse --show-ref-format >actual && test_cmp expect actual ' -backends="files reftable" for from_format in $backends do test_expect_success "re-init with same format ($from_format)" ' diff --git a/t/t0110-urlmatch-normalization.sh b/t/t0110-urlmatch-normalization.sh deleted file mode 100755 index 12d817fbd3..0000000000 --- a/t/t0110-urlmatch-normalization.sh +++ /dev/null @@ -1,182 +0,0 @@ -#!/bin/sh - -test_description='urlmatch URL normalization' - -TEST_PASSES_SANITIZE_LEAK=true -. ./test-lib.sh - -# The base name of the test url files -tu="$TEST_DIRECTORY/t0110/url" - -# Note that only file: URLs should be allowed without a host - -test_expect_success 'url scheme' ' - ! test-tool urlmatch-normalization "" && - ! test-tool urlmatch-normalization "_" && - ! test-tool urlmatch-normalization "scheme" && - ! test-tool urlmatch-normalization "scheme:" && - ! test-tool urlmatch-normalization "scheme:/" && - ! test-tool urlmatch-normalization "scheme://" && - ! test-tool urlmatch-normalization "file" && - ! test-tool urlmatch-normalization "file:" && - ! test-tool urlmatch-normalization "file:/" && - test-tool urlmatch-normalization "file://" && - ! test-tool urlmatch-normalization "://acme.co" && - ! test-tool urlmatch-normalization "x_test://acme.co" && - ! test-tool urlmatch-normalization "-test://acme.co" && - ! test-tool urlmatch-normalization "0test://acme.co" && - ! test-tool urlmatch-normalization "+test://acme.co" && - ! test-tool urlmatch-normalization ".test://acme.co" && - ! test-tool urlmatch-normalization "schem%6e://" && - test-tool urlmatch-normalization "x-Test+v1.0://acme.co" && - test "$(test-tool urlmatch-normalization -p "AbCdeF://x.Y")" = "abcdef://x.y/" -' - -test_expect_success 'url authority' ' - ! test-tool urlmatch-normalization "scheme://user:pass@" && - ! test-tool urlmatch-normalization "scheme://?" && - ! test-tool urlmatch-normalization "scheme://#" && - ! test-tool urlmatch-normalization "scheme:///" && - ! test-tool urlmatch-normalization "scheme://:" && - ! test-tool urlmatch-normalization "scheme://:555" && - test-tool urlmatch-normalization "file://user:pass@" && - test-tool urlmatch-normalization "file://?" && - test-tool urlmatch-normalization "file://#" && - test-tool urlmatch-normalization "file:///" && - test-tool urlmatch-normalization "file://:" && - ! test-tool urlmatch-normalization "file://:555" && - test-tool urlmatch-normalization "scheme://user:pass@host" && - test-tool urlmatch-normalization "scheme://@host" && - test-tool urlmatch-normalization "scheme://%00@host" && - ! test-tool urlmatch-normalization "scheme://%%@host" && - test-tool urlmatch-normalization "scheme://host_" && - test-tool urlmatch-normalization "scheme://user:pass@host/" && - test-tool urlmatch-normalization "scheme://@host/" && - test-tool urlmatch-normalization "scheme://host/" && - test-tool urlmatch-normalization "scheme://host?x" && - test-tool urlmatch-normalization "scheme://host#x" && - test-tool urlmatch-normalization "scheme://host/@" && - test-tool urlmatch-normalization "scheme://host?@x" && - test-tool urlmatch-normalization "scheme://host#@x" && - test-tool urlmatch-normalization "scheme://[::1]" && - test-tool urlmatch-normalization "scheme://[::1]/" && - ! test-tool urlmatch-normalization "scheme://hos%41/" && - test-tool urlmatch-normalization "scheme://[invalid....:/" && - test-tool urlmatch-normalization "scheme://invalid....:]/" && - ! test-tool urlmatch-normalization "scheme://invalid....:[/" && - ! test-tool urlmatch-normalization "scheme://invalid....:[" -' - -test_expect_success 'url port checks' ' - test-tool urlmatch-normalization "xyz://q@some.host:" && - test-tool urlmatch-normalization "xyz://q@some.host:456/" && - ! test-tool urlmatch-normalization "xyz://q@some.host:0" && - ! test-tool urlmatch-normalization "xyz://q@some.host:0000000" && - test-tool urlmatch-normalization "xyz://q@some.host:0000001?" && - test-tool urlmatch-normalization "xyz://q@some.host:065535#" && - test-tool urlmatch-normalization "xyz://q@some.host:65535" && - ! test-tool urlmatch-normalization "xyz://q@some.host:65536" && - ! test-tool urlmatch-normalization "xyz://q@some.host:99999" && - ! test-tool urlmatch-normalization "xyz://q@some.host:100000" && - ! test-tool urlmatch-normalization "xyz://q@some.host:100001" && - test-tool urlmatch-normalization "http://q@some.host:80" && - test-tool urlmatch-normalization "https://q@some.host:443" && - test-tool urlmatch-normalization "http://q@some.host:80/" && - test-tool urlmatch-normalization "https://q@some.host:443?" && - ! test-tool urlmatch-normalization "http://q@:8008" && - ! test-tool urlmatch-normalization "http://:8080" && - ! test-tool urlmatch-normalization "http://:" && - test-tool urlmatch-normalization "xyz://q@some.host:456/" && - test-tool urlmatch-normalization "xyz://[::1]:456/" && - test-tool urlmatch-normalization "xyz://[::1]:/" && - ! test-tool urlmatch-normalization "xyz://[::1]:000/" && - ! test-tool urlmatch-normalization "xyz://[::1]:0%300/" && - ! test-tool urlmatch-normalization "xyz://[::1]:0x80/" && - ! test-tool urlmatch-normalization "xyz://[::1]:4294967297/" && - ! test-tool urlmatch-normalization "xyz://[::1]:030f/" -' - -test_expect_success 'url port normalization' ' - test "$(test-tool urlmatch-normalization -p "http://x:800")" = "http://x:800/" && - test "$(test-tool urlmatch-normalization -p "http://x:0800")" = "http://x:800/" && - test "$(test-tool urlmatch-normalization -p "http://x:00000800")" = "http://x:800/" && - test "$(test-tool urlmatch-normalization -p "http://x:065535")" = "http://x:65535/" && - test "$(test-tool urlmatch-normalization -p "http://x:1")" = "http://x:1/" && - test "$(test-tool urlmatch-normalization -p "http://x:80")" = "http://x/" && - test "$(test-tool urlmatch-normalization -p "http://x:080")" = "http://x/" && - test "$(test-tool urlmatch-normalization -p "http://x:000000080")" = "http://x/" && - test "$(test-tool urlmatch-normalization -p "https://x:443")" = "https://x/" && - test "$(test-tool urlmatch-normalization -p "https://x:0443")" = "https://x/" && - test "$(test-tool urlmatch-normalization -p "https://x:000000443")" = "https://x/" -' - -test_expect_success 'url general escapes' ' - ! test-tool urlmatch-normalization "http://x.y?%fg" && - test "$(test-tool urlmatch-normalization -p "X://W/%7e%41^%3a")" = "x://w/~A%5E%3A" && - test "$(test-tool urlmatch-normalization -p "X://W/:/?#[]@")" = "x://w/:/?#[]@" && - test "$(test-tool urlmatch-normalization -p "X://W/$&()*+,;=")" = "x://w/$&()*+,;=" && - test "$(test-tool urlmatch-normalization -p "X://W/'\''")" = "x://w/'\''" && - test "$(test-tool urlmatch-normalization -p "X://W?'\!'")" = "x://w/?'\!'" -' - -test_expect_success !MINGW 'url high-bit escapes' ' - test "$(test-tool urlmatch-normalization -p "$(cat "$tu-1")")" = "x://q/%01%02%03%04%05%06%07%08%0E%0F%10%11%12" && - test "$(test-tool urlmatch-normalization -p "$(cat "$tu-2")")" = "x://q/%13%14%15%16%17%18%19%1B%1C%1D%1E%1F%7F" && - test "$(test-tool urlmatch-normalization -p "$(cat "$tu-3")")" = "x://q/%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F" && - test "$(test-tool urlmatch-normalization -p "$(cat "$tu-4")")" = "x://q/%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F" && - test "$(test-tool urlmatch-normalization -p "$(cat "$tu-5")")" = "x://q/%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF" && - test "$(test-tool urlmatch-normalization -p "$(cat "$tu-6")")" = "x://q/%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF" && - test "$(test-tool urlmatch-normalization -p "$(cat "$tu-7")")" = "x://q/%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF" && - test "$(test-tool urlmatch-normalization -p "$(cat "$tu-8")")" = "x://q/%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF" && - test "$(test-tool urlmatch-normalization -p "$(cat "$tu-9")")" = "x://q/%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF" && - test "$(test-tool urlmatch-normalization -p "$(cat "$tu-10")")" = "x://q/%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF" -' - -test_expect_success 'url utf-8 escapes' ' - test "$(test-tool urlmatch-normalization -p "$(cat "$tu-11")")" = "x://q/%C2%80%DF%BF%E0%A0%80%EF%BF%BD%F0%90%80%80%F0%AF%BF%BD" -' - -test_expect_success 'url username/password escapes' ' - test "$(test-tool urlmatch-normalization -p "x://%41%62(^):%70+d@foo")" = "x://Ab(%5E):p+d@foo/" -' - -test_expect_success 'url normalized lengths' ' - test "$(test-tool urlmatch-normalization -l "Http://%4d%65:%4d^%70@The.Host")" = 25 && - test "$(test-tool urlmatch-normalization -l "http://%41:%42@x.y/%61/")" = 17 && - test "$(test-tool urlmatch-normalization -l "http://@x.y/^")" = 15 -' - -test_expect_success 'url . and .. segments' ' - test "$(test-tool urlmatch-normalization -p "x://y/.")" = "x://y/" && - test "$(test-tool urlmatch-normalization -p "x://y/./")" = "x://y/" && - test "$(test-tool urlmatch-normalization -p "x://y/a/.")" = "x://y/a" && - test "$(test-tool urlmatch-normalization -p "x://y/a/./")" = "x://y/a/" && - test "$(test-tool urlmatch-normalization -p "x://y/.?")" = "x://y/?" && - test "$(test-tool urlmatch-normalization -p "x://y/./?")" = "x://y/?" && - test "$(test-tool urlmatch-normalization -p "x://y/a/.?")" = "x://y/a?" && - test "$(test-tool urlmatch-normalization -p "x://y/a/./?")" = "x://y/a/?" && - test "$(test-tool urlmatch-normalization -p "x://y/a/./b/.././../c")" = "x://y/c" && - test "$(test-tool urlmatch-normalization -p "x://y/a/./b/../.././c/")" = "x://y/c/" && - test "$(test-tool urlmatch-normalization -p "x://y/a/./b/.././../c/././.././.")" = "x://y/" && - ! test-tool urlmatch-normalization "x://y/a/./b/.././../c/././.././.." && - test "$(test-tool urlmatch-normalization -p "x://y/a/./?/././..")" = "x://y/a/?/././.." && - test "$(test-tool urlmatch-normalization -p "x://y/%2e/")" = "x://y/" && - test "$(test-tool urlmatch-normalization -p "x://y/%2E/")" = "x://y/" && - test "$(test-tool urlmatch-normalization -p "x://y/a/%2e./")" = "x://y/" && - test "$(test-tool urlmatch-normalization -p "x://y/b/.%2E/")" = "x://y/" && - test "$(test-tool urlmatch-normalization -p "x://y/c/%2e%2E/")" = "x://y/" -' - -# http://@foo specifies an empty user name but does not specify a password -# http://foo specifies neither a user name nor a password -# So they should not be equivalent -test_expect_success 'url equivalents' ' - test-tool urlmatch-normalization "httP://x" "Http://X/" && - test-tool urlmatch-normalization "Http://%4d%65:%4d^%70@The.Host" "hTTP://Me:%4D^p@the.HOST:80/" && - ! test-tool urlmatch-normalization "https://@x.y/^" "httpS://x.y:443/^" && - test-tool urlmatch-normalization "https://@x.y/^" "httpS://@x.y:0443/^" && - test-tool urlmatch-normalization "https://@x.y/^/../abc" "httpS://@x.y:0443/abc" && - test-tool urlmatch-normalization "https://@x.y/^/.." "httpS://@x.y:0443/" -' - -test_done diff --git a/t/t0110/README b/t/t0110/README deleted file mode 100644 index ad4a50ecd8..0000000000 --- a/t/t0110/README +++ /dev/null @@ -1,9 +0,0 @@ -The url data files in this directory contain URLs with characters -in the range 0x01-0x1f and 0x7f-0xff to test the proper normalization -of unprintable characters. - -A select few characters in the 0x01-0x1f range are skipped to help -avoid problems running the test itself. - -The urls are in test files in this directory rather than being -embedded in the test script for portability. diff --git a/t/t0110/url-1 b/t/t0110/url-1 deleted file mode 100644 index 519019c5ce..0000000000 --- a/t/t0110/url-1 +++ /dev/null @@ -1 +0,0 @@ -x://q/ diff --git a/t/t0110/url-10 b/t/t0110/url-10 deleted file mode 100644 index b9965de6a5..0000000000 --- a/t/t0110/url-10 +++ /dev/null @@ -1 +0,0 @@ -x://q/���������������� diff --git a/t/t0110/url-11 b/t/t0110/url-11 deleted file mode 100644 index f0a50f1009..0000000000 --- a/t/t0110/url-11 +++ /dev/null @@ -1 +0,0 @@ -x://q/߿ࠀ�𐀀 diff --git a/t/t0110/url-2 b/t/t0110/url-2 deleted file mode 100644 index 43334b05b2..0000000000 --- a/t/t0110/url-2 +++ /dev/null @@ -1 +0,0 @@ -x://q/ diff --git a/t/t0110/url-3 b/t/t0110/url-3 deleted file mode 100644 index 7378c7bec2..0000000000 --- a/t/t0110/url-3 +++ /dev/null @@ -1 +0,0 @@ -x://q/���������������� diff --git a/t/t0110/url-4 b/t/t0110/url-4 deleted file mode 100644 index 220b198c97..0000000000 --- a/t/t0110/url-4 +++ /dev/null @@ -1 +0,0 @@ -x://q/���������������� diff --git a/t/t0110/url-5 b/t/t0110/url-5 deleted file mode 100644 index 1ccd927779..0000000000 --- a/t/t0110/url-5 +++ /dev/null @@ -1 +0,0 @@ -x://q/���������������� diff --git a/t/t0110/url-6 b/t/t0110/url-6 deleted file mode 100644 index e8283aac6d..0000000000 --- a/t/t0110/url-6 +++ /dev/null @@ -1 +0,0 @@ -x://q/���������������� diff --git a/t/t0110/url-7 b/t/t0110/url-7 deleted file mode 100644 index fa7c10b615..0000000000 --- a/t/t0110/url-7 +++ /dev/null @@ -1 +0,0 @@ -x://q/���������������� diff --git a/t/t0110/url-8 b/t/t0110/url-8 deleted file mode 100644 index 79a0ba836f..0000000000 --- a/t/t0110/url-8 +++ /dev/null @@ -1 +0,0 @@ -x://q/���������������� diff --git a/t/t0110/url-9 b/t/t0110/url-9 deleted file mode 100644 index 8b44bec48b..0000000000 --- a/t/t0110/url-9 +++ /dev/null @@ -1 +0,0 @@ -x://q/���������������� diff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh index c312657a12..b9adc94aab 100755 --- a/t/t0210-trace2-normal.sh +++ b/t/t0210-trace2-normal.sh @@ -2,7 +2,7 @@ test_description='test trace2 facility (normal target)' -TEST_PASSES_SANITIZE_LEAK=false +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Turn off any inherited trace2 settings for this test. diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh index ff9bf213aa..d36cd7c086 100755 --- a/t/t1006-cat-file.sh +++ b/t/t1006-cat-file.sh @@ -2,6 +2,7 @@ test_description='git cat-file' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_cmdmode_usage () { diff --git a/t/t1050-large.sh b/t/t1050-large.sh index c71932b024..ed638f6644 100755 --- a/t/t1050-large.sh +++ b/t/t1050-large.sh @@ -3,6 +3,7 @@ test_description='adding and checking out large blobs' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'core.bigFileThreshold must be non-negative' ' diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh index 8a456b1142..280cbf3e03 100755 --- a/t/t1450-fsck.sh +++ b/t/t1450-fsck.sh @@ -6,6 +6,7 @@ test_description='git fsck random collection of tests * (main) A ' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t1601-index-bogus.sh b/t/t1601-index-bogus.sh index 4171f1e141..5dcc101882 100755 --- a/t/t1601-index-bogus.sh +++ b/t/t1601-index-bogus.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test handling of bogus index entries' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'create tree with null sha1' ' diff --git a/t/t3310-notes-merge-manual-resolve.sh b/t/t3310-notes-merge-manual-resolve.sh index 597df5ebc0..04866b89be 100755 --- a/t/t3310-notes-merge-manual-resolve.sh +++ b/t/t3310-notes-merge-manual-resolve.sh @@ -5,6 +5,7 @@ test_description='Test notes merging with manual conflict resolution' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Set up a notes merge scenario with different kinds of conflicts diff --git a/t/t3311-notes-merge-fanout.sh b/t/t3311-notes-merge-fanout.sh index 5b675417e9..ce4144db0f 100755 --- a/t/t3311-notes-merge-fanout.sh +++ b/t/t3311-notes-merge-fanout.sh @@ -5,6 +5,7 @@ test_description='Test notes merging at various fanout levels' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh verify_notes () { diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index ae34bfad60..bd8bcc381a 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -235,6 +235,12 @@ test_expect_success 'rebase --merge -q is quiet' ' test_must_be_empty output.out ' +test_expect_success 'rebase --exec -q is quiet' ' + git checkout -B quiet topic && + git rebase --exec true -q main >output.out 2>&1 && + test_must_be_empty output.out +' + test_expect_success 'Rebase a commit that sprinkles CRs in' ' ( echo "One" && diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index f92baad138..f171af3061 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -26,6 +26,7 @@ Initial setup: touch file "conflict". ' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-rebase.sh diff --git a/t/t3435-rebase-gpg-sign.sh b/t/t3435-rebase-gpg-sign.sh index 6aa2aeb628..6e329fea7c 100755 --- a/t/t3435-rebase-gpg-sign.sh +++ b/t/t3435-rebase-gpg-sign.sh @@ -8,6 +8,7 @@ test_description='test rebase --[no-]gpg-sign' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY/lib-rebase.sh" . "$TEST_DIRECTORY/lib-gpg.sh" diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh index f3947b400a..10e9c91dbb 100755 --- a/t/t3507-cherry-pick-conflict.sh +++ b/t/t3507-cherry-pick-conflict.sh @@ -13,6 +13,7 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME TEST_CREATE_REPO_NO_TEMPLATE=1 +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh pristine_detach () { diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh index 7eb52b12ed..93c725bac3 100755 --- a/t/t3510-cherry-pick-sequence.sh +++ b/t/t3510-cherry-pick-sequence.sh @@ -12,6 +12,7 @@ test_description='Test cherry-pick continuation features ' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Repeat first match 10 times diff --git a/t/t3705-add-sparse-checkout.sh b/t/t3705-add-sparse-checkout.sh index 2bade9e804..6ae45a788d 100755 --- a/t/t3705-add-sparse-checkout.sh +++ b/t/t3705-add-sparse-checkout.sh @@ -2,6 +2,7 @@ test_description='git add in sparse checked out working trees' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh SPARSE_ENTRY_BLOB="" diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index e4c0937f61..c87592ee2f 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -1398,6 +1398,21 @@ test_expect_success 'stash --keep-index with file deleted in index does not resu test_path_is_missing to-remove ' +test_expect_success 'stash --keep-index --include-untracked with empty tree' ' + test_when_finished "rm -rf empty" && + git init empty && + ( + cd empty && + git commit --allow-empty --message "empty" && + echo content >file && + git stash push --keep-index --include-untracked && + test_path_is_missing file && + git stash pop && + echo content >expect && + test_cmp expect file + ) +' + test_expect_success 'stash apply should succeed with unmodified file' ' echo base >file && git add file && diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index 3855d68dbc..87d248d034 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -8,6 +8,7 @@ test_description='Various diff formatting options' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-diff.sh diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index 884f83fb8a..1c46e963e4 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -8,6 +8,7 @@ test_description='various format-patch tests' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-terminal.sh diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh index e026fac1f4..8128c30e7f 100755 --- a/t/t4018-diff-funcname.sh +++ b/t/t4018-diff-funcname.sh @@ -5,6 +5,7 @@ test_description='Test custom diff function name patterns' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh index a39a626664..29f6d610c2 100755 --- a/t/t4030-diff-textconv.sh +++ b/t/t4030-diff-textconv.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='diff.*.textconv tests' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh find_diff() { diff --git a/t/t4042-diff-textconv-caching.sh b/t/t4042-diff-textconv-caching.sh index 8ebfa3c1be..a179205394 100755 --- a/t/t4042-diff-textconv-caching.sh +++ b/t/t4042-diff-textconv-caching.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test textconv caching' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh cat >helper <<'EOF' diff --git a/t/t4048-diff-combined-binary.sh b/t/t4048-diff-combined-binary.sh index 0260cf64f5..f399484bce 100755 --- a/t/t4048-diff-combined-binary.sh +++ b/t/t4048-diff-combined-binary.sh @@ -4,6 +4,7 @@ test_description='combined and merge diff handle binary files and textconv' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup binary merge conflict' ' diff --git a/t/t4064-diff-oidfind.sh b/t/t4064-diff-oidfind.sh index 6d8c8986fc..846f285f77 100755 --- a/t/t4064-diff-oidfind.sh +++ b/t/t4064-diff-oidfind.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test finding specific blobs in the revision walking' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup ' ' diff --git a/t/t4065-diff-anchored.sh b/t/t4065-diff-anchored.sh index b3f510f040..647537c12e 100755 --- a/t/t4065-diff-anchored.sh +++ b/t/t4065-diff-anchored.sh @@ -2,6 +2,7 @@ test_description='anchored diff algorithm' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success '--anchored' ' diff --git a/t/t4068-diff-symmetric-merge-base.sh b/t/t4068-diff-symmetric-merge-base.sh index eff63c16b0..4d6565e728 100755 --- a/t/t4068-diff-symmetric-merge-base.sh +++ b/t/t4068-diff-symmetric-merge-base.sh @@ -5,6 +5,7 @@ test_description='behavior of diff with symmetric-diff setups and --merge-base' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # build these situations: diff --git a/t/t4069-remerge-diff.sh b/t/t4069-remerge-diff.sh index ca8f999cab..df342850a0 100755 --- a/t/t4069-remerge-diff.sh +++ b/t/t4069-remerge-diff.sh @@ -2,6 +2,7 @@ test_description='remerge-diff handling' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # This test is ort-specific diff --git a/t/t4108-apply-threeway.sh b/t/t4108-apply-threeway.sh index c558282bc0..3211e1e65f 100755 --- a/t/t4108-apply-threeway.sh +++ b/t/t4108-apply-threeway.sh @@ -5,6 +5,7 @@ test_description='git apply --3way' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh print_sanitized_conflicted_diff () { diff --git a/t/t4129-apply-samemode.sh b/t/t4129-apply-samemode.sh index d9a1084b5e..87ffd2b8e1 100755 --- a/t/t4129-apply-samemode.sh +++ b/t/t4129-apply-samemode.sh @@ -153,8 +153,8 @@ test_expect_success POSIXPERM 'patch mode for new file is canonicalized' ' test_expect_success POSIXPERM 'patch mode for deleted file is canonicalized' ' test_when_finished "git reset --hard" && echo content >non-canon && - git add non-canon && chmod 666 non-canon && + git add non-canon && cat >patch <<-\EOF && diff --git a/non-canon b/non-canon diff --git a/t/t4209-log-pickaxe.sh b/t/t4209-log-pickaxe.sh index 64e1623733..b42fdc54fc 100755 --- a/t/t4209-log-pickaxe.sh +++ b/t/t4209-log-pickaxe.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='log --grep/--author/--regexp-ignore-case/-S/-G' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_log () { diff --git a/t/t5304-prune.sh b/t/t5304-prune.sh index 1f1f664871..e641df0116 100755 --- a/t/t5304-prune.sh +++ b/t/t5304-prune.sh @@ -7,6 +7,7 @@ test_description='prune' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh day=$((60*60*24)) diff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh index f052f395a7..1dd6284756 100755 --- a/t/t5333-pseudo-merge-bitmaps.sh +++ b/t/t5333-pseudo-merge-bitmaps.sh @@ -390,4 +390,60 @@ test_expect_success 'pseudo-merge reuse' ' ) ' +test_expect_success 'empty pseudo-merge group' ' + git init pseudo-merge-empty-group && + ( + cd pseudo-merge-empty-group && + + # Ensure that a pseudo-merge group with no unstable + # commits does not generate an empty pseudo-merge + # bitmap. + git config bitmapPseudoMerge.empty.pattern refs/ && + + test_commit base && + git repack -adb && + + test-tool bitmap dump-pseudo-merges >merges && + test_line_count = 1 merges && + + test 0 -eq "$(grep -c commits=0 <merges)" + ) +' + +test_expect_success 'pseudo-merge closure' ' + git init pseudo-merge-closure && + ( + cd pseudo-merge-closure && + + test_commit A && + git repack -d && + + test_commit B && + + # Note that the contents of A is packed, but B is not. A + # (and the objects reachable from it) are thus visible + # to the MIDX, but the same is not true for B and its + # objects. + # + # Ensure that we do not attempt to create a pseudo-merge + # for B, depsite it matching the below pseudo-merge + # group pattern, as doing so would result in a failure + # to write a non-closed bitmap. + git config bitmapPseudoMerge.test.pattern refs/ && + git config bitmapPseudoMerge.test.threshold now && + + git multi-pack-index write --bitmap && + + test-tool bitmap dump-pseudo-merges >pseudo-merges && + test_line_count = 1 pseudo-merges && + + git rev-parse A >expect && + + test-tool bitmap list-commits >actual && + test_cmp expect actual && + test-tool bitmap dump-pseudo-merge-commits 0 >actual && + test_cmp expect actual + ) +' + test_done diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh index 2da7291e37..8415884754 100755 --- a/t/t5616-partial-clone.sh +++ b/t/t5616-partial-clone.sh @@ -229,7 +229,7 @@ test_expect_success 'fetch --refetch triggers repacking' ' GIT_TRACE2_EVENT="$PWD/trace1.event" \ git -C pc1 fetch --refetch origin && - test_subcommand git maintenance run --auto --no-quiet <trace1.event && + test_subcommand git maintenance run --auto --no-quiet --detach <trace1.event && grep \"param\":\"gc.autopacklimit\",\"value\":\"1\" trace1.event && grep \"param\":\"maintenance.incremental-repack.auto\",\"value\":\"-1\" trace1.event && @@ -238,7 +238,7 @@ test_expect_success 'fetch --refetch triggers repacking' ' -c gc.autoPackLimit=0 \ -c maintenance.incremental-repack.auto=1234 \ -C pc1 fetch --refetch origin && - test_subcommand git maintenance run --auto --no-quiet <trace2.event && + test_subcommand git maintenance run --auto --no-quiet --detach <trace2.event && grep \"param\":\"gc.autopacklimit\",\"value\":\"0\" trace2.event && grep \"param\":\"maintenance.incremental-repack.auto\",\"value\":\"-1\" trace2.event && @@ -247,7 +247,7 @@ test_expect_success 'fetch --refetch triggers repacking' ' -c gc.autoPackLimit=1234 \ -c maintenance.incremental-repack.auto=0 \ -C pc1 fetch --refetch origin && - test_subcommand git maintenance run --auto --no-quiet <trace3.event && + test_subcommand git maintenance run --auto --no-quiet --detach <trace3.event && grep \"param\":\"gc.autopacklimit\",\"value\":\"1\" trace3.event && grep \"param\":\"maintenance.incremental-repack.auto\",\"value\":\"0\" trace3.event ' diff --git a/t/t6020-bundle-misc.sh b/t/t6020-bundle-misc.sh index fe75a06572..34b5cd62c2 100755 --- a/t/t6020-bundle-misc.sh +++ b/t/t6020-bundle-misc.sh @@ -652,4 +652,36 @@ test_expect_success 'send a bundle to standard output' ' test_cmp expect actual ' +test_expect_success 'unbundle outside of a repository' ' + git bundle create some.bundle HEAD && + echo "fatal: Need a repository to unbundle." >expect && + nongit test_must_fail git bundle unbundle "$(pwd)/some.bundle" 2>err && + test_cmp expect err +' + +test_expect_success 'list-heads outside of a repository' ' + git bundle create some.bundle HEAD && + cat >expect <<-EOF && + $(git rev-parse HEAD) HEAD + EOF + nongit git bundle list-heads "$(pwd)/some.bundle" >actual && + test_cmp expect actual +' + +for hash in sha1 sha256 +do + test_expect_success "list-heads with bundle using $hash" ' + test_when_finished "rm -rf hash" && + git init --object-format=$hash hash && + test_commit -C hash initial && + git -C hash bundle create hash.bundle HEAD && + + cat >expect <<-EOF && + $(git -C hash rev-parse HEAD) HEAD + EOF + git bundle list-heads hash/hash.bundle >actual && + test_cmp expect actual + ' +done + test_done diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh index eb6c8204e8..8d15713cc6 100755 --- a/t/t6300-for-each-ref.sh +++ b/t/t6300-for-each-ref.sh @@ -1907,6 +1907,15 @@ test_expect_success 'git for-each-ref with nested tags' ' test_cmp expect actual ' +test_expect_success 'is-base atom with non-commits' ' + git for-each-ref --format="%(is-base:HEAD) %(refname)" >out 2>err && + grep "(HEAD) refs/heads/main" out && + + test_line_count = 2 err && + grep "error: object .* is a commit, not a blob" err && + grep "error: bad tag pointer to" err +' + GRADE_FORMAT="%(signature:grade)%0a%(signature:key)%0a%(signature:signer)%0a%(signature:fingerprint)%0a%(signature:primarykeyfingerprint)" TRUSTLEVEL_FORMAT="%(signature:trustlevel)%0a%(signature:key)%0a%(signature:signer)%0a%(signature:fingerprint)%0a%(signature:primarykeyfingerprint)" diff --git a/t/t6421-merge-partial-clone.sh b/t/t6421-merge-partial-clone.sh index b99f29ef9b..30349a466e 100755 --- a/t/t6421-merge-partial-clone.sh +++ b/t/t6421-merge-partial-clone.sh @@ -26,6 +26,7 @@ test_description="limiting blob downloads when merging with partial clones" # underscore notation is to differentiate different # files that might be renamed into each other's paths.) +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-merge.sh diff --git a/t/t6428-merge-conflicts-sparse.sh b/t/t6428-merge-conflicts-sparse.sh index 9919c3fa7c..8a79bc2e92 100755 --- a/t/t6428-merge-conflicts-sparse.sh +++ b/t/t6428-merge-conflicts-sparse.sh @@ -22,6 +22,7 @@ test_description="merge cases" # underscore notation is to differentiate different # files that might be renamed into each other's paths.) +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-merge.sh diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh index 1b5909d1b7..5378455968 100755 --- a/t/t6500-gc.sh +++ b/t/t6500-gc.sh @@ -338,14 +338,14 @@ test_expect_success 'gc.maxCruftSize sets appropriate repack options' ' test_subcommand $cruft_max_size_opts --max-cruft-size=3145728 <trace2.txt ' -run_and_wait_for_auto_gc () { +run_and_wait_for_gc () { # We read stdout from gc for the side effect of waiting until the # background gc process exits, closing its fd 9. Furthermore, the # variable assignment from a command substitution preserves the # exit status of the main gc process. # Note: this fd trickery doesn't work on Windows, but there is no # need to, because on Win the auto gc always runs in the foreground. - doesnt_matter=$(git gc --auto 9>&1) + doesnt_matter=$(git gc "$@" 9>&1) } test_expect_success 'background auto gc does not run if gc.log is present and recent but does if it is old' ' @@ -361,7 +361,7 @@ test_expect_success 'background auto gc does not run if gc.log is present and re test-tool chmtime =-345600 .git/gc.log && git gc --auto && test_config gc.logexpiry 2.days && - run_and_wait_for_auto_gc && + run_and_wait_for_gc --auto && ls .git/objects/pack/pack-*.pack >packs && test_line_count = 1 packs ' @@ -391,11 +391,48 @@ test_expect_success 'background auto gc respects lock for all operations' ' printf "%d %s" "$shell_pid" "$hostname" >.git/gc.pid && # our gc should exit zero without doing anything - run_and_wait_for_auto_gc && + run_and_wait_for_gc --auto && (ls -1 .git/refs/heads .git/reftable >actual || true) && test_cmp expect actual ' +test_expect_success '--detach overrides gc.autoDetach=false' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + + # Prepare the repository such that git-gc(1) ends up repacking. + test_commit "$(test_oid blob17_1)" && + test_commit "$(test_oid blob17_2)" && + git config gc.autodetach false && + git config gc.auto 2 && + + # Note that we cannot use `test_cmp` here to compare stderr + # because it may contain output from `set -x`. + run_and_wait_for_gc --auto --detach 2>actual && + test_grep "Auto packing the repository in background for optimum performance." actual + ) +' + +test_expect_success '--no-detach overrides gc.autoDetach=true' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + + # Prepare the repository such that git-gc(1) ends up repacking. + test_commit "$(test_oid blob17_1)" && + test_commit "$(test_oid blob17_2)" && + git config gc.autodetach true && + git config gc.auto 2 && + + GIT_PROGRESS_DELAY=0 git gc --auto --no-detach 2>output && + test_grep "Auto packing the repository for optimum performance." output && + test_grep "Collecting referenced commits: 2, done." output + ) +' + # DO NOT leave a detached auto gc process running near the end of the # test script: it can run long enough in the background to racily # interfere with the cleanup in 'test_done'. diff --git a/t/t6600-test-reach.sh b/t/t6600-test-reach.sh index b330945f49..2591f8b8b3 100755 --- a/t/t6600-test-reach.sh +++ b/t/t6600-test-reach.sh @@ -612,4 +612,125 @@ test_expect_success 'for-each-ref merged:none' ' --format="%(refname)" --stdin ' +# For get_branch_base_for_tip, we only care about +# first-parent history. Here is the test graph with +# second parents removed: +# +# (10,10) +# / +# (10,9) (9,10) +# / / +# (10,8) (9,9) (8,10) +# / / / +# ( continued...) +# \ / / / +# (3,1) (2,2) (1,3) +# \ / / +# (2,1) (1,2) +# \ / +# (1,1) +# +# In short, for a commit (i,j), the first-parent history +# walks all commits (i, k) with k from j to 1, then the +# commits (l, 1) with l from i to 1. + +test_expect_success 'get_branch_base_for_tip: none reach' ' + # (2,3) branched from the first tip (i,4) in X with i > 2 + cat >input <<-\EOF && + A:commit-2-3 + X:commit-1-2 + X:commit-1-4 + X:commit-4-4 + X:commit-8-4 + X:commit-10-4 + EOF + echo "get_branch_base_for_tip(A,X):2" >expect && + test_all_modes get_branch_base_for_tip +' + +test_expect_success 'get_branch_base_for_tip: equal to tip' ' + # (2,3) branched from the first tip (i,4) in X with i > 2 + cat >input <<-\EOF && + A:commit-8-4 + X:commit-1-2 + X:commit-1-4 + X:commit-4-4 + X:commit-8-4 + X:commit-10-4 + EOF + echo "get_branch_base_for_tip(A,X):3" >expect && + test_all_modes get_branch_base_for_tip +' + +test_expect_success 'get_branch_base_for_tip: all reach tip' ' + # (2,3) branched from the first tip (i,4) in X with i > 2 + cat >input <<-\EOF && + A:commit-4-1 + X:commit-4-2 + X:commit-5-1 + EOF + echo "get_branch_base_for_tip(A,X):0" >expect && + test_all_modes get_branch_base_for_tip +' + +test_expect_success 'for-each-ref is-base: none reach' ' + cat >input <<-\EOF && + refs/heads/commit-1-1 + refs/heads/commit-4-2 + refs/heads/commit-4-4 + refs/heads/commit-8-4 + EOF + cat >expect <<-\EOF && + refs/heads/commit-1-1: + refs/heads/commit-4-2:(commit-2-3) + refs/heads/commit-4-4: + refs/heads/commit-8-4: + EOF + run_all_modes git for-each-ref \ + --format="%(refname):%(is-base:commit-2-3)" --stdin +' + +test_expect_success 'for-each-ref is-base: all reach' ' + cat >input <<-\EOF && + refs/heads/commit-4-2 + refs/heads/commit-5-1 + EOF + cat >expect <<-\EOF && + refs/heads/commit-4-2:(commit-4-1) + refs/heads/commit-5-1: + EOF + run_all_modes git for-each-ref \ + --format="%(refname):%(is-base:commit-4-1)" --stdin +' + +test_expect_success 'for-each-ref is-base: equal to tip' ' + cat >input <<-\EOF && + refs/heads/commit-4-2 + refs/heads/commit-5-1 + EOF + cat >expect <<-\EOF && + refs/heads/commit-4-2:(commit-4-2) + refs/heads/commit-5-1: + EOF + run_all_modes git for-each-ref \ + --format="%(refname):%(is-base:commit-4-2)" --stdin +' + +test_expect_success 'for-each-ref is-base:multiple' ' + cat >input <<-\EOF && + refs/heads/commit-1-1 + refs/heads/commit-4-2 + refs/heads/commit-4-4 + refs/heads/commit-8-4 + EOF + cat >expect <<-\EOF && + refs/heads/commit-1-1[-] + refs/heads/commit-4-2[(commit-2-3)-] + refs/heads/commit-4-4[-] + refs/heads/commit-8-4[-(commit-6-5)] + EOF + run_all_modes git for-each-ref \ + --format="%(refname)[%(is-base:commit-2-3)-%(is-base:commit-6-5)]" --stdin +' + test_done diff --git a/t/t7008-filter-branch-null-sha1.sh b/t/t7008-filter-branch-null-sha1.sh index 93fbc92b8d..0ce8fd2c89 100755 --- a/t/t7008-filter-branch-null-sha1.sh +++ b/t/t7008-filter-branch-null-sha1.sh @@ -2,6 +2,7 @@ test_description='filter-branch removal of trees with null sha1' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup: base commits' ' diff --git a/t/t7030-verify-tag.sh b/t/t7030-verify-tag.sh index 6f526c37c2..effa826744 100755 --- a/t/t7030-verify-tag.sh +++ b/t/t7030-verify-tag.sh @@ -4,6 +4,7 @@ test_description='signed tag tests' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY/lib-gpg.sh" diff --git a/t/t7817-grep-sparse-checkout.sh b/t/t7817-grep-sparse-checkout.sh index eb59564565..0ba7817fb7 100755 --- a/t/t7817-grep-sparse-checkout.sh +++ b/t/t7817-grep-sparse-checkout.sh @@ -33,6 +33,7 @@ should leave the following structure in the working tree: But note that sub2 should have the SKIP_WORKTREE bit set. ' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh index 8595489ceb..abae7a9754 100755 --- a/t/t7900-maintenance.sh +++ b/t/t7900-maintenance.sh @@ -49,22 +49,47 @@ test_expect_success 'run [--auto|--quiet]' ' git maintenance run --auto 2>/dev/null && GIT_TRACE2_EVENT="$(pwd)/run-no-quiet.txt" \ git maintenance run --no-quiet 2>/dev/null && - test_subcommand git gc --quiet <run-no-auto.txt && - test_subcommand ! git gc --auto --quiet <run-auto.txt && - test_subcommand git gc --no-quiet <run-no-quiet.txt + test_subcommand git gc --quiet --no-detach <run-no-auto.txt && + test_subcommand ! git gc --auto --quiet --no-detach <run-auto.txt && + test_subcommand git gc --no-quiet --no-detach <run-no-quiet.txt ' test_expect_success 'maintenance.auto config option' ' GIT_TRACE2_EVENT="$(pwd)/default" git commit --quiet --allow-empty -m 1 && - test_subcommand git maintenance run --auto --quiet <default && + test_subcommand git maintenance run --auto --quiet --detach <default && GIT_TRACE2_EVENT="$(pwd)/true" \ git -c maintenance.auto=true \ commit --quiet --allow-empty -m 2 && - test_subcommand git maintenance run --auto --quiet <true && + test_subcommand git maintenance run --auto --quiet --detach <true && GIT_TRACE2_EVENT="$(pwd)/false" \ git -c maintenance.auto=false \ commit --quiet --allow-empty -m 3 && - test_subcommand ! git maintenance run --auto --quiet <false + test_subcommand ! git maintenance run --auto --quiet --detach <false +' + +for cfg in maintenance.autoDetach gc.autoDetach +do + test_expect_success "$cfg=true config option" ' + test_when_finished "rm -f trace" && + test_config $cfg true && + GIT_TRACE2_EVENT="$(pwd)/trace" git commit --quiet --allow-empty -m 1 && + test_subcommand git maintenance run --auto --quiet --detach <trace + ' + + test_expect_success "$cfg=false config option" ' + test_when_finished "rm -f trace" && + test_config $cfg false && + GIT_TRACE2_EVENT="$(pwd)/trace" git commit --quiet --allow-empty -m 1 && + test_subcommand git maintenance run --auto --quiet --no-detach <trace + ' +done + +test_expect_success "maintenance.autoDetach overrides gc.autoDetach" ' + test_when_finished "rm -f trace" && + test_config maintenance.autoDetach false && + test_config gc.autoDetach true && + GIT_TRACE2_EVENT="$(pwd)/trace" git commit --quiet --allow-empty -m 1 && + test_subcommand git maintenance run --auto --quiet --no-detach <trace ' test_expect_success 'register uses XDG_CONFIG_HOME config if it exists' ' @@ -129,9 +154,9 @@ test_expect_success 'run --task=<task>' ' git maintenance run --task=commit-graph 2>/dev/null && GIT_TRACE2_EVENT="$(pwd)/run-both.txt" \ git maintenance run --task=commit-graph --task=gc 2>/dev/null && - test_subcommand ! git gc --quiet <run-commit-graph.txt && - test_subcommand git gc --quiet <run-gc.txt && - test_subcommand git gc --quiet <run-both.txt && + test_subcommand ! git gc --quiet --no-detach <run-commit-graph.txt && + test_subcommand git gc --quiet --no-detach <run-gc.txt && + test_subcommand git gc --quiet --no-detach <run-both.txt && test_subcommand git commit-graph write --split --reachable --no-progress <run-commit-graph.txt && test_subcommand ! git commit-graph write --split --reachable --no-progress <run-gc.txt && test_subcommand git commit-graph write --split --reachable --no-progress <run-both.txt @@ -908,4 +933,62 @@ test_expect_success 'failed schedule prevents config change' ' done ' +test_expect_success '--no-detach causes maintenance to not run in background' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + + # Prepare the repository such that git-maintenance(1) ends up + # outputting something. + test_commit something && + git config set maintenance.gc.enabled false && + git config set maintenance.loose-objects.enabled true && + git config set maintenance.loose-objects.auto 1 && + git config set maintenance.incremental-repack.enabled true && + + GIT_TRACE2_EVENT="$(pwd)/trace.txt" \ + git maintenance run --no-detach >out 2>&1 && + ! test_region maintenance detach trace.txt + ) +' + +test_expect_success '--detach causes maintenance to run in background' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + + test_commit something && + git config set maintenance.gc.enabled false && + git config set maintenance.loose-objects.enabled true && + git config set maintenance.loose-objects.auto 1 && + git config set maintenance.incremental-repack.enabled true && + + # The extra file descriptor gets inherited to the child + # process, and by reading stdout we thus essentially wait for + # that descriptor to get closed, which indicates that the child + # is done, too. + does_not_matter=$(GIT_TRACE2_EVENT="$(pwd)/trace.txt" \ + git maintenance run --detach 9>&1) && + test_region maintenance detach trace.txt + ) +' + +test_expect_success 'repacking loose objects is quiet' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + + test_commit something && + git config set maintenance.gc.enabled false && + git config set maintenance.loose-objects.enabled true && + git config set maintenance.loose-objects.auto 1 && + + git maintenance run --quiet >out 2>&1 && + test_must_be_empty out + ) +' + test_done diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 64a4ab3736..c5e862694e 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -2084,22 +2084,24 @@ test_dump_aliases '--dump-aliases mailrc format' \ 'bob' \ 'chloe' \ 'eve' <<-\EOF - alias alice Alice W Land <awol@example.com> - alias eve Eve <eve@example.com> - alias bob Robert Bobbyton <bob@example.com> + alias alice "Alice W Land <awol@example.com>" + alias eve "Eve <eve@example.com>" + alias bob "Robert Bobbyton <bob@example.com>" alias chloe chloe@example.com EOF test_dump_aliases '--dump-aliases pine format' \ 'pine' \ 'alice' \ + 'bcgrp' \ 'bob' \ 'chloe' \ 'eve' <<-\EOF - alice Alice W Land <awol@example.com> - eve Eve <eve@example.com> - bob Robert Bobbyton <bob@example.com> + alice Alice W Land awol@example.com Friend + eve Eve eve@example.com + bob Robert Bobbyton bob@example.com chloe chloe@example.com + bcgrp (bob, chloe, Other <o@example.com>) EOF test_dump_aliases '--dump-aliases gnus format' \ @@ -2118,6 +2120,110 @@ test_expect_success '--dump-aliases must be used alone' ' test_must_fail git send-email --dump-aliases --to=janice@example.com -1 refs/heads/accounting ' +test_translate_aliases () { + msg="$1" && shift && + filetype="$1" && shift && + aliases="$1" && shift && + printf '%s\n' "$@" >expect && + cat >.tmp-email-aliases && + printf '%s\n' "$aliases" >aliases && + + test_expect_success $PREREQ "$msg" ' + clean_fake_sendmail && rm -fr outdir && + git config --replace-all sendemail.aliasesfile \ + "$(pwd)/.tmp-email-aliases" && + git config sendemail.aliasfiletype "$filetype" && + git send-email --translate-aliases <aliases 2>errors >actual && + test_cmp expect actual + ' +} + +test_translate_aliases '--translate-aliases sendmail format' \ + 'sendmail' \ + 'alice bcgrp' \ + 'Alice W Land <awol@example.com>' \ + 'Robert Bobbyton <bob@example.com>' \ + 'chloe@example.com' \ + 'Other <o@example.com>' <<-\EOF + alice: Alice W Land <awol@example.com> + bob: Robert Bobbyton <bob@example.com> + chloe: chloe@example.com + abgroup: alice, bob + bcgrp: bob, chloe, Other <o@example.com> + EOF + +test_translate_aliases '--translate-aliases mutt format' \ + 'mutt' \ + 'donald bob' \ + 'Donald C Carlton <donc@example.com>' \ + 'Robert Bobbyton <bob@example.com>' <<-\EOF + alias alice Alice W Land <awol@example.com> + alias donald Donald C Carlton <donc@example.com> + alias bob Robert Bobbyton <bob@example.com> + alias chloe chloe@example.com + EOF + +test_translate_aliases '--translate-aliases mailrc format' \ + 'mailrc' \ + 'chloe eve alice' \ + 'chloe@example.com' \ + 'Eve <eve@example.com>' \ + 'Alice W Land <awol@example.com>' <<-\EOF + alias alice "Alice W Land <awol@example.com>" + alias eve "Eve <eve@example.com>" + alias bob "Robert Bobbyton <bob@example.com>" + alias chloe chloe@example.com + EOF + +test_translate_aliases '--translate-aliases pine format' \ + 'pine' \ + 'eve bob bcgrp' \ + 'eve@example.com' \ + 'bob@example.com' \ + 'bob@example.com' \ + 'chloe@example.com' \ + 'Other <o@example.com>' <<-\EOF + alice Alice W Land awol@example.com Friend + eve Eve eve@example.com + bob Robert Bobbyton bob@example.com + chloe chloe@example.com + bcgrp (bob, chloe, Other <o@example.com>) + EOF + +test_translate_aliases '--translate-aliases gnus format' \ + 'gnus' \ + 'alice chloe eve' \ + 'awol@example.com' \ + 'chloe@example.com' \ + 'eve@example.com' <<-\EOF + (define-mail-alias "alice" "awol@example.com") + (define-mail-alias "eve" "eve@example.com") + (define-mail-alias "bob" "bob@example.com") + (define-mail-alias "chloe" "chloe@example.com") + EOF + +test_expect_success $PREREQ '--translate-aliases passes valid addresses through' ' + cat >expect <<-\EOF && + Other <o@example.com> + EOF + cat >aliases <<-\EOF && + Other <o@example.com> + EOF + git send-email --translate-aliases <aliases >actual && + test_cmp expect actual +' + +test_expect_success $PREREQ '--translate-aliases passes unknown aliases through' ' + cat >expect <<-\EOF && + blargh + EOF + cat >aliases <<-\EOF && + blargh + EOF + git send-email --translate-aliases <aliases >actual && + test_cmp expect actual +' + test_expect_success $PREREQ 'aliases and sendemail.identity' ' test_must_fail git \ -c sendemail.identity=cloud \ diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index 1e68426852..3b3c371740 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -7,6 +7,7 @@ test_description='test git fast-import utility' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-diff.sh ;# test-lib chdir's into trash diff --git a/t/t9304-fast-import-marks.sh b/t/t9304-fast-import-marks.sh index 410a871c52..1f776a80f3 100755 --- a/t/t9304-fast-import-marks.sh +++ b/t/t9304-fast-import-marks.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test exotic situations with marks' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup dump of basic history' ' diff --git a/t/t9351-fast-export-anonymize.sh b/t/t9351-fast-export-anonymize.sh index 156a647484..c0d9d7be75 100755 --- a/t/t9351-fast-export-anonymize.sh +++ b/t/t9351-fast-export-anonymize.sh @@ -4,6 +4,7 @@ test_description='basic tests for fast-export --anonymize' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup simple repo' ' diff --git a/t/unit-tests/t-ctype.c b/t/unit-tests/t-ctype.c index e28a7f50f9..6043f0d9bc 100644 --- a/t/unit-tests/t-ctype.c +++ b/t/unit-tests/t-ctype.c @@ -31,7 +31,7 @@ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \ "\x7f" -int cmd_main(int argc, const char **argv) { +int cmd_main(int argc UNUSED, const char **argv UNUSED) { TEST_CHAR_CLASS(isspace, " \n\r\t"); TEST_CHAR_CLASS(isdigit, DIGIT); TEST_CHAR_CLASS(isalpha, LOWER UPPER); diff --git a/t/unit-tests/t-hash.c b/t/unit-tests/t-hash.c index e9a78bf2c0..e62647019b 100644 --- a/t/unit-tests/t-hash.c +++ b/t/unit-tests/t-hash.c @@ -38,7 +38,7 @@ static void check_hash_data(const void *data, size_t data_length, "SHA1 and SHA256 (%s) works", #literal); \ } while (0) -int cmd_main(int argc, const char **argv) +int cmd_main(int argc UNUSED, const char **argv UNUSED) { struct strbuf aaaaaaaaaa_100000 = STRBUF_INIT; struct strbuf alphabet_100000 = STRBUF_INIT; diff --git a/t/unit-tests/t-hashmap.c b/t/unit-tests/t-hashmap.c index 09a48c2c4e..83b79dff39 100644 --- a/t/unit-tests/t-hashmap.c +++ b/t/unit-tests/t-hashmap.c @@ -322,7 +322,7 @@ static void t_alloc(struct hashmap *map, unsigned int ignore_case) free(removed); } -static void t_intern(struct hashmap *map, unsigned int ignore_case) +static void t_intern(void) { const char *values[] = { "value1", "Value1", "value2", "value2" }; @@ -356,6 +356,6 @@ int cmd_main(int argc UNUSED, const char **argv UNUSED) TEST(setup(t_iterate, 0), "iterate works"); TEST(setup(t_iterate, 1), "iterate (case insensitive) works"); TEST(setup(t_alloc, 0), "grow / shrink works"); - TEST(setup(t_intern, 0), "string interning works"); + TEST(t_intern(), "string interning works"); return test_done(); } diff --git a/t/unit-tests/t-mem-pool.c b/t/unit-tests/t-mem-pool.c index a0d57df761..fe500c704b 100644 --- a/t/unit-tests/t-mem-pool.c +++ b/t/unit-tests/t-mem-pool.c @@ -20,7 +20,7 @@ static void t_calloc_100(struct mem_pool *pool) check(pool->mp_block->end != NULL); } -int cmd_main(int argc, const char **argv) +int cmd_main(int argc UNUSED, const char **argv UNUSED) { TEST(setup_static(t_calloc_100, 1024 * 1024), "mem_pool_calloc returns 100 zeroed bytes with big block"); diff --git a/t/unit-tests/t-prio-queue.c b/t/unit-tests/t-prio-queue.c index 7a4e5780e1..fe6ae37935 100644 --- a/t/unit-tests/t-prio-queue.c +++ b/t/unit-tests/t-prio-queue.c @@ -69,7 +69,7 @@ static void test_prio_queue(int *input, size_t input_size, #define TEST_INPUT(input, result) \ test_prio_queue(input, ARRAY_SIZE(input), result, ARRAY_SIZE(result)) -int cmd_main(int argc, const char **argv) +int cmd_main(int argc UNUSED, const char **argv UNUSED) { TEST(TEST_INPUT(((int []){ 2, 6, 3, 10, 9, 5, 7, 4, 5, 8, 1, DUMP }), ((int []){ 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10 })), diff --git a/t/unit-tests/t-reftable-basics.c b/t/unit-tests/t-reftable-basics.c index 1dd60ab5f0..e5556ebf52 100644 --- a/t/unit-tests/t-reftable-basics.c +++ b/t/unit-tests/t-reftable-basics.c @@ -20,7 +20,7 @@ static int integer_needle_lesseq(size_t i, void *_args) return args->needle <= args->haystack[i]; } -int cmd_main(int argc, const char *argv[]) +int cmd_main(int argc UNUSED, const char *argv[] UNUSED) { if_test ("binary search with binsearch works") { int haystack[] = { 2, 4, 6, 8, 10 }; diff --git a/t/unit-tests/t-reftable-merged.c b/t/unit-tests/t-reftable-merged.c index b6263ee8b5..c9aff3f1ea 100644 --- a/t/unit-tests/t-reftable-merged.c +++ b/t/unit-tests/t-reftable-merged.c @@ -12,7 +12,6 @@ https://developers.google.com/open-source/licenses/bsd #include "reftable/merged.h" #include "reftable/reader.h" #include "reftable/reftable-error.h" -#include "reftable/reftable-generic.h" #include "reftable/reftable-merged.h" #include "reftable/reftable-writer.h" @@ -22,7 +21,7 @@ static ssize_t strbuf_add_void(void *b, const void *data, const size_t sz) return sz; } -static int noop_flush(void *arg) +static int noop_flush(void *arg UNUSED) { return 0; } @@ -94,10 +93,8 @@ merged_table_from_records(struct reftable_ref_record **refs, struct strbuf *buf, const size_t n) { struct reftable_merged_table *mt = NULL; - struct reftable_table *tabs; int err; - REFTABLE_CALLOC_ARRAY(tabs, n); REFTABLE_CALLOC_ARRAY(*readers, n); REFTABLE_CALLOC_ARRAY(*source, n); @@ -108,10 +105,9 @@ merged_table_from_records(struct reftable_ref_record **refs, err = reftable_new_reader(&(*readers)[i], &(*source)[i], "name"); check(!err); - reftable_table_from_reader(&tabs[i], (*readers)[i]); } - err = reftable_new_merged_table(&mt, tabs, n, GIT_SHA1_FORMAT_ID); + err = reftable_merged_table_new(&mt, *readers, n, GIT_SHA1_FORMAT_ID); check(!err); return mt; } @@ -272,10 +268,8 @@ merged_table_from_log_records(struct reftable_log_record **logs, struct strbuf *buf, const size_t n) { struct reftable_merged_table *mt = NULL; - struct reftable_table *tabs; int err; - REFTABLE_CALLOC_ARRAY(tabs, n); REFTABLE_CALLOC_ARRAY(*readers, n); REFTABLE_CALLOC_ARRAY(*source, n); @@ -286,10 +280,9 @@ merged_table_from_log_records(struct reftable_log_record **logs, err = reftable_new_reader(&(*readers)[i], &(*source)[i], "name"); check(!err); - reftable_table_from_reader(&tabs[i], (*readers)[i]); } - err = reftable_new_merged_table(&mt, tabs, n, GIT_SHA1_FORMAT_ID); + err = reftable_merged_table_new(&mt, *readers, n, GIT_SHA1_FORMAT_ID); check(!err); return mt; } @@ -418,7 +411,6 @@ static void t_default_write_opts(void) }; int err; struct reftable_block_source source = { 0 }; - struct reftable_table *tab = reftable_calloc(1, sizeof(*tab)); uint32_t hash_id; struct reftable_reader *rd = NULL; struct reftable_merged_table *merged = NULL; @@ -440,10 +432,9 @@ static void t_default_write_opts(void) hash_id = reftable_reader_hash_id(rd); check_int(hash_id, ==, GIT_SHA1_FORMAT_ID); - reftable_table_from_reader(&tab[0], rd); - err = reftable_new_merged_table(&merged, tab, 1, GIT_SHA256_FORMAT_ID); + err = reftable_merged_table_new(&merged, &rd, 1, GIT_SHA256_FORMAT_ID); check_int(err, ==, REFTABLE_FORMAT_ERROR); - err = reftable_new_merged_table(&merged, tab, 1, GIT_SHA1_FORMAT_ID); + err = reftable_merged_table_new(&merged, &rd, 1, GIT_SHA1_FORMAT_ID); check(!err); reftable_reader_free(rd); @@ -452,7 +443,7 @@ static void t_default_write_opts(void) } -int cmd_main(int argc, const char *argv[]) +int cmd_main(int argc UNUSED, const char *argv[] UNUSED) { TEST(t_default_write_opts(), "merged table with default write opts"); TEST(t_merged_logs(), "merged table with multiple log updates for same ref"); diff --git a/t/unit-tests/t-reftable-pq.c b/t/unit-tests/t-reftable-pq.c index 039bd0f1f9..ada4c19f18 100644 --- a/t/unit-tests/t-reftable-pq.c +++ b/t/unit-tests/t-reftable-pq.c @@ -142,7 +142,7 @@ static void t_merged_iter_pqueue_top(void) merged_iter_pqueue_release(&pq); } -int cmd_main(int argc, const char *argv[]) +int cmd_main(int argc UNUSED, const char *argv[] UNUSED) { TEST(t_pq_record(), "pq works with record-based comparison"); TEST(t_pq_index(), "pq works with index-based comparison"); diff --git a/t/unit-tests/t-reftable-readwrite.c b/t/unit-tests/t-reftable-readwrite.c new file mode 100644 index 0000000000..1eae36cc60 --- /dev/null +++ b/t/unit-tests/t-reftable-readwrite.c @@ -0,0 +1,974 @@ +/* +Copyright 2020 Google LLC + +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file or at +https://developers.google.com/open-source/licenses/bsd +*/ + +#include "test-lib.h" +#include "reftable/basics.h" +#include "reftable/blocksource.h" +#include "reftable/reader.h" +#include "reftable/reftable-error.h" +#include "reftable/reftable-writer.h" + +static const int update_index = 5; + +static void set_test_hash(uint8_t *p, int i) +{ + memset(p, (uint8_t)i, hash_size(GIT_SHA1_FORMAT_ID)); +} + +static ssize_t strbuf_add_void(void *b, const void *data, size_t sz) +{ + strbuf_add(b, data, sz); + return sz; +} + +static int noop_flush(void *arg) +{ + return 0; +} + +static void t_buffer(void) +{ + struct strbuf buf = STRBUF_INIT; + struct reftable_block_source source = { 0 }; + struct reftable_block out = { 0 }; + int n; + uint8_t in[] = "hello"; + strbuf_add(&buf, in, sizeof(in)); + block_source_from_strbuf(&source, &buf); + check_int(block_source_size(&source), ==, 6); + n = block_source_read_block(&source, &out, 0, sizeof(in)); + check_int(n, ==, sizeof(in)); + check(!memcmp(in, out.data, n)); + reftable_block_done(&out); + + n = block_source_read_block(&source, &out, 1, 2); + check_int(n, ==, 2); + check(!memcmp(out.data, "el", 2)); + + reftable_block_done(&out); + block_source_close(&source); + strbuf_release(&buf); +} + +static void write_table(char ***names, struct strbuf *buf, int N, + int block_size, uint32_t hash_id) +{ + struct reftable_write_options opts = { + .block_size = block_size, + .hash_id = hash_id, + }; + struct reftable_writer *w = + reftable_new_writer(&strbuf_add_void, &noop_flush, buf, &opts); + struct reftable_ref_record ref = { 0 }; + int i = 0, n; + struct reftable_log_record log = { 0 }; + const struct reftable_stats *stats = NULL; + + REFTABLE_CALLOC_ARRAY(*names, N + 1); + + reftable_writer_set_limits(w, update_index, update_index); + for (i = 0; i < N; i++) { + char name[100]; + int n; + + snprintf(name, sizeof(name), "refs/heads/branch%02d", i); + + ref.refname = name; + ref.update_index = update_index; + ref.value_type = REFTABLE_REF_VAL1; + set_test_hash(ref.value.val1, i); + (*names)[i] = xstrdup(name); + + n = reftable_writer_add_ref(w, &ref); + check_int(n, ==, 0); + } + + for (i = 0; i < N; i++) { + char name[100]; + int n; + + snprintf(name, sizeof(name), "refs/heads/branch%02d", i); + + log.refname = name; + log.update_index = update_index; + log.value_type = REFTABLE_LOG_UPDATE; + set_test_hash(log.value.update.new_hash, i); + log.value.update.message = (char *) "message"; + + n = reftable_writer_add_log(w, &log); + check_int(n, ==, 0); + } + + n = reftable_writer_close(w); + check_int(n, ==, 0); + + stats = reftable_writer_stats(w); + for (i = 0; i < stats->ref_stats.blocks; i++) { + int off = i * opts.block_size; + if (!off) + off = header_size((hash_id == GIT_SHA256_FORMAT_ID) ? 2 : 1); + check_char(buf->buf[off], ==, 'r'); + } + + check_int(stats->log_stats.blocks, >, 0); + reftable_writer_free(w); +} + +static void t_log_buffer_size(void) +{ + struct strbuf buf = STRBUF_INIT; + struct reftable_write_options opts = { + .block_size = 4096, + }; + int err; + int i; + struct reftable_log_record + log = { .refname = (char *) "refs/heads/master", + .update_index = 0xa, + .value_type = REFTABLE_LOG_UPDATE, + .value = { .update = { + .name = (char *) "Han-Wen Nienhuys", + .email = (char *) "hanwen@google.com", + .tz_offset = 100, + .time = 0x5e430672, + .message = (char *) "commit: 9\n", + } } }; + struct reftable_writer *w = + reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts); + + /* This tests buffer extension for log compression. Must use a random + hash, to ensure that the compressed part is larger than the original. + */ + for (i = 0; i < GIT_SHA1_RAWSZ; i++) { + log.value.update.old_hash[i] = (uint8_t)(git_rand() % 256); + log.value.update.new_hash[i] = (uint8_t)(git_rand() % 256); + } + reftable_writer_set_limits(w, update_index, update_index); + err = reftable_writer_add_log(w, &log); + check(!err); + err = reftable_writer_close(w); + check(!err); + reftable_writer_free(w); + strbuf_release(&buf); +} + +static void t_log_overflow(void) +{ + struct strbuf buf = STRBUF_INIT; + char msg[256] = { 0 }; + struct reftable_write_options opts = { + .block_size = ARRAY_SIZE(msg), + }; + int err; + struct reftable_log_record log = { + .refname = (char *) "refs/heads/master", + .update_index = 0xa, + .value_type = REFTABLE_LOG_UPDATE, + .value = { + .update = { + .old_hash = { 1 }, + .new_hash = { 2 }, + .name = (char *) "Han-Wen Nienhuys", + .email = (char *) "hanwen@google.com", + .tz_offset = 100, + .time = 0x5e430672, + .message = msg, + }, + }, + }; + struct reftable_writer *w = + reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts); + + memset(msg, 'x', sizeof(msg) - 1); + reftable_writer_set_limits(w, update_index, update_index); + err = reftable_writer_add_log(w, &log); + check_int(err, ==, REFTABLE_ENTRY_TOO_BIG_ERROR); + reftable_writer_free(w); + strbuf_release(&buf); +} + +static void t_log_write_read(void) +{ + int N = 2; + char **names = reftable_calloc(N + 1, sizeof(*names)); + int err; + struct reftable_write_options opts = { + .block_size = 256, + }; + struct reftable_ref_record ref = { 0 }; + int i = 0; + struct reftable_log_record log = { 0 }; + int n; + struct reftable_iterator it = { 0 }; + struct reftable_reader rd = { 0 }; + struct reftable_block_source source = { 0 }; + struct strbuf buf = STRBUF_INIT; + struct reftable_writer *w = + reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts); + const struct reftable_stats *stats = NULL; + reftable_writer_set_limits(w, 0, N); + for (i = 0; i < N; i++) { + char name[256]; + struct reftable_ref_record ref = { 0 }; + snprintf(name, sizeof(name), "b%02d%0*d", i, 130, 7); + names[i] = xstrdup(name); + ref.refname = name; + ref.update_index = i; + + err = reftable_writer_add_ref(w, &ref); + check(!err); + } + for (i = 0; i < N; i++) { + struct reftable_log_record log = { 0 }; + + log.refname = names[i]; + log.update_index = i; + log.value_type = REFTABLE_LOG_UPDATE; + set_test_hash(log.value.update.old_hash, i); + set_test_hash(log.value.update.new_hash, i + 1); + + err = reftable_writer_add_log(w, &log); + check(!err); + } + + n = reftable_writer_close(w); + check_int(n, ==, 0); + + stats = reftable_writer_stats(w); + check_int(stats->log_stats.blocks, >, 0); + reftable_writer_free(w); + w = NULL; + + block_source_from_strbuf(&source, &buf); + + err = init_reader(&rd, &source, "file.log"); + check(!err); + + reftable_reader_init_ref_iterator(&rd, &it); + + err = reftable_iterator_seek_ref(&it, names[N - 1]); + check(!err); + + err = reftable_iterator_next_ref(&it, &ref); + check(!err); + + /* end of iteration. */ + err = reftable_iterator_next_ref(&it, &ref); + check_int(err, >, 0); + + reftable_iterator_destroy(&it); + reftable_ref_record_release(&ref); + + reftable_reader_init_log_iterator(&rd, &it); + + err = reftable_iterator_seek_log(&it, ""); + check(!err); + + for (i = 0; ; i++) { + int err = reftable_iterator_next_log(&it, &log); + if (err > 0) + break; + check(!err); + check_str(names[i], log.refname); + check_int(i, ==, log.update_index); + reftable_log_record_release(&log); + } + + check_int(i, ==, N); + reftable_iterator_destroy(&it); + + /* cleanup. */ + strbuf_release(&buf); + free_names(names); + reader_close(&rd); +} + +static void t_log_zlib_corruption(void) +{ + struct reftable_write_options opts = { + .block_size = 256, + }; + struct reftable_iterator it = { 0 }; + struct reftable_reader rd = { 0 }; + struct reftable_block_source source = { 0 }; + struct strbuf buf = STRBUF_INIT; + struct reftable_writer *w = + reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts); + const struct reftable_stats *stats = NULL; + char message[100] = { 0 }; + int err, i, n; + struct reftable_log_record log = { + .refname = (char *) "refname", + .value_type = REFTABLE_LOG_UPDATE, + .value = { + .update = { + .new_hash = { 1 }, + .old_hash = { 2 }, + .name = (char *) "My Name", + .email = (char *) "myname@invalid", + .message = message, + }, + }, + }; + + for (i = 0; i < sizeof(message) - 1; i++) + message[i] = (uint8_t)(git_rand() % 64 + ' '); + + reftable_writer_set_limits(w, 1, 1); + + err = reftable_writer_add_log(w, &log); + check(!err); + + n = reftable_writer_close(w); + check_int(n, ==, 0); + + stats = reftable_writer_stats(w); + check_int(stats->log_stats.blocks, >, 0); + reftable_writer_free(w); + w = NULL; + + /* corrupt the data. */ + buf.buf[50] ^= 0x99; + + block_source_from_strbuf(&source, &buf); + + err = init_reader(&rd, &source, "file.log"); + check(!err); + + reftable_reader_init_log_iterator(&rd, &it); + err = reftable_iterator_seek_log(&it, "refname"); + check_int(err, ==, REFTABLE_ZLIB_ERROR); + + reftable_iterator_destroy(&it); + + /* cleanup. */ + strbuf_release(&buf); + reader_close(&rd); +} + +static void t_table_read_write_sequential(void) +{ + char **names; + struct strbuf buf = STRBUF_INIT; + int N = 50; + struct reftable_iterator it = { 0 }; + struct reftable_block_source source = { 0 }; + struct reftable_reader rd = { 0 }; + int err = 0; + int j = 0; + + write_table(&names, &buf, N, 256, GIT_SHA1_FORMAT_ID); + + block_source_from_strbuf(&source, &buf); + + err = init_reader(&rd, &source, "file.ref"); + check(!err); + + reftable_reader_init_ref_iterator(&rd, &it); + err = reftable_iterator_seek_ref(&it, ""); + check(!err); + + for (j = 0; ; j++) { + struct reftable_ref_record ref = { 0 }; + int r = reftable_iterator_next_ref(&it, &ref); + check_int(r, >=, 0); + if (r > 0) + break; + check_str(names[j], ref.refname); + check_int(update_index, ==, ref.update_index); + reftable_ref_record_release(&ref); + } + check_int(j, ==, N); + reftable_iterator_destroy(&it); + strbuf_release(&buf); + free_names(names); + + reader_close(&rd); +} + +static void t_table_write_small_table(void) +{ + char **names; + struct strbuf buf = STRBUF_INIT; + int N = 1; + write_table(&names, &buf, N, 4096, GIT_SHA1_FORMAT_ID); + check_int(buf.len, <, 200); + strbuf_release(&buf); + free_names(names); +} + +static void t_table_read_api(void) +{ + char **names; + struct strbuf buf = STRBUF_INIT; + int N = 50; + struct reftable_reader rd = { 0 }; + struct reftable_block_source source = { 0 }; + int err; + struct reftable_log_record log = { 0 }; + struct reftable_iterator it = { 0 }; + + write_table(&names, &buf, N, 256, GIT_SHA1_FORMAT_ID); + + block_source_from_strbuf(&source, &buf); + + err = init_reader(&rd, &source, "file.ref"); + check(!err); + + reftable_reader_init_ref_iterator(&rd, &it); + err = reftable_iterator_seek_ref(&it, names[0]); + check(!err); + + err = reftable_iterator_next_log(&it, &log); + check_int(err, ==, REFTABLE_API_ERROR); + + strbuf_release(&buf); + free_names(names); + reftable_iterator_destroy(&it); + reader_close(&rd); + strbuf_release(&buf); +} + +static void t_table_read_write_seek(int index, int hash_id) +{ + char **names; + struct strbuf buf = STRBUF_INIT; + int N = 50; + struct reftable_reader rd = { 0 }; + struct reftable_block_source source = { 0 }; + int err; + int i = 0; + + struct reftable_iterator it = { 0 }; + struct strbuf pastLast = STRBUF_INIT; + struct reftable_ref_record ref = { 0 }; + + write_table(&names, &buf, N, 256, hash_id); + + block_source_from_strbuf(&source, &buf); + + err = init_reader(&rd, &source, "file.ref"); + check(!err); + check_int(hash_id, ==, reftable_reader_hash_id(&rd)); + + if (!index) + rd.ref_offsets.index_offset = 0; + else + check_int(rd.ref_offsets.index_offset, >, 0); + + for (i = 1; i < N; i++) { + reftable_reader_init_ref_iterator(&rd, &it); + err = reftable_iterator_seek_ref(&it, names[i]); + check(!err); + err = reftable_iterator_next_ref(&it, &ref); + check(!err); + check_str(names[i], ref.refname); + check_int(REFTABLE_REF_VAL1, ==, ref.value_type); + check_int(i, ==, ref.value.val1[0]); + + reftable_ref_record_release(&ref); + reftable_iterator_destroy(&it); + } + + strbuf_addstr(&pastLast, names[N - 1]); + strbuf_addstr(&pastLast, "/"); + + reftable_reader_init_ref_iterator(&rd, &it); + err = reftable_iterator_seek_ref(&it, pastLast.buf); + if (err == 0) { + struct reftable_ref_record ref = { 0 }; + int err = reftable_iterator_next_ref(&it, &ref); + check_int(err, >, 0); + } else { + check_int(err, >, 0); + } + + strbuf_release(&pastLast); + reftable_iterator_destroy(&it); + + strbuf_release(&buf); + free_names(names); + reader_close(&rd); +} + +static void t_table_read_write_seek_linear(void) +{ + t_table_read_write_seek(0, GIT_SHA1_FORMAT_ID); +} + +static void t_table_read_write_seek_linear_sha256(void) +{ + t_table_read_write_seek(0, GIT_SHA256_FORMAT_ID); +} + +static void t_table_read_write_seek_index(void) +{ + t_table_read_write_seek(1, GIT_SHA1_FORMAT_ID); +} + +static void t_table_refs_for(int indexed) +{ + int N = 50; + char **want_names = reftable_calloc(N + 1, sizeof(*want_names)); + int want_names_len = 0; + uint8_t want_hash[GIT_SHA1_RAWSZ]; + + struct reftable_write_options opts = { + .block_size = 256, + }; + struct reftable_ref_record ref = { 0 }; + int i = 0; + int n; + int err; + struct reftable_reader rd; + struct reftable_block_source source = { 0 }; + + struct strbuf buf = STRBUF_INIT; + struct reftable_writer *w = + reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts); + + struct reftable_iterator it = { 0 }; + int j; + + set_test_hash(want_hash, 4); + + for (i = 0; i < N; i++) { + uint8_t hash[GIT_SHA1_RAWSZ]; + char fill[51] = { 0 }; + char name[100]; + struct reftable_ref_record ref = { 0 }; + + memset(hash, i, sizeof(hash)); + memset(fill, 'x', 50); + /* Put the variable part in the start */ + snprintf(name, sizeof(name), "br%02d%s", i, fill); + name[40] = 0; + ref.refname = name; + + ref.value_type = REFTABLE_REF_VAL2; + set_test_hash(ref.value.val2.value, i / 4); + set_test_hash(ref.value.val2.target_value, 3 + i / 4); + + /* 80 bytes / entry, so 3 entries per block. Yields 17 + */ + /* blocks. */ + n = reftable_writer_add_ref(w, &ref); + check_int(n, ==, 0); + + if (!memcmp(ref.value.val2.value, want_hash, GIT_SHA1_RAWSZ) || + !memcmp(ref.value.val2.target_value, want_hash, GIT_SHA1_RAWSZ)) + want_names[want_names_len++] = xstrdup(name); + } + + n = reftable_writer_close(w); + check_int(n, ==, 0); + + reftable_writer_free(w); + w = NULL; + + block_source_from_strbuf(&source, &buf); + + err = init_reader(&rd, &source, "file.ref"); + check(!err); + if (!indexed) + rd.obj_offsets.is_present = 0; + + reftable_reader_init_ref_iterator(&rd, &it); + err = reftable_iterator_seek_ref(&it, ""); + check(!err); + reftable_iterator_destroy(&it); + + err = reftable_reader_refs_for(&rd, &it, want_hash); + check(!err); + + for (j = 0; ; j++) { + int err = reftable_iterator_next_ref(&it, &ref); + check_int(err, >=, 0); + if (err > 0) + break; + check_int(j, <, want_names_len); + check_str(ref.refname, want_names[j]); + reftable_ref_record_release(&ref); + } + check_int(j, ==, want_names_len); + + strbuf_release(&buf); + free_names(want_names); + reftable_iterator_destroy(&it); + reader_close(&rd); +} + +static void t_table_refs_for_no_index(void) +{ + t_table_refs_for(0); +} + +static void t_table_refs_for_obj_index(void) +{ + t_table_refs_for(1); +} + +static void t_write_empty_table(void) +{ + struct reftable_write_options opts = { 0 }; + struct strbuf buf = STRBUF_INIT; + struct reftable_writer *w = + reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts); + struct reftable_block_source source = { 0 }; + struct reftable_reader *rd = NULL; + struct reftable_ref_record rec = { 0 }; + struct reftable_iterator it = { 0 }; + int err; + + reftable_writer_set_limits(w, 1, 1); + + err = reftable_writer_close(w); + check_int(err, ==, REFTABLE_EMPTY_TABLE_ERROR); + reftable_writer_free(w); + + check_int(buf.len, ==, header_size(1) + footer_size(1)); + + block_source_from_strbuf(&source, &buf); + + err = reftable_new_reader(&rd, &source, "filename"); + check(!err); + + reftable_reader_init_ref_iterator(rd, &it); + err = reftable_iterator_seek_ref(&it, ""); + check(!err); + + err = reftable_iterator_next_ref(&it, &rec); + check_int(err, >, 0); + + reftable_iterator_destroy(&it); + reftable_reader_free(rd); + strbuf_release(&buf); +} + +static void t_write_object_id_min_length(void) +{ + struct reftable_write_options opts = { + .block_size = 75, + }; + struct strbuf buf = STRBUF_INIT; + struct reftable_writer *w = + reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts); + struct reftable_ref_record ref = { + .update_index = 1, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = {42}, + }; + int err; + int i; + + reftable_writer_set_limits(w, 1, 1); + + /* Write the same hash in many refs. If there is only 1 hash, the + * disambiguating prefix is length 0 */ + for (i = 0; i < 256; i++) { + char name[256]; + snprintf(name, sizeof(name), "ref%05d", i); + ref.refname = name; + err = reftable_writer_add_ref(w, &ref); + check(!err); + } + + err = reftable_writer_close(w); + check(!err); + check_int(reftable_writer_stats(w)->object_id_len, ==, 2); + reftable_writer_free(w); + strbuf_release(&buf); +} + +static void t_write_object_id_length(void) +{ + struct reftable_write_options opts = { + .block_size = 75, + }; + struct strbuf buf = STRBUF_INIT; + struct reftable_writer *w = + reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts); + struct reftable_ref_record ref = { + .update_index = 1, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = {42}, + }; + int err; + int i; + + reftable_writer_set_limits(w, 1, 1); + + /* Write the same hash in many refs. If there is only 1 hash, the + * disambiguating prefix is length 0 */ + for (i = 0; i < 256; i++) { + char name[256]; + snprintf(name, sizeof(name), "ref%05d", i); + ref.refname = name; + ref.value.val1[15] = i; + err = reftable_writer_add_ref(w, &ref); + check(!err); + } + + err = reftable_writer_close(w); + check(!err); + check_int(reftable_writer_stats(w)->object_id_len, ==, 16); + reftable_writer_free(w); + strbuf_release(&buf); +} + +static void t_write_empty_key(void) +{ + struct reftable_write_options opts = { 0 }; + struct strbuf buf = STRBUF_INIT; + struct reftable_writer *w = + reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts); + struct reftable_ref_record ref = { + .refname = (char *) "", + .update_index = 1, + .value_type = REFTABLE_REF_DELETION, + }; + int err; + + reftable_writer_set_limits(w, 1, 1); + err = reftable_writer_add_ref(w, &ref); + check_int(err, ==, REFTABLE_API_ERROR); + + err = reftable_writer_close(w); + check_int(err, ==, REFTABLE_EMPTY_TABLE_ERROR); + reftable_writer_free(w); + strbuf_release(&buf); +} + +static void t_write_key_order(void) +{ + struct reftable_write_options opts = { 0 }; + struct strbuf buf = STRBUF_INIT; + struct reftable_writer *w = + reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts); + struct reftable_ref_record refs[2] = { + { + .refname = (char *) "b", + .update_index = 1, + .value_type = REFTABLE_REF_SYMREF, + .value = { + .symref = (char *) "target", + }, + }, { + .refname = (char *) "a", + .update_index = 1, + .value_type = REFTABLE_REF_SYMREF, + .value = { + .symref = (char *) "target", + }, + } + }; + int err; + + reftable_writer_set_limits(w, 1, 1); + err = reftable_writer_add_ref(w, &refs[0]); + check(!err); + err = reftable_writer_add_ref(w, &refs[1]); + check_int(err, ==, REFTABLE_API_ERROR); + + refs[0].update_index = 2; + err = reftable_writer_add_ref(w, &refs[0]); + check_int(err, ==, REFTABLE_API_ERROR); + + reftable_writer_close(w); + reftable_writer_free(w); + strbuf_release(&buf); +} + +static void t_write_multiple_indices(void) +{ + struct reftable_write_options opts = { + .block_size = 100, + }; + struct strbuf writer_buf = STRBUF_INIT, buf = STRBUF_INIT; + struct reftable_block_source source = { 0 }; + struct reftable_iterator it = { 0 }; + const struct reftable_stats *stats; + struct reftable_writer *writer; + struct reftable_reader *reader; + int err, i; + + writer = reftable_new_writer(&strbuf_add_void, &noop_flush, &writer_buf, &opts); + reftable_writer_set_limits(writer, 1, 1); + for (i = 0; i < 100; i++) { + struct reftable_ref_record ref = { + .update_index = 1, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = {i}, + }; + + strbuf_reset(&buf); + strbuf_addf(&buf, "refs/heads/%04d", i); + ref.refname = buf.buf, + + err = reftable_writer_add_ref(writer, &ref); + check(!err); + } + + for (i = 0; i < 100; i++) { + struct reftable_log_record log = { + .update_index = 1, + .value_type = REFTABLE_LOG_UPDATE, + .value.update = { + .old_hash = { i }, + .new_hash = { i }, + }, + }; + + strbuf_reset(&buf); + strbuf_addf(&buf, "refs/heads/%04d", i); + log.refname = buf.buf, + + err = reftable_writer_add_log(writer, &log); + check(!err); + } + + reftable_writer_close(writer); + + /* + * The written data should be sufficiently large to result in indices + * for each of the block types. + */ + stats = reftable_writer_stats(writer); + check_int(stats->ref_stats.index_offset, >, 0); + check_int(stats->obj_stats.index_offset, >, 0); + check_int(stats->log_stats.index_offset, >, 0); + + block_source_from_strbuf(&source, &writer_buf); + err = reftable_new_reader(&reader, &source, "filename"); + check(!err); + + /* + * Seeking the log uses the log index now. In case there is any + * confusion regarding indices we would notice here. + */ + reftable_reader_init_log_iterator(reader, &it); + err = reftable_iterator_seek_log(&it, ""); + check(!err); + + reftable_iterator_destroy(&it); + reftable_writer_free(writer); + reftable_reader_free(reader); + strbuf_release(&writer_buf); + strbuf_release(&buf); +} + +static void t_write_multi_level_index(void) +{ + struct reftable_write_options opts = { + .block_size = 100, + }; + struct strbuf writer_buf = STRBUF_INIT, buf = STRBUF_INIT; + struct reftable_block_source source = { 0 }; + struct reftable_iterator it = { 0 }; + const struct reftable_stats *stats; + struct reftable_writer *writer; + struct reftable_reader *reader; + int err; + + writer = reftable_new_writer(&strbuf_add_void, &noop_flush, &writer_buf, &opts); + reftable_writer_set_limits(writer, 1, 1); + for (size_t i = 0; i < 200; i++) { + struct reftable_ref_record ref = { + .update_index = 1, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = {i}, + }; + + strbuf_reset(&buf); + strbuf_addf(&buf, "refs/heads/%03" PRIuMAX, (uintmax_t)i); + ref.refname = buf.buf, + + err = reftable_writer_add_ref(writer, &ref); + check(!err); + } + reftable_writer_close(writer); + + /* + * The written refs should be sufficiently large to result in a + * multi-level index. + */ + stats = reftable_writer_stats(writer); + check_int(stats->ref_stats.max_index_level, ==, 2); + + block_source_from_strbuf(&source, &writer_buf); + err = reftable_new_reader(&reader, &source, "filename"); + check(!err); + + /* + * Seeking the last ref should work as expected. + */ + reftable_reader_init_ref_iterator(reader, &it); + err = reftable_iterator_seek_ref(&it, "refs/heads/199"); + check(!err); + + reftable_iterator_destroy(&it); + reftable_writer_free(writer); + reftable_reader_free(reader); + strbuf_release(&writer_buf); + strbuf_release(&buf); +} + +static void t_corrupt_table_empty(void) +{ + struct strbuf buf = STRBUF_INIT; + struct reftable_block_source source = { 0 }; + struct reftable_reader rd = { 0 }; + int err; + + block_source_from_strbuf(&source, &buf); + err = init_reader(&rd, &source, "file.log"); + check_int(err, ==, REFTABLE_FORMAT_ERROR); +} + +static void t_corrupt_table(void) +{ + uint8_t zeros[1024] = { 0 }; + struct strbuf buf = STRBUF_INIT; + struct reftable_block_source source = { 0 }; + struct reftable_reader rd = { 0 }; + int err; + strbuf_add(&buf, zeros, sizeof(zeros)); + + block_source_from_strbuf(&source, &buf); + err = init_reader(&rd, &source, "file.log"); + check_int(err, ==, REFTABLE_FORMAT_ERROR); + strbuf_release(&buf); +} + +int cmd_main(int argc UNUSED, const char *argv[] UNUSED) +{ + TEST(t_buffer(), "strbuf works as blocksource"); + TEST(t_corrupt_table(), "read-write on corrupted table"); + TEST(t_corrupt_table_empty(), "read-write on an empty table"); + TEST(t_log_buffer_size(), "buffer extension for log compression"); + TEST(t_log_overflow(), "log overflow returns expected error"); + TEST(t_log_write_read(), "read-write on log records"); + TEST(t_log_zlib_corruption(), "reading corrupted log record returns expected error"); + TEST(t_table_read_api(), "read on a table"); + TEST(t_table_read_write_seek_index(), "read-write on a table with index"); + TEST(t_table_read_write_seek_linear(), "read-write on a table without index (SHA1)"); + TEST(t_table_read_write_seek_linear_sha256(), "read-write on a table without index (SHA256)"); + TEST(t_table_read_write_sequential(), "sequential read-write on a table"); + TEST(t_table_refs_for_no_index(), "refs-only table with no index"); + TEST(t_table_refs_for_obj_index(), "refs-only table with index"); + TEST(t_table_write_small_table(), "write_table works"); + TEST(t_write_empty_key(), "write on refs with empty keys"); + TEST(t_write_empty_table(), "read-write on empty tables"); + TEST(t_write_key_order(), "refs must be written in increasing order"); + TEST(t_write_multi_level_index(), "table with multi-level index"); + TEST(t_write_multiple_indices(), "table with indices for multiple block types"); + TEST(t_write_object_id_length(), "prefix compression on writing refs"); + TEST(t_write_object_id_min_length(), "prefix compression on writing refs"); + + return test_done(); +} diff --git a/t/unit-tests/t-reftable-record.c b/t/unit-tests/t-reftable-record.c index cb649ee419..a7f67d4d9f 100644 --- a/t/unit-tests/t-reftable-record.c +++ b/t/unit-tests/t-reftable-record.c @@ -532,7 +532,7 @@ static void t_reftable_index_record_roundtrip(void) strbuf_release(&in.u.idx.last_key); } -int cmd_main(int argc, const char *argv[]) +int cmd_main(int argc UNUSED, const char *argv[] UNUSED) { TEST(t_reftable_ref_record_comparison(), "comparison operations work on ref record"); TEST(t_reftable_log_record_comparison(), "comparison operations work on log record"); diff --git a/t/unit-tests/t-reftable-tree.c b/t/unit-tests/t-reftable-tree.c index e7d774d774..700479d34b 100644 --- a/t/unit-tests/t-reftable-tree.c +++ b/t/unit-tests/t-reftable-tree.c @@ -75,7 +75,7 @@ static void t_infix_walk(void) tree_free(root); } -int cmd_main(int argc, const char *argv[]) +int cmd_main(int argc UNUSED, const char *argv[] UNUSED) { TEST(t_tree_search(), "tree_search works"); TEST(t_infix_walk(), "infix_walk works"); diff --git a/t/unit-tests/t-strbuf.c b/t/unit-tests/t-strbuf.c index 6027dafef7..3f4044d697 100644 --- a/t/unit-tests/t-strbuf.c +++ b/t/unit-tests/t-strbuf.c @@ -105,7 +105,7 @@ static void t_addstr(struct strbuf *buf, const void *data) check_str(buf->buf + orig_len, text); } -int cmd_main(int argc, const char **argv) +int cmd_main(int argc UNUSED, const char **argv UNUSED) { if (!TEST(t_static_init(), "static initialization works")) test_skip_all("STRBUF_INIT is broken"); diff --git a/t/unit-tests/t-strcmp-offset.c b/t/unit-tests/t-strcmp-offset.c index fe4c2706b1..6880f21161 100644 --- a/t/unit-tests/t-strcmp-offset.c +++ b/t/unit-tests/t-strcmp-offset.c @@ -24,7 +24,7 @@ static void check_strcmp_offset(const char *string1, const char *string2, expect_offset), \ "strcmp_offset(%s, %s) works", #string1, #string2) -int cmd_main(int argc, const char **argv) +int cmd_main(int argc UNUSED, const char **argv UNUSED) { TEST_STRCMP_OFFSET("abc", "abc", 0, 3); TEST_STRCMP_OFFSET("abc", "def", -1, 0); diff --git a/t/unit-tests/t-strvec.c b/t/unit-tests/t-strvec.c index c4bac8fc91..5c844cf0c9 100644 --- a/t/unit-tests/t-strvec.c +++ b/t/unit-tests/t-strvec.c @@ -19,7 +19,7 @@ } \ } while (0) -int cmd_main(int argc, const char **argv) +int cmd_main(int argc UNUSED, const char **argv UNUSED) { if_test ("static initialization") { struct strvec vec = STRVEC_INIT; diff --git a/t/unit-tests/t-trailer.c b/t/unit-tests/t-trailer.c index 2ecca359d9..e1c6ad7461 100644 --- a/t/unit-tests/t-trailer.c +++ b/t/unit-tests/t-trailer.c @@ -308,7 +308,7 @@ static void run_t_trailer_iterator(void) } } -int cmd_main(int argc, const char **argv) +int cmd_main(int argc UNUSED, const char **argv UNUSED) { run_t_trailer_iterator(); return test_done(); diff --git a/t/unit-tests/t-urlmatch-normalization.c b/t/unit-tests/t-urlmatch-normalization.c new file mode 100644 index 0000000000..1769c357b9 --- /dev/null +++ b/t/unit-tests/t-urlmatch-normalization.c @@ -0,0 +1,271 @@ +#include "test-lib.h" +#include "urlmatch.h" + +static void check_url_normalizable(const char *url, unsigned int normalizable) +{ + char *url_norm = url_normalize(url, NULL); + + if (!check_int(normalizable, ==, url_norm ? 1 : 0)) + test_msg("input url: %s", url); + free(url_norm); +} + +static void check_normalized_url(const char *url, const char *expect) +{ + char *url_norm = url_normalize(url, NULL); + + if (!check_str(url_norm, expect)) + test_msg("input url: %s", url); + free(url_norm); +} + +static void compare_normalized_urls(const char *url1, const char *url2, + unsigned int equal) +{ + char *url1_norm = url_normalize(url1, NULL); + char *url2_norm = url_normalize(url2, NULL); + + if (equal) { + if (!check_str(url1_norm, url2_norm)) + test_msg("input url1: %s\n input url2: %s", url1, + url2); + } else if (!check_int(strcmp(url1_norm, url2_norm), !=, 0)) { + test_msg(" normalized url1: %s\n normalized url2: %s\n" + " input url1: %s\n input url2: %s", + url1_norm, url2_norm, url1, url2); + } + free(url1_norm); + free(url2_norm); +} + +static void check_normalized_url_length(const char *url, size_t len) +{ + struct url_info info; + char *url_norm = url_normalize(url, &info); + + if (!check_int(info.url_len, ==, len)) + test_msg(" input url: %s\n normalized url: %s", url, + url_norm); + free(url_norm); +} + +/* Note that only "file:" URLs should be allowed without a host */ +static void t_url_scheme(void) +{ + check_url_normalizable("", 0); + check_url_normalizable("_", 0); + check_url_normalizable("scheme", 0); + check_url_normalizable("scheme:", 0); + check_url_normalizable("scheme:/", 0); + check_url_normalizable("scheme://", 0); + check_url_normalizable("file", 0); + check_url_normalizable("file:", 0); + check_url_normalizable("file:/", 0); + check_url_normalizable("file://", 1); + check_url_normalizable("://acme.co", 0); + check_url_normalizable("x_test://acme.co", 0); + check_url_normalizable("-test://acme.co", 0); + check_url_normalizable("0test://acme.co", 0); + check_url_normalizable("+test://acme.co", 0); + check_url_normalizable(".test://acme.co", 0); + check_url_normalizable("schem%6e://", 0); + check_url_normalizable("x-Test+v1.0://acme.co", 1); + check_normalized_url("AbCdeF://x.Y", "abcdef://x.y/"); +} + +static void t_url_authority(void) +{ + check_url_normalizable("scheme://user:pass@", 0); + check_url_normalizable("scheme://?", 0); + check_url_normalizable("scheme://#", 0); + check_url_normalizable("scheme:///", 0); + check_url_normalizable("scheme://:", 0); + check_url_normalizable("scheme://:555", 0); + check_url_normalizable("file://user:pass@", 1); + check_url_normalizable("file://?", 1); + check_url_normalizable("file://#", 1); + check_url_normalizable("file:///", 1); + check_url_normalizable("file://:", 1); + check_url_normalizable("file://:555", 0); + check_url_normalizable("scheme://user:pass@host", 1); + check_url_normalizable("scheme://@host", 1); + check_url_normalizable("scheme://%00@host", 1); + check_url_normalizable("scheme://%%@host", 0); + check_url_normalizable("scheme://host_", 1); + check_url_normalizable("scheme://user:pass@host/", 1); + check_url_normalizable("scheme://@host/", 1); + check_url_normalizable("scheme://host/", 1); + check_url_normalizable("scheme://host?x", 1); + check_url_normalizable("scheme://host#x", 1); + check_url_normalizable("scheme://host/@", 1); + check_url_normalizable("scheme://host?@x", 1); + check_url_normalizable("scheme://host#@x", 1); + check_url_normalizable("scheme://[::1]", 1); + check_url_normalizable("scheme://[::1]/", 1); + check_url_normalizable("scheme://hos%41/", 0); + check_url_normalizable("scheme://[invalid....:/", 1); + check_url_normalizable("scheme://invalid....:]/", 1); + check_url_normalizable("scheme://invalid....:[/", 0); + check_url_normalizable("scheme://invalid....:[", 0); +} + +static void t_url_port(void) +{ + check_url_normalizable("xyz://q@some.host:", 1); + check_url_normalizable("xyz://q@some.host:456/", 1); + check_url_normalizable("xyz://q@some.host:0", 0); + check_url_normalizable("xyz://q@some.host:0000000", 0); + check_url_normalizable("xyz://q@some.host:0000001?", 1); + check_url_normalizable("xyz://q@some.host:065535#", 1); + check_url_normalizable("xyz://q@some.host:65535", 1); + check_url_normalizable("xyz://q@some.host:65536", 0); + check_url_normalizable("xyz://q@some.host:99999", 0); + check_url_normalizable("xyz://q@some.host:100000", 0); + check_url_normalizable("xyz://q@some.host:100001", 0); + check_url_normalizable("http://q@some.host:80", 1); + check_url_normalizable("https://q@some.host:443", 1); + check_url_normalizable("http://q@some.host:80/", 1); + check_url_normalizable("https://q@some.host:443?", 1); + check_url_normalizable("http://q@:8008", 0); + check_url_normalizable("http://:8080", 0); + check_url_normalizable("http://:", 0); + check_url_normalizable("xyz://q@some.host:456/", 1); + check_url_normalizable("xyz://[::1]:456/", 1); + check_url_normalizable("xyz://[::1]:/", 1); + check_url_normalizable("xyz://[::1]:000/", 0); + check_url_normalizable("xyz://[::1]:0%300/", 0); + check_url_normalizable("xyz://[::1]:0x80/", 0); + check_url_normalizable("xyz://[::1]:4294967297/", 0); + check_url_normalizable("xyz://[::1]:030f/", 0); +} + +static void t_url_port_normalization(void) +{ + check_normalized_url("http://x:800", "http://x:800/"); + check_normalized_url("http://x:0800", "http://x:800/"); + check_normalized_url("http://x:00000800", "http://x:800/"); + check_normalized_url("http://x:065535", "http://x:65535/"); + check_normalized_url("http://x:1", "http://x:1/"); + check_normalized_url("http://x:80", "http://x/"); + check_normalized_url("http://x:080", "http://x/"); + check_normalized_url("http://x:000000080", "http://x/"); + check_normalized_url("https://x:443", "https://x/"); + check_normalized_url("https://x:0443", "https://x/"); + check_normalized_url("https://x:000000443", "https://x/"); +} + +static void t_url_general_escape(void) +{ + check_url_normalizable("http://x.y?%fg", 0); + check_normalized_url("X://W/%7e%41^%3a", "x://w/~A%5E%3A"); + check_normalized_url("X://W/:/?#[]@", "x://w/:/?#[]@"); + check_normalized_url("X://W/$&()*+,;=", "x://w/$&()*+,;="); + check_normalized_url("X://W/'", "x://w/'"); + check_normalized_url("X://W?!", "x://w/?!"); +} + +static void t_url_high_bit(void) +{ + check_normalized_url( + "x://q/\x01\x02\x03\x04\x05\x06\x07\x08\x0e\x0f\x10\x11\x12", + "x://q/%01%02%03%04%05%06%07%08%0E%0F%10%11%12"); + check_normalized_url( + "x://q/\x13\x14\x15\x16\x17\x18\x19\x1b\x1c\x1d\x1e\x1f\x7f", + "x://q/%13%14%15%16%17%18%19%1B%1C%1D%1E%1F%7F"); + check_normalized_url( + "x://q/\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f", + "x://q/%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F"); + check_normalized_url( + "x://q/\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f", + "x://q/%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F"); + check_normalized_url( + "x://q/\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf", + "x://q/%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF"); + check_normalized_url( + "x://q/\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf", + "x://q/%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF"); + check_normalized_url( + "x://q/\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf", + "x://q/%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF"); + check_normalized_url( + "x://q/\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf", + "x://q/%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF"); + check_normalized_url( + "x://q/\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef", + "x://q/%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF"); + check_normalized_url( + "x://q/\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + "x://q/%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF"); +} + +static void t_url_utf8_escape(void) +{ + check_normalized_url( + "x://q/\xc2\x80\xdf\xbf\xe0\xa0\x80\xef\xbf\xbd\xf0\x90\x80\x80\xf0\xaf\xbf\xbd", + "x://q/%C2%80%DF%BF%E0%A0%80%EF%BF%BD%F0%90%80%80%F0%AF%BF%BD"); +} + +static void t_url_username_pass(void) +{ + check_normalized_url("x://%41%62(^):%70+d@foo", "x://Ab(%5E):p+d@foo/"); +} + +static void t_url_length(void) +{ + check_normalized_url_length("Http://%4d%65:%4d^%70@The.Host", 25); + check_normalized_url_length("http://%41:%42@x.y/%61/", 17); + check_normalized_url_length("http://@x.y/^", 15); +} + +static void t_url_dots(void) +{ + check_normalized_url("x://y/.", "x://y/"); + check_normalized_url("x://y/./", "x://y/"); + check_normalized_url("x://y/a/.", "x://y/a"); + check_normalized_url("x://y/a/./", "x://y/a/"); + check_normalized_url("x://y/.?", "x://y/?"); + check_normalized_url("x://y/./?", "x://y/?"); + check_normalized_url("x://y/a/.?", "x://y/a?"); + check_normalized_url("x://y/a/./?", "x://y/a/?"); + check_normalized_url("x://y/a/./b/.././../c", "x://y/c"); + check_normalized_url("x://y/a/./b/../.././c/", "x://y/c/"); + check_normalized_url("x://y/a/./b/.././../c/././.././.", "x://y/"); + check_url_normalizable("x://y/a/./b/.././../c/././.././..", 0); + check_normalized_url("x://y/a/./?/././..", "x://y/a/?/././.."); + check_normalized_url("x://y/%2e/", "x://y/"); + check_normalized_url("x://y/%2E/", "x://y/"); + check_normalized_url("x://y/a/%2e./", "x://y/"); + check_normalized_url("x://y/b/.%2E/", "x://y/"); + check_normalized_url("x://y/c/%2e%2E/", "x://y/"); +} + +/* + * "http://@foo" specifies an empty user name but does not specify a password. + * "http://foo" specifies neither a user name nor a password. + * So they should not be equivalent. + */ +static void t_url_equivalents(void) +{ + compare_normalized_urls("httP://x", "Http://X/", 1); + compare_normalized_urls("Http://%4d%65:%4d^%70@The.Host", "hTTP://Me:%4D^p@the.HOST:80/", 1); + compare_normalized_urls("https://@x.y/^", "httpS://x.y:443/^", 0); + compare_normalized_urls("https://@x.y/^", "httpS://@x.y:0443/^", 1); + compare_normalized_urls("https://@x.y/^/../abc", "httpS://@x.y:0443/abc", 1); + compare_normalized_urls("https://@x.y/^/..", "httpS://@x.y:0443/", 1); +} + +int cmd_main(int argc UNUSED, const char **argv UNUSED) +{ + TEST(t_url_scheme(), "url scheme"); + TEST(t_url_authority(), "url authority"); + TEST(t_url_port(), "url port checks"); + TEST(t_url_port_normalization(), "url port normalization"); + TEST(t_url_general_escape(), "url general escapes"); + TEST(t_url_high_bit(), "url high-bit escapes"); + TEST(t_url_utf8_escape(), "url utf8 escapes"); + TEST(t_url_username_pass(), "url username/password escapes"); + TEST(t_url_length(), "url normalized lengths"); + TEST(t_url_dots(), "url . and .. segments"); + TEST(t_url_equivalents(), "url equivalents"); + return test_done(); +} |
