diff options
Diffstat (limited to 't')
170 files changed, 5143 insertions, 1468 deletions
@@ -32,6 +32,13 @@ the tests. ok 2 - plain with GIT_WORK_TREE ok 3 - plain bare +t/Makefile defines a target for each test file, such that you can also use +shell pattern matching to run a subset of the tests: + + make *checkout* + +will run all tests with 'checkout' in their filename. + Since the tests all output TAP (see https://testanything.org) they can be run with any TAP harness. Here's an example of parallel testing powered by a recent version of prove(1): @@ -724,6 +731,26 @@ The "do's:" Note that we still &&-chain the loop to propagate failures from earlier commands. + - Repeat tests with slightly different arguments in a loop. + + In some cases it may make sense to re-run the same set of tests with + different options or commands to ensure that the command behaves + despite the different parameters. This can be achieved by looping + around a specific parameter: + + for arg in '' "--foo" + do + test_expect_success "test command ${arg:-without arguments}" ' + command $arg + ' + done + + Note that while the test title uses double quotes ("), the test body + should continue to use single quotes (') to avoid breakage in case the + values contain e.g. quoting characters. The loop variable will be + accessible regardless of the single quotes as the test body is passed + to `eval`. + And here are the "don'ts:" diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh index 5e21e84f38..87572459e4 100644 --- a/t/annotate-tests.sh +++ b/t/annotate-tests.sh @@ -532,7 +532,7 @@ test_expect_success 'blame -L :funcname with userdiff driver' ' "$(cat file.template)" && test_commit --author "B <B@test.git>" \ "change" "$fortran_file" \ - "$(cat file.template | sed -e s/ChangeMe/IWasChanged/)" && + "$(sed -e s/ChangeMe/IWasChanged/ file.template)" && check_count -f "$fortran_file" -L:RIGHT A 3 B 1 ' diff --git a/t/check-non-portable-shell.pl b/t/check-non-portable-shell.pl index dd8107cd7d..b2b28c2ced 100755 --- a/t/check-non-portable-shell.pl +++ b/t/check-non-portable-shell.pl @@ -47,6 +47,8 @@ while (<>) { /\bgrep\b.*--file\b/ and err 'grep --file FILE is not portable (use grep -f FILE)'; /\b[ef]grep\b/ and err 'egrep/fgrep obsolescent (use grep -E/-F)'; /\bexport\s+[A-Za-z0-9_]*=/ and err '"export FOO=bar" is not portable (use FOO=bar && export FOO)'; + /\blocal\s+[A-Za-z0-9_]*=\$([A-Za-z0-9_{]|[(][^(])/ and + err q(quote "$val" in 'local var=$val'); /^\s*([A-Z0-9_]+=(\w*|(["']).*?\3)\s+)+(\w+)/ and exists($func{$4}) and err '"FOO=bar shell_func" assignment extends beyond "shell_func"'; $line = ''; diff --git a/t/helper/test-date.c b/t/helper/test-date.c index 0683d46574..f25512de9a 100644 --- a/t/helper/test-date.c +++ b/t/helper/test-date.c @@ -52,7 +52,7 @@ static void show_dates(const char **argv, const char *format) arg++; tz = atoi(arg); - printf("%s -> %s\n", *argv, show_date(t, tz, &mode)); + printf("%s -> %s\n", *argv, show_date(t, tz, mode)); } date_mode_release(&mode); diff --git a/t/helper/test-delete-gpgsig.c b/t/helper/test-delete-gpgsig.c new file mode 100644 index 0000000000..e36831af03 --- /dev/null +++ b/t/helper/test-delete-gpgsig.c @@ -0,0 +1,62 @@ +#include "test-tool.h" +#include "gpg-interface.h" +#include "strbuf.h" + + +int cmd__delete_gpgsig(int argc, const char **argv) +{ + struct strbuf buf = STRBUF_INIT; + const char *pattern = "gpgsig"; + const char *bufptr, *tail, *eol; + int deleting = 0; + size_t plen; + + if (argc >= 2) { + pattern = argv[1]; + argv++; + argc--; + } + + plen = strlen(pattern); + strbuf_read(&buf, 0, 0); + + if (!strcmp(pattern, "trailer")) { + size_t payload_size = parse_signed_buffer(buf.buf, buf.len); + fwrite(buf.buf, 1, payload_size, stdout); + fflush(stdout); + return 0; + } + + bufptr = buf.buf; + tail = bufptr + buf.len; + + while (bufptr < tail) { + /* Find the end of the line */ + eol = memchr(bufptr, '\n', tail - bufptr); + if (!eol) + eol = tail; + + /* Drop continuation lines */ + if (deleting && (bufptr < eol) && (bufptr[0] == ' ')) { + bufptr = eol + 1; + continue; + } + deleting = 0; + + /* Does the line match the prefix? */ + if (((bufptr + plen) < eol) && + !memcmp(bufptr, pattern, plen) && + (bufptr[plen] == ' ')) { + deleting = 1; + bufptr = eol + 1; + continue; + } + + /* Print all other lines */ + fwrite(bufptr, 1, (eol - bufptr) + 1, stdout); + bufptr = eol + 1; + } + fflush(stdout); + + return 0; +} diff --git a/t/helper/test-reach.c b/t/helper/test-reach.c index 1e159a754d..1e3b431e3e 100644 --- a/t/helper/test-reach.c +++ b/t/helper/test-reach.c @@ -111,13 +111,16 @@ int cmd__reach(int ac, const char **av) repo_in_merge_bases(the_repository, A, B)); else if (!strcmp(av[1], "in_merge_bases_many")) printf("%s(A,X):%d\n", av[1], - repo_in_merge_bases_many(the_repository, A, X_nr, X_array)); + 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_merge_bases_many")) { - struct commit_list *list = repo_get_merge_bases_many(the_repository, - A, X_nr, - X_array); + struct commit_list *list = NULL; + if (repo_get_merge_bases_many(the_repository, + A, X_nr, + X_array, + &list) < 0) + exit(128); printf("%s(A,X):\n", av[1]); print_sorted_commit_ids(list); } else if (!strcmp(av[1], "reduce_heads")) { diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c index 702ec1f128..82bbf6e2e6 100644 --- a/t/helper/test-ref-store.c +++ b/t/helper/test-ref-store.c @@ -112,25 +112,6 @@ static const char **get_store(const char **argv, struct ref_store **refs) return argv + 1; } -static struct flag_definition pack_flags[] = { FLAG_DEF(PACK_REFS_PRUNE), - FLAG_DEF(PACK_REFS_ALL), - { NULL, 0 } }; - -static int cmd_pack_refs(struct ref_store *refs, const char **argv) -{ - unsigned int flags = arg_flags(*argv++, "flags", pack_flags); - static struct ref_exclusions exclusions = REF_EXCLUSIONS_INIT; - static struct string_list included_refs = STRING_LIST_INIT_NODUP; - struct pack_refs_opts pack_opts = { .flags = flags, - .exclusions = &exclusions, - .includes = &included_refs }; - - if (pack_opts.flags & PACK_REFS_ALL) - string_list_append(pack_opts.includes, "*"); - - return refs_pack_refs(refs, &pack_opts); -} - static int cmd_create_symref(struct ref_store *refs, const char **argv) { const char *refname = notnull(*argv++, "refname"); @@ -221,15 +202,21 @@ static int cmd_verify_ref(struct ref_store *refs, const char **argv) return ret; } +static int each_reflog(const char *refname, void *cb_data UNUSED) +{ + printf("%s\n", refname); + return 0; +} + static int cmd_for_each_reflog(struct ref_store *refs, const char **argv UNUSED) { - return refs_for_each_reflog(refs, each_ref, NULL); + return refs_for_each_reflog(refs, each_reflog, NULL); } -static int each_reflog(struct object_id *old_oid, struct object_id *new_oid, - const char *committer, timestamp_t timestamp, - int tz, const char *msg, void *cb_data UNUSED) +static int each_reflog_ent(struct object_id *old_oid, struct object_id *new_oid, + const char *committer, timestamp_t timestamp, + int tz, const char *msg, void *cb_data UNUSED) { printf("%s %s %s %" PRItime " %+05d%s%s", oid_to_hex(old_oid), oid_to_hex(new_oid), committer, timestamp, tz, @@ -241,14 +228,14 @@ static int cmd_for_each_reflog_ent(struct ref_store *refs, const char **argv) { const char *refname = notnull(*argv++, "refname"); - return refs_for_each_reflog_ent(refs, refname, each_reflog, refs); + return refs_for_each_reflog_ent(refs, refname, each_reflog_ent, refs); } static int cmd_for_each_reflog_ent_reverse(struct ref_store *refs, const char **argv) { const char *refname = notnull(*argv++, "refname"); - return refs_for_each_reflog_ent_reverse(refs, refname, each_reflog, refs); + return refs_for_each_reflog_ent_reverse(refs, refname, each_reflog_ent, refs); } static int cmd_reflog_exists(struct ref_store *refs, const char **argv) @@ -320,7 +307,6 @@ struct command { }; static struct command commands[] = { - { "pack-refs", cmd_pack_refs }, { "create-symref", cmd_create_symref }, { "delete-refs", cmd_delete_refs }, { "rename-ref", cmd_rename_ref }, diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c index 482a1e58a4..80a946b847 100644 --- a/t/helper/test-tool.c +++ b/t/helper/test-tool.c @@ -20,6 +20,7 @@ static struct test_cmd cmds[] = { { "crontab", cmd__crontab }, { "csprng", cmd__csprng }, { "date", cmd__date }, + { "delete-gpgsig", cmd__delete_gpgsig }, { "delta", cmd__delta }, { "dir-iterator", cmd__dir_iterator }, { "drop-caches", cmd__drop_caches }, diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h index b1be7cfcf5..2808b92419 100644 --- a/t/helper/test-tool.h +++ b/t/helper/test-tool.h @@ -14,6 +14,7 @@ int cmd__crontab(int argc, const char **argv); int cmd__csprng(int argc, const char **argv); int cmd__date(int argc, const char **argv); int cmd__delta(int argc, const char **argv); +int cmd__delete_gpgsig(int argc, const char **argv); int cmd__dir_iterator(int argc, const char **argv); int cmd__drop_caches(int argc, const char **argv); int cmd__dump_cache_tree(int argc, const char **argv); diff --git a/t/lib-credential.sh b/t/lib-credential.sh index 15fc9a31e2..44799c0d38 100644 --- a/t/lib-credential.sh +++ b/t/lib-credential.sh @@ -50,6 +50,7 @@ helper_test_clean() { reject $1 https example.com user-overwrite reject $1 https example.com user-erase1 reject $1 https example.com user-erase2 + reject $1 https victim.example.com user reject $1 http path.tld user reject $1 https timeout.tld user reject $1 https sso.tld diff --git a/t/lib-cvs.sh b/t/lib-cvs.sh index 32b3473379..57b9b2db9b 100644 --- a/t/lib-cvs.sh +++ b/t/lib-cvs.sh @@ -71,8 +71,8 @@ test_cmp_branch_tree () { find . -type d -name .git -prune -o -type f -print ) | sort >module-git-"$1".list && test_cmp module-cvs-"$1".list module-git-"$1".list && - cat module-cvs-"$1".list | while read f + while read f do test_cmp_branch_file "$1" "$f" || return 1 - done + done <module-cvs-"$1".list } diff --git a/t/lib-parallel-checkout.sh b/t/lib-parallel-checkout.sh index acaee9cbb6..8324d6c96d 100644 --- a/t/lib-parallel-checkout.sh +++ b/t/lib-parallel-checkout.sh @@ -20,7 +20,7 @@ test_checkout_workers () { BUG "too few arguments to test_checkout_workers" fi && - local expected_workers=$1 && + local expected_workers="$1" && shift && local trace_file=trace-test-checkout-workers && diff --git a/t/oid-info/hash-info b/t/oid-info/hash-info index d0736dd1a0..b8a5bcb187 100644 --- a/t/oid-info/hash-info +++ b/t/oid-info/hash-info @@ -15,3 +15,15 @@ empty_blob sha256:473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a3037218 empty_tree sha1:4b825dc642cb6eb9a060e54bf8d69288fbee4904 empty_tree sha256:6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321 + +blob17_1 sha1:263 +blob17_1 sha256:34 + +blob17_2 sha1:410 +blob17_2 sha256:174 + +blob17_3 sha1:523 +blob17_3 sha256:313 + +blob17_4 sha1:790 +blob17_4 sha256:481 diff --git a/t/perf/repos/inflate-repo.sh b/t/perf/repos/inflate-repo.sh index fcfc992b5b..412e4b450b 100755 --- a/t/perf/repos/inflate-repo.sh +++ b/t/perf/repos/inflate-repo.sh @@ -33,7 +33,7 @@ do done git ls-tree -r HEAD >GEN_src_list -nr_src_files=$(cat GEN_src_list | wc -l) +nr_src_files=$(wc -l <GEN_src_list) src_branch=$(git symbolic-ref --short HEAD) diff --git a/t/t0002-gitfile.sh b/t/t0002-gitfile.sh index 736516cc6a..bf3bf604ab 100755 --- a/t/t0002-gitfile.sh +++ b/t/t0002-gitfile.sh @@ -40,7 +40,7 @@ test_expect_success 'final setup + check rev-parse --git-dir' ' test_expect_success 'check hash-object' ' echo "foo" >bar && - SHA=$(cat bar | git hash-object -w --stdin) && + SHA=$(git hash-object -w --stdin <bar) && test_path_is_file "$REAL/objects/$(objpath $SHA)" ' diff --git a/t/t0006-date.sh b/t/t0006-date.sh index e18b160286..3031256d14 100755 --- a/t/t0006-date.sh +++ b/t/t0006-date.sh @@ -46,6 +46,7 @@ check_show () { TIME='1466000000 +0200' check_show iso8601 "$TIME" '2016-06-15 16:13:20 +0200' check_show iso8601-strict "$TIME" '2016-06-15T16:13:20+02:00' +check_show iso8601-strict "$(echo "$TIME" | sed 's/+0200$/+0000/')" '2016-06-15T14:13:20Z' check_show rfc2822 "$TIME" 'Wed, 15 Jun 2016 16:13:20 +0200' check_show short "$TIME" '2016-06-15' check_show default "$TIME" 'Wed Jun 15 16:13:20 2016 +0200' @@ -69,6 +70,14 @@ check_show 'format:%s' '123456789 +1234' 123456789 check_show 'format:%s' '123456789 -1234' 123456789 check_show 'format-local:%s' '123456789 -1234' 123456789 +# negative TZ offset +TIME='1466000000 -0200' +check_show iso8601 "$TIME" '2016-06-15 12:13:20 -0200' +check_show iso8601-strict "$TIME" '2016-06-15T12:13:20-02:00' +check_show rfc2822 "$TIME" 'Wed, 15 Jun 2016 12:13:20 -0200' +check_show default "$TIME" 'Wed Jun 15 12:13:20 2016 -0200' +check_show raw "$TIME" '1466000000 -0200' + # arbitrary time absurdly far in the future FUTURE="5758122296 -0400" check_show iso "$FUTURE" "2152-06-19 18:24:56 -0400" TIME_IS_64BIT,TIME_T_IS_64BIT diff --git a/t/t0010-racy-git.sh b/t/t0010-racy-git.sh index 837c8b7228..84172a3739 100755 --- a/t/t0010-racy-git.sh +++ b/t/t0010-racy-git.sh @@ -10,25 +10,24 @@ TEST_PASSES_SANITIZE_LEAK=true for trial in 0 1 2 3 4 do - rm -f .git/index - echo frotz >infocom - git update-index --add infocom - echo xyzzy >infocom - - files=$(git diff-files -p) - test_expect_success \ - "Racy GIT trial #$trial part A" \ - 'test "" != "$files"' - + test_expect_success "Racy git trial #$trial part A" ' + rm -f .git/index && + echo frotz >infocom && + git update-index --add infocom && + echo xyzzy >infocom && + + git diff-files -p >out && + test_file_not_empty out + ' sleep 1 - echo xyzzy >cornerstone - git update-index --add cornerstone - files=$(git diff-files -p) - test_expect_success \ - "Racy GIT trial #$trial part B" \ - 'test "" != "$files"' + test_expect_success "Racy git trial #$trial part B" ' + echo xyzzy >cornerstone && + git update-index --add cornerstone && + git diff-files -p >out && + test_file_not_empty out + ' done test_done diff --git a/t/t0011-hashmap.sh b/t/t0011-hashmap.sh index 1cb6aa6824..46e74ad107 100755 --- a/t/t0011-hashmap.sh +++ b/t/t0011-hashmap.sh @@ -239,7 +239,7 @@ test_expect_success 'grow / shrink' ' echo value40 >> expect && echo size >> in && echo 64 39 >> expect && - cat in | test-tool hashmap > out && + test-tool hashmap <in >out && test_cmp expect out ' diff --git a/t/t0028-working-tree-encoding.sh b/t/t0028-working-tree-encoding.sh index 1b55f59c23..ad151a3467 100755 --- a/t/t0028-working-tree-encoding.sh +++ b/t/t0028-working-tree-encoding.sh @@ -131,8 +131,8 @@ do test_when_finished "rm -f crlf.utf${i}.raw lf.utf${i}.raw" && test_when_finished "git reset --hard HEAD^" && - cat lf.utf8.raw | write_utf${i} >lf.utf${i}.raw && - cat crlf.utf8.raw | write_utf${i} >crlf.utf${i}.raw && + write_utf${i} <lf.utf8.raw >lf.utf${i}.raw && + write_utf${i} <crlf.utf8.raw >crlf.utf${i}.raw && cp crlf.utf${i}.raw eol.utf${i} && cat >expectIndexLF <<-EOF && diff --git a/t/t0030-stripspace.sh b/t/t0030-stripspace.sh index d1b3be8725..f10f42ff1e 100755 --- a/t/t0030-stripspace.sh +++ b/t/t0030-stripspace.sh @@ -401,6 +401,21 @@ test_expect_success 'strip comments with changed comment char' ' test -z "$(echo "; comment" | git -c core.commentchar=";" stripspace -s)" ' +test_expect_success 'strip comments with changed comment string' ' + test ! -z "$(echo "// comment" | git -c core.commentchar=// stripspace)" && + test -z "$(echo "// comment" | git -c core.commentchar="//" stripspace -s)" +' + +test_expect_success 'newline as commentchar is forbidden' ' + test_must_fail git -c core.commentChar="$LF" stripspace -s 2>err && + grep "core.commentchar cannot contain newline" err +' + +test_expect_success 'empty commentchar is forbidden' ' + test_must_fail git -c core.commentchar= stripspace -s 2>err && + grep "core.commentchar must have at least one character" err +' + test_expect_success '-c with single line' ' printf "# foo\n" >expect && printf "foo" | git stripspace -c >actual && diff --git a/t/t0035-safe-bare-repository.sh b/t/t0035-safe-bare-repository.sh index 8048856379..d3cb2a1cb9 100755 --- a/t/t0035-safe-bare-repository.sh +++ b/t/t0035-safe-bare-repository.sh @@ -29,9 +29,20 @@ expect_rejected () { grep -F "implicit-bare-repository:$pwd" "$pwd/trace.perf" } -test_expect_success 'setup bare repo in worktree' ' +test_expect_success 'setup an embedded bare repo, secondary worktree and submodule' ' git init outer-repo && - git init --bare outer-repo/bare-repo + git init --bare --initial-branch=main outer-repo/bare-repo && + git -C outer-repo worktree add ../outer-secondary && + test_path_is_dir outer-secondary && + ( + cd outer-repo && + test_commit A && + git push bare-repo +HEAD:refs/heads/main && + git -c protocol.file.allow=always \ + submodule add --name subn -- ./bare-repo subd + ) && + test_path_is_dir outer-repo/.git/worktrees/outer-secondary && + test_path_is_dir outer-repo/.git/modules/subn ' test_expect_success 'safe.bareRepository unset' ' @@ -53,8 +64,7 @@ test_expect_success 'safe.bareRepository in the repository' ' # safe.bareRepository must not be "explicit", otherwise # git config fails with "fatal: not in a git directory" (like # safe.directory) - test_config -C outer-repo/bare-repo safe.bareRepository \ - all && + test_config -C outer-repo/bare-repo safe.bareRepository all && test_config_global safe.bareRepository explicit && expect_rejected -C outer-repo/bare-repo ' @@ -86,4 +96,12 @@ test_expect_success 'no trace when "bare repository" is a subdir of .git' ' expect_accepted_implicit -C outer-repo/.git/objects ' +test_expect_success 'no trace in $GIT_DIR of secondary worktree' ' + expect_accepted_implicit -C outer-repo/.git/worktrees/outer-secondary +' + +test_expect_success 'no trace in $GIT_DIR of a submodule' ' + expect_accepted_implicit -C outer-repo/.git/modules/subn +' + test_done diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index ec974867e4..8bb2a8b453 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -210,6 +210,22 @@ test_expect_success 'superfluous value provided: boolean' ' test_cmp expect actual ' +test_expect_success 'superfluous value provided: boolean, abbreviated' ' + cat >expect <<-\EOF && + error: option `yes'\'' takes no value + EOF + test_expect_code 129 env GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=false \ + test-tool parse-options --ye=hi 2>actual && + test_cmp expect actual && + + cat >expect <<-\EOF && + error: option `no-yes'\'' takes no value + EOF + test_expect_code 129 env GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=false \ + test-tool parse-options --no-ye=hi 2>actual && + test_cmp expect actual +' + test_expect_success 'superfluous value provided: cmdmode' ' cat >expect <<-\EOF && error: option `mode1'\'' takes no value diff --git a/t/t0204-gettext-reencode-sanity.sh b/t/t0204-gettext-reencode-sanity.sh index 4f2e0dcb02..310a450012 100755 --- a/t/t0204-gettext-reencode-sanity.sh +++ b/t/t0204-gettext-reencode-sanity.sh @@ -82,7 +82,7 @@ test_expect_success GETTEXT_ISO_LOCALE 'gettext.c: git init UTF-8 -> ISO-8859-1' printf "Bjó til tóma Git lind" >expect && LANGUAGE=is LC_ALL="$is_IS_iso_locale" git init repo >actual && test_when_finished "rm -rf repo" && - grep "^$(cat expect | iconv -f UTF-8 -t ISO8859-1) " actual + grep "^$(iconv -f UTF-8 -t ISO8859-1 <expect) " actual ' test_done diff --git a/t/t0211-trace2-perf.sh b/t/t0211-trace2-perf.sh index 290b6eaaab..13ef69b92f 100755 --- a/t/t0211-trace2-perf.sh +++ b/t/t0211-trace2-perf.sh @@ -287,4 +287,235 @@ test_expect_success 'unsafe URLs are redacted by default' ' grep "d0|main|def_param|.*|remote.origin.url:https://user:pwd@example.com" actual ' +# Confirm that the requested command produces a "cmd_name" and a +# set of "def_param" events. +# +try_simple () { + test_when_finished "rm prop.perf actual" && + + cmd=$1 && + cmd_name=$2 && + + test_config_global "trace2.configParams" "cfg.prop.*" && + test_config_global "trace2.envvars" "ENV_PROP_FOO,ENV_PROP_BAR" && + + test_config_global "cfg.prop.foo" "red" && + + ENV_PROP_FOO=blue \ + GIT_TRACE2_PERF="$(pwd)/prop.perf" \ + $cmd && + perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <prop.perf >actual && + grep "d0|main|cmd_name|.*|$cmd_name" actual && + grep "d0|main|def_param|.*|cfg.prop.foo:red" actual && + grep "d0|main|def_param|.*|ENV_PROP_FOO:blue" actual +} + +# Representative mainstream builtin Git command dispatched +# in run_builtin() in git.c +# +test_expect_success 'expect def_params for normal builtin command' ' + try_simple "git version" "version" +' + +# Representative query command dispatched in handle_options() +# in git.c +# +test_expect_success 'expect def_params for query command' ' + try_simple "git --man-path" "_query_" +' + +# remote-curl.c does not use the builtin setup in git.c, so confirm +# that executables built from remote-curl.c emit def_params. +# +# Also tests the dashed-command handling where "git foo" silently +# spawns "git-foo". Make sure that both commands should emit +# def_params. +# +# Pass bogus arguments to remote-https and allow the command to fail +# because we don't actually have a remote to fetch from. We just want +# to see the run-dashed code run an executable built from +# remote-curl.c rather than git.c. Confirm that we get def_param +# events from both layers. +# +test_expect_success 'expect def_params for remote-curl and _run_dashed_' ' + test_when_finished "rm prop.perf actual" && + + test_config_global "trace2.configParams" "cfg.prop.*" && + test_config_global "trace2.envvars" "ENV_PROP_FOO,ENV_PROP_BAR" && + + test_config_global "cfg.prop.foo" "red" && + + test_might_fail env \ + ENV_PROP_FOO=blue \ + GIT_TRACE2_PERF="$(pwd)/prop.perf" \ + git remote-http x y && + + perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <prop.perf >actual && + + grep "d0|main|cmd_name|.*|_run_dashed_" actual && + grep "d0|main|def_param|.*|cfg.prop.foo:red" actual && + grep "d0|main|def_param|.*|ENV_PROP_FOO:blue" actual && + + grep "d1|main|cmd_name|.*|remote-curl" actual && + grep "d1|main|def_param|.*|cfg.prop.foo:red" actual && + grep "d1|main|def_param|.*|ENV_PROP_FOO:blue" actual +' + +# Similarly, `git-http-fetch` is not built from git.c so do a +# trivial fetch so that the main git.c run-dashed code spawns +# an executable built from http-fetch.c. Confirm that we get +# def_param events from both layers. +# +test_expect_success 'expect def_params for http-fetch and _run_dashed_' ' + test_when_finished "rm prop.perf actual" && + + test_config_global "trace2.configParams" "cfg.prop.*" && + test_config_global "trace2.envvars" "ENV_PROP_FOO,ENV_PROP_BAR" && + + test_config_global "cfg.prop.foo" "red" && + + test_might_fail env \ + ENV_PROP_FOO=blue \ + GIT_TRACE2_PERF="$(pwd)/prop.perf" \ + git http-fetch --stdin file:/// <<-EOF && + EOF + + perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <prop.perf >actual && + + grep "d0|main|cmd_name|.*|_run_dashed_" actual && + grep "d0|main|def_param|.*|cfg.prop.foo:red" actual && + grep "d0|main|def_param|.*|ENV_PROP_FOO:blue" actual && + + grep "d1|main|cmd_name|.*|http-fetch" actual && + grep "d1|main|def_param|.*|cfg.prop.foo:red" actual && + grep "d1|main|def_param|.*|ENV_PROP_FOO:blue" actual +' + +# Historically, alias expansion explicitly emitted the def_param +# events (independent of whether the command was a builtin, a Git +# command or arbitrary shell command) so that it wasn't dependent +# upon the unpeeling of the alias. Let's make sure that we preserve +# the net effect. +# +test_expect_success 'expect def_params during git alias expansion' ' + test_when_finished "rm prop.perf actual" && + + test_config_global "trace2.configParams" "cfg.prop.*" && + test_config_global "trace2.envvars" "ENV_PROP_FOO,ENV_PROP_BAR" && + + test_config_global "cfg.prop.foo" "red" && + + test_config_global "alias.xxx" "version" && + + ENV_PROP_FOO=blue \ + GIT_TRACE2_PERF="$(pwd)/prop.perf" \ + git xxx && + + perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <prop.perf >actual && + + # "git xxx" is first mapped to "git-xxx" and the child will fail. + grep "d0|main|cmd_name|.*|_run_dashed_ (_run_dashed_)" actual && + + # We unpeel that and substitute "version" into "xxx" (giving + # "git version") and update the cmd_name event. + grep "d0|main|cmd_name|.*|_run_git_alias_ (_run_dashed_/_run_git_alias_)" actual && + + # These def_param events could be associated with either of the + # above cmd_name events. It does not matter. + grep "d0|main|def_param|.*|cfg.prop.foo:red" actual && + grep "d0|main|def_param|.*|ENV_PROP_FOO:blue" actual && + + # The "git version" child sees a different cmd_name hierarchy. + # Also test the def_param (only for completeness). + grep "d1|main|cmd_name|.*|version (_run_dashed_/_run_git_alias_/version)" actual && + grep "d1|main|def_param|.*|cfg.prop.foo:red" actual && + grep "d1|main|def_param|.*|ENV_PROP_FOO:blue" actual +' + +test_expect_success 'expect def_params during shell alias expansion' ' + test_when_finished "rm prop.perf actual" && + + test_config_global "trace2.configParams" "cfg.prop.*" && + test_config_global "trace2.envvars" "ENV_PROP_FOO,ENV_PROP_BAR" && + + test_config_global "cfg.prop.foo" "red" && + + test_config_global "alias.xxx" "!git version" && + + ENV_PROP_FOO=blue \ + GIT_TRACE2_PERF="$(pwd)/prop.perf" \ + git xxx && + + perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <prop.perf >actual && + + # "git xxx" is first mapped to "git-xxx" and the child will fail. + grep "d0|main|cmd_name|.*|_run_dashed_ (_run_dashed_)" actual && + + # We unpeel that and substitute "git version" for "git xxx" (as a + # shell command. Another cmd_name event is emitted as we unpeel. + grep "d0|main|cmd_name|.*|_run_shell_alias_ (_run_dashed_/_run_shell_alias_)" actual && + + # These def_param events could be associated with either of the + # above cmd_name events. It does not matter. + grep "d0|main|def_param|.*|cfg.prop.foo:red" actual && + grep "d0|main|def_param|.*|ENV_PROP_FOO:blue" actual && + + # We get the following only because we used a git command for the + # shell command. In general, it could have been a shell script and + # we would see nothing. + # + # The child knows the cmd_name hierarchy so it includes it. + grep "d1|main|cmd_name|.*|version (_run_dashed_/_run_shell_alias_/version)" actual && + grep "d1|main|def_param|.*|cfg.prop.foo:red" actual && + grep "d1|main|def_param|.*|ENV_PROP_FOO:blue" actual +' + +test_expect_success 'expect def_params during nested git alias expansion' ' + test_when_finished "rm prop.perf actual" && + + test_config_global "trace2.configParams" "cfg.prop.*" && + test_config_global "trace2.envvars" "ENV_PROP_FOO,ENV_PROP_BAR" && + + test_config_global "cfg.prop.foo" "red" && + + test_config_global "alias.xxx" "yyy" && + test_config_global "alias.yyy" "version" && + + ENV_PROP_FOO=blue \ + GIT_TRACE2_PERF="$(pwd)/prop.perf" \ + git xxx && + + perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <prop.perf >actual && + + # "git xxx" is first mapped to "git-xxx" and try to spawn "git-xxx" + # and the child will fail. + grep "d0|main|cmd_name|.*|_run_dashed_ (_run_dashed_)" actual && + grep "d0|main|child_start|.*|.* class:dashed argv:\[git-xxx\]" actual && + + # We unpeel that and substitute "yyy" into "xxx" (giving "git yyy") + # and spawn "git-yyy" and the child will fail. + grep "d0|main|alias|.*|alias:xxx argv:\[yyy\]" actual && + grep "d0|main|cmd_name|.*|_run_dashed_ (_run_dashed_/_run_dashed_)" actual && + grep "d0|main|child_start|.*|.* class:dashed argv:\[git-yyy\]" actual && + + # We unpeel that and substitute "version" into "xxx" (giving + # "git version") and update the cmd_name event. + grep "d0|main|alias|.*|alias:yyy argv:\[version\]" actual && + grep "d0|main|cmd_name|.*|_run_git_alias_ (_run_dashed_/_run_dashed_/_run_git_alias_)" actual && + + # These def_param events could be associated with any of the + # above cmd_name events. It does not matter. + grep "d0|main|def_param|.*|cfg.prop.foo:red" actual >actual.matches && + grep "d0|main|def_param|.*|ENV_PROP_FOO:blue" actual && + + # However, we do not want them repeated each time we unpeel. + test_line_count = 1 actual.matches && + + # The "git version" child sees a different cmd_name hierarchy. + # Also test the def_param (only for completeness). + grep "d1|main|cmd_name|.*|version (_run_dashed_/_run_dashed_/_run_git_alias_/version)" actual && + grep "d1|main|def_param|.*|cfg.prop.foo:red" actual && + grep "d1|main|def_param|.*|ENV_PROP_FOO:blue" actual +' + test_done diff --git a/t/t0301-credential-cache.sh b/t/t0301-credential-cache.sh index 8300faadea..f2c146fa2a 100755 --- a/t/t0301-credential-cache.sh +++ b/t/t0301-credential-cache.sh @@ -8,6 +8,14 @@ test -z "$NO_UNIX_SOCKETS" || { skip_all='skipping credential-cache tests, unix sockets not available' test_done } +if test_have_prereq MINGW +then + service_running=$(sc query afunix | grep "4 RUNNING") + test -z "$service_running" || { + skip_all='skipping credential-cache tests, unix sockets not available' + test_done + } +fi uname_s=$(uname -s) case $uname_s in diff --git a/t/t0303-credential-external.sh b/t/t0303-credential-external.sh index 095574bfc6..72ae405c3e 100755 --- a/t/t0303-credential-external.sh +++ b/t/t0303-credential-external.sh @@ -32,9 +32,24 @@ commands. . ./test-lib.sh . "$TEST_DIRECTORY"/lib-credential.sh +# If we're not given a specific external helper to run against, +# there isn't much to test. But we can still run through our +# battery of tests with a fake helper and check that the +# test themselves are self-consistent and clean up after +# themselves. +# +# We'll use the "store" helper, since we can easily inspect +# its state by looking at the on-disk file. But since it doesn't +# implement any caching or expiry logic, we'll cheat and override +# the "check" function to just report all results as OK. if test -z "$GIT_TEST_CREDENTIAL_HELPER"; then - skip_all="used to test external credential helpers" - test_done + GIT_TEST_CREDENTIAL_HELPER=store + GIT_TEST_CREDENTIAL_HELPER_TIMEOUT=store + check () { + test "$1" = "approve" || return 0 + git -c credential.helper=store credential approve + } + check_cleanup=t fi test -z "$GIT_TEST_CREDENTIAL_HELPER_SETUP" || @@ -59,4 +74,11 @@ fi # might be long-term system storage helper_test_clean "$GIT_TEST_CREDENTIAL_HELPER" +if test "$check_cleanup" = "t" +then + test_expect_success 'test cleanup removes everything' ' + test_must_be_empty "$HOME/.git-credentials" + ' +fi + test_done diff --git a/t/t0410-partial-clone.sh b/t/t0410-partial-clone.sh index 6b6424b3df..88a66f0904 100755 --- a/t/t0410-partial-clone.sh +++ b/t/t0410-partial-clone.sh @@ -49,7 +49,7 @@ test_expect_success 'convert shallow clone to partial clone' ' test_cmp_config -C client 1 core.repositoryformatversion ' -test_expect_success SHA1,REFFILES 'convert to partial clone with noop extension' ' +test_expect_success DEFAULT_REPO_FORMAT 'convert to partial clone with noop extension' ' rm -fr server client && test_create_repo server && test_commit -C server my_commit 1 && @@ -60,7 +60,7 @@ test_expect_success SHA1,REFFILES 'convert to partial clone with noop extension' git -C client fetch --unshallow --filter="blob:none" ' -test_expect_success SHA1,REFFILES 'converting to partial clone fails with unrecognized extension' ' +test_expect_success DEFAULT_REPO_FORMAT 'converting to partial clone fails with unrecognized extension' ' rm -fr server client && test_create_repo server && test_commit -C server my_commit 1 && @@ -665,6 +665,21 @@ test_expect_success 'lazy-fetch when accessing object not in the_repository' ' git -C partial.git rev-list --objects --missing=print HEAD >out && grep "[?]$FILE_HASH" out && + # The no-lazy-fetch mechanism prevents Git from fetching + test_must_fail env GIT_NO_LAZY_FETCH=1 \ + git -C partial.git cat-file -e "$FILE_HASH" && + + # The same with command line option to "git" + test_must_fail git --no-lazy-fetch -C partial.git cat-file -e "$FILE_HASH" && + + # The same, forcing a subprocess via an alias + test_must_fail git --no-lazy-fetch -C partial.git \ + -c alias.foo="!git cat-file" foo -e "$FILE_HASH" && + + # Sanity check that the file is still missing + git -C partial.git rev-list --objects --missing=print HEAD >out && + grep "[?]$FILE_HASH" out && + git -C full cat-file -s "$FILE_HASH" >expect && test-tool partial-clone object-info partial.git "$FILE_HASH" >actual && test_cmp expect actual && diff --git a/t/t0450-txt-doc-vs-help.sh b/t/t0450-txt-doc-vs-help.sh index cd3969e852..69917d7b84 100755 --- a/t/t0450-txt-doc-vs-help.sh +++ b/t/t0450-txt-doc-vs-help.sh @@ -59,7 +59,9 @@ txt_to_synopsis () { -e '/^\[verse\]$/,/^$/ { /^$/d; /^\[verse\]$/d; - + s/_//g; + s/++//g; + s/`//g; s/{litdd}/--/g; s/'\''\(git[ a-z-]*\)'\''/\1/g; diff --git a/t/t0600-reffiles-backend.sh b/t/t0600-reffiles-backend.sh index e6a5f1868f..64214340e7 100755 --- a/t/t0600-reffiles-backend.sh +++ b/t/t0600-reffiles-backend.sh @@ -279,31 +279,31 @@ test_expect_success 'setup worktree' ' # direct FS access for creating the reflogs. 3) PSEUDO-WT and refs/bisect/random # do not create reflogs by default, so it is not testing a realistic scenario. test_expect_success 'for_each_reflog()' ' - echo $ZERO_OID > .git/logs/PSEUDO-MAIN && + echo $ZERO_OID >.git/logs/PSEUDO_MAIN_HEAD && mkdir -p .git/logs/refs/bisect && - echo $ZERO_OID > .git/logs/refs/bisect/random && + echo $ZERO_OID >.git/logs/refs/bisect/random && - echo $ZERO_OID > .git/worktrees/wt/logs/PSEUDO-WT && + echo $ZERO_OID >.git/worktrees/wt/logs/PSEUDO_WT_HEAD && mkdir -p .git/worktrees/wt/logs/refs/bisect && - echo $ZERO_OID > .git/worktrees/wt/logs/refs/bisect/wt-random && + echo $ZERO_OID >.git/worktrees/wt/logs/refs/bisect/wt-random && - $RWT for-each-reflog | cut -d" " -f 2- | sort >actual && + $RWT for-each-reflog >actual && cat >expected <<-\EOF && - HEAD 0x1 - PSEUDO-WT 0x0 - refs/bisect/wt-random 0x0 - refs/heads/main 0x0 - refs/heads/wt-main 0x0 + HEAD + PSEUDO_WT_HEAD + refs/bisect/wt-random + refs/heads/main + refs/heads/wt-main EOF test_cmp expected actual && - $RMAIN for-each-reflog | cut -d" " -f 2- | sort >actual && + $RMAIN for-each-reflog >actual && cat >expected <<-\EOF && - HEAD 0x1 - PSEUDO-MAIN 0x0 - refs/bisect/random 0x0 - refs/heads/main 0x0 - refs/heads/wt-main 0x0 + HEAD + PSEUDO_MAIN_HEAD + refs/bisect/random + refs/heads/main + refs/heads/wt-main EOF test_cmp expected actual ' @@ -381,4 +381,95 @@ test_expect_success 'log diagnoses bogus HEAD symref' ' test_grep broken stderr ' +test_expect_success 'empty directory removal' ' + git branch d1/d2/r1 HEAD && + git branch d1/r2 HEAD && + test_path_is_file .git/refs/heads/d1/d2/r1 && + test_path_is_file .git/logs/refs/heads/d1/d2/r1 && + git branch -d d1/d2/r1 && + test_must_fail git show-ref --verify -q refs/heads/d1/d2 && + test_must_fail git show-ref --verify -q logs/refs/heads/d1/d2 && + test_path_is_file .git/refs/heads/d1/r2 && + test_path_is_file .git/logs/refs/heads/d1/r2 +' + +test_expect_success 'symref empty directory removal' ' + git branch e1/e2/r1 HEAD && + git branch e1/r2 HEAD && + git checkout e1/e2/r1 && + test_when_finished "git checkout main" && + test_path_is_file .git/refs/heads/e1/e2/r1 && + test_path_is_file .git/logs/refs/heads/e1/e2/r1 && + git update-ref -d HEAD && + test_must_fail git show-ref --verify -q refs/heads/e1/e2 && + test_must_fail git show-ref --verify -q logs/refs/heads/e1/e2 && + test_path_is_file .git/refs/heads/e1/r2 && + test_path_is_file .git/logs/refs/heads/e1/r2 && + test_path_is_file .git/logs/HEAD +' + +test_expect_success 'directory not created deleting packed ref' ' + git branch d1/d2/r1 HEAD && + git pack-refs --all && + test_path_is_missing .git/refs/heads/d1/d2 && + git update-ref -d refs/heads/d1/d2/r1 && + test_path_is_missing .git/refs/heads/d1/d2 && + test_path_is_missing .git/refs/heads/d1 +' + +test_expect_success SYMLINKS 'git branch -m u v should fail when the reflog for u is a symlink' ' + git branch --create-reflog u && + mv .git/logs/refs/heads/u real-u && + ln -s real-u .git/logs/refs/heads/u && + test_must_fail git branch -m u v +' + +test_expect_success SYMLINKS 'git branch -m with symlinked .git/refs' ' + test_when_finished "rm -rf subdir" && + git init --bare subdir && + + rm -rfv subdir/refs subdir/objects subdir/packed-refs && + ln -s ../.git/refs subdir/refs && + ln -s ../.git/objects subdir/objects && + ln -s ../.git/packed-refs subdir/packed-refs && + + git -C subdir rev-parse --absolute-git-dir >subdir.dir && + git rev-parse --absolute-git-dir >our.dir && + ! test_cmp subdir.dir our.dir && + + git -C subdir log && + git -C subdir branch rename-src && + git rev-parse rename-src >expect && + git -C subdir branch -m rename-src rename-dest && + git rev-parse rename-dest >actual && + test_cmp expect actual && + git branch -D rename-dest +' + +test_expect_success MINGW,SYMLINKS_WINDOWS 'rebase when .git/logs is a symlink' ' + git checkout main && + mv .git/logs actual_logs && + cmd //c "mklink /D .git\logs ..\actual_logs" && + git rebase -f HEAD^ && + test -L .git/logs && + rm .git/logs && + mv actual_logs .git/logs +' + +test_expect_success POSIXPERM 'git reflog expire honors core.sharedRepository' ' + umask 077 && + git config core.sharedRepository group && + git reflog expire --all && + actual="$(ls -l .git/logs/refs/heads/main)" && + case "$actual" in + -rw-rw-*) + : happy + ;; + *) + echo Ooops, .git/logs/refs/heads/main is not 066x [$actual] + false + ;; + esac +' + test_done diff --git a/t/t0601-reffiles-pack-refs.sh b/t/t0601-reffiles-pack-refs.sh index c309d2bae8..7d4ab0b91a 100755 --- a/t/t0601-reffiles-pack-refs.sh +++ b/t/t0601-reffiles-pack-refs.sh @@ -32,11 +32,16 @@ test_expect_success 'prepare a trivial repository' ' HEAD=$(git rev-parse --verify HEAD) ' -test_expect_success 'pack_refs(PACK_REFS_ALL | PACK_REFS_PRUNE)' ' - N=`find .git/refs -type f | wc -l` && +test_expect_success 'pack-refs --prune --all' ' + test_path_is_missing .git/packed-refs && + git pack-refs --no-prune --all && + test_path_is_file .git/packed-refs && + N=$(find .git/refs -type f | wc -l) && test "$N" != 0 && - test-tool ref-store main pack-refs PACK_REFS_PRUNE,PACK_REFS_ALL && - N=`find .git/refs -type f` && + + git pack-refs --prune --all && + test_path_is_file .git/packed-refs && + N=$(find .git/refs -type f) && test -z "$N" ' @@ -159,6 +164,13 @@ test_expect_success 'test --exclude takes precedence over --include' ' git pack-refs --include "refs/heads/pack*" --exclude "refs/heads/pack*" && test -f .git/refs/heads/dont_pack5' +test_expect_success '--auto packs and prunes refs as usual' ' + git branch auto && + test_path_is_file .git/refs/heads/auto && + git pack-refs --auto --all && + test_path_is_missing .git/refs/heads/auto +' + test_expect_success 'see if up-to-date packed refs are preserved' ' git branch q && git pack-refs --all --prune && @@ -358,4 +370,14 @@ test_expect_success 'pack-refs does not drop broken refs during deletion' ' test_cmp expect actual ' +test_expect_success 'maintenance --auto unconditionally packs loose refs' ' + git update-ref refs/heads/something HEAD && + test_path_is_file .git/refs/heads/something && + git rev-parse refs/heads/something >expect && + git maintenance run --task=pack-refs --auto && + test_path_is_missing .git/refs/heads/something && + git rev-parse refs/heads/something >actual && + test_cmp expect actual +' + test_done diff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh new file mode 100755 index 0000000000..178791e086 --- /dev/null +++ b/t/t0610-reftable-basics.sh @@ -0,0 +1,1032 @@ +#!/bin/sh +# +# Copyright (c) 2020 Google LLC +# + +test_description='reftable basics' +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +. ./test-lib.sh + +if ! test_have_prereq REFTABLE +then + skip_all='skipping reftable tests; set GIT_TEST_DEFAULT_REF_FORMAT=reftable' + test_done +fi + +INVALID_OID=$(test_oid 001) + +test_expect_success 'init: creates basic reftable structures' ' + test_when_finished "rm -rf repo" && + git init repo && + test_path_is_dir repo/.git/reftable && + test_path_is_file repo/.git/reftable/tables.list && + echo reftable >expect && + git -C repo rev-parse --show-ref-format >actual && + test_cmp expect actual +' + +test_expect_success 'init: sha256 object format via environment variable' ' + test_when_finished "rm -rf repo" && + GIT_DEFAULT_HASH=sha256 git init repo && + cat >expect <<-EOF && + sha256 + reftable + EOF + git -C repo rev-parse --show-object-format --show-ref-format >actual && + test_cmp expect actual +' + +test_expect_success 'init: sha256 object format via option' ' + test_when_finished "rm -rf repo" && + git init --object-format=sha256 repo && + cat >expect <<-EOF && + sha256 + reftable + EOF + git -C repo rev-parse --show-object-format --show-ref-format >actual && + test_cmp expect actual +' + +test_expect_success 'init: reinitializing reftable backend succeeds' ' + test_when_finished "rm -rf repo" && + git init repo && + test_commit -C repo A && + + git -C repo for-each-ref >expect && + git init --ref-format=reftable repo && + git -C repo for-each-ref >actual && + test_cmp expect actual +' + +test_expect_success 'init: reinitializing files with reftable backend fails' ' + test_when_finished "rm -rf repo" && + git init --ref-format=files repo && + test_commit -C repo file && + + cp repo/.git/HEAD expect && + test_must_fail git init --ref-format=reftable repo && + test_cmp expect repo/.git/HEAD +' + +test_expect_success 'init: reinitializing reftable with files backend fails' ' + test_when_finished "rm -rf repo" && + git init --ref-format=reftable repo && + test_commit -C repo file && + + cp repo/.git/HEAD expect && + test_must_fail git init --ref-format=files repo && + test_cmp expect repo/.git/HEAD +' + +test_expect_perms () { + local perms="$1" + local file="$2" + local actual="$(ls -l "$file")" && + + case "$actual" in + $perms*) + : happy + ;; + *) + echo "$(basename $2) is not $perms but $actual" + false + ;; + esac +} + +test_expect_reftable_perms () { + local umask="$1" + local shared="$2" + local expect="$3" + + test_expect_success POSIXPERM "init: honors --shared=$shared with umask $umask" ' + test_when_finished "rm -rf repo" && + ( + umask $umask && + git init --shared=$shared repo + ) && + test_expect_perms "$expect" repo/.git/reftable/tables.list && + for table in repo/.git/reftable/*.ref + do + test_expect_perms "$expect" "$table" || + return 1 + done + ' + + test_expect_success POSIXPERM "pack-refs: honors --shared=$shared with umask $umask" ' + test_when_finished "rm -rf repo" && + ( + umask $umask && + git init --shared=$shared repo && + test_commit -C repo A && + test_line_count = 2 repo/.git/reftable/tables.list && + git -C repo pack-refs + ) && + test_expect_perms "$expect" repo/.git/reftable/tables.list && + for table in repo/.git/reftable/*.ref + do + test_expect_perms "$expect" "$table" || + return 1 + done + ' +} + +test_expect_reftable_perms 002 umask "-rw-rw-r--" +test_expect_reftable_perms 022 umask "-rw-r--r--" +test_expect_reftable_perms 027 umask "-rw-r-----" + +test_expect_reftable_perms 002 group "-rw-rw-r--" +test_expect_reftable_perms 022 group "-rw-rw-r--" +test_expect_reftable_perms 027 group "-rw-rw----" + +test_expect_reftable_perms 002 world "-rw-rw-r--" +test_expect_reftable_perms 022 world "-rw-rw-r--" +test_expect_reftable_perms 027 world "-rw-rw-r--" + +test_expect_success 'clone: can clone reftable repository' ' + test_when_finished "rm -rf repo clone" && + git init repo && + test_commit -C repo message1 file1 && + + git clone repo cloned && + echo reftable >expect && + git -C cloned rev-parse --show-ref-format >actual && + test_cmp expect actual && + test_path_is_file cloned/file1 +' + +test_expect_success 'clone: can clone reffiles into reftable repository' ' + test_when_finished "rm -rf reffiles reftable" && + git init --ref-format=files reffiles && + test_commit -C reffiles A && + git clone --ref-format=reftable ./reffiles reftable && + + git -C reffiles rev-parse HEAD >expect && + git -C reftable rev-parse HEAD >actual && + test_cmp expect actual && + + git -C reftable rev-parse --show-ref-format >actual && + echo reftable >expect && + test_cmp expect actual && + + git -C reffiles rev-parse --show-ref-format >actual && + echo files >expect && + test_cmp expect actual +' + +test_expect_success 'clone: can clone reftable into reffiles repository' ' + test_when_finished "rm -rf reffiles reftable" && + git init --ref-format=reftable reftable && + test_commit -C reftable A && + git clone --ref-format=files ./reftable reffiles && + + git -C reftable rev-parse HEAD >expect && + git -C reffiles rev-parse HEAD >actual && + test_cmp expect actual && + + git -C reftable rev-parse --show-ref-format >actual && + echo reftable >expect && + test_cmp expect actual && + + git -C reffiles rev-parse --show-ref-format >actual && + echo files >expect && + test_cmp expect actual +' + +test_expect_success 'ref transaction: corrupted tables cause failure' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit file1 && + for f in .git/reftable/*.ref + do + : >"$f" || return 1 + done && + test_must_fail git update-ref refs/heads/main HEAD + ) +' + +test_expect_success 'ref transaction: corrupted tables.list cause failure' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit file1 && + echo garbage >.git/reftable/tables.list && + test_must_fail git update-ref refs/heads/main HEAD + ) +' + +test_expect_success 'ref transaction: refuses to write ref causing F/D conflict' ' + test_when_finished "rm -rf repo" && + git init repo && + test_commit -C repo file && + test_must_fail git -C repo update-ref refs/heads/main/forbidden +' + +test_expect_success 'ref transaction: deleting ref with invalid name fails' ' + test_when_finished "rm -rf repo" && + git init repo && + test_commit -C repo file && + test_must_fail git -C repo update-ref -d ../../my-private-file +' + +test_expect_success 'ref transaction: can skip object ID verification' ' + test_when_finished "rm -rf repo" && + git init repo && + test_must_fail test-tool -C repo ref-store main update-ref msg refs/heads/branch $INVALID_OID $ZERO_OID 0 && + test-tool -C repo ref-store main update-ref msg refs/heads/branch $INVALID_OID $ZERO_OID REF_SKIP_OID_VERIFICATION +' + +test_expect_success 'ref transaction: updating same ref multiple times fails' ' + test_when_finished "rm -rf repo" && + git init repo && + test_commit -C repo A && + cat >updates <<-EOF && + update refs/heads/main $A + update refs/heads/main $A + EOF + cat >expect <<-EOF && + fatal: multiple updates for ref ${SQ}refs/heads/main${SQ} not allowed + EOF + test_must_fail git -C repo update-ref --stdin <updates 2>err && + test_cmp expect err +' + +test_expect_success 'ref transaction: can delete symbolic self-reference with git-symbolic-ref(1)' ' + test_when_finished "rm -rf repo" && + git init repo && + git -C repo symbolic-ref refs/heads/self refs/heads/self && + git -C repo symbolic-ref -d refs/heads/self +' + +test_expect_success 'ref transaction: deleting symbolic self-reference without --no-deref fails' ' + test_when_finished "rm -rf repo" && + git init repo && + git -C repo symbolic-ref refs/heads/self refs/heads/self && + cat >expect <<-EOF && + error: multiple updates for ${SQ}refs/heads/self${SQ} (including one via symref ${SQ}refs/heads/self${SQ}) are not allowed + EOF + test_must_fail git -C repo update-ref -d refs/heads/self 2>err && + test_cmp expect err +' + +test_expect_success 'ref transaction: deleting symbolic self-reference with --no-deref succeeds' ' + test_when_finished "rm -rf repo" && + git init repo && + git -C repo symbolic-ref refs/heads/self refs/heads/self && + git -C repo update-ref -d --no-deref refs/heads/self +' + +test_expect_success 'ref transaction: creating symbolic ref fails with F/D conflict' ' + test_when_finished "rm -rf repo" && + git init repo && + test_commit -C repo A && + cat >expect <<-EOF && + error: unable to write symref for refs/heads: file/directory conflict + EOF + test_must_fail git -C repo symbolic-ref refs/heads refs/heads/foo 2>err && + test_cmp expect err +' + +test_expect_success 'ref transaction: ref deletion' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit file && + HEAD_OID=$(git show-ref -s --verify HEAD) && + cat >expect <<-EOF && + $HEAD_OID refs/heads/main + $HEAD_OID refs/tags/file + EOF + git show-ref >actual && + test_cmp expect actual && + + test_must_fail git update-ref -d refs/tags/file $INVALID_OID && + git show-ref >actual && + test_cmp expect actual && + + git update-ref -d refs/tags/file $HEAD_OID && + echo "$HEAD_OID refs/heads/main" >expect && + git show-ref >actual && + test_cmp expect actual + ) +' + +test_expect_success 'ref transaction: writes cause auto-compaction' ' + test_when_finished "rm -rf repo" && + + git init repo && + test_line_count = 1 repo/.git/reftable/tables.list && + + test_commit -C repo --no-tag A && + test_line_count = 1 repo/.git/reftable/tables.list && + + test_commit -C repo --no-tag B && + test_line_count = 1 repo/.git/reftable/tables.list +' + +test_expect_success 'ref transaction: env var disables compaction' ' + test_when_finished "rm -rf repo" && + + git init repo && + test_commit -C repo A && + + start=$(wc -l <repo/.git/reftable/tables.list) && + iterations=5 && + expected=$((start + iterations)) && + + for i in $(test_seq $iterations) + do + GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ + git -C repo update-ref branch-$i HEAD || return 1 + done && + test_line_count = $expected repo/.git/reftable/tables.list && + + git -C repo update-ref foo HEAD && + test_line_count -lt $expected repo/.git/reftable/tables.list +' + +test_expect_success 'ref transaction: alternating table sizes are compacted' ' + test_when_finished "rm -rf repo" && + + git init repo && + test_commit -C repo A && + for i in $(test_seq 5) + do + git -C repo branch -f foo && + git -C repo branch -d foo || return 1 + done && + test_line_count = 2 repo/.git/reftable/tables.list +' + +check_fsync_events () { + local trace="$1" && + shift && + + cat >expect && + sed -n \ + -e '/^{"event":"counter",.*"category":"fsync",/ { + s/.*"category":"fsync",//; + s/}$//; + p; + }' \ + <"$trace" >actual && + test_cmp expect actual +} + +test_expect_success 'ref transaction: writes are synced' ' + test_when_finished "rm -rf repo" && + git init repo && + test_commit -C repo initial && + + GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ + GIT_TEST_FSYNC=true \ + git -C repo -c core.fsync=reference \ + -c core.fsyncMethod=fsync update-ref refs/heads/branch HEAD && + check_fsync_events trace2.txt <<-EOF + "name":"hardware-flush","count":4 + EOF +' + +test_expect_success 'ref transaction: empty transaction in empty repo' ' + test_when_finished "rm -rf repo" && + git init repo && + test_commit -C repo --no-tag A && + git -C repo update-ref -d refs/heads/main && + test-tool -C repo ref-store main delete-refs REF_NO_DEREF msg HEAD && + git -C repo update-ref --stdin <<-EOF + prepare + commit + EOF +' + +test_expect_success 'ref transaction: fails gracefully when auto compaction fails' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + + test_commit A && + for i in $(test_seq 10) + do + git branch branch-$i && + for table in .git/reftable/*.ref + do + touch "$table.lock" || exit 1 + done || + exit 1 + done && + test_line_count = 10 .git/reftable/tables.list + ) +' + +test_expect_success 'pack-refs: compacts tables' ' + test_when_finished "rm -rf repo" && + git init repo && + + test_commit -C repo A && + ls -1 repo/.git/reftable >table-files && + test_line_count = 3 table-files && + test_line_count = 2 repo/.git/reftable/tables.list && + + git -C repo pack-refs && + ls -1 repo/.git/reftable >table-files && + test_line_count = 2 table-files && + test_line_count = 1 repo/.git/reftable/tables.list +' + +test_expect_success 'pack-refs: compaction raises locking errors' ' + test_when_finished "rm -rf repo" && + git init repo && + test_commit -C repo A && + touch repo/.git/reftable/tables.list.lock && + cat >expect <<-EOF && + error: unable to compact stack: data is locked + EOF + test_must_fail git -C repo pack-refs 2>err && + test_cmp expect err +' + +for command in pack-refs gc "maintenance run --task=pack-refs" +do +test_expect_success "$command: auto compaction" ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + + test_commit A && + + # We need a bit of setup to ensure that git-gc(1) actually + # triggers, and that it does not write anything to the refdb. + git config gc.auto 1 && + git config gc.autoDetach 0 && + git config gc.reflogExpire never && + git config gc.reflogExpireUnreachable never && + test_oid blob17_1 | git hash-object -w --stdin && + + # The tables should have been auto-compacted, and thus auto + # compaction should not have to do anything. + ls -1 .git/reftable >tables-expect && + test_line_count = 3 tables-expect && + git $command --auto && + ls -1 .git/reftable >tables-actual && + test_cmp tables-expect tables-actual && + + test_oid blob17_2 | git hash-object -w --stdin && + + # Lock all tables write some refs. Auto-compaction will be + # unable to compact tables and thus fails gracefully, leaving + # the stack in a sub-optimal state. + ls .git/reftable/*.ref | + while read table + do + touch "$table.lock" || exit 1 + done && + git branch B && + git branch C && + rm .git/reftable/*.lock && + test_line_count = 4 .git/reftable/tables.list && + + git $command --auto && + test_line_count = 1 .git/reftable/tables.list + ) +' +done + +test_expect_success 'pack-refs: prunes stale tables' ' + test_when_finished "rm -rf repo" && + git init repo && + touch repo/.git/reftable/stale-table.ref && + git -C repo pack-refs && + test_path_is_missing repo/.git/reftable/stable-ref.ref +' + +test_expect_success 'pack-refs: does not prune non-table files' ' + test_when_finished "rm -rf repo" && + git init repo && + touch repo/.git/reftable/garbage && + git -C repo pack-refs && + test_path_is_file repo/.git/reftable/garbage +' + +test_expect_success 'packed-refs: writes are synced' ' + test_when_finished "rm -rf repo" && + git init repo && + test_commit -C repo initial && + test_line_count = 2 table-files && + + : >trace2.txt && + GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ + GIT_TEST_FSYNC=true \ + git -C repo -c core.fsync=reference \ + -c core.fsyncMethod=fsync pack-refs && + check_fsync_events trace2.txt <<-EOF + "name":"hardware-flush","count":2 + EOF +' + +test_expect_success 'ref iterator: bogus names are flagged' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit --no-tag file && + test-tool ref-store main update-ref msg "refs/heads/bogus..name" $(git rev-parse HEAD) $ZERO_OID REF_SKIP_REFNAME_VERIFICATION && + + cat >expect <<-EOF && + $ZERO_OID refs/heads/bogus..name 0xc + $(git rev-parse HEAD) refs/heads/main 0x0 + EOF + test-tool ref-store main for-each-ref "" >actual && + test_cmp expect actual + ) +' + +test_expect_success 'ref iterator: missing object IDs are not flagged' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test-tool ref-store main update-ref msg "refs/heads/broken-hash" $INVALID_OID $ZERO_OID REF_SKIP_OID_VERIFICATION && + + cat >expect <<-EOF && + $INVALID_OID refs/heads/broken-hash 0x0 + EOF + test-tool ref-store main for-each-ref "" >actual && + test_cmp expect actual + ) +' + +test_expect_success 'basic: commit and list refs' ' + test_when_finished "rm -rf repo" && + git init repo && + test_commit -C repo file && + test_write_lines refs/heads/main refs/tags/file >expect && + git -C repo for-each-ref --format="%(refname)" >actual && + test_cmp actual expect +' + +test_expect_success 'basic: can write large commit message' ' + test_when_finished "rm -rf repo" && + git init repo && + perl -e " + print \"this is a long commit message\" x 50000 + " >commit-msg && + git -C repo commit --allow-empty --file=../commit-msg +' + +test_expect_success 'basic: show-ref fails with empty repository' ' + test_when_finished "rm -rf repo" && + git init repo && + test_must_fail git -C repo show-ref >actual && + test_must_be_empty actual +' + +test_expect_success 'basic: can check out unborn branch' ' + test_when_finished "rm -rf repo" && + git init repo && + git -C repo checkout -b main +' + +test_expect_success 'basic: peeled tags are stored' ' + test_when_finished "rm -rf repo" && + git init repo && + test_commit -C repo file && + git -C repo tag -m "annotated tag" test_tag HEAD && + for ref in refs/heads/main refs/tags/file refs/tags/test_tag refs/tags/test_tag^{} + do + echo "$(git -C repo rev-parse "$ref") $ref" || return 1 + done >expect && + git -C repo show-ref -d >actual && + test_cmp expect actual +' + +test_expect_success 'basic: for-each-ref can print symrefs' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit file && + git branch && + git symbolic-ref refs/heads/sym refs/heads/main && + cat >expected <<-EOF && + refs/heads/main + EOF + git for-each-ref --format="%(symref)" refs/heads/sym >actual && + test_cmp expected actual + ) +' + +test_expect_success 'basic: notes' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + write_script fake_editor <<-\EOF && + echo "$MSG" >"$1" + echo "$MSG" >&2 + EOF + + test_commit 1st && + test_commit 2nd && + GIT_EDITOR=./fake_editor MSG=b4 git notes add && + GIT_EDITOR=./fake_editor MSG=b3 git notes edit && + echo b4 >expect && + git notes --ref commits@{1} show >actual && + test_cmp expect actual + ) +' + +test_expect_success 'basic: stash' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit file && + git stash list >expect && + test_line_count = 0 expect && + + echo hoi >>file.t && + git stash push -m stashed && + git stash list >expect && + test_line_count = 1 expect && + + git stash clear && + git stash list >expect && + test_line_count = 0 expect + ) +' + +test_expect_success 'basic: cherry-pick' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit message1 file1 && + test_commit message2 file2 && + git branch source && + git checkout HEAD^ && + test_commit message3 file3 && + git cherry-pick source && + test_path_is_file file2 + ) +' + +test_expect_success 'basic: rebase' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit message1 file1 && + test_commit message2 file2 && + git branch source && + git checkout HEAD^ && + test_commit message3 file3 && + git rebase source && + test_path_is_file file2 + ) +' + +test_expect_success 'reflog: can delete separate reflog entries' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + + test_commit file && + test_commit file2 && + test_commit file3 && + test_commit file4 && + git reflog >actual && + grep file3 actual && + + git reflog delete HEAD@{1} && + git reflog >actual && + ! grep file3 actual + ) +' + +test_expect_success 'reflog: can switch to previous branch' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit file1 && + git checkout -b branch1 && + test_commit file2 && + git checkout -b branch2 && + git switch - && + git rev-parse --symbolic-full-name HEAD >actual && + echo refs/heads/branch1 >expect && + test_cmp actual expect + ) +' + +test_expect_success 'reflog: copying branch writes reflog entry' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit file1 && + test_commit file2 && + oid=$(git rev-parse --short HEAD) && + git branch src && + cat >expect <<-EOF && + ${oid} dst@{0}: Branch: copied refs/heads/src to refs/heads/dst + ${oid} dst@{1}: branch: Created from main + EOF + git branch -c src dst && + git reflog dst >actual && + test_cmp expect actual + ) +' + +test_expect_success 'reflog: renaming branch writes reflog entry' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + git symbolic-ref HEAD refs/heads/before && + test_commit file && + git show-ref >expected.refs && + sed s/before/after/g <expected.refs >expected && + git branch -M after && + git show-ref >actual && + test_cmp expected actual && + echo refs/heads/after >expected && + git symbolic-ref HEAD >actual && + test_cmp expected actual + ) +' + +test_expect_success 'reflog: can store empty logs' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + + test_must_fail test-tool ref-store main reflog-exists refs/heads/branch && + test-tool ref-store main create-reflog refs/heads/branch && + test-tool ref-store main reflog-exists refs/heads/branch && + test-tool ref-store main for-each-reflog-ent-reverse refs/heads/branch >actual && + test_must_be_empty actual + ) +' + +test_expect_success 'reflog: expiry empties reflog' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + + test_commit initial && + git checkout -b branch && + test_commit fileA && + test_commit fileB && + + cat >expect <<-EOF && + commit: fileB + commit: fileA + branch: Created from HEAD + EOF + git reflog show --format="%gs" refs/heads/branch >actual && + test_cmp expect actual && + + git reflog expire branch --expire=all && + git reflog show --format="%gs" refs/heads/branch >actual && + test_must_be_empty actual && + test-tool ref-store main reflog-exists refs/heads/branch + ) +' + +test_expect_success 'reflog: can be deleted' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit initial && + test-tool ref-store main reflog-exists refs/heads/main && + test-tool ref-store main delete-reflog refs/heads/main && + test_must_fail test-tool ref-store main reflog-exists refs/heads/main + ) +' + +test_expect_success 'reflog: garbage collection deletes reflog entries' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + + for count in $(test_seq 1 10) + do + test_commit "number $count" file.t $count number-$count || + return 1 + done && + git reflog refs/heads/main >actual && + test_line_count = 10 actual && + grep "commit (initial): number 1" actual && + grep "commit: number 10" actual && + + git gc && + git reflog refs/heads/main >actual && + test_line_count = 0 actual + ) +' + +test_expect_success 'reflog: updates via HEAD update HEAD reflog' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit main-one && + git checkout -b new-branch && + test_commit new-one && + test_commit new-two && + + echo new-one >expect && + git log -1 --format=%s HEAD@{1} >actual && + test_cmp expect actual + ) +' + +test_expect_success 'worktree: adding worktree creates separate stack' ' + test_when_finished "rm -rf repo worktree" && + git init repo && + test_commit -C repo A && + + git -C repo worktree add ../worktree && + test_path_is_file repo/.git/worktrees/worktree/refs/heads && + echo "ref: refs/heads/.invalid" >expect && + test_cmp expect repo/.git/worktrees/worktree/HEAD && + test_path_is_dir repo/.git/worktrees/worktree/reftable && + test_path_is_file repo/.git/worktrees/worktree/reftable/tables.list +' + +test_expect_success 'worktree: pack-refs in main repo packs main refs' ' + test_when_finished "rm -rf repo worktree" && + git init repo && + test_commit -C repo A && + + GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ + git -C repo worktree add ../worktree && + GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ + git -C worktree update-ref refs/worktree/per-worktree HEAD && + + test_line_count = 4 repo/.git/worktrees/worktree/reftable/tables.list && + test_line_count = 3 repo/.git/reftable/tables.list && + git -C repo pack-refs && + test_line_count = 4 repo/.git/worktrees/worktree/reftable/tables.list && + test_line_count = 1 repo/.git/reftable/tables.list +' + +test_expect_success 'worktree: pack-refs in worktree packs worktree refs' ' + test_when_finished "rm -rf repo worktree" && + git init repo && + test_commit -C repo A && + + GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ + git -C repo worktree add ../worktree && + GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ + git -C worktree update-ref refs/worktree/per-worktree HEAD && + + test_line_count = 4 repo/.git/worktrees/worktree/reftable/tables.list && + test_line_count = 3 repo/.git/reftable/tables.list && + git -C worktree pack-refs && + test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && + test_line_count = 3 repo/.git/reftable/tables.list +' + +test_expect_success 'worktree: creating shared ref updates main stack' ' + test_when_finished "rm -rf repo worktree" && + git init repo && + test_commit -C repo A && + + git -C repo worktree add ../worktree && + git -C repo pack-refs && + git -C worktree pack-refs && + test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && + test_line_count = 1 repo/.git/reftable/tables.list && + + GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ + git -C worktree update-ref refs/heads/shared HEAD && + test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && + test_line_count = 2 repo/.git/reftable/tables.list +' + +test_expect_success 'worktree: creating per-worktree ref updates worktree stack' ' + test_when_finished "rm -rf repo worktree" && + git init repo && + test_commit -C repo A && + + git -C repo worktree add ../worktree && + git -C repo pack-refs && + git -C worktree pack-refs && + test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && + test_line_count = 1 repo/.git/reftable/tables.list && + + git -C worktree update-ref refs/bisect/per-worktree HEAD && + test_line_count = 2 repo/.git/worktrees/worktree/reftable/tables.list && + test_line_count = 1 repo/.git/reftable/tables.list +' + +test_expect_success 'worktree: creating per-worktree ref from main repo' ' + test_when_finished "rm -rf repo worktree" && + git init repo && + test_commit -C repo A && + + git -C repo worktree add ../worktree && + git -C repo pack-refs && + git -C worktree pack-refs && + test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && + test_line_count = 1 repo/.git/reftable/tables.list && + + git -C repo update-ref worktrees/worktree/refs/bisect/per-worktree HEAD && + test_line_count = 2 repo/.git/worktrees/worktree/reftable/tables.list && + test_line_count = 1 repo/.git/reftable/tables.list +' + +test_expect_success 'worktree: creating per-worktree ref from second worktree' ' + test_when_finished "rm -rf repo wt1 wt2" && + git init repo && + test_commit -C repo A && + + git -C repo worktree add ../wt1 && + git -C repo worktree add ../wt2 && + git -C repo pack-refs && + git -C wt1 pack-refs && + git -C wt2 pack-refs && + test_line_count = 1 repo/.git/worktrees/wt1/reftable/tables.list && + test_line_count = 1 repo/.git/worktrees/wt2/reftable/tables.list && + test_line_count = 1 repo/.git/reftable/tables.list && + + git -C wt1 update-ref worktrees/wt2/refs/bisect/per-worktree HEAD && + test_line_count = 1 repo/.git/worktrees/wt1/reftable/tables.list && + test_line_count = 2 repo/.git/worktrees/wt2/reftable/tables.list && + test_line_count = 1 repo/.git/reftable/tables.list +' + +test_expect_success 'worktree: can create shared and per-worktree ref in one transaction' ' + test_when_finished "rm -rf repo worktree" && + git init repo && + test_commit -C repo A && + + git -C repo worktree add ../worktree && + git -C repo pack-refs && + git -C worktree pack-refs && + test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && + test_line_count = 1 repo/.git/reftable/tables.list && + + cat >stdin <<-EOF && + create worktrees/worktree/refs/bisect/per-worktree HEAD + create refs/branches/shared HEAD + EOF + git -C repo update-ref --stdin <stdin && + test_line_count = 2 repo/.git/worktrees/worktree/reftable/tables.list && + test_line_count = 2 repo/.git/reftable/tables.list +' + +test_expect_success 'worktree: can access common refs' ' + test_when_finished "rm -rf repo worktree" && + git init repo && + test_commit -C repo file1 && + git -C repo branch branch1 && + git -C repo worktree add ../worktree && + + echo refs/heads/worktree >expect && + git -C worktree symbolic-ref HEAD >actual && + test_cmp expect actual && + git -C worktree checkout branch1 +' + +test_expect_success 'worktree: adds worktree with detached HEAD' ' + test_when_finished "rm -rf repo worktree" && + + git init repo && + test_commit -C repo A && + git -C repo rev-parse main >expect && + + git -C repo worktree add --detach ../worktree main && + git -C worktree rev-parse HEAD >actual && + test_cmp expect actual +' + +test_expect_success 'fetch: accessing FETCH_HEAD special ref works' ' + test_when_finished "rm -rf repo sub" && + + git init sub && + test_commit -C sub two && + git -C sub rev-parse HEAD >expect && + + git init repo && + test_commit -C repo one && + git -C repo fetch ../sub && + git -C repo rev-parse FETCH_HEAD >actual && + test_cmp expect actual +' + +test_done diff --git a/t/t0611-reftable-httpd.sh b/t/t0611-reftable-httpd.sh new file mode 100755 index 0000000000..5e05b9c1f2 --- /dev/null +++ b/t/t0611-reftable-httpd.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +test_description='reftable HTTPD tests' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-httpd.sh + +start_httpd + +REPO="$HTTPD_DOCUMENT_ROOT_PATH/repo" + +test_expect_success 'serving ls-remote' ' + git init --ref-format=reftable -b main "$REPO" && + cd "$REPO" && + test_commit m1 && + >.git/git-daemon-export-ok && + git ls-remote "http://127.0.0.1:$LIB_HTTPD_PORT/smart/repo" | cut -f 2-2 -d " " >actual && + cat >expect <<-EOF && + HEAD + refs/heads/main + refs/tags/m1 + EOF + test_cmp actual expect +' + +test_done diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh index e0c6482797..e12b221972 100755 --- a/t/t1006-cat-file.sh +++ b/t/t1006-cat-file.sh @@ -112,65 +112,65 @@ strlen () { run_tests () { type=$1 - sha1=$2 + oid=$2 size=$3 content=$4 pretty_content=$5 - batch_output="$sha1 $type $size + batch_output="$oid $type $size $content" test_expect_success "$type exists" ' - git cat-file -e $sha1 + git cat-file -e $oid ' test_expect_success "Type of $type is correct" ' echo $type >expect && - git cat-file -t $sha1 >actual && + git cat-file -t $oid >actual && test_cmp expect actual ' test_expect_success "Size of $type is correct" ' echo $size >expect && - git cat-file -s $sha1 >actual && + git cat-file -s $oid >actual && test_cmp expect actual ' test_expect_success "Type of $type is correct using --allow-unknown-type" ' echo $type >expect && - git cat-file -t --allow-unknown-type $sha1 >actual && + git cat-file -t --allow-unknown-type $oid >actual && test_cmp expect actual ' test_expect_success "Size of $type is correct using --allow-unknown-type" ' echo $size >expect && - git cat-file -s --allow-unknown-type $sha1 >actual && + git cat-file -s --allow-unknown-type $oid >actual && test_cmp expect actual ' test -z "$content" || test_expect_success "Content of $type is correct" ' echo_without_newline "$content" >expect && - git cat-file $type $sha1 >actual && + git cat-file $type $oid >actual && test_cmp expect actual ' test_expect_success "Pretty content of $type is correct" ' echo_without_newline "$pretty_content" >expect && - git cat-file -p $sha1 >actual && + git cat-file -p $oid >actual && test_cmp expect actual ' test -z "$content" || test_expect_success "--batch output of $type is correct" ' echo "$batch_output" >expect && - echo $sha1 | git cat-file --batch >actual && + echo $oid | git cat-file --batch >actual && test_cmp expect actual ' test_expect_success "--batch-check output of $type is correct" ' - echo "$sha1 $type $size" >expect && - echo_without_newline $sha1 | git cat-file --batch-check >actual && + echo "$oid $type $size" >expect && + echo_without_newline $oid | git cat-file --batch-check >actual && test_cmp expect actual ' @@ -179,33 +179,33 @@ $content" test -z "$content" || test_expect_success "--batch-command $opt output of $type content is correct" ' echo "$batch_output" >expect && - test_write_lines "contents $sha1" | git cat-file --batch-command $opt >actual && + test_write_lines "contents $oid" | git cat-file --batch-command $opt >actual && test_cmp expect actual ' test_expect_success "--batch-command $opt output of $type info is correct" ' - echo "$sha1 $type $size" >expect && - test_write_lines "info $sha1" | + echo "$oid $type $size" >expect && + test_write_lines "info $oid" | git cat-file --batch-command $opt >actual && test_cmp expect actual ' done test_expect_success "custom --batch-check format" ' - echo "$type $sha1" >expect && - echo $sha1 | git cat-file --batch-check="%(objecttype) %(objectname)" >actual && + echo "$type $oid" >expect && + echo $oid | git cat-file --batch-check="%(objecttype) %(objectname)" >actual && test_cmp expect actual ' test_expect_success "custom --batch-command format" ' - echo "$type $sha1" >expect && - echo "info $sha1" | git cat-file --batch-command="%(objecttype) %(objectname)" >actual && + echo "$type $oid" >expect && + echo "info $oid" | git cat-file --batch-command="%(objecttype) %(objectname)" >actual && test_cmp expect actual ' test_expect_success '--batch-check with %(rest)' ' echo "$type this is some extra content" >expect && - echo "$sha1 this is some extra content" | + echo "$oid this is some extra content" | git cat-file --batch-check="%(objecttype) %(rest)" >actual && test_cmp expect actual ' @@ -216,7 +216,7 @@ $content" echo "$size" && echo "$content" } >expect && - echo $sha1 | git cat-file --batch="%(objectsize)" >actual && + echo $oid | git cat-file --batch="%(objectsize)" >actual && test_cmp expect actual ' @@ -226,114 +226,154 @@ $content" echo "$type" && echo "$content" } >expect && - echo $sha1 | git cat-file --batch="%(objecttype)" >actual && + echo $oid | git cat-file --batch="%(objecttype)" >actual && test_cmp expect actual ' } hello_content="Hello World" hello_size=$(strlen "$hello_content") -hello_sha1=$(echo_without_newline "$hello_content" | git hash-object --stdin) +hello_oid=$(echo_without_newline "$hello_content" | git hash-object --stdin) test_expect_success "setup" ' + git config core.repositoryformatversion 1 && + git config extensions.objectformat $test_hash_algo && + git config extensions.compatobjectformat $test_compat_hash_algo && echo_without_newline "$hello_content" > hello && git update-index --add hello ' -run_tests 'blob' $hello_sha1 $hello_size "$hello_content" "$hello_content" +run_blob_tests () { + oid=$1 -test_expect_success '--batch-command --buffer with flush for blob info' ' - echo "$hello_sha1 blob $hello_size" >expect && - test_write_lines "info $hello_sha1" "flush" | + run_tests 'blob' $oid $hello_size "$hello_content" "$hello_content" + + test_expect_success '--batch-command --buffer with flush for blob info' ' + echo "$oid blob $hello_size" >expect && + test_write_lines "info $oid" "flush" | GIT_TEST_CAT_FILE_NO_FLUSH_ON_EXIT=1 \ git cat-file --batch-command --buffer >actual && test_cmp expect actual -' + ' -test_expect_success '--batch-command --buffer without flush for blob info' ' + test_expect_success '--batch-command --buffer without flush for blob info' ' touch output && - test_write_lines "info $hello_sha1" | + test_write_lines "info $oid" | GIT_TEST_CAT_FILE_NO_FLUSH_ON_EXIT=1 \ git cat-file --batch-command --buffer >>output && test_must_be_empty output -' + ' +} + +hello_compat_oid=$(git rev-parse --output-object-format=$test_compat_hash_algo $hello_oid) +run_blob_tests $hello_oid +run_blob_tests $hello_compat_oid test_expect_success '--batch-check without %(rest) considers whole line' ' - echo "$hello_sha1 blob $hello_size" >expect && - git update-index --add --cacheinfo 100644 $hello_sha1 "white space" && + echo "$hello_oid blob $hello_size" >expect && + git update-index --add --cacheinfo 100644 $hello_oid "white space" && test_when_finished "git update-index --remove \"white space\"" && echo ":white space" | git cat-file --batch-check >actual && test_cmp expect actual ' -tree_sha1=$(git write-tree) +tree_oid=$(git write-tree) +tree_compat_oid=$(git rev-parse --output-object-format=$test_compat_hash_algo $tree_oid) tree_size=$(($(test_oid rawsz) + 13)) -tree_pretty_content="100644 blob $hello_sha1 hello${LF}" +tree_compat_size=$(($(test_oid --hash=compat rawsz) + 13)) +tree_pretty_content="100644 blob $hello_oid hello${LF}" +tree_compat_pretty_content="100644 blob $hello_compat_oid hello${LF}" -run_tests 'tree' $tree_sha1 $tree_size "" "$tree_pretty_content" +run_tests 'tree' $tree_oid $tree_size "" "$tree_pretty_content" +run_tests 'tree' $tree_compat_oid $tree_compat_size "" "$tree_compat_pretty_content" commit_message="Initial commit" -commit_sha1=$(echo_without_newline "$commit_message" | git commit-tree $tree_sha1) +commit_oid=$(echo_without_newline "$commit_message" | git commit-tree $tree_oid) +commit_compat_oid=$(git rev-parse --output-object-format=$test_compat_hash_algo $commit_oid) commit_size=$(($(test_oid hexsz) + 137)) -commit_content="tree $tree_sha1 +commit_compat_size=$(($(test_oid --hash=compat hexsz) + 137)) +commit_content="tree $tree_oid +author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + +$commit_message" + +commit_compat_content="tree $tree_compat_oid author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE $commit_message" -run_tests 'commit' $commit_sha1 $commit_size "$commit_content" "$commit_content" +run_tests 'commit' $commit_oid $commit_size "$commit_content" "$commit_content" +run_tests 'commit' $commit_compat_oid $commit_compat_size "$commit_compat_content" "$commit_compat_content" -tag_header_without_timestamp="object $hello_sha1 -type blob +tag_header_without_oid="type blob tag hellotag tagger $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" +tag_header_without_timestamp="object $hello_oid +$tag_header_without_oid" +tag_compat_header_without_timestamp="object $hello_compat_oid +$tag_header_without_oid" tag_description="This is a tag" tag_content="$tag_header_without_timestamp 0 +0000 $tag_description" +tag_compat_content="$tag_compat_header_without_timestamp 0 +0000 -tag_sha1=$(echo_without_newline "$tag_content" | git hash-object -t tag --stdin -w) +$tag_description" + +tag_oid=$(echo_without_newline "$tag_content" | git hash-object -t tag --stdin -w) tag_size=$(strlen "$tag_content") -run_tests 'tag' $tag_sha1 $tag_size "$tag_content" "$tag_content" +tag_compat_oid=$(git rev-parse --output-object-format=$test_compat_hash_algo $tag_oid) +tag_compat_size=$(strlen "$tag_compat_content") + +run_tests 'tag' $tag_oid $tag_size "$tag_content" "$tag_content" +run_tests 'tag' $tag_compat_oid $tag_compat_size "$tag_compat_content" "$tag_compat_content" test_expect_success "Reach a blob from a tag pointing to it" ' echo_without_newline "$hello_content" >expect && - git cat-file blob $tag_sha1 >actual && + git cat-file blob $tag_oid >actual && test_cmp expect actual ' -for batch in batch batch-check batch-command +for oid in $hello_oid $hello_compat_oid do - for opt in t s e p + for batch in batch batch-check batch-command do + for opt in t s e p + do test_expect_success "Passing -$opt with --$batch fails" ' - test_must_fail git cat-file --$batch -$opt $hello_sha1 + test_must_fail git cat-file --$batch -$opt $oid ' test_expect_success "Passing --$batch with -$opt fails" ' - test_must_fail git cat-file -$opt --$batch $hello_sha1 + test_must_fail git cat-file -$opt --$batch $oid ' - done + done - test_expect_success "Passing <type> with --$batch fails" ' - test_must_fail git cat-file --$batch blob $hello_sha1 - ' + test_expect_success "Passing <type> with --$batch fails" ' + test_must_fail git cat-file --$batch blob $oid + ' - test_expect_success "Passing --$batch with <type> fails" ' - test_must_fail git cat-file blob --$batch $hello_sha1 - ' + test_expect_success "Passing --$batch with <type> fails" ' + test_must_fail git cat-file blob --$batch $oid + ' - test_expect_success "Passing sha1 with --$batch fails" ' - test_must_fail git cat-file --$batch $hello_sha1 - ' + test_expect_success "Passing oid with --$batch fails" ' + test_must_fail git cat-file --$batch $oid + ' + done done -for opt in t s e p +for oid in $hello_oid $hello_compat_oid do - test_expect_success "Passing -$opt with --follow-symlinks fails" ' - test_must_fail git cat-file --follow-symlinks -$opt $hello_sha1 + for opt in t s e p + do + test_expect_success "Passing -$opt with --follow-symlinks fails" ' + test_must_fail git cat-file --follow-symlinks -$opt $oid ' + done done test_expect_success "--batch-check for a non-existent named object" ' @@ -360,12 +400,12 @@ test_expect_success "--batch-check for a non-existent hash" ' test_expect_success "--batch for an existent and a non-existent hash" ' cat >expect <<-EOF && - $tag_sha1 tag $tag_size + $tag_oid tag $tag_size $tag_content 0000000000000000000000000000000000000000 missing EOF - printf "$tag_sha1\n0000000000000000000000000000000000000000" >in && + printf "$tag_oid\n0000000000000000000000000000000000000000" >in && git cat-file --batch <in >actual && test_cmp expect actual ' @@ -386,112 +426,102 @@ test_expect_success 'empty --batch-check notices missing object' ' test_cmp expect actual ' -batch_input="$hello_sha1 -$commit_sha1 -$tag_sha1 +batch_tests () { + boid=$1 + loid=$2 + lsize=$3 + coid=$4 + csize=$5 + ccontent=$6 + toid=$7 + tsize=$8 + tcontent=$9 + + batch_input="$boid +$coid +$toid deadbeef " -printf "%s\0" \ - "$hello_sha1 blob $hello_size" \ + printf "%s\0" \ + "$boid blob $hello_size" \ "$hello_content" \ - "$commit_sha1 commit $commit_size" \ - "$commit_content" \ - "$tag_sha1 tag $tag_size" \ - "$tag_content" \ + "$coid commit $csize" \ + "$ccontent" \ + "$toid tag $tsize" \ + "$tcontent" \ "deadbeef missing" \ " missing" >batch_output -test_expect_success '--batch with multiple sha1s gives correct format' ' + test_expect_success '--batch with multiple oids gives correct format' ' tr "\0" "\n" <batch_output >expect && echo_without_newline "$batch_input" >in && git cat-file --batch <in >actual && test_cmp expect actual -' + ' -test_expect_success '--batch, -z with multiple sha1s gives correct format' ' + test_expect_success '--batch, -z with multiple oids gives correct format' ' echo_without_newline_nul "$batch_input" >in && tr "\0" "\n" <batch_output >expect && git cat-file --batch -z <in >actual && test_cmp expect actual -' + ' -test_expect_success '--batch, -Z with multiple sha1s gives correct format' ' + test_expect_success '--batch, -Z with multiple oids gives correct format' ' echo_without_newline_nul "$batch_input" >in && git cat-file --batch -Z <in >actual && test_cmp batch_output actual -' + ' -batch_check_input="$hello_sha1 -$tree_sha1 -$commit_sha1 -$tag_sha1 +batch_check_input="$boid +$loid +$coid +$toid deadbeef " -printf "%s\0" \ - "$hello_sha1 blob $hello_size" \ - "$tree_sha1 tree $tree_size" \ - "$commit_sha1 commit $commit_size" \ - "$tag_sha1 tag $tag_size" \ + printf "%s\0" \ + "$boid blob $hello_size" \ + "$loid tree $lsize" \ + "$coid commit $csize" \ + "$toid tag $tsize" \ "deadbeef missing" \ " missing" >batch_check_output -test_expect_success "--batch-check with multiple sha1s gives correct format" ' + test_expect_success "--batch-check with multiple oids gives correct format" ' tr "\0" "\n" <batch_check_output >expect && echo_without_newline "$batch_check_input" >in && git cat-file --batch-check <in >actual && test_cmp expect actual -' + ' -test_expect_success "--batch-check, -z with multiple sha1s gives correct format" ' + test_expect_success "--batch-check, -z with multiple oids gives correct format" ' tr "\0" "\n" <batch_check_output >expect && echo_without_newline_nul "$batch_check_input" >in && git cat-file --batch-check -z <in >actual && test_cmp expect actual -' + ' -test_expect_success "--batch-check, -Z with multiple sha1s gives correct format" ' + test_expect_success "--batch-check, -Z with multiple oids gives correct format" ' echo_without_newline_nul "$batch_check_input" >in && git cat-file --batch-check -Z <in >actual && test_cmp batch_check_output actual -' - -test_expect_success FUNNYNAMES 'setup with newline in input' ' - touch -- "newline${LF}embedded" && - git add -- "newline${LF}embedded" && - git commit -m "file with newline embedded" && - test_tick && - - printf "HEAD:newline${LF}embedded" >in -' - -test_expect_success FUNNYNAMES '--batch-check, -z with newline in input' ' - git cat-file --batch-check -z <in >actual && - echo "$(git rev-parse "HEAD:newline${LF}embedded") blob 0" >expect && - test_cmp expect actual -' - -test_expect_success FUNNYNAMES '--batch-check, -Z with newline in input' ' - git cat-file --batch-check -Z <in >actual && - printf "%s\0" "$(git rev-parse "HEAD:newline${LF}embedded") blob 0" >expect && - test_cmp expect actual -' + ' -batch_command_multiple_info="info $hello_sha1 -info $tree_sha1 -info $commit_sha1 -info $tag_sha1 +batch_command_multiple_info="info $boid +info $loid +info $coid +info $toid info deadbeef" -test_expect_success '--batch-command with multiple info calls gives correct format' ' + test_expect_success '--batch-command with multiple info calls gives correct format' ' cat >expect <<-EOF && - $hello_sha1 blob $hello_size - $tree_sha1 tree $tree_size - $commit_sha1 commit $commit_size - $tag_sha1 tag $tag_size + $boid blob $hello_size + $loid tree $lsize + $coid commit $csize + $toid tag $tsize deadbeef missing EOF @@ -510,22 +540,22 @@ test_expect_success '--batch-command with multiple info calls gives correct form git cat-file --batch-command --buffer -Z <in >actual && test_cmp expect_nul actual -' + ' -batch_command_multiple_contents="contents $hello_sha1 -contents $commit_sha1 -contents $tag_sha1 +batch_command_multiple_contents="contents $boid +contents $coid +contents $toid contents deadbeef flush" -test_expect_success '--batch-command with multiple command calls gives correct format' ' + test_expect_success '--batch-command with multiple command calls gives correct format' ' printf "%s\0" \ - "$hello_sha1 blob $hello_size" \ + "$boid blob $hello_size" \ "$hello_content" \ - "$commit_sha1 commit $commit_size" \ - "$commit_content" \ - "$tag_sha1 tag $tag_size" \ - "$tag_content" \ + "$coid commit $csize" \ + "$ccontent" \ + "$toid tag $tsize" \ + "$tcontent" \ "deadbeef missing" >expect_nul && tr "\0" "\n" <expect_nul >expect && @@ -543,6 +573,33 @@ test_expect_success '--batch-command with multiple command calls gives correct f git cat-file --batch-command --buffer -Z <in >actual && test_cmp expect_nul actual + ' + +} + +batch_tests $hello_oid $tree_oid $tree_size $commit_oid $commit_size "$commit_content" $tag_oid $tag_size "$tag_content" +batch_tests $hello_compat_oid $tree_compat_oid $tree_compat_size $commit_compat_oid $commit_compat_size "$commit_compat_content" $tag_compat_oid $tag_compat_size "$tag_compat_content" + + +test_expect_success FUNNYNAMES 'setup with newline in input' ' + touch -- "newline${LF}embedded" && + git add -- "newline${LF}embedded" && + git commit -m "file with newline embedded" && + test_tick && + + printf "HEAD:newline${LF}embedded" >in +' + +test_expect_success FUNNYNAMES '--batch-check, -z with newline in input' ' + git cat-file --batch-check -z <in >actual && + echo "$(git rev-parse "HEAD:newline${LF}embedded") blob 0" >expect && + test_cmp expect actual +' + +test_expect_success FUNNYNAMES '--batch-check, -Z with newline in input' ' + git cat-file --batch-check -Z <in >actual && + printf "%s\0" "$(git rev-parse "HEAD:newline${LF}embedded") blob 0" >expect && + test_cmp expect actual ' test_expect_success 'setup blobs which are likely to delta' ' @@ -569,7 +626,7 @@ test_expect_success 'confirm that neither loose blob is a delta' ' # we will check only that one of the two objects is a delta # against the other, but not the order. We can do so by just # asking for the base of both, and checking whether either -# sha1 appears in the output. +# oid appears in the output. test_expect_success '%(deltabase) reports packed delta bases' ' git repack -ad && git cat-file --batch-check="%(deltabase)" <blobs >actual && @@ -583,12 +640,12 @@ test_expect_success 'setup bogus data' ' bogus_short_type="bogus" && bogus_short_content="bogus" && bogus_short_size=$(strlen "$bogus_short_content") && - bogus_short_sha1=$(echo_without_newline "$bogus_short_content" | git hash-object -t $bogus_short_type --literally -w --stdin) && + bogus_short_oid=$(echo_without_newline "$bogus_short_content" | git hash-object -t $bogus_short_type --literally -w --stdin) && bogus_long_type="abcdefghijklmnopqrstuvwxyz1234679" && bogus_long_content="bogus" && bogus_long_size=$(strlen "$bogus_long_content") && - bogus_long_sha1=$(echo_without_newline "$bogus_long_content" | git hash-object -t $bogus_long_type --literally -w --stdin) + bogus_long_oid=$(echo_without_newline "$bogus_long_content" | git hash-object -t $bogus_long_type --literally -w --stdin) ' for arg1 in '' --allow-unknown-type @@ -608,9 +665,9 @@ do if test "$arg1" = "--allow-unknown-type" then - git cat-file $arg1 $arg2 $bogus_short_sha1 + git cat-file $arg1 $arg2 $bogus_short_oid else - test_must_fail git cat-file $arg1 $arg2 $bogus_short_sha1 >out 2>actual && + test_must_fail git cat-file $arg1 $arg2 $bogus_short_oid >out 2>actual && test_must_be_empty out && test_cmp expect actual fi @@ -620,21 +677,21 @@ do if test "$arg2" = "-p" then cat >expect <<-EOF - error: header for $bogus_long_sha1 too long, exceeds 32 bytes - fatal: Not a valid object name $bogus_long_sha1 + error: header for $bogus_long_oid too long, exceeds 32 bytes + fatal: Not a valid object name $bogus_long_oid EOF else cat >expect <<-EOF - error: header for $bogus_long_sha1 too long, exceeds 32 bytes + error: header for $bogus_long_oid too long, exceeds 32 bytes fatal: git cat-file: could not get object info EOF fi && if test "$arg1" = "--allow-unknown-type" then - git cat-file $arg1 $arg2 $bogus_short_sha1 + git cat-file $arg1 $arg2 $bogus_short_oid else - test_must_fail git cat-file $arg1 $arg2 $bogus_long_sha1 >out 2>actual && + test_must_fail git cat-file $arg1 $arg2 $bogus_long_oid >out 2>actual && test_must_be_empty out && test_cmp expect actual fi @@ -668,28 +725,28 @@ do done test_expect_success '-e is OK with a broken object without --allow-unknown-type' ' - git cat-file -e $bogus_short_sha1 + git cat-file -e $bogus_short_oid ' test_expect_success '-e can not be combined with --allow-unknown-type' ' - test_expect_code 128 git cat-file -e --allow-unknown-type $bogus_short_sha1 + test_expect_code 128 git cat-file -e --allow-unknown-type $bogus_short_oid ' test_expect_success '-p cannot print a broken object even with --allow-unknown-type' ' - test_must_fail git cat-file -p $bogus_short_sha1 && - test_expect_code 128 git cat-file -p --allow-unknown-type $bogus_short_sha1 + test_must_fail git cat-file -p $bogus_short_oid && + test_expect_code 128 git cat-file -p --allow-unknown-type $bogus_short_oid ' test_expect_success '<type> <hash> does not work with objects of broken types' ' cat >err.expect <<-\EOF && fatal: invalid object type "bogus" EOF - test_must_fail git cat-file $bogus_short_type $bogus_short_sha1 2>err.actual && + test_must_fail git cat-file $bogus_short_type $bogus_short_oid 2>err.actual && test_cmp err.expect err.actual ' test_expect_success 'broken types combined with --batch and --batch-check' ' - echo $bogus_short_sha1 >bogus-oid && + echo $bogus_short_oid >bogus-oid && cat >err.expect <<-\EOF && fatal: invalid object type @@ -711,52 +768,52 @@ test_expect_success 'the --allow-unknown-type option does not consider replaceme cat >expect <<-EOF && $bogus_short_type EOF - git cat-file -t --allow-unknown-type $bogus_short_sha1 >actual && + git cat-file -t --allow-unknown-type $bogus_short_oid >actual && test_cmp expect actual && # Create it manually, as "git replace" will die on bogus # types. head=$(git rev-parse --verify HEAD) && - test_when_finished "test-tool ref-store main delete-refs 0 msg refs/replace/$bogus_short_sha1" && - test-tool ref-store main update-ref msg "refs/replace/$bogus_short_sha1" $head $ZERO_OID REF_SKIP_OID_VERIFICATION && + test_when_finished "test-tool ref-store main delete-refs 0 msg refs/replace/$bogus_short_oid" && + test-tool ref-store main update-ref msg "refs/replace/$bogus_short_oid" $head $ZERO_OID REF_SKIP_OID_VERIFICATION && cat >expect <<-EOF && commit EOF - git cat-file -t --allow-unknown-type $bogus_short_sha1 >actual && + git cat-file -t --allow-unknown-type $bogus_short_oid >actual && test_cmp expect actual ' test_expect_success "Type of broken object is correct" ' echo $bogus_short_type >expect && - git cat-file -t --allow-unknown-type $bogus_short_sha1 >actual && + git cat-file -t --allow-unknown-type $bogus_short_oid >actual && test_cmp expect actual ' test_expect_success "Size of broken object is correct" ' echo $bogus_short_size >expect && - git cat-file -s --allow-unknown-type $bogus_short_sha1 >actual && + git cat-file -s --allow-unknown-type $bogus_short_oid >actual && test_cmp expect actual ' test_expect_success 'clean up broken object' ' - rm .git/objects/$(test_oid_to_path $bogus_short_sha1) + rm .git/objects/$(test_oid_to_path $bogus_short_oid) ' test_expect_success "Type of broken object is correct when type is large" ' echo $bogus_long_type >expect && - git cat-file -t --allow-unknown-type $bogus_long_sha1 >actual && + git cat-file -t --allow-unknown-type $bogus_long_oid >actual && test_cmp expect actual ' test_expect_success "Size of large broken object is correct when type is large" ' echo $bogus_long_size >expect && - git cat-file -s --allow-unknown-type $bogus_long_sha1 >actual && + git cat-file -s --allow-unknown-type $bogus_long_oid >actual && test_cmp expect actual ' test_expect_success 'clean up broken object' ' - rm .git/objects/$(test_oid_to_path $bogus_long_sha1) + rm .git/objects/$(test_oid_to_path $bogus_long_oid) ' test_expect_success 'cat-file -t and -s on corrupt loose object' ' @@ -853,7 +910,7 @@ test_expect_success 'prep for symlink tests' ' test_ln_s_add loop2 loop1 && git add morx dir/subdir/ind2 dir/ind1 && git commit -am "test" && - echo $hello_sha1 blob $hello_size >found + echo $hello_oid blob $hello_size >found ' test_expect_success 'git cat-file --batch-check --follow-symlinks works for non-links' ' @@ -941,7 +998,7 @@ test_expect_success 'git cat-file --batch-check --follow-symlinks works for dir/ echo HEAD:dirlink/morx >>expect && echo HEAD:dirlink/morx | git cat-file --batch-check --follow-symlinks >actual && test_cmp expect actual && - echo $hello_sha1 blob $hello_size >expect && + echo $hello_oid blob $hello_size >expect && echo HEAD:dirlink/ind1 | git cat-file --batch-check --follow-symlinks >actual && test_cmp expect actual ' diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh index ac3d173767..64aea38486 100755 --- a/t/t1007-hash-object.sh +++ b/t/t1007-hash-object.sh @@ -124,8 +124,8 @@ test_expect_success 'check that appropriate filter is invoke when --path is used path0_sha=$(git hash-object --path=file0 file1) && test "$file0_sha" = "$path0_sha" && test "$file1_sha" = "$path1_sha" && - path1_sha=$(cat file0 | git hash-object --path=file1 --stdin) && - path0_sha=$(cat file1 | git hash-object --path=file0 --stdin) && + path1_sha=$(git hash-object --path=file1 --stdin <file0) && + path0_sha=$(git hash-object --path=file0 --stdin <file1) && test "$file0_sha" = "$path0_sha" && test "$file1_sha" = "$path1_sha" ' @@ -154,7 +154,7 @@ test_expect_success '--path works in a subdirectory' ' test_expect_success 'check that --no-filters option works' ' nofilters_file1=$(git hash-object --no-filters file1) && test "$file0_sha" = "$nofilters_file1" && - nofilters_file1=$(cat file1 | git hash-object --stdin) && + nofilters_file1=$(git hash-object --stdin <file1) && test "$file0_sha" = "$nofilters_file1" ' diff --git a/t/t1016-compatObjectFormat.sh b/t/t1016-compatObjectFormat.sh new file mode 100755 index 0000000000..be3206a16f --- /dev/null +++ b/t/t1016-compatObjectFormat.sh @@ -0,0 +1,281 @@ +#!/bin/sh +# +# Copyright (c) 2023 Eric Biederman +# + +test_description='Test how well compatObjectFormat works' + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-gpg.sh + +# All of the follow variables must be defined in the environment: +# GIT_AUTHOR_NAME +# GIT_AUTHOR_EMAIL +# GIT_AUTHOR_DATE +# GIT_COMMITTER_NAME +# GIT_COMMITTER_EMAIL +# GIT_COMMITTER_DATE +# +# The test relies on these variables being set so that the two +# different commits in two different repositories encoded with two +# different hash functions result in the same content in the commits. +# This means that when the commit is translated between hash functions +# the commit is identical to the commit in the other repository. + +compat_hash () { + case "$1" in + "sha1") + echo "sha256" + ;; + "sha256") + echo "sha1" + ;; + esac +} + +hello_oid () { + case "$1" in + "sha1") + echo "$hello_sha1_oid" + ;; + "sha256") + echo "$hello_sha256_oid" + ;; + esac +} + +tree_oid () { + case "$1" in + "sha1") + echo "$tree_sha1_oid" + ;; + "sha256") + echo "$tree_sha256_oid" + ;; + esac +} + +commit_oid () { + case "$1" in + "sha1") + echo "$commit_sha1_oid" + ;; + "sha256") + echo "$commit_sha256_oid" + ;; + esac +} + +commit2_oid () { + case "$1" in + "sha1") + echo "$commit2_sha1_oid" + ;; + "sha256") + echo "$commit2_sha256_oid" + ;; + esac +} + +del_sigcommit () { + local delete="$1" + + if test "$delete" = "sha256" ; then + local pattern="gpgsig-sha256" + else + local pattern="gpgsig" + fi + test-tool delete-gpgsig "$pattern" +} + + +del_sigtag () { + local storage="$1" + local delete="$2" + + if test "$storage" = "$delete" ; then + local pattern="trailer" + elif test "$storage" = "sha256" ; then + local pattern="gpgsig" + else + local pattern="gpgsig-sha256" + fi + test-tool delete-gpgsig "$pattern" +} + +base=$(pwd) +for hash in sha1 sha256 +do + cd "$base" + mkdir -p repo-$hash + cd repo-$hash + + test_expect_success "setup $hash repository" ' + git init --object-format=$hash && + git config core.repositoryformatversion 1 && + git config extensions.objectformat $hash && + git config extensions.compatobjectformat $(compat_hash $hash) && + git config gpg.program $TEST_DIRECTORY/t1016/gpg && + echo "Hellow World!" > hello && + eval hello_${hash}_oid=$(git hash-object hello) && + git update-index --add hello && + git commit -m "Initial commit" && + eval commit_${hash}_oid=$(git rev-parse HEAD) && + eval tree_${hash}_oid=$(git rev-parse HEAD^{tree}) + ' + test_expect_success "create a $hash tagged blob" ' + git tag --no-sign -m "This is a tag" hellotag $(hello_oid $hash) && + eval hellotag_${hash}_oid=$(git rev-parse hellotag) + ' + test_expect_success "create a $hash tagged tree" ' + git tag --no-sign -m "This is a tag" treetag $(tree_oid $hash) && + eval treetag_${hash}_oid=$(git rev-parse treetag) + ' + test_expect_success "create a $hash tagged commit" ' + git tag --no-sign -m "This is a tag" committag $(commit_oid $hash) && + eval committag_${hash}_oid=$(git rev-parse committag) + ' + test_expect_success GPG2 "create a $hash signed commit" ' + git commit --gpg-sign --allow-empty -m "This is a signed commit" && + eval signedcommit_${hash}_oid=$(git rev-parse HEAD) + ' + test_expect_success GPG2 "create a $hash signed tag" ' + git tag -s -m "This is a signed tag" signedtag HEAD && + eval signedtag_${hash}_oid=$(git rev-parse signedtag) + ' + test_expect_success "create a $hash branch" ' + git checkout -b branch $(commit_oid $hash) && + echo "More more more give me more!" > more && + eval more_${hash}_oid=$(git hash-object more) && + echo "Another and another and another" > another && + eval another_${hash}_oid=$(git hash-object another) && + git update-index --add more another && + git commit -m "Add more files!" && + eval commit2_${hash}_oid=$(git rev-parse HEAD) && + eval tree2_${hash}_oid=$(git rev-parse HEAD^{tree}) + ' + test_expect_success GPG2 "create another $hash signed tag" ' + git tag -s -m "This is another signed tag" signedtag2 $(commit2_oid $hash) && + eval signedtag2_${hash}_oid=$(git rev-parse signedtag2) + ' + test_expect_success GPG2 "merge the $hash branches together" ' + git merge -S -m "merge some signed tags together" signedtag signedtag2 && + eval signedcommit2_${hash}_oid=$(git rev-parse HEAD) + ' + test_expect_success GPG2 "create additional $hash signed commits" ' + git commit --gpg-sign --allow-empty -m "This is an additional signed commit" && + git cat-file commit HEAD | del_sigcommit sha256 > "../${hash}_signedcommit3" && + git cat-file commit HEAD | del_sigcommit sha1 > "../${hash}_signedcommit4" && + eval signedcommit3_${hash}_oid=$(git hash-object -t commit -w ../${hash}_signedcommit3) && + eval signedcommit4_${hash}_oid=$(git hash-object -t commit -w ../${hash}_signedcommit4) + ' + test_expect_success GPG2 "create additional $hash signed tags" ' + git tag -s -m "This is an additional signed tag" signedtag34 HEAD && + git cat-file tag signedtag34 | del_sigtag "${hash}" sha256 > ../${hash}_signedtag3 && + git cat-file tag signedtag34 | del_sigtag "${hash}" sha1 > ../${hash}_signedtag4 && + eval signedtag3_${hash}_oid=$(git hash-object -t tag -w ../${hash}_signedtag3) && + eval signedtag4_${hash}_oid=$(git hash-object -t tag -w ../${hash}_signedtag4) + ' +done +cd "$base" + +compare_oids () { + test "$#" = 5 && { local PREREQ="$1"; shift; } || PREREQ= + local type="$1" + local name="$2" + local sha1_oid="$3" + local sha256_oid="$4" + + echo ${sha1_oid} > ${name}_sha1_expected + echo ${sha256_oid} > ${name}_sha256_expected + echo ${type} > ${name}_type_expected + + git --git-dir=repo-sha1/.git rev-parse --output-object-format=sha256 ${sha1_oid} > ${name}_sha1_sha256_found + git --git-dir=repo-sha256/.git rev-parse --output-object-format=sha1 ${sha256_oid} > ${name}_sha256_sha1_found + local sha1_sha256_oid="$(cat ${name}_sha1_sha256_found)" + local sha256_sha1_oid="$(cat ${name}_sha256_sha1_found)" + + test_expect_success $PREREQ "Verify ${type} ${name}'s sha1 oid" ' + git --git-dir=repo-sha256/.git rev-parse --output-object-format=sha1 ${sha256_oid} > ${name}_sha1 && + test_cmp ${name}_sha1 ${name}_sha1_expected +' + + test_expect_success $PREREQ "Verify ${type} ${name}'s sha256 oid" ' + git --git-dir=repo-sha1/.git rev-parse --output-object-format=sha256 ${sha1_oid} > ${name}_sha256 && + test_cmp ${name}_sha256 ${name}_sha256_expected +' + + test_expect_success $PREREQ "Verify ${name}'s sha1 type" ' + git --git-dir=repo-sha1/.git cat-file -t ${sha1_oid} > ${name}_type1 && + git --git-dir=repo-sha256/.git cat-file -t ${sha256_sha1_oid} > ${name}_type2 && + test_cmp ${name}_type1 ${name}_type2 && + test_cmp ${name}_type1 ${name}_type_expected +' + + test_expect_success $PREREQ "Verify ${name}'s sha256 type" ' + git --git-dir=repo-sha256/.git cat-file -t ${sha256_oid} > ${name}_type3 && + git --git-dir=repo-sha1/.git cat-file -t ${sha1_sha256_oid} > ${name}_type4 && + test_cmp ${name}_type3 ${name}_type4 && + test_cmp ${name}_type3 ${name}_type_expected +' + + test_expect_success $PREREQ "Verify ${name}'s sha1 size" ' + git --git-dir=repo-sha1/.git cat-file -s ${sha1_oid} > ${name}_size1 && + git --git-dir=repo-sha256/.git cat-file -s ${sha256_sha1_oid} > ${name}_size2 && + test_cmp ${name}_size1 ${name}_size2 +' + + test_expect_success $PREREQ "Verify ${name}'s sha256 size" ' + git --git-dir=repo-sha256/.git cat-file -s ${sha256_oid} > ${name}_size3 && + git --git-dir=repo-sha1/.git cat-file -s ${sha1_sha256_oid} > ${name}_size4 && + test_cmp ${name}_size3 ${name}_size4 +' + + test_expect_success $PREREQ "Verify ${name}'s sha1 pretty content" ' + git --git-dir=repo-sha1/.git cat-file -p ${sha1_oid} > ${name}_content1 && + git --git-dir=repo-sha256/.git cat-file -p ${sha256_sha1_oid} > ${name}_content2 && + test_cmp ${name}_content1 ${name}_content2 +' + + test_expect_success $PREREQ "Verify ${name}'s sha256 pretty content" ' + git --git-dir=repo-sha256/.git cat-file -p ${sha256_oid} > ${name}_content3 && + git --git-dir=repo-sha1/.git cat-file -p ${sha1_sha256_oid} > ${name}_content4 && + test_cmp ${name}_content3 ${name}_content4 +' + + test_expect_success $PREREQ "Verify ${name}'s sha1 content" ' + git --git-dir=repo-sha1/.git cat-file ${type} ${sha1_oid} > ${name}_content5 && + git --git-dir=repo-sha256/.git cat-file ${type} ${sha256_sha1_oid} > ${name}_content6 && + test_cmp ${name}_content5 ${name}_content6 +' + + test_expect_success $PREREQ "Verify ${name}'s sha256 content" ' + git --git-dir=repo-sha256/.git cat-file ${type} ${sha256_oid} > ${name}_content7 && + git --git-dir=repo-sha1/.git cat-file ${type} ${sha1_sha256_oid} > ${name}_content8 && + test_cmp ${name}_content7 ${name}_content8 +' + +} + +compare_oids 'blob' hello "$hello_sha1_oid" "$hello_sha256_oid" +compare_oids 'tree' tree "$tree_sha1_oid" "$tree_sha256_oid" +compare_oids 'commit' commit "$commit_sha1_oid" "$commit_sha256_oid" +compare_oids GPG2 'commit' signedcommit "$signedcommit_sha1_oid" "$signedcommit_sha256_oid" +compare_oids 'tag' hellotag "$hellotag_sha1_oid" "$hellotag_sha256_oid" +compare_oids 'tag' treetag "$treetag_sha1_oid" "$treetag_sha256_oid" +compare_oids 'tag' committag "$committag_sha1_oid" "$committag_sha256_oid" +compare_oids GPG2 'tag' signedtag "$signedtag_sha1_oid" "$signedtag_sha256_oid" + +compare_oids 'blob' more "$more_sha1_oid" "$more_sha256_oid" +compare_oids 'blob' another "$another_sha1_oid" "$another_sha256_oid" +compare_oids 'tree' tree2 "$tree2_sha1_oid" "$tree2_sha256_oid" +compare_oids 'commit' commit2 "$commit2_sha1_oid" "$commit2_sha256_oid" +compare_oids GPG2 'tag' signedtag2 "$signedtag2_sha1_oid" "$signedtag2_sha256_oid" +compare_oids GPG2 'commit' signedcommit2 "$signedcommit2_sha1_oid" "$signedcommit2_sha256_oid" +compare_oids GPG2 'commit' signedcommit3 "$signedcommit3_sha1_oid" "$signedcommit3_sha256_oid" +compare_oids GPG2 'commit' signedcommit4 "$signedcommit4_sha1_oid" "$signedcommit4_sha256_oid" +compare_oids GPG2 'tag' signedtag3 "$signedtag3_sha1_oid" "$signedtag3_sha256_oid" +compare_oids GPG2 'tag' signedtag4 "$signedtag4_sha1_oid" "$signedtag4_sha256_oid" + +test_done diff --git a/t/t1016/gpg b/t/t1016/gpg new file mode 100755 index 0000000000..2601cb18a5 --- /dev/null +++ b/t/t1016/gpg @@ -0,0 +1,2 @@ +#!/bin/sh +exec gpg --faked-system-time "20230918T154812" "$@" diff --git a/t/t1091-sparse-checkout-builtin.sh b/t/t1091-sparse-checkout-builtin.sh index e49b8024ac..ab3a105fff 100755 --- a/t/t1091-sparse-checkout-builtin.sh +++ b/t/t1091-sparse-checkout-builtin.sh @@ -968,7 +968,7 @@ test_expect_success 'check-rules non-cone mode' ' git -C bare sparse-checkout check-rules --no-cone --rules-file ../rules\ >check-rules-file <all-files && - cat rules | git -C repo sparse-checkout set --no-cone --stdin && + git -C repo sparse-checkout set --no-cone --stdin <rules && git -C repo ls-files -t >out && sed -n "/^S /!s/^. //p" out >ls-files && diff --git a/t/t1300-config.sh b/t/t1300-config.sh index 31c3878687..9b65d9eaf5 100755 --- a/t/t1300-config.sh +++ b/t/t1300-config.sh @@ -11,6 +11,98 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh +test_expect_success 'setup whitespace config' ' + sed -e "s/^|//" \ + -e "s/[$]$//" \ + -e "s/X/ /g" >.git/config <<-\EOF + [section] + | solid = rock + | sparse = big XX blue + | sparseAndTail = big XX blue $ + | sparseAndTailQuoted = "big XX blue " + | sparseAndBiggerTail = big XX blue X X + | sparseAndBiggerTailQuoted = "big XX blue X X" + | sparseAndBiggerTailQuotedPlus = "big XX blue X X"X $ + | headAndTail = Xbig blue $ + | headAndTailQuoted = "Xbig blue " + | headAndTailQuotedPlus = "Xbig blue " $ + | annotated = big blueX# to be discarded + | annotatedQuoted = "big blue"X# to be discarded + EOF +' + +test_expect_success 'no internal whitespace' ' + echo "rock" >expect && + git config --get section.solid >actual && + test_cmp expect actual +' + +test_expect_success 'internal whitespace' ' + echo "big QQ blue" | q_to_tab >expect && + git config --get section.sparse >actual && + test_cmp expect actual +' + +test_expect_success 'internal and trailing whitespace' ' + echo "big QQ blue" | q_to_tab >expect && + git config --get section.sparseAndTail >actual && + test_cmp expect actual +' + +test_expect_success 'internal and trailing whitespace, all quoted' ' + echo "big QQ blue " | q_to_tab >expect && + git config --get section.sparseAndTailQuoted >actual && + test_cmp expect actual +' + +test_expect_success 'internal and more trailing whitespace' ' + echo "big QQ blue" | q_to_tab >expect && + git config --get section.sparseAndBiggerTail >actual && + test_cmp expect actual +' + +test_expect_success 'internal and more trailing whitespace, all quoted' ' + echo "big QQ blue Q Q" | q_to_tab >expect && + git config --get section.sparseAndBiggerTailQuoted >actual && + test_cmp expect actual +' + +test_expect_success 'internal and more trailing whitespace, not all quoted' ' + echo "big QQ blue Q Q" | q_to_tab >expect && + git config --get section.sparseAndBiggerTailQuotedPlus >actual && + test_cmp expect actual +' + +test_expect_success 'leading and trailing whitespace' ' + echo "big blue" >expect && + git config --get section.headAndTail >actual && + test_cmp expect actual +' + +test_expect_success 'leading and trailing whitespace, all quoted' ' + echo "Qbig blue " | q_to_tab >expect && + git config --get section.headAndTailQuoted >actual && + test_cmp expect actual +' + +test_expect_success 'leading and trailing whitespace, not all quoted' ' + echo "Qbig blue " | q_to_tab >expect && + git config --get section.headAndTailQuotedPlus >actual && + test_cmp expect actual +' + +test_expect_success 'inline comment' ' + echo "big blue" >expect && + git config --get section.annotated >actual && + test_cmp expect actual +' + +test_expect_success 'inline comment, quoted' ' + echo "big blue" >expect && + git config --get section.annotatedQuoted >actual && + test_cmp expect actual +' + test_expect_success 'clear default config' ' rm -f .git/config ' @@ -69,14 +161,32 @@ test_expect_success 'replace with non-match (actually matching)' ' cat > expect << EOF [section] - penguin = very blue Movie = BadPhysics UPPERCASE = true - penguin = kingpin + penguin = gentoo # Pygoscelis papua + disposition = peckish # find fish + foo = bar #abc + spsp = value # and comment + htsp = value # and comment [Sections] WhatEver = Second EOF +test_expect_success 'append comments' ' + git config --replace-all --comment="Pygoscelis papua" section.penguin gentoo && + git config --comment="find fish" section.disposition peckish && + git config --comment="#abc" section.foo bar && + + git config --comment="and comment" section.spsp value && + git config --comment=" # and comment" section.htsp value && + + test_cmp expect .git/config +' + +test_expect_success 'Prohibited LF in comment' ' + test_must_fail git config --comment="a${LF}b" section.k v +' + test_expect_success 'non-match result' 'test_cmp expect .git/config' test_expect_success 'find mixed-case key by canonical name' ' @@ -1066,9 +1176,25 @@ test_expect_success '--null --get-regexp' ' test_cmp expect result ' -test_expect_success 'inner whitespace kept verbatim' ' - git config section.val "foo bar" && - test_cmp_config "foo bar" section.val +test_expect_success 'inner whitespace kept verbatim, spaces only' ' + echo "foo bar" >expect && + git config section.val "foo bar" && + git config --get section.val >actual && + test_cmp expect actual +' + +test_expect_success 'inner whitespace kept verbatim, horizontal tabs only' ' + echo "fooQQbar" | q_to_tab >expect && + git config section.val "$(cat expect)" && + git config --get section.val >actual && + test_cmp expect actual +' + +test_expect_success 'inner whitespace kept verbatim, horizontal tabs and spaces' ' + echo "foo Q bar" | q_to_tab >expect && + git config section.val "$(cat expect)" && + git config --get section.val >actual && + test_cmp expect actual ' test_expect_success SYMLINKS 'symlinked configuration' ' diff --git a/t/t1301-shared-repo.sh b/t/t1301-shared-repo.sh index 8e2c01e760..29cf8a9661 100755 --- a/t/t1301-shared-repo.sh +++ b/t/t1301-shared-repo.sh @@ -52,7 +52,7 @@ test_expect_success 'shared=all' ' test 2 = $(git config core.sharedrepository) ' -test_expect_failure 'template can set core.bare' ' +test_expect_success 'template cannot set core.bare' ' test_when_finished "rm -rf subdir" && test_when_finished "rm -rf templates" && test_config core.bare true && @@ -60,18 +60,7 @@ test_expect_failure 'template can set core.bare' ' mkdir -p templates/ && cp .git/config templates/config && git init --template=templates subdir && - test_path_exists subdir/HEAD -' - -test_expect_success 'template can set core.bare but overridden by command line' ' - test_when_finished "rm -rf subdir" && - test_when_finished "rm -rf templates" && - test_config core.bare true && - umask 0022 && - mkdir -p templates/ && - cp .git/config templates/config && - git init --no-bare --template=templates subdir && - test_path_exists subdir/.git/HEAD + test_path_is_missing subdir/HEAD ' test_expect_success POSIXPERM 'update-server-info honors core.sharedRepository' ' @@ -137,22 +126,6 @@ test_expect_success POSIXPERM 'info/refs respects umask in unshared repo' ' test_cmp expect actual ' -test_expect_success REFFILES,POSIXPERM 'git reflog expire honors core.sharedRepository' ' - umask 077 && - git config core.sharedRepository group && - git reflog expire --all && - actual="$(ls -l .git/logs/refs/heads/main)" && - case "$actual" in - -rw-rw-*) - : happy - ;; - *) - echo Ooops, .git/logs/refs/heads/main is not 066x [$actual] - false - ;; - esac -' - test_expect_success POSIXPERM 'forced modes' ' test_when_finished "rm -rf new" && mkdir -p templates/hooks && diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh index 78a09abc35..ec3443cc87 100755 --- a/t/t1400-update-ref.sh +++ b/t/t1400-update-ref.sh @@ -288,33 +288,6 @@ test_expect_success "set $m (logged by touch)" ' test $A = $(git show-ref -s --verify $m) ' -test_expect_success REFFILES 'empty directory removal' ' - git branch d1/d2/r1 HEAD && - git branch d1/r2 HEAD && - test_path_is_file .git/refs/heads/d1/d2/r1 && - test_path_is_file .git/logs/refs/heads/d1/d2/r1 && - git branch -d d1/d2/r1 && - test_must_fail git show-ref --verify -q refs/heads/d1/d2 && - test_must_fail git show-ref --verify -q logs/refs/heads/d1/d2 && - test_path_is_file .git/refs/heads/d1/r2 && - test_path_is_file .git/logs/refs/heads/d1/r2 -' - -test_expect_success REFFILES 'symref empty directory removal' ' - git branch e1/e2/r1 HEAD && - git branch e1/r2 HEAD && - git checkout e1/e2/r1 && - test_when_finished "git checkout main" && - test_path_is_file .git/refs/heads/e1/e2/r1 && - test_path_is_file .git/logs/refs/heads/e1/e2/r1 && - git update-ref -d HEAD && - test_must_fail git show-ref --verify -q refs/heads/e1/e2 && - test_must_fail git show-ref --verify -q logs/refs/heads/e1/e2 && - test_path_is_file .git/refs/heads/e1/r2 && - test_path_is_file .git/logs/refs/heads/e1/r2 && - test_path_is_file .git/logs/HEAD -' - cat >expect <<EOF $Z $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 Initial Creation $A $B $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150260 +0000 Switch @@ -453,15 +426,15 @@ test_expect_success 'Query "main@{2005-05-28}" (past end of history)' ' rm -f expect git update-ref -d $m -test_expect_success REFFILES 'query reflog with gap' ' +test_expect_success 'query reflog with gap' ' test_when_finished "git update-ref -d $m" && - git update-ref $m $F && - cat >.git/logs/$m <<-EOF && - $Z $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150320 -0500 - $A $B $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150380 -0500 - $D $F $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150680 -0500 - EOF + GIT_COMMITTER_DATE="1117150320 -0500" git update-ref $m $A && + GIT_COMMITTER_DATE="1117150380 -0500" git update-ref $m $B && + GIT_COMMITTER_DATE="1117150480 -0500" git update-ref $m $C && + GIT_COMMITTER_DATE="1117150580 -0500" git update-ref $m $D && + GIT_COMMITTER_DATE="1117150680 -0500" git update-ref $m $F && + git reflog delete $m@{2} && git rev-parse --verify "main@{2005-05-26 23:33:01}" >actual 2>stderr && echo "$B" >expect && @@ -649,7 +622,7 @@ test_expect_success 'stdin fails create with no ref' ' test_expect_success 'stdin fails create with no new value' ' echo "create $a" >stdin && test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: create $a: missing <newvalue>" err + grep "fatal: create $a: missing <new-oid>" err ' test_expect_success 'stdin fails create with too many arguments' ' @@ -667,7 +640,7 @@ test_expect_success 'stdin fails update with no ref' ' test_expect_success 'stdin fails update with no new value' ' echo "update $a" >stdin && test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: update $a: missing <newvalue>" err + grep "fatal: update $a: missing <new-oid>" err ' test_expect_success 'stdin fails update with too many arguments' ' @@ -792,21 +765,21 @@ test_expect_success 'stdin update ref fails with wrong old value' ' test_expect_success 'stdin update ref fails with bad old value' ' echo "update $c $m does-not-exist" >stdin && test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: update $c: invalid <oldvalue>: does-not-exist" err && + grep "fatal: update $c: invalid <old-oid>: does-not-exist" err && test_must_fail git rev-parse --verify -q $c ' test_expect_success 'stdin create ref fails with bad new value' ' echo "create $c does-not-exist" >stdin && test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: create $c: invalid <newvalue>: does-not-exist" err && + grep "fatal: create $c: invalid <new-oid>: does-not-exist" err && test_must_fail git rev-parse --verify -q $c ' test_expect_success 'stdin create ref fails with zero new value' ' echo "create $c " >stdin && test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: create $c: zero <newvalue>" err && + grep "fatal: create $c: zero <new-oid>" err && test_must_fail git rev-parse --verify -q $c ' @@ -830,7 +803,7 @@ test_expect_success 'stdin delete ref fails with wrong old value' ' test_expect_success 'stdin delete ref fails with zero old value' ' echo "delete $a " >stdin && test_must_fail git update-ref --stdin <stdin 2>err && - grep "fatal: delete $a: zero <oldvalue>" err && + grep "fatal: delete $a: zero <old-oid>" err && git rev-parse $m >expect && git rev-parse $a >actual && test_cmp expect actual @@ -1054,7 +1027,7 @@ test_expect_success 'stdin -z fails create with no ref' ' test_expect_success 'stdin -z fails create with no new value' ' printf $F "create $a" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: create $a: unexpected end of input when reading <newvalue>" err + grep "fatal: create $a: unexpected end of input when reading <new-oid>" err ' test_expect_success 'stdin -z fails create with too many arguments' ' @@ -1072,27 +1045,27 @@ test_expect_success 'stdin -z fails update with no ref' ' test_expect_success 'stdin -z fails update with too few args' ' printf $F "update $a" "$m" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: update $a: unexpected end of input when reading <oldvalue>" err + grep "fatal: update $a: unexpected end of input when reading <old-oid>" err ' test_expect_success 'stdin -z emits warning with empty new value' ' git update-ref $a $m && printf $F "update $a" "" "" >stdin && git update-ref -z --stdin <stdin 2>err && - grep "warning: update $a: missing <newvalue>, treating as zero" err && + grep "warning: update $a: missing <new-oid>, treating as zero" err && test_must_fail git rev-parse --verify -q $a ' test_expect_success 'stdin -z fails update with no new value' ' printf $F "update $a" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: update $a: unexpected end of input when reading <newvalue>" err + grep "fatal: update $a: unexpected end of input when reading <new-oid>" err ' test_expect_success 'stdin -z fails update with no old value' ' printf $F "update $a" "$m" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: update $a: unexpected end of input when reading <oldvalue>" err + grep "fatal: update $a: unexpected end of input when reading <old-oid>" err ' test_expect_success 'stdin -z fails update with too many arguments' ' @@ -1110,7 +1083,7 @@ test_expect_success 'stdin -z fails delete with no ref' ' test_expect_success 'stdin -z fails delete with no old value' ' printf $F "delete $a" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: delete $a: unexpected end of input when reading <oldvalue>" err + grep "fatal: delete $a: unexpected end of input when reading <old-oid>" err ' test_expect_success 'stdin -z fails delete with too many arguments' ' @@ -1128,7 +1101,7 @@ test_expect_success 'stdin -z fails verify with too many arguments' ' test_expect_success 'stdin -z fails verify with no old value' ' printf $F "verify $a" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: verify $a: unexpected end of input when reading <oldvalue>" err + grep "fatal: verify $a: unexpected end of input when reading <old-oid>" err ' test_expect_success 'stdin -z fails option with unknown name' ' @@ -1187,7 +1160,7 @@ test_expect_success 'stdin -z update ref fails with wrong old value' ' test_expect_success 'stdin -z update ref fails with bad old value' ' printf $F "update $c" "$m" "does-not-exist" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: update $c: invalid <oldvalue>: does-not-exist" err && + grep "fatal: update $c: invalid <old-oid>: does-not-exist" err && test_must_fail git rev-parse --verify -q $c ' @@ -1205,14 +1178,14 @@ test_expect_success 'stdin -z create ref fails with bad new value' ' git update-ref -d "$c" && printf $F "create $c" "does-not-exist" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: create $c: invalid <newvalue>: does-not-exist" err && + grep "fatal: create $c: invalid <new-oid>: does-not-exist" err && test_must_fail git rev-parse --verify -q $c ' test_expect_success 'stdin -z create ref fails with empty new value' ' printf $F "create $c" "" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: create $c: missing <newvalue>" err && + grep "fatal: create $c: missing <new-oid>" err && test_must_fail git rev-parse --verify -q $c ' @@ -1236,7 +1209,7 @@ test_expect_success 'stdin -z delete ref fails with wrong old value' ' test_expect_success 'stdin -z delete ref fails with zero old value' ' printf $F "delete $a" "$Z" >stdin && test_must_fail git update-ref -z --stdin <stdin 2>err && - grep "fatal: delete $a: zero <oldvalue>" err && + grep "fatal: delete $a: zero <old-oid>" err && git rev-parse $m >expect && git rev-parse $a >actual && test_cmp expect actual @@ -1668,13 +1641,4 @@ test_expect_success PIPE 'transaction flushes status updates' ' test_cmp expected actual ' -test_expect_success REFFILES 'directory not created deleting packed ref' ' - git branch d1/d2/r1 HEAD && - git pack-refs --all && - test_path_is_missing .git/refs/heads/d1/d2 && - git update-ref -d refs/heads/d1/d2/r1 && - test_path_is_missing .git/refs/heads/d1/d2 && - test_path_is_missing .git/refs/heads/d1 -' - test_done diff --git a/t/t1404-update-ref-errors.sh b/t/t1404-update-ref-errors.sh index 00b7013705..98e9158bd2 100755 --- a/t/t1404-update-ref-errors.sh +++ b/t/t1404-update-ref-errors.sh @@ -92,9 +92,6 @@ df_test() { else delname="$delref" fi && - cat >expected-err <<-EOF && - fatal: cannot lock ref $SQ$addname$SQ: $SQ$delref$SQ exists; cannot create $SQ$addref$SQ - EOF $pack && if $add_del then @@ -103,7 +100,7 @@ df_test() { printf "%s\n" "delete $delname" "create $addname $D" fi >commands && test_must_fail git update-ref --stdin <commands 2>output.err && - test_cmp expected-err output.err && + grep "fatal:\( cannot lock ref $SQ$addname$SQ:\)\? $SQ$delref$SQ exists; cannot create $SQ$addref$SQ" output.err && printf "%s\n" "$C $delref" >expected-refs && git for-each-ref --format="%(objectname) %(refname)" $prefix/r >actual-refs && test_cmp expected-refs actual-refs @@ -191,69 +188,69 @@ test_expect_success 'one new ref is a simple prefix of another' ' ' -test_expect_success REFFILES 'D/F conflict prevents add long + delete short' ' +test_expect_success 'D/F conflict prevents add long + delete short' ' df_test refs/df-al-ds --add-del foo/bar foo ' -test_expect_success REFFILES 'D/F conflict prevents add short + delete long' ' +test_expect_success 'D/F conflict prevents add short + delete long' ' df_test refs/df-as-dl --add-del foo foo/bar ' -test_expect_success REFFILES 'D/F conflict prevents delete long + add short' ' +test_expect_success 'D/F conflict prevents delete long + add short' ' df_test refs/df-dl-as --del-add foo/bar foo ' -test_expect_success REFFILES 'D/F conflict prevents delete short + add long' ' +test_expect_success 'D/F conflict prevents delete short + add long' ' df_test refs/df-ds-al --del-add foo foo/bar ' -test_expect_success REFFILES 'D/F conflict prevents add long + delete short packed' ' +test_expect_success 'D/F conflict prevents add long + delete short packed' ' df_test refs/df-al-dsp --pack --add-del foo/bar foo ' -test_expect_success REFFILES 'D/F conflict prevents add short + delete long packed' ' +test_expect_success 'D/F conflict prevents add short + delete long packed' ' df_test refs/df-as-dlp --pack --add-del foo foo/bar ' -test_expect_success REFFILES 'D/F conflict prevents delete long packed + add short' ' +test_expect_success 'D/F conflict prevents delete long packed + add short' ' df_test refs/df-dlp-as --pack --del-add foo/bar foo ' -test_expect_success REFFILES 'D/F conflict prevents delete short packed + add long' ' +test_expect_success 'D/F conflict prevents delete short packed + add long' ' df_test refs/df-dsp-al --pack --del-add foo foo/bar ' # Try some combinations involving symbolic refs... -test_expect_success REFFILES 'D/F conflict prevents indirect add long + delete short' ' +test_expect_success 'D/F conflict prevents indirect add long + delete short' ' df_test refs/df-ial-ds --sym-add --add-del foo/bar foo ' -test_expect_success REFFILES 'D/F conflict prevents indirect add long + indirect delete short' ' +test_expect_success 'D/F conflict prevents indirect add long + indirect delete short' ' df_test refs/df-ial-ids --sym-add --sym-del --add-del foo/bar foo ' -test_expect_success REFFILES 'D/F conflict prevents indirect add short + indirect delete long' ' +test_expect_success 'D/F conflict prevents indirect add short + indirect delete long' ' df_test refs/df-ias-idl --sym-add --sym-del --add-del foo foo/bar ' -test_expect_success REFFILES 'D/F conflict prevents indirect delete long + indirect add short' ' +test_expect_success 'D/F conflict prevents indirect delete long + indirect add short' ' df_test refs/df-idl-ias --sym-add --sym-del --del-add foo/bar foo ' -test_expect_success REFFILES 'D/F conflict prevents indirect add long + delete short packed' ' +test_expect_success 'D/F conflict prevents indirect add long + delete short packed' ' df_test refs/df-ial-dsp --sym-add --pack --add-del foo/bar foo ' -test_expect_success REFFILES 'D/F conflict prevents indirect add long + indirect delete short packed' ' +test_expect_success 'D/F conflict prevents indirect add long + indirect delete short packed' ' df_test refs/df-ial-idsp --sym-add --sym-del --pack --add-del foo/bar foo ' -test_expect_success REFFILES 'D/F conflict prevents add long + indirect delete short packed' ' +test_expect_success 'D/F conflict prevents add long + indirect delete short packed' ' df_test refs/df-al-idsp --sym-del --pack --add-del foo/bar foo ' -test_expect_success REFFILES 'D/F conflict prevents indirect delete long packed + indirect add short' ' +test_expect_success 'D/F conflict prevents indirect delete long packed + indirect add short' ' df_test refs/df-idlp-ias --sym-add --sym-del --pack --del-add foo/bar foo ' diff --git a/t/t1405-main-ref-store.sh b/t/t1405-main-ref-store.sh index 976bd71efb..a6bcd62ab6 100755 --- a/t/t1405-main-ref-store.sh +++ b/t/t1405-main-ref-store.sh @@ -33,12 +33,6 @@ test_expect_success 'delete_refs(FOO, refs/tags/new-tag)' ' test_must_fail git rev-parse refs/tags/new-tag -- ' -# In reftable, we keep the reflogs around for deleted refs. -test_expect_success !REFFILES 'delete-reflog(FOO, refs/tags/new-tag)' ' - $RUN delete-reflog FOO && - $RUN delete-reflog refs/tags/new-tag -' - test_expect_success 'rename_refs(main, new-main)' ' git rev-parse main >expected && $RUN rename-ref refs/heads/main refs/heads/new-main && @@ -74,11 +68,11 @@ test_expect_success 'verify_ref(new-main)' ' ' test_expect_success 'for_each_reflog()' ' - $RUN for-each-reflog | sort -k2 | cut -d" " -f 2- >actual && + $RUN for-each-reflog >actual && cat >expected <<-\EOF && - HEAD 0x1 - refs/heads/main 0x0 - refs/heads/new-main 0x0 + HEAD + refs/heads/main + refs/heads/new-main EOF test_cmp expected actual ' diff --git a/t/t1406-submodule-ref-store.sh b/t/t1406-submodule-ref-store.sh index e6a7f7334b..c01f0f14a1 100755 --- a/t/t1406-submodule-ref-store.sh +++ b/t/t1406-submodule-ref-store.sh @@ -63,11 +63,11 @@ test_expect_success 'verify_ref(new-main)' ' ' test_expect_success 'for_each_reflog()' ' - $RUN for-each-reflog | sort | cut -d" " -f 2- >actual && + $RUN for-each-reflog >actual && cat >expected <<-\EOF && - HEAD 0x1 - refs/heads/main 0x0 - refs/heads/new-main 0x0 + HEAD + refs/heads/main + refs/heads/new-main EOF test_cmp expected actual ' diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh index d2f5f42e67..5bf883f1e3 100755 --- a/t/t1410-reflog.sh +++ b/t/t1410-reflog.sh @@ -436,4 +436,112 @@ test_expect_success 'empty reflog' ' test_must_be_empty err ' +test_expect_success 'list reflogs' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + git reflog list >actual && + test_must_be_empty actual && + + test_commit A && + cat >expect <<-EOF && + HEAD + refs/heads/main + EOF + git reflog list >actual && + test_cmp expect actual && + + git branch b && + cat >expect <<-EOF && + HEAD + refs/heads/b + refs/heads/main + EOF + git reflog list >actual && + test_cmp expect actual + ) +' + +test_expect_success 'list reflogs with worktree' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + + test_commit A && + git worktree add wt && + git -c core.logAllRefUpdates=always \ + update-ref refs/worktree/main HEAD && + git -c core.logAllRefUpdates=always \ + update-ref refs/worktree/per-worktree HEAD && + git -c core.logAllRefUpdates=always -C wt \ + update-ref refs/worktree/per-worktree HEAD && + git -c core.logAllRefUpdates=always -C wt \ + update-ref refs/worktree/worktree HEAD && + + cat >expect <<-EOF && + HEAD + refs/heads/main + refs/heads/wt + refs/worktree/main + refs/worktree/per-worktree + EOF + git reflog list >actual && + test_cmp expect actual && + + cat >expect <<-EOF && + HEAD + refs/heads/main + refs/heads/wt + refs/worktree/per-worktree + refs/worktree/worktree + EOF + git -C wt reflog list >actual && + test_cmp expect actual + ) +' + +test_expect_success 'reflog list returns error with additional args' ' + cat >expect <<-EOF && + error: list does not accept arguments: ${SQ}bogus${SQ} + EOF + test_must_fail git reflog list bogus 2>err && + test_cmp expect err +' + +test_expect_success 'reflog for symref with unborn target can be listed' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit A && + git symbolic-ref HEAD refs/heads/unborn && + cat >expect <<-EOF && + HEAD + refs/heads/main + EOF + git reflog list >actual && + test_cmp expect actual + ) +' + +test_expect_success 'reflog with invalid object ID can be listed' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit A && + test-tool ref-store main update-ref msg refs/heads/missing \ + $(test_oid deadbeef) "$ZERO_OID" REF_SKIP_OID_VERIFICATION && + cat >expect <<-EOF && + HEAD + refs/heads/main + refs/heads/missing + EOF + git reflog list >actual && + test_cmp expect actual + ) +' + test_done diff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh index f0737593c3..b754b9fd74 100755 --- a/t/t1502-rev-parse-parseopt.sh +++ b/t/t1502-rev-parse-parseopt.sh @@ -322,4 +322,15 @@ check_invalid_long_option optionspec-neg --no-positive-only check_invalid_long_option optionspec-neg --negative check_invalid_long_option optionspec-neg --no-no-negative +test_expect_success 'ambiguous: --no matches both --noble and --no-noble' ' + cat >spec <<-\EOF && + some-command [options] + -- + noble The feudal switch. + EOF + test_expect_code 129 env GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=false \ + git rev-parse --parseopt -- <spec 2>err --no && + grep "error: ambiguous option: no (could be --noble or --no-noble)" err +' + test_done diff --git a/t/t1509/prepare-chroot.sh b/t/t1509/prepare-chroot.sh index 6d47e2c725..dc997e0a64 100755 --- a/t/t1509/prepare-chroot.sh +++ b/t/t1509/prepare-chroot.sh @@ -43,7 +43,7 @@ rsync --exclude-from t/t1509/excludes -Ha . "$R$(pwd)" # env might slip through, see test-lib.sh, unset.*PERL_PATH sed 's|^PERL_PATH=.*|PERL_PATH=/bin/true|' GIT-BUILD-OPTIONS > "$R$(pwd)/GIT-BUILD-OPTIONS" for cmd in git $BB;do - ldd $cmd | grep '/' | sed 's,.*\s\(/[^ ]*\).*,\1,' | while read i; do + ldd $cmd | sed -n '/\//s,.*\s\(/[^ ]*\).*,\1,p' | while read i; do mkdir -p "$R$(dirname $i)" cp "$i" "$R/$i" done diff --git a/t/t2011-checkout-invalid-head.sh b/t/t2011-checkout-invalid-head.sh index 3c8135831b..04f53b1ea1 100755 --- a/t/t2011-checkout-invalid-head.sh +++ b/t/t2011-checkout-invalid-head.sh @@ -29,36 +29,33 @@ test_expect_success REFFILES 'checkout notices failure to lock HEAD' ' test_must_fail git checkout -b other ' -test_expect_success REFFILES 'create ref directory/file conflict scenario' ' +test_expect_success 'create ref directory/file conflict scenario' ' git update-ref refs/heads/outer/inner main && - - # do not rely on symbolic-ref to get a known state, - # as it may use the same code we are testing reset_to_df () { - echo "ref: refs/heads/outer" >.git/HEAD + git symbolic-ref HEAD refs/heads/outer } ' -test_expect_success REFFILES 'checkout away from d/f HEAD (unpacked, to branch)' ' +test_expect_success 'checkout away from d/f HEAD (unpacked, to branch)' ' reset_to_df && git checkout main ' -test_expect_success REFFILES 'checkout away from d/f HEAD (unpacked, to detached)' ' +test_expect_success 'checkout away from d/f HEAD (unpacked, to detached)' ' reset_to_df && git checkout --detach main ' -test_expect_success REFFILES 'pack refs' ' +test_expect_success 'pack refs' ' git pack-refs --all --prune ' -test_expect_success REFFILES 'checkout away from d/f HEAD (packed, to branch)' ' +test_expect_success 'checkout away from d/f HEAD (packed, to branch)' ' reset_to_df && git checkout main ' -test_expect_success REFFILES 'checkout away from d/f HEAD (packed, to detached)' ' +test_expect_success 'checkout away from d/f HEAD (packed, to detached)' ' reset_to_df && git checkout --detach main ' diff --git a/t/t2016-checkout-patch.sh b/t/t2016-checkout-patch.sh index 747eb5563e..c40b661ac1 100755 --- a/t/t2016-checkout-patch.sh +++ b/t/t2016-checkout-patch.sh @@ -2,6 +2,7 @@ test_description='git checkout --patch' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-patch-mode.sh test_expect_success 'setup' ' @@ -38,26 +39,32 @@ test_expect_success 'git checkout -p with staged changes' ' verify_state dir/foo index index ' -test_expect_success 'git checkout -p HEAD with NO staged changes: abort' ' - set_and_save_state dir/foo work head && - test_write_lines n y n | git checkout -p HEAD && - verify_saved_state bar && - verify_saved_state dir/foo -' - -test_expect_success 'git checkout -p HEAD with NO staged changes: apply' ' - test_write_lines n y y | git checkout -p HEAD && - verify_saved_state bar && - verify_state dir/foo head head -' - -test_expect_success 'git checkout -p HEAD with change already staged' ' - set_state dir/foo index index && - # the third n is to get out in case it mistakenly does not apply - test_write_lines n y n | git checkout -p HEAD && - verify_saved_state bar && - verify_state dir/foo head head -' +for opt in "HEAD" "@" +do + test_expect_success "git checkout -p $opt with NO staged changes: abort" ' + set_and_save_state dir/foo work head && + test_write_lines n y n | git checkout -p $opt >output && + verify_saved_state bar && + verify_saved_state dir/foo && + test_grep "Discard" output + ' + + test_expect_success "git checkout -p $opt with NO staged changes: apply" ' + test_write_lines n y y | git checkout -p $opt >output && + verify_saved_state bar && + verify_state dir/foo head head && + test_grep "Discard" output + ' + + test_expect_success "git checkout -p $opt with change already staged" ' + set_state dir/foo index index && + # the third n is to get out in case it mistakenly does not apply + test_write_lines n y n | git checkout -p $opt >output && + verify_saved_state bar && + verify_state dir/foo head head && + test_grep "Discard" output + ' +done test_expect_success 'git checkout -p HEAD^...' ' # the third n is to get out in case it mistakenly does not apply diff --git a/t/t2020-checkout-detach.sh b/t/t2020-checkout-detach.sh index 8202ef8c74..8d90d02850 100755 --- a/t/t2020-checkout-detach.sh +++ b/t/t2020-checkout-detach.sh @@ -45,6 +45,18 @@ test_expect_success 'checkout branch does not detach' ' check_not_detached ' +for opt in "HEAD" "@" +do + test_expect_success "checkout $opt no-op/don't detach" ' + reset && + cat .git/HEAD >expect && + git checkout $opt && + cat .git/HEAD >actual && + check_not_detached && + test_cmp expect actual + ' +done + test_expect_success 'checkout tag detaches' ' reset && git checkout tag && @@ -164,7 +176,10 @@ test_expect_success 'tracking count is accurate after orphan check' ' git config branch.child.merge refs/heads/main && git checkout child^ && git checkout child >stdout && - test_cmp expect stdout + test_cmp expect stdout && + + git checkout --detach child >stdout && + test_grep ! "can be fast-forwarded\." stdout ' test_expect_success 'no advice given for explicit detached head state' ' diff --git a/t/t2024-checkout-dwim.sh b/t/t2024-checkout-dwim.sh index a97416ce65..a3b1449ef1 100755 --- a/t/t2024-checkout-dwim.sh +++ b/t/t2024-checkout-dwim.sh @@ -113,7 +113,7 @@ test_expect_success 'checkout of branch from multiple remotes fails with advice' test_grep ! "^hint: " stderr ' -test_expect_success PERL 'checkout -p with multiple remotes does not print advice' ' +test_expect_success 'checkout -p with multiple remotes does not print advice' ' git checkout -B main && test_might_fail git branch -D foo && diff --git a/t/t2070-restore.sh b/t/t2070-restore.sh index 16d6348b69..ac404945d4 100755 --- a/t/t2070-restore.sh +++ b/t/t2070-restore.sh @@ -5,6 +5,7 @@ test_description='restore basic functionality' 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' ' diff --git a/t/t2071-restore-patch.sh b/t/t2071-restore-patch.sh index b5c5c0ff7e..42d5522119 100755 --- a/t/t2071-restore-patch.sh +++ b/t/t2071-restore-patch.sh @@ -2,9 +2,10 @@ test_description='git restore --patch' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-patch-mode.sh -test_expect_success PERL 'setup' ' +test_expect_success 'setup' ' mkdir dir && echo parent >dir/foo && echo dummy >bar && @@ -16,43 +17,47 @@ test_expect_success PERL 'setup' ' save_head ' -test_expect_success PERL 'restore -p without pathspec is fine' ' +test_expect_success 'restore -p without pathspec is fine' ' echo q >cmd && git restore -p <cmd ' # note: bar sorts before dir/foo, so the first 'n' is always to skip 'bar' -test_expect_success PERL 'saying "n" does nothing' ' +test_expect_success 'saying "n" does nothing' ' set_and_save_state dir/foo work head && test_write_lines n n | git restore -p && verify_saved_state bar && verify_saved_state dir/foo ' -test_expect_success PERL 'git restore -p' ' +test_expect_success 'git restore -p' ' set_and_save_state dir/foo work head && test_write_lines n y | git restore -p && verify_saved_state bar && verify_state dir/foo head head ' -test_expect_success PERL 'git restore -p with staged changes' ' +test_expect_success 'git restore -p with staged changes' ' set_state dir/foo work index && test_write_lines n y | git restore -p && verify_saved_state bar && verify_state dir/foo index index ' -test_expect_success PERL 'git restore -p --source=HEAD' ' - set_state dir/foo work index && - # the third n is to get out in case it mistakenly does not apply - test_write_lines n y n | git restore -p --source=HEAD && - verify_saved_state bar && - verify_state dir/foo head index -' - -test_expect_success PERL 'git restore -p --source=HEAD^' ' +for opt in "HEAD" "@" +do + test_expect_success "git restore -p --source=$opt" ' + set_state dir/foo work index && + # the third n is to get out in case it mistakenly does not apply + test_write_lines n y n | git restore -p --source=$opt >output && + verify_saved_state bar && + verify_state dir/foo head index && + test_grep "Discard" output + ' +done + +test_expect_success 'git restore -p --source=HEAD^' ' set_state dir/foo work index && # the third n is to get out in case it mistakenly does not apply test_write_lines n y n | git restore -p --source=HEAD^ && @@ -60,7 +65,7 @@ test_expect_success PERL 'git restore -p --source=HEAD^' ' verify_state dir/foo parent index ' -test_expect_success PERL 'git restore -p --source=HEAD^...' ' +test_expect_success 'git restore -p --source=HEAD^...' ' set_state dir/foo work index && # the third n is to get out in case it mistakenly does not apply test_write_lines n y n | git restore -p --source=HEAD^... && @@ -68,7 +73,7 @@ test_expect_success PERL 'git restore -p --source=HEAD^...' ' verify_state dir/foo parent index ' -test_expect_success PERL 'git restore -p handles deletion' ' +test_expect_success 'git restore -p handles deletion' ' set_state dir/foo work index && rm dir/foo && test_write_lines n y | git restore -p && @@ -81,21 +86,21 @@ test_expect_success PERL 'git restore -p handles deletion' ' # dir/foo. There's always an extra 'n' to reject edits to dir/foo in # the failure case (and thus get out of the loop). -test_expect_success PERL 'path limiting works: dir' ' +test_expect_success 'path limiting works: dir' ' set_state dir/foo work head && test_write_lines y n | git restore -p dir && verify_saved_state bar && verify_state dir/foo head head ' -test_expect_success PERL 'path limiting works: -- dir' ' +test_expect_success 'path limiting works: -- dir' ' set_state dir/foo work head && test_write_lines y n | git restore -p -- dir && verify_saved_state bar && verify_state dir/foo head head ' -test_expect_success PERL 'path limiting works: HEAD^ -- dir' ' +test_expect_success 'path limiting works: HEAD^ -- dir' ' set_state dir/foo work head && # the third n is to get out in case it mistakenly does not apply test_write_lines y n n | git restore -p --source=HEAD^ -- dir && @@ -103,7 +108,7 @@ test_expect_success PERL 'path limiting works: HEAD^ -- dir' ' verify_state dir/foo parent head ' -test_expect_success PERL 'path limiting works: foo inside dir' ' +test_expect_success 'path limiting works: foo inside dir' ' set_state dir/foo work head && # the third n is to get out in case it mistakenly does not apply test_write_lines y n n | (cd dir && git restore -p foo) && @@ -111,7 +116,7 @@ test_expect_success PERL 'path limiting works: foo inside dir' ' verify_state dir/foo head head ' -test_expect_success PERL 'none of this moved HEAD' ' +test_expect_success 'none of this moved HEAD' ' verify_saved_head ' diff --git a/t/t2072-restore-pathspec-file.sh b/t/t2072-restore-pathspec-file.sh index 8198a1e578..86c9c88788 100755 --- a/t/t2072-restore-pathspec-file.sh +++ b/t/t2072-restore-pathspec-file.sh @@ -2,6 +2,7 @@ test_description='restore --pathspec-from-file' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_tick diff --git a/t/t2104-update-index-skip-worktree.sh b/t/t2104-update-index-skip-worktree.sh index 0bab134d71..7ec7f30b44 100755 --- a/t/t2104-update-index-skip-worktree.sh +++ b/t/t2104-update-index-skip-worktree.sh @@ -11,27 +11,27 @@ TEST_PASSES_SANITIZE_LEAK=true sane_unset GIT_TEST_SPLIT_INDEX test_set_index_version () { - GIT_INDEX_VERSION="$1" - export GIT_INDEX_VERSION + GIT_INDEX_VERSION="$1" + export GIT_INDEX_VERSION } test_set_index_version 3 -cat >expect.full <<EOF -H 1 -H 2 -H sub/1 -H sub/2 -EOF +test_expect_success 'setup' ' + cat >expect.full <<-\EOF && + H 1 + H 2 + H sub/1 + H sub/2 + EOF -cat >expect.skip <<EOF -S 1 -H 2 -S sub/1 -H sub/2 -EOF + cat >expect.skip <<-\EOF && + S 1 + H 2 + S sub/1 + H sub/2 + EOF -test_expect_success 'setup' ' mkdir sub && touch ./1 ./2 sub/1 sub/2 && git add 1 2 sub/1 sub/2 && diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh index c01492f33f..df235ac306 100755 --- a/t/t2200-add-update.sh +++ b/t/t2200-add-update.sh @@ -65,6 +65,16 @@ test_expect_success 'update did not touch untracked files' ' test_must_be_empty out ' +test_expect_success 'error out when passing untracked path' ' + git reset --hard && + echo content >>baz && + echo content >>top && + test_must_fail git add -u baz top 2>err && + test_grep -e "error: pathspec .baz. did not match any file(s) known to git" err && + git diff --cached --name-only >actual && + test_must_be_empty actual +' + test_expect_success 'cache tree has not been corrupted' ' git ls-files -s | diff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh index c28c04133c..ba320dc417 100755 --- a/t/t2400-worktree-add.sh +++ b/t/t2400-worktree-add.sh @@ -427,7 +427,7 @@ test_expect_success '"add" worktree with orphan branch, lock, and reason' ' # Note: Quoted arguments containing spaces are not supported. test_wt_add_orphan_hint () { local context="$1" && - local use_branch=$2 && + local use_branch="$2" && shift 2 && local opts="$*" && test_expect_success "'worktree add' show orphan hint in bad/orphan HEAD w/ $context" ' diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index de7d3014e4..ccfa6a720d 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -75,13 +75,13 @@ test_expect_success 'git branch HEAD should fail' ' test_must_fail git branch HEAD ' -cat >expect <<EOF -$HEAD refs/heads/d/e/f@{0}: branch: Created from main -EOF test_expect_success 'git branch --create-reflog d/e/f should create a branch and a log' ' GIT_COMMITTER_DATE="2005-05-26 23:30" \ git -c core.logallrefupdates=false branch --create-reflog d/e/f && test_ref_exists refs/heads/d/e/f && + cat >expect <<-EOF && + $HEAD refs/heads/d/e/f@{0}: branch: Created from main + EOF git reflog show --no-abbrev-commit refs/heads/d/e/f >actual && test_cmp expect actual ' @@ -440,10 +440,10 @@ test_expect_success 'git branch --list -v with --abbrev' ' test_expect_success 'git branch --column' ' COLUMNS=81 git branch --column=column >actual && - cat >expect <<\EOF && - a/b/c bam foo l * main n o/p r - abc bar j/k m/m mb o/o q topic -EOF + cat >expect <<-\EOF && + a/b/c bam foo l * main n o/p r + abc bar j/k m/m mb o/o q topic + EOF test_cmp expect actual ' @@ -453,25 +453,25 @@ test_expect_success 'git branch --column with an extremely long branch name' ' test_when_finished "git branch -d $long" && git branch $long && COLUMNS=80 git branch --column=column >actual && - cat >expect <<EOF && - a/b/c - abc - bam - bar - foo - j/k - l - m/m -* main - mb - n - o/o - o/p - q - r - topic - $long -EOF + cat >expect <<-EOF && + a/b/c + abc + bam + bar + foo + j/k + l + m/m + * main + mb + n + o/o + o/p + q + r + topic + $long + EOF test_cmp expect actual ' @@ -481,10 +481,10 @@ test_expect_success 'git branch with column.*' ' COLUMNS=80 git branch >actual && git config --unset column.branch && git config --unset column.ui && - cat >expect <<\EOF && - a/b/c bam foo l * main n o/p r - abc bar j/k m/m mb o/o q topic -EOF + cat >expect <<-\EOF && + a/b/c bam foo l * main n o/p r + abc bar j/k m/m mb o/o q topic + EOF test_cmp expect actual ' @@ -496,39 +496,36 @@ test_expect_success 'git branch -v with column.ui ignored' ' git config column.ui column && COLUMNS=80 git branch -v | cut -c -8 | sed "s/ *$//" >actual && git config --unset column.ui && - cat >expect <<\EOF && - a/b/c - abc - bam - bar - foo - j/k - l - m/m -* main - mb - n - o/o - o/p - q - r - topic -EOF + cat >expect <<-\EOF && + a/b/c + abc + bam + bar + foo + j/k + l + m/m + * main + mb + n + o/o + o/p + q + r + topic + EOF test_cmp expect actual ' -mv .git/config .git/config-saved - test_expect_success DEFAULT_REPO_FORMAT 'git branch -m q q2 without config should succeed' ' + test_when_finished mv .git/config-saved .git/config && + mv .git/config .git/config-saved && git branch -m q q2 && git branch -m q2 q ' -mv .git/config-saved .git/config - -git config branch.s/s.dummy Hello - test_expect_success 'git branch -m s/s s should work when s/t is deleted' ' + git config branch.s/s.dummy Hello && git branch --create-reflog s/s && git reflog exists refs/heads/s/s && git branch --create-reflog s/t && @@ -579,7 +576,7 @@ EOF # ...and that the comments for those sections are also # preserved. - cat config.branch | sed "s/\"source\"/\"dest\"/" >expect && + sed "s/\"source\"/\"dest\"/" config.branch >expect && sed -n -e "/Note the lack/,\$p" .git/config >actual && test_cmp expect actual ' @@ -836,35 +833,6 @@ test_expect_success 'renaming a symref is not allowed' ' test_ref_missing refs/heads/new-topic ' -test_expect_success SYMLINKS,REFFILES 'git branch -m u v should fail when the reflog for u is a symlink' ' - git branch --create-reflog u && - mv .git/logs/refs/heads/u real-u && - ln -s real-u .git/logs/refs/heads/u && - test_must_fail git branch -m u v -' - -test_expect_success SYMLINKS,REFFILES 'git branch -m with symlinked .git/refs' ' - test_when_finished "rm -rf subdir" && - git init --bare subdir && - - rm -rfv subdir/refs subdir/objects subdir/packed-refs && - ln -s ../.git/refs subdir/refs && - ln -s ../.git/objects subdir/objects && - ln -s ../.git/packed-refs subdir/packed-refs && - - git -C subdir rev-parse --absolute-git-dir >subdir.dir && - git rev-parse --absolute-git-dir >our.dir && - ! test_cmp subdir.dir our.dir && - - git -C subdir log && - git -C subdir branch rename-src && - git rev-parse rename-src >expect && - git -C subdir branch -m rename-src rename-dest && - git rev-parse rename-dest >actual && - test_cmp expect actual && - git branch -D rename-dest -' - test_expect_success 'test tracking setup via --track' ' git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && @@ -1141,14 +1109,14 @@ test_expect_success '--set-upstream-to notices an error to set branch as own ups test_cmp expect actual " -# Keep this test last, as it changes the current branch -cat >expect <<EOF -$HEAD refs/heads/g/h/i@{0}: branch: Created from main -EOF test_expect_success 'git checkout -b g/h/i -l should create a branch and a log' ' + test_when_finished git checkout main && GIT_COMMITTER_DATE="2005-05-26 23:30" \ git checkout -b g/h/i -l main && test_ref_exists refs/heads/g/h/i && + cat >expect <<-EOF && + $HEAD refs/heads/g/h/i@{0}: branch: Created from main + EOF git reflog show --no-abbrev-commit refs/heads/g/h/i >actual && test_cmp expect actual ' @@ -1186,9 +1154,9 @@ test_expect_success 'avoid ambiguous track and advise' ' hint: tracking ref '\''refs/heads/main'\'': hint: ambi1 hint: ambi2 - hint: '' + hint: hint: This is typically a configuration error. - hint: '' + hint: hint: To support setting up tracking branches, ensure that hint: different remotes'\'' fetch refspecs map into different hint: tracking namespaces. @@ -1725,4 +1693,14 @@ test_expect_success '--track overrides branch.autoSetupMerge' ' test_cmp_config "" --default "" branch.foo5.merge ' +test_expect_success 'errors if given a bad branch name' ' + cat <<-\EOF >expect && + fatal: '\''foo..bar'\'' is not a valid branch name + hint: See `man git check-ref-format` + hint: Disable this message with "git config advice.refSyntax false" + EOF + test_must_fail git branch foo..bar >actual 2>&1 && + test_cmp expect actual +' + test_done diff --git a/t/t3202-show-branch.sh b/t/t3202-show-branch.sh index 6a98b2df76..a1139f79e2 100755 --- a/t/t3202-show-branch.sh +++ b/t/t3202-show-branch.sh @@ -4,9 +4,6 @@ test_description='test show-branch' . ./test-lib.sh -# arbitrary reference time: 2009-08-30 19:20:00 -GIT_TEST_DATE_NOW=1251660000; export GIT_TEST_DATE_NOW - test_expect_success 'error descriptions on empty repository' ' current=$(git branch --show-current) && cat >expect <<-EOF && @@ -187,18 +184,6 @@ test_expect_success 'show branch --merge-base with N arguments' ' test_cmp expect actual ' -test_expect_success 'show branch --reflog=2' ' - sed "s/^> //" >expect <<-\EOF && - > ! [refs/heads/branch10@{0}] (4 years, 5 months ago) commit: branch10 - > ! [refs/heads/branch10@{1}] (4 years, 5 months ago) commit: branch10 - > -- - > + [refs/heads/branch10@{0}] branch10 - > ++ [refs/heads/branch10@{1}] initial - EOF - git show-branch --reflog=2 >actual && - test_cmp actual expect -' - # incompatible options while read combo do @@ -264,4 +249,38 @@ test_expect_success 'error descriptions on orphan branch' ' test_branch_op_in_wt -c new-branch ' +test_expect_success 'setup reflogs' ' + test_commit base && + git checkout -b branch && + test_commit one && + git reset --hard HEAD^ && + test_commit two && + test_commit three +' + +test_expect_success '--reflog shows reflog entries' ' + cat >expect <<-\EOF && + ! [branch@{0}] (0 seconds ago) commit: three + ! [branch@{1}] (60 seconds ago) commit: two + ! [branch@{2}] (2 minutes ago) reset: moving to HEAD^ + ! [branch@{3}] (2 minutes ago) commit: one + ---- + + [branch@{0}] three + ++ [branch@{1}] two + + [branch@{3}] one + ++++ [branch@{2}] base + EOF + # the output always contains relative timestamps; use + # a known time to get deterministic results + GIT_TEST_DATE_NOW=$test_tick \ + git show-branch --reflog branch >actual && + test_cmp expect actual +' + +test_expect_success '--reflog handles missing reflog' ' + git reflog expire --expire=now branch && + git show-branch --reflog branch >actual && + test_must_be_empty actual +' + test_done diff --git a/t/t3321-notes-stripspace.sh b/t/t3321-notes-stripspace.sh index 088a852dd4..beca346056 100755 --- a/t/t3321-notes-stripspace.sh +++ b/t/t3321-notes-stripspace.sh @@ -442,7 +442,7 @@ test_expect_success 'add note by specifying "-C", "--no-stripspace" is the defau ${LF} EOF - cat expect | git hash-object -w --stdin >blob && + git hash-object -w --stdin <expect >blob && git notes add -C $(cat blob) && git notes show >actual && test_cmp expect actual && @@ -468,7 +468,7 @@ test_expect_success 'reuse note by specifying "-C" and "--stripspace"' ' second-line EOF - cat data | git hash-object -w --stdin >blob && + git hash-object -w --stdin <data >blob && git notes add --stripspace -C $(cat blob) && git notes show >actual && test_cmp expect actual @@ -492,7 +492,7 @@ test_expect_success 'reuse with "-C" and add note with "-m", "-m" will stripspac third-line EOF - cat data | git hash-object -w --stdin >blob && + git hash-object -w --stdin <data >blob && git notes add -C $(cat blob) -m "third-line" && git notes show >actual && test_cmp expect actual @@ -511,7 +511,7 @@ test_expect_success 'add note with "-m" and reuse note with "-C", "-C" will not second-line EOF - cat data | git hash-object -w --stdin >blob && + git hash-object -w --stdin <data >blob && git notes add -m "first-line" -C $(cat blob) && git notes show >actual && test_cmp expect actual diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index 57f1392926..e1c8c5f701 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -424,16 +424,6 @@ test_expect_success 'refuse to switch to branch checked out elsewhere' ' test_grep "already used by worktree at" err ' -test_expect_success REFFILES,MINGW,SYMLINKS_WINDOWS 'rebase when .git/logs is a symlink' ' - git checkout main && - mv .git/logs actual_logs && - cmd //c "mklink /D .git\logs ..\actual_logs" && - git rebase -f HEAD^ && - test -L .git/logs && - rm .git/logs && - mv actual_logs .git/logs -' - test_expect_success 'rebase when inside worktree subdirectory' ' git init main-wt && ( diff --git a/t/t3424-rebase-empty.sh b/t/t3424-rebase-empty.sh index 5e1045a0af..1ee6b00fd5 100755 --- a/t/t3424-rebase-empty.sh +++ b/t/t3424-rebase-empty.sh @@ -72,6 +72,17 @@ test_expect_success 'rebase --merge --empty=keep' ' test_cmp expect actual ' +test_expect_success 'rebase --merge --empty=stop' ' + git checkout -B testing localmods && + test_must_fail git rebase --merge --empty=stop upstream && + + git rebase --skip && + + test_write_lines D C B A >expect && + git log --format=%s >actual && + test_cmp expect actual +' + test_expect_success 'rebase --merge --empty=ask' ' git checkout -B testing localmods && test_must_fail git rebase --merge --empty=ask upstream && @@ -101,9 +112,9 @@ test_expect_success 'rebase --interactive --empty=keep' ' test_cmp expect actual ' -test_expect_success 'rebase --interactive --empty=ask' ' +test_expect_success 'rebase --interactive --empty=stop' ' git checkout -B testing localmods && - test_must_fail git rebase --interactive --empty=ask upstream && + test_must_fail git rebase --interactive --empty=stop upstream && git rebase --skip && @@ -112,7 +123,7 @@ test_expect_success 'rebase --interactive --empty=ask' ' test_cmp expect actual ' -test_expect_success 'rebase --interactive uses default of --empty=ask' ' +test_expect_success 'rebase --interactive uses default of --empty=stop' ' git checkout -B testing localmods && test_must_fail git rebase --interactive upstream && @@ -167,4 +178,42 @@ test_expect_success 'rebase --merge does not leave state laying around' ' test_path_is_missing .git/MERGE_MSG ' +test_expect_success 'rebase --exec --empty=drop' ' + git checkout -B testing localmods && + git rebase --exec "true" --empty=drop upstream && + + test_write_lines D C B A >expect && + git log --format=%s >actual && + test_cmp expect actual +' + +test_expect_success 'rebase --exec --empty=keep' ' + git checkout -B testing localmods && + git rebase --exec "true" --empty=keep upstream && + + test_write_lines D C2 C B A >expect && + git log --format=%s >actual && + test_cmp expect actual +' + +test_expect_success 'rebase --exec uses default of --empty=keep' ' + git checkout -B testing localmods && + git rebase --exec "true" upstream && + + test_write_lines D C2 C B A >expect && + git log --format=%s >actual && + test_cmp expect actual +' + +test_expect_success 'rebase --exec --empty=stop' ' + git checkout -B testing localmods && + test_must_fail git rebase --exec "true" --empty=stop upstream && + + git rebase --skip && + + test_write_lines D C B A >expect && + git log --format=%s >actual && + test_cmp expect actual +' + test_done diff --git a/t/t3428-rebase-signoff.sh b/t/t3428-rebase-signoff.sh index e1b1e94764..1bebd1ce74 100755 --- a/t/t3428-rebase-signoff.sh +++ b/t/t3428-rebase-signoff.sh @@ -8,47 +8,45 @@ This test runs git rebase --signoff and make sure that it works. TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh -# A simple file to commit -cat >file <<EOF -a -EOF +test_expect_success 'setup' ' + git commit --allow-empty -m "Initial empty commit" && + test_commit first file a && + + ident="$GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" && -# Expected commit message for initial commit after rebase --signoff -cat >expected-initial-signed <<EOF -Initial empty commit + # Expected commit message for initial commit after rebase --signoff + cat >expected-initial-signed <<-EOF && + Initial empty commit -Signed-off-by: $(git var GIT_COMMITTER_IDENT | sed -e "s/>.*/>/") -EOF + Signed-off-by: $ident + EOF -# Expected commit message after rebase --signoff -cat >expected-signed <<EOF -first + # Expected commit message after rebase --signoff + cat >expected-signed <<-EOF && + first -Signed-off-by: $(git var GIT_COMMITTER_IDENT | sed -e "s/>.*/>/") -EOF + Signed-off-by: $ident + EOF -# Expected commit message after rebase without --signoff (or with --no-signoff) -cat >expected-unsigned <<EOF -first -EOF + # Expected commit message after rebase without --signoff (or with --no-signoff) + cat >expected-unsigned <<-EOF && + first + EOF + git config alias.rbs "rebase --signoff" +' # We configure an alias to do the rebase --signoff so that # on the next subtest we can show that --no-signoff overrides the alias -test_expect_success 'rebase --signoff adds a sign-off line' ' - git commit --allow-empty -m "Initial empty commit" && - git add file && git commit -m first && - git config alias.rbs "rebase --signoff" && - git rbs HEAD^ && - git cat-file commit HEAD | sed -e "1,/^\$/d" > actual && - test_cmp expected-signed actual +test_expect_success 'rebase --apply --signoff adds a sign-off line' ' + git rbs --apply HEAD^ && + test_commit_message HEAD expected-signed ' test_expect_success 'rebase --no-signoff does not add a sign-off line' ' git commit --amend -m "first" && git rbs --no-signoff HEAD^ && - git cat-file commit HEAD | sed -e "1,/^\$/d" > actual && - test_cmp expected-unsigned actual + test_commit_message HEAD expected-unsigned ' test_expect_success 'rebase --exec --signoff adds a sign-off line' ' @@ -56,30 +54,25 @@ test_expect_success 'rebase --exec --signoff adds a sign-off line' ' git commit --amend -m "first" && git rebase --exec "touch exec" --signoff HEAD^ && test_path_is_file exec && - git cat-file commit HEAD | sed -e "1,/^\$/d" >actual && - test_cmp expected-signed actual + test_commit_message HEAD expected-signed ' test_expect_success 'rebase --root --signoff adds a sign-off line' ' git commit --amend -m "first" && git rebase --root --keep-empty --signoff && - git cat-file commit HEAD^ | sed -e "1,/^\$/d" >actual && - test_cmp expected-initial-signed actual && - git cat-file commit HEAD | sed -e "1,/^\$/d" >actual && - test_cmp expected-signed actual + test_commit_message HEAD^ expected-initial-signed && + test_commit_message HEAD expected-signed ' test_expect_success 'rebase -i --signoff fails' ' git commit --amend -m "first" && git rebase -i --signoff HEAD^ && - git cat-file commit HEAD | sed -e "1,/^\$/d" >actual && - test_cmp expected-signed actual + test_commit_message HEAD expected-signed ' test_expect_success 'rebase -m --signoff fails' ' git commit --amend -m "first" && git rebase -m --signoff HEAD^ && - git cat-file commit HEAD | sed -e "1,/^\$/d" >actual && - test_cmp expected-signed actual + test_commit_message HEAD expected-signed ' test_done diff --git a/t/t3438-rebase-broken-files.sh b/t/t3438-rebase-broken-files.sh index c614c4f2e4..821f08e5af 100755 --- a/t/t3438-rebase-broken-files.sh +++ b/t/t3438-rebase-broken-files.sh @@ -58,4 +58,13 @@ test_expect_success 'unknown key in author-script' ' check_resolve_fails ' +test_expect_success POSIXPERM,SANITY 'unwritable rebased-patches does not leak' ' + >.git/rebased-patches && + chmod a-w .git/rebased-patches && + + git checkout -b side HEAD^ && + test_commit unrelated && + test_must_fail git rebase --apply --onto tmp HEAD^ +' + test_done diff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh index aeab689a98..411027fb58 100755 --- a/t/t3501-revert-cherry-pick.sh +++ b/t/t3501-revert-cherry-pick.sh @@ -104,11 +104,19 @@ test_expect_success 'revert forbidden on dirty working tree' ' ' test_expect_success 'cherry-pick on unborn branch' ' - git checkout --orphan unborn && + git switch --orphan unborn && git rm --cached -r . && - rm -rf * && git cherry-pick initial && - git diff --quiet initial && + git diff --exit-code initial && + test_cmp_rev ! initial HEAD +' + +test_expect_success 'cherry-pick on unborn branch with --allow-empty' ' + git checkout --detach && + git branch -D unborn && + git switch --orphan unborn && + git cherry-pick initial --allow-empty && + git diff --exit-code initial && test_cmp_rev ! initial HEAD ' @@ -170,6 +178,7 @@ test_expect_success 'advice from failed revert' ' hint: You can instead skip this commit with "git revert --skip". hint: To abort and get back to the state before "git revert", hint: run "git revert --abort". + hint: Disable this message with "git config advice.mergeConflict false" EOF test_commit --append --no-tag "double-add dream" dream dream && test_must_fail git revert HEAD^ 2>actual && diff --git a/t/t3505-cherry-pick-empty.sh b/t/t3505-cherry-pick-empty.sh index eba3c38d5a..9748443530 100755 --- a/t/t3505-cherry-pick-empty.sh +++ b/t/t3505-cherry-pick-empty.sh @@ -84,7 +84,7 @@ test_expect_success 'cherry-pick a commit that becomes no-op (prep)' ' git commit -m "add file2 on the side" ' -test_expect_success 'cherry-pick a no-op without --keep-redundant' ' +test_expect_success 'cherry-pick a no-op with neither --keep-redundant nor --empty' ' git reset --hard && git checkout fork^0 && test_must_fail git cherry-pick main @@ -99,4 +99,53 @@ test_expect_success 'cherry-pick a no-op with --keep-redundant' ' test_cmp expect actual ' +test_expect_success '--keep-redundant-commits is incompatible with operations' ' + test_must_fail git cherry-pick HEAD 2>output && + test_grep "The previous cherry-pick is now empty" output && + test_must_fail git cherry-pick --keep-redundant-commits --continue 2>output && + test_grep "fatal: cherry-pick: --keep-redundant-commits cannot be used with --continue" output && + test_must_fail git cherry-pick --keep-redundant-commits --skip 2>output && + test_grep "fatal: cherry-pick: --keep-redundant-commits cannot be used with --skip" output && + test_must_fail git cherry-pick --keep-redundant-commits --abort 2>output && + test_grep "fatal: cherry-pick: --keep-redundant-commits cannot be used with --abort" output && + test_must_fail git cherry-pick --keep-redundant-commits --quit 2>output && + test_grep "fatal: cherry-pick: --keep-redundant-commits cannot be used with --quit" output && + git cherry-pick --abort +' + +test_expect_success '--empty is incompatible with operations' ' + test_must_fail git cherry-pick HEAD 2>output && + test_grep "The previous cherry-pick is now empty" output && + test_must_fail git cherry-pick --empty=stop --continue 2>output && + test_grep "fatal: cherry-pick: --empty cannot be used with --continue" output && + test_must_fail git cherry-pick --empty=stop --skip 2>output && + test_grep "fatal: cherry-pick: --empty cannot be used with --skip" output && + test_must_fail git cherry-pick --empty=stop --abort 2>output && + test_grep "fatal: cherry-pick: --empty cannot be used with --abort" output && + test_must_fail git cherry-pick --empty=stop --quit 2>output && + test_grep "fatal: cherry-pick: --empty cannot be used with --quit" output && + git cherry-pick --abort +' + +test_expect_success 'cherry-pick a no-op with --empty=stop' ' + git reset --hard && + git checkout fork^0 && + test_must_fail git cherry-pick --empty=stop main 2>output && + test_grep "The previous cherry-pick is now empty" output +' + +test_expect_success 'cherry-pick a no-op with --empty=drop' ' + git reset --hard && + git checkout fork^0 && + git cherry-pick --empty=drop main && + test_commit_message HEAD -m "add file2 on the side" +' + +test_expect_success 'cherry-pick a no-op with --empty=keep' ' + git reset --hard && + git checkout fork^0 && + git cherry-pick --empty=keep main && + test_commit_message HEAD -m "add file2 on main" +' + test_done diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh index c88d597b12..f3947b400a 100755 --- a/t/t3507-cherry-pick-conflict.sh +++ b/t/t3507-cherry-pick-conflict.sh @@ -60,6 +60,7 @@ test_expect_success 'advice from failed cherry-pick' ' hint: You can instead skip this commit with "git cherry-pick --skip". hint: To abort and get back to the state before "git cherry-pick", hint: run "git cherry-pick --abort". + hint: Disable this message with "git config advice.mergeConflict false" EOF test_must_fail git cherry-pick picked 2>actual && @@ -74,6 +75,7 @@ test_expect_success 'advice from failed cherry-pick --no-commit' " error: could not apply \$picked... picked hint: after resolving the conflicts, mark the corrected paths hint: with 'git add <paths>' or 'git rm <paths>' + hint: Disable this message with \"git config advice.mergeConflict false\" EOF test_must_fail git cherry-pick --no-commit picked 2>actual && diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh index 72020a51c4..7eb52b12ed 100755 --- a/t/t3510-cherry-pick-sequence.sh +++ b/t/t3510-cherry-pick-sequence.sh @@ -90,6 +90,38 @@ test_expect_success 'cherry-pick persists opts correctly' ' test_cmp expect actual ' +test_expect_success 'cherry-pick persists --empty=stop correctly' ' + pristine_detach yetanotherpick && + # Picking `anotherpick` forces a conflict so that we stop. That + # commit is then skipped, after which we pick `yetanotherpick` + # while already on `yetanotherpick` to cause an empty commit + test_must_fail git cherry-pick --empty=stop anotherpick yetanotherpick && + test_must_fail git cherry-pick --skip 2>msg && + test_grep "The previous cherry-pick is now empty" msg && + rm msg && + git cherry-pick --abort +' + +test_expect_success 'cherry-pick persists --empty=drop correctly' ' + pristine_detach yetanotherpick && + # Picking `anotherpick` forces a conflict so that we stop. That + # commit is then skipped, after which we pick `yetanotherpick` + # while already on `yetanotherpick` to cause an empty commit + test_must_fail git cherry-pick --empty=drop anotherpick yetanotherpick && + git cherry-pick --skip && + test_cmp_rev yetanotherpick HEAD +' + +test_expect_success 'cherry-pick persists --empty=keep correctly' ' + pristine_detach yetanotherpick && + # Picking `anotherpick` forces a conflict so that we stop. That + # commit is then skipped, after which we pick `yetanotherpick` + # while already on `yetanotherpick` to cause an empty commit + test_must_fail git cherry-pick --empty=keep anotherpick yetanotherpick && + git cherry-pick --skip && + test_cmp_rev yetanotherpick HEAD^ +' + test_expect_success 'revert persists opts correctly' ' pristine_detach initial && # to make sure that the session to revert a sequence diff --git a/t/t3700-add.sh b/t/t3700-add.sh index f23d39f0d5..839c904745 100755 --- a/t/t3700-add.sh +++ b/t/t3700-add.sh @@ -28,6 +28,16 @@ test_expect_success 'Test of git add' ' touch foo && git add foo ' +test_expect_success 'Test with no pathspecs' ' + cat >expect <<-EOF && + Nothing specified, nothing added. + hint: Maybe you wanted to say ${SQ}git add .${SQ}? + hint: Disable this message with "git config advice.addEmptyPathspec false" + EOF + git add 2>actual && + test_cmp expect actual +' + test_expect_success 'Post-check that foo is in the index' ' git ls-files foo | grep foo ' @@ -339,6 +349,40 @@ test_expect_success '"git add ." in empty repo' ' ) ' +test_expect_success '"git add" a embedded repository' ' + rm -fr outer && git init outer && + ( + cd outer && + for i in 1 2 + do + name=inner$i && + git init $name && + git -C $name commit --allow-empty -m $name || + return 1 + done && + git add . 2>actual && + cat >expect <<-EOF && + warning: adding embedded git repository: inner1 + hint: You${SQ}ve added another git repository inside your current repository. + hint: Clones of the outer repository will not contain the contents of + hint: the embedded repository and will not know how to obtain it. + hint: If you meant to add a submodule, use: + hint: + hint: git submodule add <url> inner1 + hint: + hint: If you added this path by mistake, you can remove it from the + hint: index with: + hint: + hint: git rm --cached inner1 + hint: + hint: See "git help submodule" for more information. + hint: Disable this message with "git config advice.addEmbeddedRepo false" + warning: adding embedded git repository: inner2 + EOF + test_cmp expect actual + ) +' + test_expect_success 'error on a repository with no commits' ' rm -fr empty && git init empty && @@ -370,8 +414,7 @@ cat >expect.err <<\EOF The following paths are ignored by one of your .gitignore files: ignored-file hint: Use -f if you really want to add them. -hint: Turn this message off by running -hint: "git config advice.addIgnoredFile false" +hint: Disable this message with "git config advice.addIgnoredFile false" EOF cat >expect.out <<\EOF add 'track-this' diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh index 0b5339ac6c..04d8333373 100755 --- a/t/t3701-add-interactive.sh +++ b/t/t3701-add-interactive.sh @@ -4,6 +4,7 @@ test_description='add -i basic 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 @@ -325,9 +326,9 @@ test_expect_success 'different prompts for mode change/deleted' ' git -c core.filemode=true add -p >actual && sed -n "s/^\(([0-9/]*) Stage .*?\).*/\1/p" actual >actual.filtered && cat >expect <<-\EOF && - (1/1) Stage deletion [y,n,q,a,d,?]? - (1/2) Stage mode change [y,n,q,a,d,j,J,g,/,?]? - (2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,?]? + (1/1) Stage deletion [y,n,q,a,d,p,?]? + (1/2) Stage mode change [y,n,q,a,d,j,J,g,/,p,?]? + (2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,p,?]? EOF test_cmp expect actual.filtered ' @@ -514,13 +515,13 @@ test_expect_success 'split hunk setup' ' test_expect_success 'goto hunk' ' test_when_finished "git reset" && tr _ " " >expect <<-EOF && - (2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,?]? + 1: -1,2 +1,3 +15 + (2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,p,?]? + 1: -1,2 +1,3 +15 _ 2: -2,4 +3,8 +21 go to which hunk? @@ -1,2 +1,3 @@ _10 +15 _20 - (1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]?_ + (1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]?_ EOF test_write_lines s y g 1 | git add -p >actual && tail -n 7 <actual >actual.trimmed && @@ -530,11 +531,11 @@ test_expect_success 'goto hunk' ' test_expect_success 'navigate to hunk via regex' ' test_when_finished "git reset" && tr _ " " >expect <<-EOF && - (2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,?]? @@ -1,2 +1,3 @@ + (2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,p,?]? @@ -1,2 +1,3 @@ _10 +15 _20 - (1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]?_ + (1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]?_ EOF test_write_lines s y /1,2 | git add -p >actual && tail -n 5 <actual >actual.trimmed && @@ -715,21 +716,21 @@ test_expect_success 'colors can be overridden' ' <BLUE>+<RESET><BLUE>new<RESET> <CYAN> more-context<RESET> <BLUE>+<RESET><BLUE>another-one<RESET> - <YELLOW>(1/1) Stage this hunk [y,n,q,a,d,s,e,?]? <RESET><BOLD>Split into 2 hunks.<RESET> + <YELLOW>(1/1) Stage this hunk [y,n,q,a,d,s,e,p,?]? <RESET><BOLD>Split into 2 hunks.<RESET> <MAGENTA>@@ -1,3 +1,3 @@<RESET> <CYAN> context<RESET> <BOLD>-old<RESET> <BLUE>+<RESET><BLUE>new<RESET> <CYAN> more-context<RESET> - <YELLOW>(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]? <RESET><MAGENTA>@@ -3 +3,2 @@<RESET> + <YELLOW>(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]? <RESET><MAGENTA>@@ -3 +3,2 @@<RESET> <CYAN> more-context<RESET> <BLUE>+<RESET><BLUE>another-one<RESET> - <YELLOW>(2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,?]? <RESET><MAGENTA>@@ -1,3 +1,3 @@<RESET> + <YELLOW>(2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,p,?]? <RESET><MAGENTA>@@ -1,3 +1,3 @@<RESET> <CYAN> context<RESET> <BOLD>-old<RESET> <BLUE>+new<RESET> <CYAN> more-context<RESET> - <YELLOW>(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]? <RESET> + <YELLOW>(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]? <RESET> EOF test_cmp expect actual ' diff --git a/t/t3904-stash-patch.sh b/t/t3904-stash-patch.sh index accfe3845c..368fc2a6cc 100755 --- a/t/t3904-stash-patch.sh +++ b/t/t3904-stash-patch.sh @@ -3,12 +3,6 @@ test_description='stash -p' . ./lib-patch-mode.sh -if ! test_have_prereq PERL -then - skip_all='skipping stash -p tests, perl not available' - test_done -fi - test_expect_success 'setup' ' mkdir dir && echo parent > dir/foo && diff --git a/t/t3920-crlf-messages.sh b/t/t3920-crlf-messages.sh index 67fd2345af..50ae222f08 100755 --- a/t/t3920-crlf-messages.sh +++ b/t/t3920-crlf-messages.sh @@ -10,7 +10,7 @@ LIB_CRLF_BRANCHES="" create_crlf_ref () { branch="$1" && cat >.crlf-orig-$branch.txt && - cat .crlf-orig-$branch.txt | append_cr >.crlf-message-$branch.txt && + append_cr <.crlf-orig-$branch.txt >.crlf-message-$branch.txt && grep 'Subject' .crlf-orig-$branch.txt | tr '\n' ' ' | sed 's/[ ]*$//' | tr -d '\n' >.crlf-subject-$branch.txt && grep 'Body' .crlf-orig-$branch.txt | append_cr >.crlf-body-$branch.txt && LIB_CRLF_BRANCHES="${LIB_CRLF_BRANCHES} ${branch}" && @@ -97,7 +97,7 @@ test_expect_success 'branch: --verbose works with messages using CRLF' ' git branch -v >tmp && # Remove first two columns, and the line for the currently checked out branch current=$(git branch --show-current) && - grep -v $current <tmp | awk "{\$1=\$2=\"\"}1" >actual && + awk "/$current/ { next } { \$1 = \$2 = \"\" } 1" <tmp >actual && test_cmp expect actual ' diff --git a/t/t4002-diff-basic.sh b/t/t4002-diff-basic.sh index 7afc883ec3..cb3307010c 100755 --- a/t/t4002-diff-basic.sh +++ b/t/t4002-diff-basic.sh @@ -405,7 +405,7 @@ test_expect_success 'diff-tree -r B A == diff-tree -r -R A B' ' test_expect_success 'diff can read from stdin' ' test_must_fail git diff --no-index -- MN - < NN | - grep -v "^index" | sed "s#/-#/NN#" >.test-a && + sed "/^index/d; s#/-#/NN#" >.test-a && test_must_fail git diff --no-index -- MN NN | grep -v "^index" >.test-b && test_cmp .test-a .test-b diff --git a/t/t4011-diff-symlink.sh b/t/t4011-diff-symlink.sh index d7a5f7ae78..bc8ba88719 100755 --- a/t/t4011-diff-symlink.sh +++ b/t/t4011-diff-symlink.sh @@ -13,13 +13,13 @@ TEST_PASSES_SANITIZE_LEAK=true # Print the short OID of a symlink with the given name. symlink_oid () { - local oid=$(printf "%s" "$1" | git hash-object --stdin) && + local oid="$(printf "%s" "$1" | git hash-object --stdin)" && git rev-parse --short "$oid" } # Print the short OID of the given file. short_oid () { - local oid=$(git hash-object "$1") && + local oid="$(git hash-object "$1")" && git rev-parse --short "$oid" } diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index 1e3b2dbea4..3855d68dbc 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -633,8 +633,8 @@ check_prefix () { test_cmp expect actual.paths } -test_expect_success 'diff-files does not respect diff.noprefix' ' - git -c diff.noprefix diff-files -p >actual && +test_expect_success 'diff-files does not respect diff.noPrefix' ' + git -c diff.noPrefix diff-files -p >actual && check_prefix actual a/file0 b/file0 ' @@ -643,23 +643,58 @@ test_expect_success 'diff-files respects --no-prefix' ' check_prefix actual file0 file0 ' -test_expect_success 'diff respects diff.noprefix' ' - git -c diff.noprefix diff >actual && +test_expect_success 'diff respects diff.noPrefix' ' + git -c diff.noPrefix diff >actual && check_prefix actual file0 file0 ' -test_expect_success 'diff --default-prefix overrides diff.noprefix' ' - git -c diff.noprefix diff --default-prefix >actual && +test_expect_success 'diff --default-prefix overrides diff.noPrefix' ' + git -c diff.noPrefix diff --default-prefix >actual && check_prefix actual a/file0 b/file0 ' -test_expect_success 'diff respects diff.mnemonicprefix' ' - git -c diff.mnemonicprefix diff >actual && +test_expect_success 'diff respects diff.mnemonicPrefix' ' + git -c diff.mnemonicPrefix diff >actual && check_prefix actual i/file0 w/file0 ' -test_expect_success 'diff --default-prefix overrides diff.mnemonicprefix' ' - git -c diff.mnemonicprefix diff --default-prefix >actual && +test_expect_success 'diff --default-prefix overrides diff.mnemonicPrefix' ' + git -c diff.mnemonicPrefix diff --default-prefix >actual && + check_prefix actual a/file0 b/file0 +' + +test_expect_success 'diff respects diff.srcPrefix' ' + git -c diff.srcPrefix=x/ diff >actual && + check_prefix actual x/file0 b/file0 +' + +test_expect_success 'diff respects diff.dstPrefix' ' + git -c diff.dstPrefix=y/ diff >actual && + check_prefix actual a/file0 y/file0 +' + +test_expect_success 'diff --src-prefix overrides diff.srcPrefix' ' + git -c diff.srcPrefix=y/ diff --src-prefix=z/ >actual && + check_prefix actual z/file0 b/file0 +' + +test_expect_success 'diff --dst-prefix overrides diff.dstPrefix' ' + git -c diff.dstPrefix=y/ diff --dst-prefix=z/ >actual && + check_prefix actual a/file0 z/file0 +' + +test_expect_success 'diff.{src,dst}Prefix ignored with diff.noPrefix' ' + git -c diff.dstPrefix=y/ -c diff.srcPrefix=x/ -c diff.noPrefix diff >actual && + check_prefix actual file0 file0 +' + +test_expect_success 'diff.{src,dst}Prefix ignored with diff.mnemonicPrefix' ' + git -c diff.dstPrefix=x/ -c diff.srcPrefix=y/ -c diff.mnemonicPrefix diff >actual && + check_prefix actual i/file0 w/file0 +' + +test_expect_success 'diff.{src,dst}Prefix ignored with --default-prefix' ' + git -c diff.dstPrefix=x/ -c diff.srcPrefix=y/ diff --default-prefix >actual && check_prefix actual a/file0 b/file0 ' diff --git a/t/t4018/csharp-exclude-assignments b/t/t4018/csharp-exclude-assignments new file mode 100644 index 0000000000..239f312963 --- /dev/null +++ b/t/t4018/csharp-exclude-assignments @@ -0,0 +1,20 @@ +class Example +{ + string Method(int RIGHT) + { + var constantAssignment = "test"; + var methodAssignment = MethodCall(); + var multiLineMethodAssignment = MethodCall( + ); + var multiLine = "first" + + MethodCall() + + + ( MethodCall() + ) + + MethodCall(); + + return "ChangeMe"; + } + + string MethodCall(int a = 0, int b = 0) => "test"; +} diff --git a/t/t4018/csharp-exclude-control-statements b/t/t4018/csharp-exclude-control-statements new file mode 100644 index 0000000000..3a0f404ee1 --- /dev/null +++ b/t/t4018/csharp-exclude-control-statements @@ -0,0 +1,34 @@ +class Example +{ + string Method(int RIGHT) + { + if (false) + { + return "out"; + } + else { } + if (true) MethodCall( + ); + else MethodCall( + ); + switch ("test") + { + case "one": + return MethodCall( + ); + case "two": + break; + } + (int, int) tuple = (1, 4); + switch (tuple) + { + case (1, 4): + MethodCall(); + break; + } + + return "ChangeMe"; + } + + string MethodCall(int a = 0, int b = 0) => "test"; +} diff --git a/t/t4018/csharp-exclude-exceptions b/t/t4018/csharp-exclude-exceptions new file mode 100644 index 0000000000..b1e64256cf --- /dev/null +++ b/t/t4018/csharp-exclude-exceptions @@ -0,0 +1,29 @@ +using System; + +class Example +{ + string Method(int RIGHT) + { + try + { + throw new Exception("fail"); + } + catch (Exception) + { + } + finally + { + } + try { } catch (Exception) {} + try + { + throw GetException( + ); + } + catch (Exception) { } + + return "ChangeMe"; + } + + Exception GetException() => new Exception("fail"); +} diff --git a/t/t4018/csharp-exclude-generic-method-calls b/t/t4018/csharp-exclude-generic-method-calls new file mode 100644 index 0000000000..31af546665 --- /dev/null +++ b/t/t4018/csharp-exclude-generic-method-calls @@ -0,0 +1,12 @@ +class Example +{ + string Method(int RIGHT) + { + GenericMethodCall<int, int>( + ); + + return "ChangeMe"; + } + + string GenericMethodCall<T, T2>() => "test"; +} diff --git a/t/t4018/csharp-exclude-init-dispose b/t/t4018/csharp-exclude-init-dispose new file mode 100644 index 0000000000..2bc8e194e2 --- /dev/null +++ b/t/t4018/csharp-exclude-init-dispose @@ -0,0 +1,22 @@ +using System; + +class Example : IDisposable +{ + string Method(int RIGHT) + { + new Example(); + new Example( + ); + new Example { }; + using (this) + { + } + var def = + this is default( + Example); + + return "ChangeMe"; + } + + public void Dispose() {} +} diff --git a/t/t4018/csharp-exclude-iterations b/t/t4018/csharp-exclude-iterations new file mode 100644 index 0000000000..960aa182ae --- /dev/null +++ b/t/t4018/csharp-exclude-iterations @@ -0,0 +1,26 @@ +using System.Linq; + +class Example +{ + string Method(int RIGHT) + { + do { } while (true); + do MethodCall( + ); while (true); + while (true); + while (true) { + break; + } + for (int i = 0; i < 10; ++i) + { + } + foreach (int i in Enumerable.Range(0, 10)) + { + } + int[] numbers = [5, 4, 1, 3, 9, 8, 6, 7, 2, 0]; + + return "ChangeMe"; + } + + string MethodCall(int a = 0, int b = 0) => "test"; +} diff --git a/t/t4018/csharp-exclude-method-calls b/t/t4018/csharp-exclude-method-calls new file mode 100644 index 0000000000..51e2dc2040 --- /dev/null +++ b/t/t4018/csharp-exclude-method-calls @@ -0,0 +1,20 @@ +class Example +{ + string Method(int RIGHT) + { + MethodCall(); + MethodCall(1, 2); + MethodCall( + 1, 2); + MethodCall( + 1, 2, + 3); + MethodCall( + 1, MethodCall(), + 2); + + return "ChangeMe"; + } + + int MethodCall(int a = 0, int b = 0, int c = 0) => 42; +} diff --git a/t/t4018/csharp-exclude-other b/t/t4018/csharp-exclude-other new file mode 100644 index 0000000000..4d5581cf3e --- /dev/null +++ b/t/t4018/csharp-exclude-other @@ -0,0 +1,18 @@ +class Example +{ + string Method(int RIGHT) + { + lock (this) + { + } + unsafe + { + byte[] bytes = [1, 2, 3]; + fixed (byte* pointerToFirst = bytes) + { + } + } + + return "ChangeMe"; + } +} diff --git a/t/t4018/csharp-method b/t/t4018/csharp-method new file mode 100644 index 0000000000..16b367aca2 --- /dev/null +++ b/t/t4018/csharp-method @@ -0,0 +1,10 @@ +class Example +{ + string Method(int RIGHT) + { + // Filler + // Filler + + return "ChangeMe"; + } +} diff --git a/t/t4018/csharp-method-array b/t/t4018/csharp-method-array new file mode 100644 index 0000000000..1126de8201 --- /dev/null +++ b/t/t4018/csharp-method-array @@ -0,0 +1,10 @@ +class Example +{ + string[] Method(int RIGHT) + { + // Filler + // Filler + + return ["ChangeMe"]; + } +} diff --git a/t/t4018/csharp-method-explicit b/t/t4018/csharp-method-explicit new file mode 100644 index 0000000000..5a710116cc --- /dev/null +++ b/t/t4018/csharp-method-explicit @@ -0,0 +1,12 @@ +using System; + +class Example : IDisposable +{ + void IDisposable.Dispose() // RIGHT + { + // Filler + // Filler + + // ChangeMe + } +} diff --git a/t/t4018/csharp-method-generics b/t/t4018/csharp-method-generics new file mode 100644 index 0000000000..b3216bfb2a --- /dev/null +++ b/t/t4018/csharp-method-generics @@ -0,0 +1,11 @@ +class Example<T1, T2> +{ + Example<int, string> Method<TA, TB>(TA RIGHT, TB b) + { + // Filler + // Filler + + // ChangeMe + return null; + } +} diff --git a/t/t4018/csharp-method-generics-alternate-spaces b/t/t4018/csharp-method-generics-alternate-spaces new file mode 100644 index 0000000000..9583621743 --- /dev/null +++ b/t/t4018/csharp-method-generics-alternate-spaces @@ -0,0 +1,11 @@ +class Example<T1, T2> +{ + Example<int,string> Method<TA ,TB>(TA RIGHT, TB b) + { + // Filler + // Filler + + // ChangeMe + return null; + } +} diff --git a/t/t4018/csharp-method-modifiers b/t/t4018/csharp-method-modifiers new file mode 100644 index 0000000000..caefa8ee99 --- /dev/null +++ b/t/t4018/csharp-method-modifiers @@ -0,0 +1,13 @@ +using System.Threading.Tasks; + +class Example +{ + static internal async Task Method(int RIGHT) + { + // Filler + // Filler + + // ChangeMe + await Task.Delay(1); + } +} diff --git a/t/t4018/csharp-method-multiline b/t/t4018/csharp-method-multiline new file mode 100644 index 0000000000..3983ff42f5 --- /dev/null +++ b/t/t4018/csharp-method-multiline @@ -0,0 +1,10 @@ +class Example +{ + string Method_RIGHT( + int a, + int b, + int c) + { + return "ChangeMe"; + } +} diff --git a/t/t4018/csharp-method-params b/t/t4018/csharp-method-params new file mode 100644 index 0000000000..3f00410ba1 --- /dev/null +++ b/t/t4018/csharp-method-params @@ -0,0 +1,10 @@ +class Example +{ + string Method(int RIGHT, int b, int c = 42) + { + // Filler + // Filler + + return "ChangeMe"; + } +} diff --git a/t/t4018/csharp-method-special-chars b/t/t4018/csharp-method-special-chars new file mode 100644 index 0000000000..e6c7bc01a1 --- /dev/null +++ b/t/t4018/csharp-method-special-chars @@ -0,0 +1,11 @@ +class @Some_Type +{ + @Some_Type @Method_With_Underscore(int RIGHT) + { + // Filler + // Filler + + // ChangeMe + return new @Some_Type(); + } +} diff --git a/t/t4018/csharp-method-with-spacing b/t/t4018/csharp-method-with-spacing new file mode 100644 index 0000000000..233bb976cc --- /dev/null +++ b/t/t4018/csharp-method-with-spacing @@ -0,0 +1,10 @@ +class Example +{ + string Method ( int RIGHT ) + { + // Filler + // Filler + + return "ChangeMe"; + } +} diff --git a/t/t4018/csharp-property b/t/t4018/csharp-property new file mode 100644 index 0000000000..e56dfce34c --- /dev/null +++ b/t/t4018/csharp-property @@ -0,0 +1,11 @@ +class Example +{ + public bool RIGHT + { + get { return true; } + set + { + // ChangeMe + } + } +} diff --git a/t/t4018/csharp-property-braces-same-line b/t/t4018/csharp-property-braces-same-line new file mode 100644 index 0000000000..608131d3d3 --- /dev/null +++ b/t/t4018/csharp-property-braces-same-line @@ -0,0 +1,10 @@ +class Example +{ + public bool RIGHT { + get { return true; } + set + { + // ChangeMe + } + } +} diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh index c1ac09ecc7..fdd865f7c3 100755 --- a/t/t4020-diff-external.sh +++ b/t/t4020-diff-external.sh @@ -232,7 +232,7 @@ keep_only_cr () { test_expect_success 'external diff with autocrlf = true' ' test_config core.autocrlf true && GIT_EXTERNAL_DIFF=./fake-diff.sh git diff && - test $(wc -l < crlfed.txt) = $(cat crlfed.txt | keep_only_cr | wc -c) + test $(wc -l <crlfed.txt) = $(keep_only_cr <crlfed.txt | wc -c) ' test_expect_success 'diff --cached' ' diff --git a/t/t4042-diff-textconv-caching.sh b/t/t4042-diff-textconv-caching.sh index bf33aedf4b..8ebfa3c1be 100755 --- a/t/t4042-diff-textconv-caching.sh +++ b/t/t4042-diff-textconv-caching.sh @@ -118,4 +118,26 @@ test_expect_success 'log notes cache and still use cache for -p' ' git log --no-walk -p refs/notes/textconv/magic HEAD ' +test_expect_success 'caching is silently ignored outside repo' ' + mkdir -p non-repo && + echo one >non-repo/one && + echo two >non-repo/two && + echo "* diff=test" >attr && + test_expect_code 1 \ + nongit git -c core.attributesFile="$PWD/attr" \ + -c diff.test.textconv="tr a-z A-Z <" \ + -c diff.test.cachetextconv=true \ + diff --no-index one two >actual && + cat >expect <<-\EOF && + diff --git a/one b/two + index 5626abf..f719efd 100644 + --- a/one + +++ b/two + @@ -1 +1 @@ + -ONE + +TWO + EOF + test_cmp expect actual +' + test_done diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh index d370ecfe0d..144619ab87 100755 --- a/t/t4103-apply-binary.sh +++ b/t/t4103-apply-binary.sh @@ -9,6 +9,7 @@ test_description='git apply handling binary patches 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' ' diff --git a/t/t4104-apply-boundary.sh b/t/t4104-apply-boundary.sh index 71ef4132d1..dc501aac38 100755 --- a/t/t4104-apply-boundary.sh +++ b/t/t4104-apply-boundary.sh @@ -5,6 +5,7 @@ test_description='git apply boundary tests' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh L="c d e f g h i j k l m n o p q r s t u v w x" diff --git a/t/t4113-apply-ending.sh b/t/t4113-apply-ending.sh index 66fa51591e..2c65c6a169 100755 --- a/t/t4113-apply-ending.sh +++ b/t/t4113-apply-ending.sh @@ -6,6 +6,7 @@ test_description='git apply trying to add an ending line. ' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # setup diff --git a/t/t4117-apply-reject.sh b/t/t4117-apply-reject.sh index c86d05a96f..4d15ccd28e 100755 --- a/t/t4117-apply-reject.sh +++ b/t/t4117-apply-reject.sh @@ -7,6 +7,7 @@ test_description='git apply with rejects ' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t4123-apply-shrink.sh b/t/t4123-apply-shrink.sh index 3ef84619f5..3601c0c5dc 100755 --- a/t/t4123-apply-shrink.sh +++ b/t/t4123-apply-shrink.sh @@ -2,6 +2,7 @@ test_description='apply a patch that is larger than the preimage' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh cat >F <<\EOF diff --git a/t/t4126-apply-empty.sh b/t/t4126-apply-empty.sh index ece9fae207..56210b5609 100755 --- a/t/t4126-apply-empty.sh +++ b/t/t4126-apply-empty.sh @@ -66,4 +66,28 @@ test_expect_success 'apply --index create' ' git diff --exit-code ' +test_expect_success !MINGW 'apply with no-contents and a funny pathname' ' + test_when_finished "rm -fr \"funny \"; git reset --hard" && + + mkdir "funny " && + >"funny /empty" && + git add "funny /empty" && + git diff HEAD -- "funny /" >sample.patch && + git diff -R HEAD -- "funny /" >elpmas.patch && + + git reset --hard && + + git apply --stat --check --apply sample.patch && + test_must_be_empty "funny /empty" && + + git apply --stat --check --apply elpmas.patch && + test_path_is_missing "funny /empty" && + + git apply -R --stat --check --apply elpmas.patch && + test_must_be_empty "funny /empty" && + + git apply -R --stat --check --apply sample.patch && + test_path_is_missing "funny /empty" +' + test_done diff --git a/t/t4129-apply-samemode.sh b/t/t4129-apply-samemode.sh index 2775bfadd8..4eb8444029 100755 --- a/t/t4129-apply-samemode.sh +++ b/t/t4129-apply-samemode.sh @@ -103,4 +103,31 @@ test_expect_success POSIXPERM 'do not use core.sharedRepository for working tree ) ' +test_expect_success 'git apply respects core.fileMode' ' + test_config core.fileMode false && + echo true >script.sh && + git add --chmod=+x script.sh && + git ls-files -s script.sh >ls-files-output && + test_grep "^100755" ls-files-output && + test_tick && git commit -m "Add script" && + git ls-tree -r HEAD script.sh >ls-tree-output && + test_grep "^100755" ls-tree-output && + + echo true >>script.sh && + test_tick && git commit -m "Modify script" script.sh && + git format-patch -1 --stdout >patch && + test_grep "^index.*100755$" patch && + + git switch -c branch HEAD^ && + git apply --index patch 2>err && + test_grep ! "has type 100644, expected 100755" err && + git reset --hard && + + git apply patch 2>err && + test_grep ! "has type 100644, expected 100755" err && + + git apply --cached patch 2>err && + test_grep ! "has type 100644, expected 100755" err +' + test_done diff --git a/t/t4150-am.sh b/t/t4150-am.sh index 3b12576269..5e2b6c80ea 100755 --- a/t/t4150-am.sh +++ b/t/t4150-am.sh @@ -1224,8 +1224,8 @@ test_expect_success 'record as an empty commit when meeting e-mail message that test_expect_success 'skip an empty patch in the middle of an am session' ' git checkout empty-commit^ && - test_must_fail git am empty-commit.patch >err && - grep "Patch is empty." err && + test_must_fail git am empty-commit.patch >out 2>err && + grep "Patch is empty." out && grep "To record the empty patch as an empty commit, run \"git am --allow-empty\"." err && git am --skip && test_path_is_missing .git/rebase-apply && @@ -1236,8 +1236,8 @@ test_expect_success 'skip an empty patch in the middle of an am session' ' test_expect_success 'record an empty patch as an empty commit in the middle of an am session' ' git checkout empty-commit^ && - test_must_fail git am empty-commit.patch >err && - grep "Patch is empty." err && + test_must_fail git am empty-commit.patch >out 2>err && + grep "Patch is empty." out && grep "To record the empty patch as an empty commit, run \"git am --allow-empty\"." err && git am --allow-empty >output && grep "No changes - recorded it as an empty commit." output && diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh index fb53dddf79..b0a3e84984 100755 --- a/t/t4200-rerere.sh +++ b/t/t4200-rerere.sh @@ -671,4 +671,67 @@ test_expect_success 'test simple stage 1 handling' ' ) ' +test_expect_success 'rerere does not crash with missing preimage' ' + git config rerere.enabled true && + + echo bar >test && + git add test && + git commit -m "one" && + git branch rerere_no_crash && + + echo foo >>test && + git add test && + git commit -m "two" && + + git checkout rerere_no_crash && + echo "bar" >>test && + git add test && + git commit -m "three" && + + test_must_fail git rebase main && + rm .git/rr-cache/*/preimage && + git rebase --abort +' + +test_expect_success 'rerere does not crash with unmatched conflict marker' ' + git config rerere.enabled true && + + echo bar >test && + git add test && + git commit -m "one" && + git branch rerere_no_preimage && + + cat >test <<-EOF && + test + bar + foobar + EOF + git add test && + git commit -m "two" && + + git checkout rerere_no_preimage && + echo "bar" >>test && + git add test && + git commit -m "three" && + + cat >test <<-EOF && + foobar + bar + bar + EOF + git add test && + git commit -m "four" && + + test_must_fail git rebase main && + cat >test <<-EOF && + test + bar + <<<<<<< HEAD + foobar + bar + EOF + git add test && + test_must_fail git rebase --continue +' + test_done diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh index d7382709fc..f698d0c9ad 100755 --- a/t/t4201-shortlog.sh +++ b/t/t4201-shortlog.sh @@ -312,6 +312,38 @@ test_expect_success 'shortlog de-duplicates trailers in a single commit' ' test_cmp expect actual ' +# Trailers that have unfolded (single line) and folded (multiline) values which +# are otherwise identical are treated as the same trailer for de-duplication. +test_expect_success 'shortlog de-duplicates trailers in a single commit (folded/unfolded values)' ' + git commit --allow-empty -F - <<-\EOF && + subject one + + this message has two distinct values, plus a repeat (folded) + + Repeated-trailer: Foo foo foo + Repeated-trailer: Bar + Repeated-trailer: Foo + foo foo + EOF + + git commit --allow-empty -F - <<-\EOF && + subject two + + similar to the previous, but without the second distinct value + + Repeated-trailer: Foo foo foo + Repeated-trailer: Foo + foo foo + EOF + + cat >expect <<-\EOF && + 2 Foo foo foo + 1 Bar + EOF + git shortlog -ns --group=trailer:repeated-trailer -2 HEAD >actual && + test_cmp expect actual +' + test_expect_success 'shortlog can match multiple groups' ' git commit --allow-empty -F - <<-\EOF && subject one diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh index e3d655e6b8..158b49d4b6 100755 --- a/t/t4205-log-pretty-formats.sh +++ b/t/t4205-log-pretty-formats.sh @@ -30,40 +30,46 @@ test_expect_success 'set up basic repos' ' >bar && git add foo && test_tick && - git config i18n.commitEncoding $test_encoding && + test_config i18n.commitEncoding $test_encoding && commit_msg $test_encoding | git commit -F - && git add bar && test_tick && - git commit -m "add bar" && - git config --unset i18n.commitEncoding + git commit -m "add bar" ' test_expect_success 'alias builtin format' ' git log --pretty=oneline >expected && - git config pretty.test-alias oneline && + test_config pretty.test-alias oneline && git log --pretty=test-alias >actual && test_cmp expected actual ' test_expect_success 'alias masking builtin format' ' git log --pretty=oneline >expected && - git config pretty.oneline "%H" && + test_config pretty.oneline "%H" && git log --pretty=oneline >actual && test_cmp expected actual ' test_expect_success 'alias user-defined format' ' git log --pretty="format:%h" >expected && - git config pretty.test-alias "format:%h" && + test_config pretty.test-alias "format:%h" && git log --pretty=test-alias >actual && test_cmp expected actual ' +test_expect_success 'alias user-defined format is matched case-insensitively' ' + git log --pretty="format:%h" >expected && + test_config pretty.testone "format:%h" && + test_config pretty.testtwo testOne && + git log --pretty=testTwo >actual && + test_cmp expected actual +' + test_expect_success 'alias user-defined tformat with %s (ISO8859-1 encoding)' ' - git config i18n.logOutputEncoding $test_encoding && + test_config i18n.logOutputEncoding $test_encoding && git log --oneline >expected-s && git log --pretty="tformat:%h %s" >actual-s && - git config --unset i18n.logOutputEncoding && test_cmp expected-s actual-s ' @@ -75,34 +81,34 @@ test_expect_success 'alias user-defined tformat with %s (utf-8 encoding)' ' test_expect_success 'alias user-defined tformat' ' git log --pretty="tformat:%h" >expected && - git config pretty.test-alias "tformat:%h" && + test_config pretty.test-alias "tformat:%h" && git log --pretty=test-alias >actual && test_cmp expected actual ' test_expect_success 'alias non-existent format' ' - git config pretty.test-alias format-that-will-never-exist && + test_config pretty.test-alias format-that-will-never-exist && test_must_fail git log --pretty=test-alias ' test_expect_success 'alias of an alias' ' git log --pretty="tformat:%h" >expected && - git config pretty.test-foo "tformat:%h" && - git config pretty.test-bar test-foo && + test_config pretty.test-foo "tformat:%h" && + test_config pretty.test-bar test-foo && git log --pretty=test-bar >actual && test_cmp expected actual ' test_expect_success 'alias masking an alias' ' git log --pretty=format:"Two %H" >expected && - git config pretty.duplicate "format:One %H" && - git config --add pretty.duplicate "format:Two %H" && + test_config pretty.duplicate "format:One %H" && + test_config pretty.duplicate "format:Two %H" --add && git log --pretty=duplicate >actual && test_cmp expected actual ' test_expect_success 'alias loop' ' - git config pretty.test-foo test-bar && - git config pretty.test-bar test-foo && + test_config pretty.test-foo test-bar && + test_config pretty.test-bar test-foo && test_must_fail git log --pretty=test-foo ' @@ -156,7 +162,7 @@ test_expect_success 'NUL termination with --reflog --pretty=oneline' ' for r in $revs do git show -s --pretty=oneline "$r" >raw && - cat raw | lf_to_nul || return 1 + lf_to_nul <raw || return 1 done >expect && # the trailing NUL is already produced so we do not need to # output another one diff --git a/t/t4210-log-i18n.sh b/t/t4210-log-i18n.sh index d2dfcf164e..75216f19ce 100755 --- a/t/t4210-log-i18n.sh +++ b/t/t4210-log-i18n.sh @@ -64,7 +64,7 @@ test_expect_success 'log --grep does not find non-reencoded values (latin1)' ' ' triggers_undefined_behaviour () { - local engine=$1 + local engine="$1" case $engine in fixed) @@ -85,7 +85,7 @@ triggers_undefined_behaviour () { } mismatched_git_log () { - local pattern=$1 + local pattern="$1" LC_ALL=$is_IS_locale git log --encoding=ISO-8859-1 --format=%s \ --grep=$pattern diff --git a/t/t4252-am-options.sh b/t/t4252-am-options.sh index e758e634a3..5b680dc755 100755 --- a/t/t4252-am-options.sh +++ b/t/t4252-am-options.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='git am with options and not losing them' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh tm="$TEST_DIRECTORY/t4252" diff --git a/t/t4254-am-corrupt.sh b/t/t4254-am-corrupt.sh index 45f1d4f95e..661feb6070 100755 --- a/t/t4254-am-corrupt.sh +++ b/t/t4254-am-corrupt.sh @@ -59,7 +59,7 @@ test_expect_success setup ' # Also, it had the unwanted side-effect of deleting f. test_expect_success 'try to apply corrupted patch' ' test_when_finished "git am --abort" && - test_must_fail git -c advice.amWorkDir=false am bad-patch.diff 2>actual && + test_must_fail git -c advice.amWorkDir=false -c advice.mergeConflict=false am bad-patch.diff 2>actual && echo "error: git diff header lacks filename information (line 4)" >expected && test_path_is_file f && test_cmp expected actual diff --git a/t/t4258-am-quoted-cr.sh b/t/t4258-am-quoted-cr.sh index 201915b45a..3573c9147f 100755 --- a/t/t4258-am-quoted-cr.sh +++ b/t/t4258-am-quoted-cr.sh @@ -2,6 +2,7 @@ test_description='test am --quoted-cr=<action>' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh DATA="$TEST_DIRECTORY/t4258" diff --git a/t/t4301-merge-tree-write-tree.sh b/t/t4301-merge-tree-write-tree.sh index 12ac436873..eea19907b5 100755 --- a/t/t4301-merge-tree-write-tree.sh +++ b/t/t4301-merge-tree-write-tree.sh @@ -313,7 +313,7 @@ test_expect_success 'rename/add handling' ' # First, check that the bar that appears at stage 3 does not # correspond to an individual blob anywhere in history # - hash=$(cat out | tr "\0" "\n" | head -n 3 | grep 3.bar | cut -f 2 -d " ") && + hash=$(tr "\0" "\n" <out | head -n 3 | grep 3.bar | cut -f 2 -d " ") && git rev-list --objects --all >all_blobs && ! grep $hash all_blobs && @@ -380,7 +380,7 @@ test_expect_success SYMLINKS 'rename/add, where add is a mode conflict' ' # First, check that the bar that appears at stage 3 does not # correspond to an individual blob anywhere in history # - hash=$(cat out | tr "\0" "\n" | head -n 3 | grep 3.bar | cut -f 2 -d " ") && + hash=$(tr "\0" "\n" <out | head -n 3 | grep 3.bar | cut -f 2 -d " ") && git rev-list --objects --all >all_blobs && ! grep $hash all_blobs && @@ -630,8 +630,8 @@ test_expect_success 'mod6: chains of rename/rename(1to2) and add/add via collidi # conflict entries do not appear as individual blobs anywhere # in history. # - hash1=$(cat out | tr "\0" "\n" | head | grep 2.four | cut -f 2 -d " ") && - hash2=$(cat out | tr "\0" "\n" | head | grep 3.two | cut -f 2 -d " ") && + hash1=$(tr "\0" "\n" <out | head | grep 2.four | cut -f 2 -d " ") && + hash2=$(tr "\0" "\n" <out | head | grep 3.two | cut -f 2 -d " ") && git rev-list --objects --all >all_blobs && ! grep $hash1 all_blobs && ! grep $hash2 all_blobs && @@ -945,4 +945,49 @@ test_expect_success 'check the input format when --stdin is passed' ' test_cmp expect actual ' +test_expect_success '--merge-base with tree OIDs' ' + git merge-tree --merge-base=side1^ side1 side3 >with-commits && + git merge-tree --merge-base=side1^^{tree} side1^{tree} side3^{tree} >with-trees && + test_cmp with-commits with-trees +' + +test_expect_success 'error out on missing tree objects' ' + git init --bare missing-tree.git && + git rev-list side3 >list && + git rev-parse side3^: >>list && + git pack-objects missing-tree.git/objects/pack/side3-tree-is-missing <list && + side3=$(git rev-parse side3) && + test_must_fail git --git-dir=missing-tree.git merge-tree $side3^ $side3 >actual 2>err && + test_grep "Could not read $(git rev-parse $side3:)" err && + test_must_be_empty actual +' + +test_expect_success 'error out on missing blob objects' ' + echo 1 | git hash-object -w --stdin >blob1 && + echo 2 | git hash-object -w --stdin >blob2 && + echo 3 | git hash-object -w --stdin >blob3 && + printf "100644 blob $(cat blob1)\tblob\n" | git mktree >tree1 && + printf "100644 blob $(cat blob2)\tblob\n" | git mktree >tree2 && + printf "100644 blob $(cat blob3)\tblob\n" | git mktree >tree3 && + git init --bare missing-blob.git && + cat blob1 blob3 tree1 tree2 tree3 | + git pack-objects missing-blob.git/objects/pack/side1-whatever-is-missing && + test_must_fail git --git-dir=missing-blob.git >actual 2>err \ + merge-tree --merge-base=$(cat tree1) $(cat tree2) $(cat tree3) && + test_grep "unable to read blob object $(cat blob2)" err && + test_must_be_empty actual +' + +test_expect_success 'error out on missing commits as well' ' + git init --bare missing-commit.git && + git rev-list --objects side1 side3 >list-including-initial && + grep -v ^$(git rev-parse side1^) <list-including-initial >list && + git pack-objects missing-commit.git/objects/pack/missing-initial <list && + side1=$(git rev-parse side1) && + side3=$(git rev-parse side3) && + test_must_fail git --git-dir=missing-commit.git \ + merge-tree --allow-unrelated-histories $side1 $side3 >actual && + test_must_be_empty actual +' + test_done diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh index 654d8cf3ee..c8d0655454 100755 --- a/t/t5100-mailinfo.sh +++ b/t/t5100-mailinfo.sh @@ -70,7 +70,7 @@ test_expect_success 'respect NULs' ' git mailsplit -d3 -o. "$DATA/nul-plain" && test_cmp "$DATA/nul-plain" 001 && - (cat 001 | git mailinfo msg patch) && + git mailinfo msg patch <001 && test_line_count = 4 patch ' diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index a58f91035d..61e2be2903 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -465,7 +465,7 @@ test_with_bad_commit () { must_pass_arg="$2" && ( cd strict && - test_expect_fail git index-pack "$must_fail_arg" "test-$(cat pack-name).pack" + test_must_fail git index-pack "$must_fail_arg" "test-$(cat pack-name).pack" && git index-pack "$must_pass_arg" "test-$(cat pack-name).pack" ) } diff --git a/t/t5317-pack-objects-filter-objects.sh b/t/t5317-pack-objects-filter-objects.sh index 2ff3eef9a3..79552d6ef7 100755 --- a/t/t5317-pack-objects-filter-objects.sh +++ b/t/t5317-pack-objects-filter-objects.sh @@ -455,7 +455,7 @@ test_expect_success 'setup r1 - delete loose blobs' ' test_parse_ls_files_stage_oids <ls_files_result | sort >expected && - for id in `cat expected | sed "s|..|&/|"` + for id in `sed "s|..|&/|" expected` do rm r1/.git/objects/$id || return 1 done diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh index 70d1b58709..5d7d321840 100755 --- a/t/t5326-multi-pack-bitmaps.sh +++ b/t/t5326-multi-pack-bitmaps.sh @@ -513,4 +513,21 @@ test_expect_success 'corrupt MIDX with bitmap causes fallback' ' ) ' +for allow_pack_reuse in single multi +do + test_expect_success "reading MIDX without BTMP chunk does not complain with $allow_pack_reuse pack reuse" ' + test_when_finished "rm -rf midx-without-btmp" && + git init midx-without-btmp && + ( + cd midx-without-btmp && + test_commit initial && + + git repack -Adbl --write-bitmap-index --write-midx && + GIT_TEST_MIDX_READ_BTMP=false git -c pack.allowPackReuse=$allow_pack_reuse \ + pack-objects --all --use-bitmap-index --stdout </dev/null >/dev/null 2>err && + test_must_be_empty err + ) + ' +done + test_done diff --git a/t/t5401-update-hooks.sh b/t/t5401-update-hooks.sh index 8b8bc47dc0..d8cadeec73 100755 --- a/t/t5401-update-hooks.sh +++ b/t/t5401-update-hooks.sh @@ -123,7 +123,7 @@ remote: STDOUT post-update remote: STDERR post-update EOF test_expect_success 'send-pack stderr contains hook messages' ' - grep ^remote: send.err | sed "s/ *\$//" >actual && + sed -n "/^remote:/s/ *\$//p" send.err >actual && test_cmp expect actual ' diff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh index b4bc24691c..c91a62b77a 100755 --- a/t/t5534-push-signed.sh +++ b/t/t5534-push-signed.sh @@ -303,7 +303,7 @@ test_expect_success GPGSM 'fail without key and heed user.signingkey x509' ' EOF sed -n -e "s/^nonce /NONCE=/p" -e "/^$/q" dst/push-cert ) >expect.in && - key=$(cat "${GNUPGHOME}/trustlist.txt" | cut -d" " -f1 | tr -d ":") && + key=$(cut -d" " -f1 <"${GNUPGHOME}/trustlist.txt" | tr -d ":") && sed -e "s/^KEY=/KEY=${key}/" expect.in >expect && noop=$(git rev-parse noop) && diff --git a/t/t5555-http-smart-common.sh b/t/t5555-http-smart-common.sh index b1cfe8b7db..3dcb3340a3 100755 --- a/t/t5555-http-smart-common.sh +++ b/t/t5555-http-smart-common.sh @@ -131,7 +131,6 @@ test_expect_success 'git upload-pack --advertise-refs: v2' ' fetch=shallow wait-for-done server-option object-format=$(test_oid algo) - object-info 0000 EOF diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh index 8c26b0b7d7..deb1c282c7 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -842,6 +842,18 @@ test_expect_success 'clone with init.templatedir runs hooks' ' . "$TEST_DIRECTORY"/lib-httpd.sh start_httpd +test_expect_success 'clone with includeIf' ' + test_when_finished "rm -rf repo \"$HTTPD_DOCUMENT_ROOT_PATH/repo.git\"" && + git clone --bare --no-local src "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + + test_when_finished "rm \"$HOME\"/.gitconfig" && + cat >"$HOME"/.gitconfig <<-EOF && + [includeIf "onbranch:something"] + path = /does/not/exist.inc + EOF + git clone $HTTPD_URL/smart/repo.git repo +' + test_expect_success 'partial clone using HTTP' ' partial_clone "$HTTPD_DOCUMENT_ROOT_PATH/server" "$HTTPD_URL/smart/server" ' diff --git a/t/t5606-clone-options.sh b/t/t5606-clone-options.sh index a400bcca62..e93e0d0cc3 100755 --- a/t/t5606-clone-options.sh +++ b/t/t5606-clone-options.sh @@ -120,14 +120,14 @@ test_expect_success 'prefers -c config over --template config' ' ' -test_expect_failure 'prefers --template config even for core.bare' ' +test_expect_success 'ignore --template config for core.bare' ' template="$TRASH_DIRECTORY/template-with-bare-config" && mkdir "$template" && git config --file "$template/config" core.bare true && git clone "--template=$template" parent clone-bare-config && - test "$(git -C clone-bare-config config --local core.bare)" = "true" && - test_path_is_file clone-bare-config/HEAD + test "$(git -C clone-bare-config config --local core.bare)" = "false" && + test_path_is_missing clone-bare-config/HEAD ' test_expect_success 'prefers config "clone.defaultRemoteName" over default' ' diff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh index 3591bc2417..c48830de8f 100755 --- a/t/t5701-git-serve.sh +++ b/t/t5701-git-serve.sh @@ -20,7 +20,6 @@ test_expect_success 'test capability advertisement' ' fetch=shallow wait-for-done server-option object-format=$(test_oid algo) - object-info EOF cat >expect.trailer <<-EOF && 0000 @@ -323,6 +322,8 @@ test_expect_success 'unexpected lines are not allowed in fetch request' ' # Test the basics of object-info # test_expect_success 'basics of object-info' ' + test_config transfer.advertiseObjectInfo true && + test-tool pkt-line pack >in <<-EOF && command=object-info object-format=$(test_oid algo) @@ -380,4 +381,25 @@ test_expect_success 'basics of bundle-uri: dies if not enabled' ' test_must_be_empty out ' +test_expect_success 'object-info missing from capabilities when disabled' ' + test_config transfer.advertiseObjectInfo false && + + GIT_TEST_SIDEBAND_ALL=0 test-tool serve-v2 \ + --advertise-capabilities >out && + test-tool pkt-line unpack <out >actual && + + ! grep object.info actual +' + +test_expect_success 'object-info commands rejected when disabled' ' + test_config transfer.advertiseObjectInfo false && + + test-tool pkt-line pack >in <<-EOF && + command=object-info + EOF + + test_must_fail test-tool serve-v2 --stateless-rpc <in 2>err && + grep invalid.command err +' + test_done diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh index 6ef4971845..1ef540f73d 100755 --- a/t/t5702-protocol-v2.sh +++ b/t/t5702-protocol-v2.sh @@ -778,6 +778,25 @@ test_expect_success 'archive with custom path does not request v2' ' ! grep ^GIT_PROTOCOL env.trace ' +test_expect_success 'reject client packfile-uris if not advertised' ' + { + packetize command=fetch && + packetize object-format=$(test_oid algo) && + printf 0001 && + packetize packfile-uris https && + packetize done && + printf 0000 + } >input && + test_must_fail env GIT_PROTOCOL=version=2 \ + git upload-pack client <input && + test_must_fail env GIT_PROTOCOL=version=2 \ + git -c uploadpack.blobpackfileuri \ + upload-pack client <input && + GIT_PROTOCOL=version=2 \ + git -c uploadpack.blobpackfileuri=anything \ + upload-pack client <input +' + # Test protocol v2 with 'http://' transport # . "$TEST_DIRECTORY"/lib-httpd.sh diff --git a/t/t5801/git-remote-testgit b/t/t5801/git-remote-testgit index 1544d6dc6b..c5b10f5775 100755 --- a/t/t5801/git-remote-testgit +++ b/t/t5801/git-remote-testgit @@ -12,6 +12,11 @@ url=$2 dir="$GIT_DIR/testgit/$alias" +if ! git rev-parse --is-inside-git-dir +then + exit 1 +fi + h_refspec="refs/heads/*:refs/testgit/$alias/heads/*" t_refspec="refs/tags/*:refs/testgit/$alias/tags/*" @@ -25,6 +30,7 @@ GIT_DIR="$url/.git" export GIT_DIR force= +object_format= mkdir -p "$dir" @@ -56,7 +62,8 @@ do echo ;; list) - echo ":object-format $(git rev-parse --show-object-format=storage)" + test -n "$object_format" && + echo ":object-format $(git rev-parse --show-object-format=storage)" git for-each-ref --format='? %(refname)' 'refs/heads/' 'refs/tags/' head=$(git symbolic-ref HEAD) echo "@$head HEAD" diff --git a/t/t6022-rev-list-missing.sh b/t/t6022-rev-list-missing.sh index 211672759a..127180e1c9 100755 --- a/t/t6022-rev-list-missing.sh +++ b/t/t6022-rev-list-missing.sh @@ -10,7 +10,10 @@ TEST_PASSES_SANITIZE_LEAK=true test_expect_success 'create repository and alternate directory' ' test_commit 1 && test_commit 2 && - test_commit 3 + test_commit 3 && + git tag -m "tag message" annot_tag HEAD~1 && + git tag regul_tag HEAD~1 && + git branch a_branch HEAD~1 ' # We manually corrupt the repository, which means that the commit-graph may @@ -46,9 +49,10 @@ do git rev-list --objects --no-object-names \ HEAD ^$obj >expect.raw && - # Blobs are shared by all commits, so evethough a commit/tree + # Blobs are shared by all commits, so even though a commit/tree # might be skipped, its blob must be accounted for. - if [ $obj != "HEAD:1.t" ]; then + if test $obj != "HEAD:1.t" + then echo $(git rev-parse HEAD:1.t) >>expect.raw && echo $(git rev-parse HEAD:2.t) >>expect.raw fi && @@ -77,4 +81,69 @@ do done done +for missing_tip in "annot_tag" "regul_tag" "a_branch" "HEAD~1" "HEAD~1^{tree}" "HEAD:1.t" +do + # We want to check that things work when both + # - all the tips passed are missing (case existing_tip = ""), and + # - there is one missing tip and one existing tip (case existing_tip = "HEAD") + for existing_tip in "" "HEAD" + do + for action in "allow-any" "print" + do + test_expect_success "--missing=$action with tip '$missing_tip' missing and tip '$existing_tip'" ' + # Before the object is made missing, we use rev-list to + # get the expected oids. + if test "$existing_tip" = "HEAD" + then + git rev-list --objects --no-object-names \ + HEAD ^$missing_tip >expect.raw + else + >expect.raw + fi && + + # Blobs are shared by all commits, so even though a commit/tree + # might be skipped, its blob must be accounted for. + if test "$existing_tip" = "HEAD" && test $missing_tip != "HEAD:1.t" + then + echo $(git rev-parse HEAD:1.t) >>expect.raw && + echo $(git rev-parse HEAD:2.t) >>expect.raw + fi && + + missing_oid="$(git rev-parse $missing_tip)" && + + if test "$missing_tip" = "annot_tag" + then + oid="$(git rev-parse $missing_tip^{commit})" && + echo "$missing_oid" >>expect.raw + else + oid="$missing_oid" + fi && + + path=".git/objects/$(test_oid_to_path $oid)" && + + mv "$path" "$path.hidden" && + test_when_finished "mv $path.hidden $path" && + + git rev-list --missing=$action --objects --no-object-names \ + $missing_oid $existing_tip >actual.raw && + + # When the action is to print, we should also add the missing + # oid to the expect list. + case $action in + allow-any) + ;; + print) + grep ?$oid actual.raw && + echo ?$oid >>expect.raw + ;; + esac && + + sort actual.raw >actual && + sort expect.raw >expect && + test_cmp expect actual + ' + done + done +done + test_done diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh index 561080bf24..cdc0270640 100755 --- a/t/t6030-bisect-porcelain.sh +++ b/t/t6030-bisect-porcelain.sh @@ -878,7 +878,7 @@ test_expect_success 'broken branch creation' ' echo "" > expected.ok cat > expected.missing-tree.default <<EOF -fatal: unable to read tree $deleted +fatal: unable to read tree ($deleted) EOF test_expect_success 'bisect fails if tree is broken on start commit' ' diff --git a/t/t6112-rev-list-filters-objects.sh b/t/t6112-rev-list-filters-objects.sh index 52822b9461..43e1afd44c 100755 --- a/t/t6112-rev-list-filters-objects.sh +++ b/t/t6112-rev-list-filters-objects.sh @@ -670,7 +670,7 @@ test_expect_success 'rev-list W/ --missing=print' ' awk -f print_2.awk ls_files_result | sort >expected && - for id in `cat expected | sed "s|..|&/|"` + for id in `sed "s|..|&/|" expected` do rm r1/.git/objects/$id || return 1 done && diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh index 82f3d1ea0f..948f1bb5f4 100755 --- a/t/t6302-for-each-ref-filter.sh +++ b/t/t6302-for-each-ref-filter.sh @@ -31,6 +31,37 @@ test_expect_success 'setup some history and refs' ' git update-ref refs/odd/spot main ' +test_expect_success '--include-root-refs pattern prints pseudorefs' ' + cat >expect <<-\EOF && + HEAD + ORIG_HEAD + refs/heads/main + refs/heads/side + refs/odd/spot + refs/tags/annotated-tag + refs/tags/doubly-annotated-tag + refs/tags/doubly-signed-tag + refs/tags/four + refs/tags/one + refs/tags/signed-tag + refs/tags/three + refs/tags/two + EOF + git update-ref ORIG_HEAD main && + git for-each-ref --format="%(refname)" --include-root-refs >actual && + test_cmp expect actual +' + +test_expect_success '--include-root-refs with other patterns' ' + cat >expect <<-\EOF && + HEAD + ORIG_HEAD + EOF + git update-ref ORIG_HEAD main && + git for-each-ref --format="%(refname)" --include-root-refs "*HEAD" >actual && + test_cmp expect actual +' + test_expect_success 'filtering with --points-at' ' cat >expect <<-\EOF && refs/heads/main diff --git a/t/t6413-merge-crlf.sh b/t/t6413-merge-crlf.sh index b4f4a313f4..647ea1e838 100755 --- a/t/t6413-merge-crlf.sh +++ b/t/t6413-merge-crlf.sh @@ -34,14 +34,14 @@ test_expect_success setup ' test_expect_success 'Check "ours" is CRLF' ' git reset --hard initial && git merge side -s ours && - cat file | remove_cr | append_cr >file.temp && + remove_cr <file | append_cr >file.temp && test_cmp file file.temp ' test_expect_success 'Check that conflict file is CRLF' ' git reset --hard a && test_must_fail git merge side && - cat file | remove_cr | append_cr >file.temp && + remove_cr <file | append_cr >file.temp && test_cmp file file.temp ' diff --git a/t/t6418-merge-text-auto.sh b/t/t6418-merge-text-auto.sh index 41288a60ce..48a62cb855 100755 --- a/t/t6418-merge-text-auto.sh +++ b/t/t6418-merge-text-auto.sh @@ -15,6 +15,7 @@ test_description='CRLF merge conflict across text=auto change GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_have_prereq SED_STRIPS_CR && SED_OPTIONS=-b diff --git a/t/t6437-submodule-merge.sh b/t/t6437-submodule-merge.sh index 70650521b0..7a3f1cb27c 100755 --- a/t/t6437-submodule-merge.sh +++ b/t/t6437-submodule-merge.sh @@ -113,7 +113,7 @@ test_expect_success 'merging should conflict for non fast-forward' ' git checkout -b test-nonforward-a b && if test "$GIT_TEST_MERGE_ALGORITHM" = ort then - test_must_fail git merge c >actual && + test_must_fail git merge c 2>actual && sub_expect="go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)" && grep "$sub_expect" actual else @@ -154,9 +154,9 @@ test_expect_success 'merging should conflict for non fast-forward (resolution ex git rev-parse --short sub-d > ../expect) && if test "$GIT_TEST_MERGE_ALGORITHM" = ort then - test_must_fail git merge c >actual && + test_must_fail git merge c >actual 2>sub-actual && sub_expect="go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)" && - grep "$sub_expect" actual + grep "$sub_expect" sub-actual else test_must_fail git merge c 2> actual fi && @@ -181,9 +181,9 @@ test_expect_success 'merging should fail for ambiguous common parent' ' ) && if test "$GIT_TEST_MERGE_ALGORITHM" = ort then - test_must_fail git merge c >actual && + test_must_fail git merge c >actual 2>sub-actual && sub_expect="go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)" && - grep "$sub_expect" actual + grep "$sub_expect" sub-actual else test_must_fail git merge c 2> actual fi && @@ -227,7 +227,7 @@ test_expect_success 'merging should fail for changes that are backwards' ' git commit -a -m "f" && git checkout -b test-backward e && - test_must_fail git merge f >actual && + test_must_fail git merge f 2>actual && if test "$GIT_TEST_MERGE_ALGORITHM" = ort then sub_expect="go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-d)" && @@ -535,7 +535,7 @@ test_expect_success 'merging should fail with no merge base' ' git checkout -b b init && git add sub && git commit -m "b" && - test_must_fail git merge a >actual && + test_must_fail git merge a 2>actual && if test "$GIT_TEST_MERGE_ALGORITHM" = ort then sub_expect="go to submodule (sub), and either merge commit $(git -C sub rev-parse --short HEAD^1)" && diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh index 18fe1c25e6..43d40175f8 100755 --- a/t/t6500-gc.sh +++ b/t/t6500-gc.sh @@ -11,23 +11,7 @@ test_expect_success 'setup' ' # behavior, make sure we always pack everything to one pack by # default git config gc.bigPackThreshold 2g && - - # These are simply values which, when hashed as a blob with a newline, - # produce a hash where the first byte is 0x17 in their respective - # algorithms. - test_oid_cache <<-EOF - obj1 sha1:263 - obj1 sha256:34 - - obj2 sha1:410 - obj2 sha256:174 - - obj3 sha1:523 - obj3 sha256:313 - - obj4 sha1:790 - obj4 sha256:481 - EOF + test_oid_init ' test_expect_success 'gc empty repository' ' @@ -114,8 +98,8 @@ test_expect_success 'pre-auto-gc hook can stop auto gc' ' # We need to create two object whose sha1s start with 17 # since this is what git gc counts. As it happens, these # two blobs will do so. - test_commit "$(test_oid obj1)" && - test_commit "$(test_oid obj2)" && + test_commit "$(test_oid blob17_1)" && + test_commit "$(test_oid blob17_2)" && git gc --auto >../out.actual 2>../err.actual ) && @@ -146,13 +130,13 @@ test_expect_success 'auto gc with too many loose objects does not attempt to cre # We need to create two object whose sha1s start with 17 # since this is what git gc counts. As it happens, these # two blobs will do so. - test_commit "$(test_oid obj1)" && - test_commit "$(test_oid obj2)" && + test_commit "$(test_oid blob17_1)" && + test_commit "$(test_oid blob17_2)" && # Our first gc will create a pack; our second will create a second pack git gc --auto && ls .git/objects/pack/pack-*.pack | sort >existing_packs && - test_commit "$(test_oid obj3)" && - test_commit "$(test_oid obj4)" && + test_commit "$(test_oid blob17_3)" && + test_commit "$(test_oid blob17_4)" && git gc --auto 2>err && test_grep ! "^warning:" err && diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh index f6aebe92ff..5ab4d41ee7 100755 --- a/t/t7003-filter-branch.sh +++ b/t/t7003-filter-branch.sh @@ -396,10 +396,7 @@ test_expect_success '--prune-empty is able to prune entire branch' ' git branch prune-entire B && git filter-branch -f --prune-empty --index-filter "git update-index --remove A.t B.t" prune-entire && test_must_fail git rev-parse refs/heads/prune-entire && - if test_have_prereq REFFILES - then - test_must_fail git reflog exists refs/heads/prune-entire - fi + test_must_fail git reflog exists refs/heads/prune-entire ' test_expect_success '--remap-to-ancestor with filename filters' ' diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index b41a47eb94..696866d779 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -1777,10 +1777,10 @@ test_expect_success '--points-at finds annotated tags of tags' ' ' test_expect_success 'recursive tagging should give advice' ' - sed -e "s/|$//" <<-EOF >expect && + cat >expect <<-EOF && hint: You have created a nested tag. The object referred to by your new tag is hint: already a tag. If you meant to tag the object that it points to, use: - hint: | + hint: hint: git tag -f nested annotated-v4.0^{} hint: Disable this message with "git config advice.nestedTag false" EOF diff --git a/t/t7105-reset-patch.sh b/t/t7105-reset-patch.sh index 05079c7246..f4f3b7a677 100755 --- a/t/t7105-reset-patch.sh +++ b/t/t7105-reset-patch.sh @@ -5,7 +5,7 @@ test_description='git reset --patch' TEST_PASSES_SANITIZE_LEAK=true . ./lib-patch-mode.sh -test_expect_success PERL 'setup' ' +test_expect_success 'setup' ' mkdir dir && echo parent > dir/foo && echo dummy > bar && @@ -19,42 +19,46 @@ test_expect_success PERL 'setup' ' # note: bar sorts before foo, so the first 'n' is always to skip 'bar' -test_expect_success PERL 'saying "n" does nothing' ' +test_expect_success 'saying "n" does nothing' ' set_and_save_state dir/foo work work && test_write_lines n n | git reset -p && verify_saved_state dir/foo && verify_saved_state bar ' -test_expect_success PERL 'git reset -p' ' - test_write_lines n y | git reset -p >output && - verify_state dir/foo work head && - verify_saved_state bar && - test_grep "Unstage" output -' - -test_expect_success PERL 'git reset -p HEAD^' ' +for opt in "HEAD" "@" "" +do + test_expect_success "git reset -p $opt" ' + set_and_save_state dir/foo work work && + test_write_lines n y | git reset -p $opt >output && + verify_state dir/foo work head && + verify_saved_state bar && + test_grep "Unstage" output + ' +done + +test_expect_success 'git reset -p HEAD^' ' test_write_lines n y | git reset -p HEAD^ >output && verify_state dir/foo work parent && verify_saved_state bar && test_grep "Apply" output ' -test_expect_success PERL 'git reset -p HEAD^^{tree}' ' +test_expect_success 'git reset -p HEAD^^{tree}' ' test_write_lines n y | git reset -p HEAD^^{tree} >output && verify_state dir/foo work parent && verify_saved_state bar && test_grep "Apply" output ' -test_expect_success PERL 'git reset -p HEAD^:dir/foo (blob fails)' ' +test_expect_success 'git reset -p HEAD^:dir/foo (blob fails)' ' set_and_save_state dir/foo work work && test_must_fail git reset -p HEAD^:dir/foo && verify_saved_state dir/foo && verify_saved_state bar ' -test_expect_success PERL 'git reset -p aaaaaaaa (unknown fails)' ' +test_expect_success 'git reset -p aaaaaaaa (unknown fails)' ' set_and_save_state dir/foo work work && test_must_fail git reset -p aaaaaaaa && verify_saved_state dir/foo && @@ -66,27 +70,27 @@ test_expect_success PERL 'git reset -p aaaaaaaa (unknown fails)' ' # dir/foo. There's always an extra 'n' to reject edits to dir/foo in # the failure case (and thus get out of the loop). -test_expect_success PERL 'git reset -p dir' ' +test_expect_success 'git reset -p dir' ' set_state dir/foo work work && test_write_lines y n | git reset -p dir && verify_state dir/foo work head && verify_saved_state bar ' -test_expect_success PERL 'git reset -p -- foo (inside dir)' ' +test_expect_success 'git reset -p -- foo (inside dir)' ' set_state dir/foo work work && test_write_lines y n | (cd dir && git reset -p -- foo) && verify_state dir/foo work head && verify_saved_state bar ' -test_expect_success PERL 'git reset -p HEAD^ -- dir' ' +test_expect_success 'git reset -p HEAD^ -- dir' ' test_write_lines y n | git reset -p HEAD^ -- dir && verify_state dir/foo work parent && verify_saved_state bar ' -test_expect_success PERL 'none of this moved HEAD' ' +test_expect_success 'none of this moved HEAD' ' verify_saved_head ' diff --git a/t/t7106-reset-unborn-branch.sh b/t/t7106-reset-unborn-branch.sh index d20e5709f9..88d1c8adf4 100755 --- a/t/t7106-reset-unborn-branch.sh +++ b/t/t7106-reset-unborn-branch.sh @@ -34,7 +34,7 @@ test_expect_success 'reset $file' ' test_cmp expect actual ' -test_expect_success PERL 'reset -p' ' +test_expect_success 'reset -p' ' rm .git/index && git add a && echo y >yes && diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 10cc6c4605..42352dc0db 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -631,6 +631,72 @@ test_expect_success 'checkout --conflict=diff3' ' test_cmp merged file ' +test_expect_success 'checkout --conflict=diff3 --no-conflict does not merge' ' + setup_conflicting_index && + echo "none of the above" >expect && + cat expect >fild && + cat expect >file && + test_must_fail git checkout --conflict=diff3 --no-conflict -- fild file 2>err && + test_cmp expect file && + test_cmp expect fild && + echo "error: path ${SQ}file${SQ} is unmerged" >expect && + test_cmp expect err +' + +test_expect_success 'checkout --conflict=diff3 --no-merge does not merge' ' + setup_conflicting_index && + echo "none of the above" >expect && + cat expect >fild && + cat expect >file && + test_must_fail git checkout --conflict=diff3 --no-merge -- fild file 2>err && + test_cmp expect file && + test_cmp expect fild && + echo "error: path ${SQ}file${SQ} is unmerged" >expect && + test_cmp expect err +' + +test_expect_success 'checkout --no-merge --conflict=diff3 does merge' ' + setup_conflicting_index && + echo "none of the above" >fild && + echo "none of the above" >file && + git checkout --no-merge --conflict=diff3 -- fild file && + echo "ourside" >expect && + test_cmp expect fild && + cat >expect <<-\EOF && + <<<<<<< ours + ourside + ||||||| base + original + ======= + theirside + >>>>>>> theirs + EOF + test_cmp expect file +' + +test_expect_success 'checkout --merge --conflict=diff3 --no-conflict does merge' ' + setup_conflicting_index && + echo "none of the above" >fild && + echo "none of the above" >file && + git checkout --merge --conflict=diff3 --no-conflict -- fild file && + echo "ourside" >expect && + test_cmp expect fild && + cat >expect <<-\EOF && + <<<<<<< ours + ourside + ======= + theirside + >>>>>>> theirs + EOF + test_cmp expect file +' + +test_expect_success 'checkout with invalid conflict style' ' + test_must_fail git checkout --conflict=bad 2>actual -- file && + echo "error: unknown conflict style ${SQ}bad${SQ}" >expect && + test_cmp expect actual +' + test_expect_success 'failing checkout -b should not break working tree' ' git clean -fd && # Remove untracked files in the way git reset --hard main && diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh index 611b3dd3ae..0aae0dee67 100755 --- a/t/t7300-clean.sh +++ b/t/t7300-clean.sh @@ -5,6 +5,7 @@ test_description='git clean basic tests' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh git config clean.requireForce no @@ -407,6 +408,12 @@ test_expect_success 'clean.requireForce and -f' ' ' +test_expect_success 'clean.requireForce and --interactive' ' + git clean --interactive </dev/null >output 2>error && + test_grep ! "requireForce is true and" error && + test_grep "\*\*\* Commands \*\*\*" output +' + test_expect_success 'core.excludesfile' ' echo excludes >excludes && diff --git a/t/t7301-clean-interactive.sh b/t/t7301-clean-interactive.sh index d82a3210a1..4afe53c66a 100755 --- a/t/t7301-clean-interactive.sh +++ b/t/t7301-clean-interactive.sh @@ -25,18 +25,18 @@ test_expect_success 'git clean -i (c: clean hotkey)' ' touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \ docs/manual.txt obj.o build/lib.so && echo c | git clean -i && - test -f Makefile && - test -f README && - test -f src/part1.c && - test -f src/part2.c && - test ! -f a.out && - test -f docs/manual.txt && - test ! -f src/part3.c && - test ! -f src/part3.h && - test ! -f src/part4.c && - test ! -f src/part4.h && - test -f obj.o && - test -f build/lib.so + test_path_is_file Makefile && + test_path_is_file README && + test_path_is_file src/part1.c && + test_path_is_file src/part2.c && + test_path_is_missing a.out && + test_path_is_file docs/manual.txt && + test_path_is_missing src/part3.c && + test_path_is_missing src/part3.h && + test_path_is_missing src/part4.c && + test_path_is_missing src/part4.h && + test_path_is_file obj.o && + test_path_is_file build/lib.so ' @@ -46,18 +46,18 @@ test_expect_success 'git clean -i (cl: clean prefix)' ' touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \ docs/manual.txt obj.o build/lib.so && echo cl | git clean -i && - test -f Makefile && - test -f README && - test -f src/part1.c && - test -f src/part2.c && - test ! -f a.out && - test -f docs/manual.txt && - test ! -f src/part3.c && - test ! -f src/part3.h && - test ! -f src/part4.c && - test ! -f src/part4.h && - test -f obj.o && - test -f build/lib.so + test_path_is_file Makefile && + test_path_is_file README && + test_path_is_file src/part1.c && + test_path_is_file src/part2.c && + test_path_is_missing a.out && + test_path_is_file docs/manual.txt && + test_path_is_missing src/part3.c && + test_path_is_missing src/part3.h && + test_path_is_missing src/part4.c && + test_path_is_missing src/part4.h && + test_path_is_file obj.o && + test_path_is_file build/lib.so ' @@ -67,18 +67,18 @@ test_expect_success 'git clean -i (quit)' ' touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \ docs/manual.txt obj.o build/lib.so && echo quit | git clean -i && - test -f Makefile && - test -f README && - test -f src/part1.c && - test -f src/part2.c && - test -f a.out && - test -f docs/manual.txt && - test -f src/part3.c && - test -f src/part3.h && - test -f src/part4.c && - test -f src/part4.h && - test -f obj.o && - test -f build/lib.so + test_path_is_file Makefile && + test_path_is_file README && + test_path_is_file src/part1.c && + test_path_is_file src/part2.c && + test_path_is_file a.out && + test_path_is_file docs/manual.txt && + test_path_is_file src/part3.c && + test_path_is_file src/part3.h && + test_path_is_file src/part4.c && + test_path_is_file src/part4.h && + test_path_is_file obj.o && + test_path_is_file build/lib.so ' @@ -88,18 +88,18 @@ test_expect_success 'git clean -i (Ctrl+D)' ' touch a.out src/part3.c src/part3.h src/part4.c src/part4.h \ docs/manual.txt obj.o build/lib.so && echo "\04" | git clean -i && - test -f Makefile && - test -f README && - test -f src/part1.c && - test -f src/part2.c && - test -f a.out && - test -f docs/manual.txt && - test -f src/part3.c && - test -f src/part3.h && - test -f src/part4.c && - test -f src/part4.h && - test -f obj.o && - test -f build/lib.so + test_path_is_file Makefile && + test_path_is_file README && + test_path_is_file src/part1.c && + test_path_is_file src/part2.c && + test_path_is_file a.out && + test_path_is_file docs/manual.txt && + test_path_is_file src/part3.c && + test_path_is_file src/part3.h && + test_path_is_file src/part4.c && + test_path_is_file src/part4.h && + test_path_is_file obj.o && + test_path_is_file build/lib.so ' @@ -110,18 +110,18 @@ test_expect_success 'git clean -id (filter all)' ' docs/manual.txt obj.o build/lib.so && test_write_lines f "*" "" c | git clean -id && - test -f Makefile && - test -f README && - test -f src/part1.c && - test -f src/part2.c && - test -f a.out && - test -f docs/manual.txt && - test -f src/part3.c && - test -f src/part3.h && - test -f src/part4.c && - test -f src/part4.h && - test -f obj.o && - test -f build/lib.so + test_path_is_file Makefile && + test_path_is_file README && + test_path_is_file src/part1.c && + test_path_is_file src/part2.c && + test_path_is_file a.out && + test_path_is_file docs/manual.txt && + test_path_is_file src/part3.c && + test_path_is_file src/part3.h && + test_path_is_file src/part4.c && + test_path_is_file src/part4.h && + test_path_is_file obj.o && + test_path_is_file build/lib.so ' @@ -132,18 +132,18 @@ test_expect_success 'git clean -id (filter patterns)' ' docs/manual.txt obj.o build/lib.so && test_write_lines f "part3.* *.out" "" c | git clean -id && - test -f Makefile && - test -f README && - test -f src/part1.c && - test -f src/part2.c && - test -f a.out && - test ! -f docs/manual.txt && - test -f src/part3.c && - test -f src/part3.h && - test ! -f src/part4.c && - test ! -f src/part4.h && - test -f obj.o && - test -f build/lib.so + test_path_is_file Makefile && + test_path_is_file README && + test_path_is_file src/part1.c && + test_path_is_file src/part2.c && + test_path_is_file a.out && + test_path_is_missing docs/manual.txt && + test_path_is_file src/part3.c && + test_path_is_file src/part3.h && + test_path_is_missing src/part4.c && + test_path_is_missing src/part4.h && + test_path_is_file obj.o && + test_path_is_file build/lib.so ' @@ -154,18 +154,18 @@ test_expect_success 'git clean -id (filter patterns 2)' ' docs/manual.txt obj.o build/lib.so && test_write_lines f "* !*.out" "" c | git clean -id && - test -f Makefile && - test -f README && - test -f src/part1.c && - test -f src/part2.c && - test ! -f a.out && - test -f docs/manual.txt && - test -f src/part3.c && - test -f src/part3.h && - test -f src/part4.c && - test -f src/part4.h && - test -f obj.o && - test -f build/lib.so + test_path_is_file Makefile && + test_path_is_file README && + test_path_is_file src/part1.c && + test_path_is_file src/part2.c && + test_path_is_missing a.out && + test_path_is_file docs/manual.txt && + test_path_is_file src/part3.c && + test_path_is_file src/part3.h && + test_path_is_file src/part4.c && + test_path_is_file src/part4.h && + test_path_is_file obj.o && + test_path_is_file build/lib.so ' @@ -176,18 +176,18 @@ test_expect_success 'git clean -id (select - all)' ' docs/manual.txt obj.o build/lib.so && test_write_lines s "*" "" c | git clean -id && - test -f Makefile && - test -f README && - test -f src/part1.c && - test -f src/part2.c && - test ! -f a.out && - test ! -f docs/manual.txt && - test ! -f src/part3.c && - test ! -f src/part3.h && - test ! -f src/part4.c && - test ! -f src/part4.h && - test -f obj.o && - test -f build/lib.so + test_path_is_file Makefile && + test_path_is_file README && + test_path_is_file src/part1.c && + test_path_is_file src/part2.c && + test_path_is_missing a.out && + test_path_is_missing docs/manual.txt && + test_path_is_missing src/part3.c && + test_path_is_missing src/part3.h && + test_path_is_missing src/part4.c && + test_path_is_missing src/part4.h && + test_path_is_file obj.o && + test_path_is_file build/lib.so ' @@ -198,18 +198,18 @@ test_expect_success 'git clean -id (select - none)' ' docs/manual.txt obj.o build/lib.so && test_write_lines s "" c | git clean -id && - test -f Makefile && - test -f README && - test -f src/part1.c && - test -f src/part2.c && - test -f a.out && - test -f docs/manual.txt && - test -f src/part3.c && - test -f src/part3.h && - test -f src/part4.c && - test -f src/part4.h && - test -f obj.o && - test -f build/lib.so + test_path_is_file Makefile && + test_path_is_file README && + test_path_is_file src/part1.c && + test_path_is_file src/part2.c && + test_path_is_file a.out && + test_path_is_file docs/manual.txt && + test_path_is_file src/part3.c && + test_path_is_file src/part3.h && + test_path_is_file src/part4.c && + test_path_is_file src/part4.h && + test_path_is_file obj.o && + test_path_is_file build/lib.so ' @@ -220,18 +220,18 @@ test_expect_success 'git clean -id (select - number)' ' docs/manual.txt obj.o build/lib.so && test_write_lines s 3 "" c | git clean -id && - test -f Makefile && - test -f README && - test -f src/part1.c && - test -f src/part2.c && - test -f a.out && - test -f docs/manual.txt && - test ! -f src/part3.c && - test -f src/part3.h && - test -f src/part4.c && - test -f src/part4.h && - test -f obj.o && - test -f build/lib.so + test_path_is_file Makefile && + test_path_is_file README && + test_path_is_file src/part1.c && + test_path_is_file src/part2.c && + test_path_is_file a.out && + test_path_is_file docs/manual.txt && + test_path_is_missing src/part3.c && + test_path_is_file src/part3.h && + test_path_is_file src/part4.c && + test_path_is_file src/part4.h && + test_path_is_file obj.o && + test_path_is_file build/lib.so ' @@ -242,18 +242,18 @@ test_expect_success 'git clean -id (select - number 2)' ' docs/manual.txt obj.o build/lib.so && test_write_lines s "2 3" 5 "" c | git clean -id && - test -f Makefile && - test -f README && - test -f src/part1.c && - test -f src/part2.c && - test -f a.out && - test ! -f docs/manual.txt && - test ! -f src/part3.c && - test -f src/part3.h && - test ! -f src/part4.c && - test -f src/part4.h && - test -f obj.o && - test -f build/lib.so + test_path_is_file Makefile && + test_path_is_file README && + test_path_is_file src/part1.c && + test_path_is_file src/part2.c && + test_path_is_file a.out && + test_path_is_missing docs/manual.txt && + test_path_is_missing src/part3.c && + test_path_is_file src/part3.h && + test_path_is_missing src/part4.c && + test_path_is_file src/part4.h && + test_path_is_file obj.o && + test_path_is_file build/lib.so ' @@ -264,18 +264,18 @@ test_expect_success 'git clean -id (select - number 3)' ' docs/manual.txt obj.o build/lib.so && test_write_lines s "3,4 5" "" c | git clean -id && - test -f Makefile && - test -f README && - test -f src/part1.c && - test -f src/part2.c && - test -f a.out && - test -f docs/manual.txt && - test ! -f src/part3.c && - test ! -f src/part3.h && - test ! -f src/part4.c && - test -f src/part4.h && - test -f obj.o && - test -f build/lib.so + test_path_is_file Makefile && + test_path_is_file README && + test_path_is_file src/part1.c && + test_path_is_file src/part2.c && + test_path_is_file a.out && + test_path_is_file docs/manual.txt && + test_path_is_missing src/part3.c && + test_path_is_missing src/part3.h && + test_path_is_missing src/part4.c && + test_path_is_file src/part4.h && + test_path_is_file obj.o && + test_path_is_file build/lib.so ' @@ -285,11 +285,11 @@ test_expect_success 'git clean -id (select - filenames)' ' touch a.out foo.txt bar.txt baz.txt && test_write_lines s "a.out fo ba bar" "" c | git clean -id && - test -f Makefile && - test ! -f a.out && - test ! -f foo.txt && - test ! -f bar.txt && - test -f baz.txt && + test_path_is_file Makefile && + test_path_is_missing a.out && + test_path_is_missing foo.txt && + test_path_is_missing bar.txt && + test_path_is_file baz.txt && rm baz.txt ' @@ -301,18 +301,18 @@ test_expect_success 'git clean -id (select - range)' ' docs/manual.txt obj.o build/lib.so && test_write_lines s "1,3-4" 2 "" c | git clean -id && - test -f Makefile && - test -f README && - test -f src/part1.c && - test -f src/part2.c && - test ! -f a.out && - test ! -f src/part3.c && - test ! -f src/part3.h && - test -f src/part4.c && - test -f src/part4.h && - test ! -f docs/manual.txt && - test -f obj.o && - test -f build/lib.so + test_path_is_file Makefile && + test_path_is_file README && + test_path_is_file src/part1.c && + test_path_is_file src/part2.c && + test_path_is_missing a.out && + test_path_is_missing src/part3.c && + test_path_is_missing src/part3.h && + test_path_is_file src/part4.c && + test_path_is_file src/part4.h && + test_path_is_missing docs/manual.txt && + test_path_is_file obj.o && + test_path_is_file build/lib.so ' @@ -323,18 +323,18 @@ test_expect_success 'git clean -id (select - range 2)' ' docs/manual.txt obj.o build/lib.so && test_write_lines s "4- 1" "" c | git clean -id && - test -f Makefile && - test -f README && - test -f src/part1.c && - test -f src/part2.c && - test ! -f a.out && - test -f docs/manual.txt && - test -f src/part3.c && - test ! -f src/part3.h && - test ! -f src/part4.c && - test ! -f src/part4.h && - test -f obj.o && - test -f build/lib.so + test_path_is_file Makefile && + test_path_is_file README && + test_path_is_file src/part1.c && + test_path_is_file src/part2.c && + test_path_is_missing a.out && + test_path_is_file docs/manual.txt && + test_path_is_file src/part3.c && + test_path_is_missing src/part3.h && + test_path_is_missing src/part4.c && + test_path_is_missing src/part4.h && + test_path_is_file obj.o && + test_path_is_file build/lib.so ' @@ -345,18 +345,18 @@ test_expect_success 'git clean -id (inverse select)' ' docs/manual.txt obj.o build/lib.so && test_write_lines s "*" "-5- 1 -2" "" c | git clean -id && - test -f Makefile && - test -f README && - test -f src/part1.c && - test -f src/part2.c && - test ! -f a.out && - test -f docs/manual.txt && - test ! -f src/part3.c && - test ! -f src/part3.h && - test -f src/part4.c && - test -f src/part4.h && - test -f obj.o && - test -f build/lib.so + test_path_is_file Makefile && + test_path_is_file README && + test_path_is_file src/part1.c && + test_path_is_file src/part2.c && + test_path_is_missing a.out && + test_path_is_file docs/manual.txt && + test_path_is_missing src/part3.c && + test_path_is_missing src/part3.h && + test_path_is_file src/part4.c && + test_path_is_file src/part4.h && + test_path_is_file obj.o && + test_path_is_file build/lib.so ' @@ -367,18 +367,18 @@ test_expect_success 'git clean -id (ask)' ' docs/manual.txt obj.o build/lib.so && test_write_lines a Y y no yes bad "" | git clean -id && - test -f Makefile && - test -f README && - test -f src/part1.c && - test -f src/part2.c && - test ! -f a.out && - test ! -f docs/manual.txt && - test -f src/part3.c && - test ! -f src/part3.h && - test -f src/part4.c && - test -f src/part4.h && - test -f obj.o && - test -f build/lib.so + test_path_is_file Makefile && + test_path_is_file README && + test_path_is_file src/part1.c && + test_path_is_file src/part2.c && + test_path_is_missing a.out && + test_path_is_missing docs/manual.txt && + test_path_is_file src/part3.c && + test_path_is_missing src/part3.h && + test_path_is_file src/part4.c && + test_path_is_file src/part4.h && + test_path_is_file obj.o && + test_path_is_file build/lib.so ' @@ -389,18 +389,18 @@ test_expect_success 'git clean -id (ask - Ctrl+D)' ' docs/manual.txt obj.o build/lib.so && test_write_lines a Y no yes "\04" | git clean -id && - test -f Makefile && - test -f README && - test -f src/part1.c && - test -f src/part2.c && - test ! -f a.out && - test -f docs/manual.txt && - test ! -f src/part3.c && - test -f src/part3.h && - test -f src/part4.c && - test -f src/part4.h && - test -f obj.o && - test -f build/lib.so + test_path_is_file Makefile && + test_path_is_file README && + test_path_is_file src/part1.c && + test_path_is_file src/part2.c && + test_path_is_missing a.out && + test_path_is_file docs/manual.txt && + test_path_is_missing src/part3.c && + test_path_is_file src/part3.h && + test_path_is_file src/part4.c && + test_path_is_file src/part4.h && + test_path_is_file obj.o && + test_path_is_file build/lib.so ' @@ -412,18 +412,18 @@ test_expect_success 'git clean -id with prefix and path (filter)' ' (cd build/ && test_write_lines f docs "*.h" "" c | git clean -id ..) && - test -f Makefile && - test -f README && - test -f src/part1.c && - test -f src/part2.c && - test ! -f a.out && - test -f docs/manual.txt && - test ! -f src/part3.c && - test -f src/part3.h && - test ! -f src/part4.c && - test -f src/part4.h && - test -f obj.o && - test -f build/lib.so + test_path_is_file Makefile && + test_path_is_file README && + test_path_is_file src/part1.c && + test_path_is_file src/part2.c && + test_path_is_missing a.out && + test_path_is_file docs/manual.txt && + test_path_is_missing src/part3.c && + test_path_is_file src/part3.h && + test_path_is_missing src/part4.c && + test_path_is_file src/part4.h && + test_path_is_file obj.o && + test_path_is_file build/lib.so ' @@ -435,18 +435,18 @@ test_expect_success 'git clean -id with prefix and path (select by name)' ' (cd build/ && test_write_lines s ../docs/ ../src/part3.c ../src/part4.c "" c | git clean -id ..) && - test -f Makefile && - test -f README && - test -f src/part1.c && - test -f src/part2.c && - test -f a.out && - test ! -f docs/manual.txt && - test ! -f src/part3.c && - test -f src/part3.h && - test ! -f src/part4.c && - test -f src/part4.h && - test -f obj.o && - test -f build/lib.so + test_path_is_file Makefile && + test_path_is_file README && + test_path_is_file src/part1.c && + test_path_is_file src/part2.c && + test_path_is_file a.out && + test_path_is_missing docs/manual.txt && + test_path_is_missing src/part3.c && + test_path_is_file src/part3.h && + test_path_is_missing src/part4.c && + test_path_is_file src/part4.h && + test_path_is_file obj.o && + test_path_is_file build/lib.so ' @@ -458,18 +458,18 @@ test_expect_success 'git clean -id with prefix and path (ask)' ' (cd build/ && test_write_lines a Y y no yes bad "" | git clean -id ..) && - test -f Makefile && - test -f README && - test -f src/part1.c && - test -f src/part2.c && - test ! -f a.out && - test ! -f docs/manual.txt && - test -f src/part3.c && - test ! -f src/part3.h && - test -f src/part4.c && - test -f src/part4.h && - test -f obj.o && - test -f build/lib.so + test_path_is_file Makefile && + test_path_is_file README && + test_path_is_file src/part1.c && + test_path_is_file src/part2.c && + test_path_is_missing a.out && + test_path_is_missing docs/manual.txt && + test_path_is_file src/part3.c && + test_path_is_missing src/part3.h && + test_path_is_file src/part4.c && + test_path_is_file src/part4.h && + test_path_is_file obj.o && + test_path_is_file build/lib.so ' diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index 7223c8f74f..981488885f 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -212,8 +212,7 @@ test_expect_success 'submodule add to .gitignored path fails' ' The following paths are ignored by one of your .gitignore files: submod hint: Use -f if you really want to add them. - hint: Turn this message off by running - hint: "git config advice.addIgnoredFile false" + hint: Disable this message with "git config advice.addIgnoredFile false" EOF # Does not use test_commit due to the ignore echo "*" > .gitignore && diff --git a/t/t7402-submodule-rebase.sh b/t/t7402-submodule-rebase.sh index 2b3c363078..aa2fdc31d1 100755 --- a/t/t7402-submodule-rebase.sh +++ b/t/t7402-submodule-rebase.sh @@ -116,7 +116,7 @@ test_expect_success 'rebasing submodule that should conflict' ' test_tick && git commit -m fourth && - test_must_fail git rebase --onto HEAD^^ HEAD^ HEAD^0 >actual_output && + test_must_fail git rebase --onto HEAD^^ HEAD^ HEAD^0 2>actual_output && git ls-files -s submodule >actual && ( cd submodule && diff --git a/t/t7501-commit-basic-functionality.sh b/t/t7501-commit-basic-functionality.sh index bced44a0fc..cc12f99f11 100755 --- a/t/t7501-commit-basic-functionality.sh +++ b/t/t7501-commit-basic-functionality.sh @@ -101,22 +101,8 @@ test_expect_success 'fail to commit untracked file (even with --include/--only)' test_must_fail git commit --only -m "baz" baz 2>err && test_grep -e "$error" err && - # TODO: as for --include, the below command will fail because - # nothing is staged. If something was staged, it would not fail - # even though the provided pathspec does not match any tracked - # path. (However, the untracked paths that match the pathspec are - # not committed and only the staged changes get committed.) - # In either cases, no error is returned to stderr like in (--only - # and without --only/--include) cases. In a similar manner, - # "git add -u baz" also does not error out. - # - # Therefore, the below test is just to document the current behavior - # and is not an endorsement to the current behavior, and we may - # want to fix this. And when that happens, this test should be - # updated accordingly. - test_must_fail git commit --include -m "baz" baz 2>err && - test_must_be_empty err + test_grep -e "$error" err ' test_expect_success 'setup: non-initial commit' ' diff --git a/t/t7502-commit-porcelain.sh b/t/t7502-commit-porcelain.sh index a87c211d0b..b37e2018a7 100755 --- a/t/t7502-commit-porcelain.sh +++ b/t/t7502-commit-porcelain.sh @@ -736,6 +736,11 @@ test_expect_success 'message shows date when it is explicitly set' ' .git/COMMIT_EDITMSG ' +test_expect_success 'message does not have multiple scissors lines' ' + git commit --cleanup=scissors -v --allow-empty -e -m foo && + test $(grep -c -e "--- >8 ---" .git/COMMIT_EDITMSG) -eq 1 +' + test_expect_success AUTOIDENT 'message shows committer when it is automatic' ' echo >>negative && diff --git a/t/t7507-commit-verbose.sh b/t/t7507-commit-verbose.sh index c3281b192e..4c7db19ce7 100755 --- a/t/t7507-commit-verbose.sh +++ b/t/t7507-commit-verbose.sh @@ -101,6 +101,16 @@ test_expect_success 'verbose diff is stripped out with set core.commentChar' ' test_grep "Aborting commit due to empty commit message." err ' +test_expect_success 'verbose diff is stripped with multi-byte comment char' ' + ( + GIT_EDITOR=cat && + export GIT_EDITOR && + test_must_fail git -c core.commentchar="foo>" commit -a -v >out 2>err + ) && + grep "^foo> " out && + test_grep "Aborting commit due to empty commit message." err +' + test_expect_success 'status does not verbose without --verbose' ' git status >actual && ! grep "^diff --git" actual diff --git a/t/t7508-status.sh b/t/t7508-status.sh index a3c18a4fc2..773383fefb 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -419,14 +419,19 @@ Changes not staged for commit: Untracked files not listed (use -u option to show untracked files) EOF git status -uno >output && + test_cmp expect output && + git status -ufalse >output && test_cmp expect output ' -test_expect_success 'status (status.showUntrackedFiles no)' ' - test_config status.showuntrackedfiles no && - git status >output && - test_cmp expect output -' +for no in no false 0 +do + test_expect_success "status (status.showUntrackedFiles $no)" ' + test_config status.showuntrackedfiles "$no" && + git status >output && + test_cmp expect output + ' +done test_expect_success 'status -uno (advice.statusHints false)' ' cat >expect <<EOF && @@ -488,14 +493,21 @@ Untracked files: EOF git status -unormal >output && + test_cmp expect output && + git status -utrue >output && + test_cmp expect output && + git status -uyes >output && test_cmp expect output ' -test_expect_success 'status (status.showUntrackedFiles normal)' ' - test_config status.showuntrackedfiles normal && - git status >output && - test_cmp expect output -' +for normal in normal true 1 +do + test_expect_success "status (status.showUntrackedFiles $normal)" ' + test_config status.showuntrackedfiles $normal && + git status >output && + test_cmp expect output + ' +done cat >expect <<EOF M dir1/modified @@ -1403,7 +1415,9 @@ test_expect_success "status (core.commentchar with submodule summary)" ' test_expect_success "status (core.commentchar with two chars with submodule summary)" ' test_config core.commentchar ";;" && - test_must_fail git -c status.displayCommentPrefix=true status + sed "s/^/;/" <expect >expect.double && + git -c status.displayCommentPrefix=true status >output && + test_cmp expect.double output ' test_expect_success "--ignore-submodules=all suppresses submodule summary" ' diff --git a/t/t7513-interpret-trailers.sh b/t/t7513-interpret-trailers.sh index ec9c6de114..3d3e13ccf8 100755 --- a/t/t7513-interpret-trailers.sh +++ b/t/t7513-interpret-trailers.sh @@ -1935,4 +1935,18 @@ test_expect_success 'suppressing --- does not disable cut-line handling' ' test_cmp expected actual ' +test_expect_success 'handling of --- lines in conjunction with cut-lines' ' + echo "my-trailer: here" >expected && + + git interpret-trailers --parse >actual <<-\EOF && + subject + + my-trailer: here + --- + # ------------------------ >8 ------------------------ + EOF + + test_cmp expected actual +' + test_done diff --git a/t/t7514-commit-patch.sh b/t/t7514-commit-patch.sh index 998a2103c7..03ba0c0e73 100755 --- a/t/t7514-commit-patch.sh +++ b/t/t7514-commit-patch.sh @@ -1,13 +1,9 @@ #!/bin/sh test_description='hunk edit with "commit -p -m"' -. ./test-lib.sh -if ! test_have_prereq PERL -then - skip_all="skipping '$test_description' tests, perl not available" - test_done -fi +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh test_expect_success 'setup (initial)' ' echo line1 >file && diff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh index 363f9dc0e4..730f3c7f81 100755 --- a/t/t7527-builtin-fsmonitor.sh +++ b/t/t7527-builtin-fsmonitor.sh @@ -1037,4 +1037,227 @@ test_expect_success 'split-index and FSMonitor work well together' ' ) ' +# The FSMonitor daemon reports the OBSERVED pathname of modified files +# and thus contains the OBSERVED spelling on case-insensitive file +# systems. The daemon does not (and should not) load the .git/index +# file and therefore does not know the expected case-spelling. Since +# it is possible for the user to create files/subdirectories with the +# incorrect case, a modified file event for a tracked will not have +# the EXPECTED case. This can cause `index_name_pos()` to incorrectly +# report that the file is untracked. This causes the client to fail to +# mark the file as possibly dirty (keeping the CE_FSMONITOR_VALID bit +# set) so that `git status` will avoid inspecting it and thus not +# present in the status output. +# +# The setup is a little contrived. +# +test_expect_success CASE_INSENSITIVE_FS 'fsmonitor subdir case wrong on disk' ' + test_when_finished "stop_daemon_delete_repo subdir_case_wrong" && + + git init subdir_case_wrong && + ( + cd subdir_case_wrong && + echo x >AAA && + echo x >BBB && + + mkdir dir1 && + echo x >dir1/file1 && + mkdir dir1/dir2 && + echo x >dir1/dir2/file2 && + mkdir dir1/dir2/dir3 && + echo x >dir1/dir2/dir3/file3 && + + echo x >yyy && + echo x >zzz && + git add . && + git commit -m "data" && + + # This will cause "dir1/" and everything under it + # to be deleted. + git sparse-checkout set --cone --sparse-index && + + # Create dir2 with the wrong case and then let Git + # repopulate dir3 -- it will not correct the spelling + # of dir2. + mkdir dir1 && + mkdir dir1/DIR2 && + git sparse-checkout add dir1/dir2/dir3 + ) && + + start_daemon -C subdir_case_wrong --tf "$PWD/subdir_case_wrong.trace" && + + # Enable FSMonitor in the client. Run enough commands for + # the .git/index to sync up with the daemon with everything + # marked clean. + git -C subdir_case_wrong config core.fsmonitor true && + git -C subdir_case_wrong update-index --fsmonitor && + git -C subdir_case_wrong status && + + # Make some files dirty so that FSMonitor gets FSEvents for + # each of them. + echo xx >>subdir_case_wrong/AAA && + echo xx >>subdir_case_wrong/dir1/DIR2/dir3/file3 && + echo xx >>subdir_case_wrong/zzz && + + GIT_TRACE_FSMONITOR="$PWD/subdir_case_wrong.log" \ + git -C subdir_case_wrong --no-optional-locks status --short \ + >"$PWD/subdir_case_wrong.out" && + + # "git status" should have gotten file events for each of + # the 3 files. + # + # "dir2" should be in the observed case on disk. + grep "fsmonitor_refresh_callback" \ + <"$PWD/subdir_case_wrong.log" \ + >"$PWD/subdir_case_wrong.log1" && + + grep -q "AAA.*pos 0" "$PWD/subdir_case_wrong.log1" && + grep -q "zzz.*pos 6" "$PWD/subdir_case_wrong.log1" && + + grep -q "dir1/DIR2/dir3/file3.*pos -3" "$PWD/subdir_case_wrong.log1" && + + # Verify that we get a mapping event to correct the case. + grep -q "MAP:.*dir1/DIR2/dir3/file3.*dir1/dir2/dir3/file3" \ + "$PWD/subdir_case_wrong.log1" && + + # The refresh-callbacks should have caused "git status" to clear + # the CE_FSMONITOR_VALID bit on each of those files and caused + # the worktree scan to visit them and mark them as modified. + grep -q " M AAA" "$PWD/subdir_case_wrong.out" && + grep -q " M zzz" "$PWD/subdir_case_wrong.out" && + grep -q " M dir1/dir2/dir3/file3" "$PWD/subdir_case_wrong.out" +' + +test_expect_success CASE_INSENSITIVE_FS 'fsmonitor file case wrong on disk' ' + test_when_finished "stop_daemon_delete_repo file_case_wrong" && + + git init file_case_wrong && + ( + cd file_case_wrong && + echo x >AAA && + echo x >BBB && + + mkdir dir1 && + mkdir dir1/dir2 && + mkdir dir1/dir2/dir3 && + echo x >dir1/dir2/dir3/FILE-3-B && + echo x >dir1/dir2/dir3/XXXX-3-X && + echo x >dir1/dir2/dir3/file-3-a && + echo x >dir1/dir2/dir3/yyyy-3-y && + mkdir dir1/dir2/dir4 && + echo x >dir1/dir2/dir4/FILE-4-A && + echo x >dir1/dir2/dir4/XXXX-4-X && + echo x >dir1/dir2/dir4/file-4-b && + echo x >dir1/dir2/dir4/yyyy-4-y && + + echo x >yyy && + echo x >zzz && + git add . && + git commit -m "data" + ) && + + start_daemon -C file_case_wrong --tf "$PWD/file_case_wrong.trace" && + + # Enable FSMonitor in the client. Run enough commands for + # the .git/index to sync up with the daemon with everything + # marked clean. + git -C file_case_wrong config core.fsmonitor true && + git -C file_case_wrong update-index --fsmonitor && + git -C file_case_wrong status && + + # Make some files dirty so that FSMonitor gets FSEvents for + # each of them. + echo xx >>file_case_wrong/AAA && + echo xx >>file_case_wrong/zzz && + + # Rename some files so that FSMonitor sees a create and delete + # FSEvent for each. (A simple "mv foo FOO" is not portable + # between macOS and Windows. It works on both platforms, but makes + # the test messy, since (1) one platform updates "ctime" on the + # moved file and one does not and (2) it causes a directory event + # on one platform and not on the other which causes additional + # scanning during "git status" which causes a "H" vs "h" discrepancy + # in "git ls-files -f".) So old-school it and move it out of the + # way and copy it to the case-incorrect name so that we get fresh + # "ctime" and "mtime" values. + + mv file_case_wrong/dir1/dir2/dir3/file-3-a file_case_wrong/dir1/dir2/dir3/ORIG && + cp file_case_wrong/dir1/dir2/dir3/ORIG file_case_wrong/dir1/dir2/dir3/FILE-3-A && + rm file_case_wrong/dir1/dir2/dir3/ORIG && + mv file_case_wrong/dir1/dir2/dir4/FILE-4-A file_case_wrong/dir1/dir2/dir4/ORIG && + cp file_case_wrong/dir1/dir2/dir4/ORIG file_case_wrong/dir1/dir2/dir4/file-4-a && + rm file_case_wrong/dir1/dir2/dir4/ORIG && + + # Run status enough times to fully sync. + # + # The first instance should get the create and delete FSEvents + # for each pair. Status should update the index with a new FSM + # token (so the next invocation will not see data for these + # events). + + GIT_TRACE_FSMONITOR="$PWD/file_case_wrong-try1.log" \ + git -C file_case_wrong status --short \ + >"$PWD/file_case_wrong-try1.out" && + grep -q "fsmonitor_refresh_callback.*FILE-3-A.*pos -3" "$PWD/file_case_wrong-try1.log" && + grep -q "fsmonitor_refresh_callback.*file-3-a.*pos 4" "$PWD/file_case_wrong-try1.log" && + grep -q "fsmonitor_refresh_callback.*FILE-4-A.*pos 6" "$PWD/file_case_wrong-try1.log" && + grep -q "fsmonitor_refresh_callback.*file-4-a.*pos -9" "$PWD/file_case_wrong-try1.log" && + + # FSM refresh will have invalidated the FSM bit and cause a regular + # (real) scan of these tracked files, so they should have "H" status. + # (We will not see a "h" status until the next refresh (on the next + # command).) + + git -C file_case_wrong ls-files -f >"$PWD/file_case_wrong-lsf1.out" && + grep -q "H dir1/dir2/dir3/file-3-a" "$PWD/file_case_wrong-lsf1.out" && + grep -q "H dir1/dir2/dir4/FILE-4-A" "$PWD/file_case_wrong-lsf1.out" && + + + # Try the status again. We assume that the above status command + # advanced the token so that the next one will not see those events. + + GIT_TRACE_FSMONITOR="$PWD/file_case_wrong-try2.log" \ + git -C file_case_wrong status --short \ + >"$PWD/file_case_wrong-try2.out" && + ! grep -q "fsmonitor_refresh_callback.*FILE-3-A.*pos" "$PWD/file_case_wrong-try2.log" && + ! grep -q "fsmonitor_refresh_callback.*file-3-a.*pos" "$PWD/file_case_wrong-try2.log" && + ! grep -q "fsmonitor_refresh_callback.*FILE-4-A.*pos" "$PWD/file_case_wrong-try2.log" && + ! grep -q "fsmonitor_refresh_callback.*file-4-a.*pos" "$PWD/file_case_wrong-try2.log" && + + # FSM refresh saw nothing, so it will mark all files as valid, + # so they should now have "h" status. + + git -C file_case_wrong ls-files -f >"$PWD/file_case_wrong-lsf2.out" && + grep -q "h dir1/dir2/dir3/file-3-a" "$PWD/file_case_wrong-lsf2.out" && + grep -q "h dir1/dir2/dir4/FILE-4-A" "$PWD/file_case_wrong-lsf2.out" && + + + # We now have files with clean content, but with case-incorrect + # file names. Modify them to see if status properly reports + # them. + + echo xx >>file_case_wrong/dir1/dir2/dir3/FILE-3-A && + echo xx >>file_case_wrong/dir1/dir2/dir4/file-4-a && + + GIT_TRACE_FSMONITOR="$PWD/file_case_wrong-try3.log" \ + git -C file_case_wrong --no-optional-locks status --short \ + >"$PWD/file_case_wrong-try3.out" && + + # Verify that we get a mapping event to correct the case. + grep -q "fsmonitor_refresh_callback MAP:.*dir1/dir2/dir3/FILE-3-A.*dir1/dir2/dir3/file-3-a" \ + "$PWD/file_case_wrong-try3.log" && + grep -q "fsmonitor_refresh_callback MAP:.*dir1/dir2/dir4/file-4-a.*dir1/dir2/dir4/FILE-4-A" \ + "$PWD/file_case_wrong-try3.log" && + + # FSEvents are in observed case. + grep -q "fsmonitor_refresh_callback.*FILE-3-A.*pos -3" "$PWD/file_case_wrong-try3.log" && + grep -q "fsmonitor_refresh_callback.*file-4-a.*pos -9" "$PWD/file_case_wrong-try3.log" && + + # The refresh-callbacks should have caused "git status" to clear + # the CE_FSMONITOR_VALID bit on each of those files and caused + # the worktree scan to visit them and mark them as modified. + grep -q " M dir1/dir2/dir3/file-3-a" "$PWD/file_case_wrong-try3.out" && + grep -q " M dir1/dir2/dir4/FILE-4-A" "$PWD/file_case_wrong-try3.out" +' + test_done diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh index 94f9f4a1da..127efe99f8 100755 --- a/t/t7700-repack.sh +++ b/t/t7700-repack.sh @@ -629,6 +629,7 @@ test_expect_success '--write-midx with preferred bitmap tips' ' git log --format="create refs/tags/%s/%s %H" HEAD >refs && git update-ref --stdin <refs && + GIT_TEST_MULTI_PACK_INDEX=0 \ git repack --write-midx --write-bitmap-index && test_path_is_file $midx && test_path_is_file $midx-$(midx_checksum $objdir).bitmap && @@ -749,6 +750,7 @@ test_expect_success '--write-midx with --pack-kept-objects' ' keep="$objdir/pack/pack-$one.keep" && touch "$keep" && + GIT_TEST_MULTI_PACK_INDEX=0 \ git repack --write-midx --write-bitmap-index --geometric=2 -d \ --pack-kept-objects && diff --git a/t/t7704-repack-cruft.sh b/t/t7704-repack-cruft.sh index be3735dff0..71e1ef3a10 100755 --- a/t/t7704-repack-cruft.sh +++ b/t/t7704-repack-cruft.sh @@ -48,7 +48,7 @@ test_expect_success '--expire-to stores pruned objects (now)' ' # ...in other words, the combined contents of this # repository and expired.git should be the same as the # set of objects we started with. - cat expired.objects remaining.objects | sort >actual && + sort expired.objects remaining.objects >actual && test_cmp expect actual && # The "moved" objects (i.e., those in expired.git) diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh index 6a36be1e63..cc917b257e 100755 --- a/t/t7800-difftool.sh +++ b/t/t7800-difftool.sh @@ -91,58 +91,67 @@ test_expect_success 'difftool forwards arguments to diff' ' rm for-diff ' -test_expect_success 'difftool ignores exit code' ' - test_config difftool.error.cmd false && - git difftool -y -t error branch -' - -test_expect_success 'difftool forwards exit code with --trust-exit-code' ' - test_config difftool.error.cmd false && - test_must_fail git difftool -y --trust-exit-code -t error branch -' - -test_expect_success 'difftool forwards exit code with --trust-exit-code for built-ins' ' - test_config difftool.vimdiff.path false && - test_must_fail git difftool -y --trust-exit-code -t vimdiff branch -' - -test_expect_success 'difftool honors difftool.trustExitCode = true' ' - test_config difftool.error.cmd false && - test_config difftool.trustExitCode true && - test_must_fail git difftool -y -t error branch -' - -test_expect_success 'difftool honors difftool.trustExitCode = false' ' - test_config difftool.error.cmd false && - test_config difftool.trustExitCode false && - git difftool -y -t error branch -' - -test_expect_success 'difftool ignores exit code with --no-trust-exit-code' ' - test_config difftool.error.cmd false && - test_config difftool.trustExitCode true && - git difftool -y --no-trust-exit-code -t error branch -' - -test_expect_success 'difftool stops on error with --trust-exit-code' ' - test_when_finished "rm -f for-diff .git/fail-right-file" && - test_when_finished "git reset -- for-diff" && - write_script .git/fail-right-file <<-\EOF && - echo failed - exit 1 - EOF - >for-diff && - git add for-diff && - test_must_fail git difftool -y --trust-exit-code \ - --extcmd .git/fail-right-file branch >actual && - test_line_count = 1 actual -' - -test_expect_success 'difftool honors exit status if command not found' ' - test_config difftool.nonexistent.cmd i-dont-exist && - test_config difftool.trustExitCode false && - test_must_fail git difftool -y -t nonexistent branch -' +for opt in '' '--dir-diff' +do + test_expect_success "difftool ${opt:-without options} ignores exit code" ' + test_config difftool.error.cmd false && + git difftool ${opt} -y -t error branch + ' + + test_expect_success "difftool ${opt:-without options} forwards exit code with --trust-exit-code" ' + test_config difftool.error.cmd false && + test_must_fail git difftool ${opt} -y --trust-exit-code -t error branch + ' + + test_expect_success "difftool ${opt:-without options} forwards exit code with --trust-exit-code for built-ins" ' + test_config difftool.vimdiff.path false && + test_must_fail git difftool ${opt} -y --trust-exit-code -t vimdiff branch + ' + + test_expect_success "difftool ${opt:-without options} honors difftool.trustExitCode = true" ' + test_config difftool.error.cmd false && + test_config difftool.trustExitCode true && + test_must_fail git difftool ${opt} -y -t error branch + ' + + test_expect_success "difftool ${opt:-without options} honors difftool.trustExitCode = false" ' + test_config difftool.error.cmd false && + test_config difftool.trustExitCode false && + git difftool ${opt} -y -t error branch + ' + + test_expect_success "difftool ${opt:-without options} ignores exit code with --no-trust-exit-code" ' + test_config difftool.error.cmd false && + test_config difftool.trustExitCode true && + git difftool ${opt} -y --no-trust-exit-code -t error branch + ' + + test_expect_success "difftool ${opt:-without options} stops on error with --trust-exit-code" ' + test_when_finished "rm -f for-diff .git/fail-right-file" && + test_when_finished "git reset -- for-diff" && + write_script .git/fail-right-file <<-\EOF && + echo failed + exit 1 + EOF + >for-diff && + git add for-diff && + test_must_fail git difftool ${opt} -y --trust-exit-code \ + --extcmd .git/fail-right-file branch >actual && + test_line_count = 1 actual + ' + + test_expect_success "difftool ${opt:-without options} honors exit status if command not found" ' + test_config difftool.nonexistent.cmd i-dont-exist && + test_config difftool.trustExitCode false && + if test "${opt}" = --dir-diff + then + expected_code=127 + else + expected_code=128 + fi && + test_expect_code ${expected_code} git difftool ${opt} -y -t nonexistent branch + ' +done test_expect_success 'difftool honors --gui' ' difftool_test_setup && diff --git a/t/t8010-cat-file-filters.sh b/t/t8010-cat-file-filters.sh index ca04242ca0..eb64b766bd 100755 --- a/t/t8010-cat-file-filters.sh +++ b/t/t8010-cat-file-filters.sh @@ -43,7 +43,7 @@ test_expect_success 'cat-file --textconv --path=<path> works' ' sha1=$(git rev-parse -q --verify HEAD:world.txt) && test_config diff.txt.textconv "tr A-Za-z N-ZA-Mn-za-m <" && git cat-file --textconv --path=hello.txt $sha1 >rot13 && - test uryyb = "$(cat rot13 | remove_cr)" + test uryyb = "$(remove_cr <rot13)" ' test_expect_success '--path=<path> complains without --textconv/--filters' ' diff --git a/t/t8013-blame-ignore-revs.sh b/t/t8013-blame-ignore-revs.sh index 9a03b0f361..dbfbd86e83 100755 --- a/t/t8013-blame-ignore-revs.sh +++ b/t/t8013-blame-ignore-revs.sh @@ -25,11 +25,11 @@ test_expect_success setup ' git blame --line-porcelain file >blame_raw && - grep -E "^[0-9a-f]+ [0-9]+ 1" blame_raw | sed -e "s/ .*//" >actual && + sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual && git rev-parse X >expect && test_cmp expect actual && - grep -E "^[0-9a-f]+ [0-9]+ 2" blame_raw | sed -e "s/ .*//" >actual && + sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual && git rev-parse X >expect && test_cmp expect actual ' @@ -53,11 +53,11 @@ do test_expect_success "ignore_rev_changing_lines ($I)" ' git blame --line-porcelain --ignore-rev $I file >blame_raw && - grep -E "^[0-9a-f]+ [0-9]+ 1" blame_raw | sed -e "s/ .*//" >actual && + sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual && git rev-parse A >expect && test_cmp expect actual && - grep -E "^[0-9a-f]+ [0-9]+ 2" blame_raw | sed -e "s/ .*//" >actual && + sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual && git rev-parse B >expect && test_cmp expect actual ' @@ -79,10 +79,10 @@ test_expect_success ignore_rev_adding_unblamable_lines ' git rev-parse Y >expect && git blame --line-porcelain file --ignore-rev Y >blame_raw && - grep -E "^[0-9a-f]+ [0-9]+ 3" blame_raw | sed -e "s/ .*//" >actual && + sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 3/s/ .*//p" blame_raw >actual && test_cmp expect actual && - grep -E "^[0-9a-f]+ [0-9]+ 4" blame_raw | sed -e "s/ .*//" >actual && + sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 4/s/ .*//p" blame_raw >actual && test_cmp expect actual ' @@ -92,11 +92,11 @@ test_expect_success ignore_revs_from_files ' git rev-parse Y >ignore_y && git blame --line-porcelain file --ignore-revs-file ignore_x --ignore-revs-file ignore_y >blame_raw && - grep -E "^[0-9a-f]+ [0-9]+ 1" blame_raw | sed -e "s/ .*//" >actual && + sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual && git rev-parse A >expect && test_cmp expect actual && - grep -E "^[0-9a-f]+ [0-9]+ 2" blame_raw | sed -e "s/ .*//" >actual && + sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual && git rev-parse B >expect && test_cmp expect actual ' @@ -106,11 +106,11 @@ test_expect_success ignore_revs_from_configs_and_files ' git config --add blame.ignoreRevsFile ignore_x && git blame --line-porcelain file --ignore-revs-file ignore_y >blame_raw && - grep -E "^[0-9a-f]+ [0-9]+ 1" blame_raw | sed -e "s/ .*//" >actual && + sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual && git rev-parse A >expect && test_cmp expect actual && - grep -E "^[0-9a-f]+ [0-9]+ 2" blame_raw | sed -e "s/ .*//" >actual && + sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual && git rev-parse B >expect && test_cmp expect actual ' @@ -121,10 +121,10 @@ test_expect_success override_ignore_revs_file ' git blame --line-porcelain file --ignore-revs-file "" --ignore-revs-file ignore_y >blame_raw && git rev-parse X >expect && - grep -E "^[0-9a-f]+ [0-9]+ 1" blame_raw | sed -e "s/ .*//" >actual && + sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual && test_cmp expect actual && - grep -E "^[0-9a-f]+ [0-9]+ 2" blame_raw | sed -e "s/ .*//" >actual && + sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual && test_cmp expect actual ' test_expect_success bad_files_and_revs ' @@ -279,11 +279,11 @@ test_expect_success ignore_merge ' test_merge M B && git blame --line-porcelain file --ignore-rev M >blame_raw && - grep -E "^[0-9a-f]+ [0-9]+ 1" blame_raw | sed -e "s/ .*//" >actual && + sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual && git rev-parse B >expect && test_cmp expect actual && - grep -E "^[0-9a-f]+ [0-9]+ 9" blame_raw | sed -e "s/ .*//" >actual && + sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 9/s/ .*//p" blame_raw >actual && git rev-parse C >expect && test_cmp expect actual ' diff --git a/t/t9002-column.sh b/t/t9002-column.sh index 348cc40658..d5b98e615b 100755 --- a/t/t9002-column.sh +++ b/t/t9002-column.sh @@ -196,4 +196,15 @@ EOF test_cmp expected actual ' +test_expect_success 'padding must be non-negative' ' + cat >input <<\EOF && +1 2 3 4 5 6 +EOF + cat >expected <<\EOF && +fatal: --padding must be non-negative +EOF + test_must_fail git column --mode=column --padding=-1 <input >actual 2>&1 && + test_cmp expected actual +' + test_done diff --git a/t/t9117-git-svn-init-clone.sh b/t/t9117-git-svn-init-clone.sh index 62de819a44..3b038c338f 100755 --- a/t/t9117-git-svn-init-clone.sh +++ b/t/t9117-git-svn-init-clone.sh @@ -17,32 +17,32 @@ test_expect_success 'setup svnrepo' ' test_expect_success 'basic clone' ' test ! -d trunk && git svn clone "$svnrepo"/project/trunk && - test -d trunk/.git/svn && - test -e trunk/foo && + test_path_is_dir trunk/.git/svn && + test_path_exists trunk/foo && rm -rf trunk ' test_expect_success 'clone to target directory' ' test ! -d target && git svn clone "$svnrepo"/project/trunk target && - test -d target/.git/svn && - test -e target/foo && + test_path_is_dir target/.git/svn && + test_path_exists target/foo && rm -rf target ' test_expect_success 'clone with --stdlayout' ' test ! -d project && git svn clone -s "$svnrepo"/project && - test -d project/.git/svn && - test -e project/foo && + test_path_is_dir project/.git/svn && + test_path_exists project/foo && rm -rf project ' test_expect_success 'clone to target directory with --stdlayout' ' test ! -d target && git svn clone -s "$svnrepo"/project target && - test -d target/.git/svn && - test -e target/foo && + test_path_is_dir target/.git/svn && + test_path_exists target/foo && rm -rf target ' diff --git a/t/t9118-git-svn-funky-branch-names.sh b/t/t9118-git-svn-funky-branch-names.sh index a159ff96b7..d3261e35b8 100755 --- a/t/t9118-git-svn-funky-branch-names.sh +++ b/t/t9118-git-svn-funky-branch-names.sh @@ -38,7 +38,7 @@ test_expect_success 'setup svnrepo' ' # SVN 1.7 will truncate "not-a%40{0]" to just "not-a". # Look at what SVN wound up naming the branch and use that. # Be sure to escape the @ if it shows up. -non_reflog=$(svn_cmd ls "$svnrepo/pr ject/branches" | grep not-a | sed 's/\///' | sed 's/@/%40/') +non_reflog=$(svn_cmd ls "$svnrepo/pr ject/branches" | sed -ne '/not-a/ { s/\///; s/@/%40/; p }') test_expect_success 'test clone with funky branch names' ' git svn clone -s "$svnrepo/pr ject" project && diff --git a/t/t9146-git-svn-empty-dirs.sh b/t/t9146-git-svn-empty-dirs.sh index 09606f1b3c..926ac81439 100755 --- a/t/t9146-git-svn-empty-dirs.sh +++ b/t/t9146-git-svn-empty-dirs.sh @@ -20,11 +20,7 @@ test_expect_success 'empty directories exist' ' cd cloned && for i in a b c d d/e d/e/f "weird file name" do - if ! test -d "$i" - then - echo >&2 "$i does not exist" && - exit 1 - fi + test_path_is_dir "$i" || exit 1 done ) ' @@ -37,11 +33,7 @@ test_expect_success 'option automkdirs set to false' ' git svn fetch && for i in a b c d d/e d/e/f "weird file name" do - if test -d "$i" - then - echo >&2 "$i exists" && - exit 1 - fi + test_path_is_missing "$i" || exit 1 done ) ' @@ -52,7 +44,7 @@ test_expect_success 'more emptiness' ' test_expect_success 'git svn rebase creates empty directory' ' ( cd cloned && git svn rebase ) && - test -d cloned/"! !" + test_path_is_dir cloned/"! !" ' test_expect_success 'git svn mkdirs recreates empty directories' ' @@ -62,11 +54,7 @@ test_expect_success 'git svn mkdirs recreates empty directories' ' git svn mkdirs && for i in a b c d d/e d/e/f "weird file name" "! !" do - if ! test -d "$i" - then - echo >&2 "$i does not exist" && - exit 1 - fi + test_path_is_dir "$i" || exit 1 done ) ' @@ -78,25 +66,13 @@ test_expect_success 'git svn mkdirs -r works' ' git svn mkdirs -r7 && for i in a b c d d/e d/e/f "weird file name" do - if ! test -d "$i" - then - echo >&2 "$i does not exist" && - exit 1 - fi + test_path_is_dir "$i" || exit 1 done && - if test -d "! !" - then - echo >&2 "$i should not exist" && - exit 1 - fi && + test_path_is_missing "! !" || exit 1 && git svn mkdirs -r8 && - if ! test -d "! !" - then - echo >&2 "$i not exist" && - exit 1 - fi + test_path_is_dir "! !" || exit 1 ) ' @@ -114,11 +90,7 @@ test_expect_success 'empty directories in trunk exist' ' cd trunk && for i in a "weird file name" do - if ! test -d "$i" - then - echo >&2 "$i does not exist" && - exit 1 - fi + test_path_is_dir "$i" || exit 1 done ) ' @@ -129,7 +101,7 @@ test_expect_success 'remove a top-level directory from svn' ' test_expect_success 'removed top-level directory does not exist' ' git svn clone "$svnrepo" removed && - test ! -e removed/d + test_path_is_missing removed/d ' unhandled=.git/svn/refs/remotes/git-svn/unhandled.log @@ -143,15 +115,11 @@ test_expect_success 'git svn gc-ed files work' ' svn_cmd mkdir -m gz "$svnrepo"/gz && git reset --hard $(git rev-list HEAD | tail -1) && git svn rebase && - test -f "$unhandled".gz && - test -f "$unhandled" && + test_path_is_file "$unhandled".gz && + test_path_is_file "$unhandled" && for i in a b c "weird file name" gz "! !" do - if ! test -d "$i" - then - echo >&2 "$i does not exist" && - exit 1 - fi + test_path_is_dir "$i" || exit 1 done fi ) diff --git a/t/t9210-scalar.sh b/t/t9210-scalar.sh index 4432a30d10..428339e342 100755 --- a/t/t9210-scalar.sh +++ b/t/t9210-scalar.sh @@ -154,7 +154,14 @@ test_expect_success 'scalar clone' ' test_cmp expect actual && test_path_is_missing 1/2 && - test_must_fail git rev-list --missing=print $second && + + # This relies on the fact that the presence of "--missing" + # on the command line forces lazy fetching off before + # "$second^{blob}" gets parsed. Without "^{blob}", a + # bare object name "$second" is taken into the queue and + # the command may not fail with a fixed "rev-list --missing". + test_must_fail git rev-list --missing=print "$second^{blob}" -- && + git rev-list $second && git cat-file blob $second >actual && echo "second" >expect && diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index dbb5042b0b..1e68426852 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -986,7 +986,7 @@ test_expect_success 'L: nested tree copy does not corrupt deltas' ' test_when_finished "git update-ref -d refs/heads/L2" && git fast-import <input && git ls-tree L2 g/b/ >tmp && - cat tmp | cut -f 2 >actual && + cut -f 2 <tmp >actual && test_cmp expect actual && git fsck $(git rev-parse L2) ' @@ -1059,30 +1059,33 @@ test_expect_success 'M: rename subdirectory to new subdirectory' ' compare_diff_raw expect actual ' -test_expect_success 'M: rename root to subdirectory' ' - cat >input <<-INPUT_END && - commit refs/heads/M4 - committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - data <<COMMIT - rename root - COMMIT +for root in '""' '' +do + test_expect_success "M: rename root ($root) to subdirectory" ' + cat >input <<-INPUT_END && + commit refs/heads/M4 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + rename root + COMMIT - from refs/heads/M2^0 - R "" sub + from refs/heads/M2^0 + R $root sub - INPUT_END + INPUT_END - cat >expect <<-EOF && - :100644 100644 $oldf $oldf R100 file2/oldf sub/file2/oldf - :100755 100755 $f4id $f4id R100 file4 sub/file4 - :100755 100755 $newf $newf R100 i/am/new/to/you sub/i/am/new/to/you - :100755 100755 $f6id $f6id R100 newdir/exec.sh sub/newdir/exec.sh - :100644 100644 $f5id $f5id R100 newdir/interesting sub/newdir/interesting - EOF - git fast-import <input && - git diff-tree -M -r M4^ M4 >actual && - compare_diff_raw expect actual -' + cat >expect <<-EOF && + :100644 100644 $oldf $oldf R100 file2/oldf sub/file2/oldf + :100755 100755 $f4id $f4id R100 file4 sub/file4 + :100755 100755 $newf $newf R100 i/am/new/to/you sub/i/am/new/to/you + :100755 100755 $f6id $f6id R100 newdir/exec.sh sub/newdir/exec.sh + :100644 100644 $f5id $f5id R100 newdir/interesting sub/newdir/interesting + EOF + git fast-import <input && + git diff-tree -M -r M4^ M4 >actual && + compare_diff_raw expect actual + ' +done ### ### series N @@ -1259,49 +1262,52 @@ test_expect_success PIPE 'N: empty directory reads as missing' ' test_cmp expect actual ' -test_expect_success 'N: copy root directory by tree hash' ' - cat >expect <<-EOF && - :100755 000000 $newf $zero D file3/newf - :100644 000000 $oldf $zero D file3/oldf - EOF - root=$(git rev-parse refs/heads/branch^0^{tree}) && - cat >input <<-INPUT_END && - commit refs/heads/N6 - committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - data <<COMMIT - copy root directory by tree hash - COMMIT - - from refs/heads/branch^0 - M 040000 $root "" - INPUT_END - git fast-import <input && - git diff-tree -C --find-copies-harder -r N4 N6 >actual && - compare_diff_raw expect actual -' +for root in '""' '' +do + test_expect_success "N: copy root ($root) by tree hash" ' + cat >expect <<-EOF && + :100755 000000 $newf $zero D file3/newf + :100644 000000 $oldf $zero D file3/oldf + EOF + root_tree=$(git rev-parse refs/heads/branch^0^{tree}) && + cat >input <<-INPUT_END && + commit refs/heads/N6 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + copy root directory by tree hash + COMMIT -test_expect_success 'N: copy root by path' ' - cat >expect <<-EOF && - :100755 100755 $newf $newf C100 file2/newf oldroot/file2/newf - :100644 100644 $oldf $oldf C100 file2/oldf oldroot/file2/oldf - :100755 100755 $f4id $f4id C100 file4 oldroot/file4 - :100755 100755 $f6id $f6id C100 newdir/exec.sh oldroot/newdir/exec.sh - :100644 100644 $f5id $f5id C100 newdir/interesting oldroot/newdir/interesting - EOF - cat >input <<-INPUT_END && - commit refs/heads/N-copy-root-path - committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - data <<COMMIT - copy root directory by (empty) path - COMMIT + from refs/heads/branch^0 + M 040000 $root_tree $root + INPUT_END + git fast-import <input && + git diff-tree -C --find-copies-harder -r N4 N6 >actual && + compare_diff_raw expect actual + ' + + test_expect_success "N: copy root ($root) by path" ' + cat >expect <<-EOF && + :100755 100755 $newf $newf C100 file2/newf oldroot/file2/newf + :100644 100644 $oldf $oldf C100 file2/oldf oldroot/file2/oldf + :100755 100755 $f4id $f4id C100 file4 oldroot/file4 + :100755 100755 $f6id $f6id C100 newdir/exec.sh oldroot/newdir/exec.sh + :100644 100644 $f5id $f5id C100 newdir/interesting oldroot/newdir/interesting + EOF + cat >input <<-INPUT_END && + commit refs/heads/N-copy-root-path + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + copy root directory by (empty) path + COMMIT - from refs/heads/branch^0 - C "" oldroot - INPUT_END - git fast-import <input && - git diff-tree -C --find-copies-harder -r branch N-copy-root-path >actual && - compare_diff_raw expect actual -' + from refs/heads/branch^0 + C $root oldroot + INPUT_END + git fast-import <input && + git diff-tree -C --find-copies-harder -r branch N-copy-root-path >actual && + compare_diff_raw expect actual + ' +done test_expect_success 'N: delete directory by copying' ' cat >expect <<-\EOF && @@ -1431,98 +1437,102 @@ test_expect_success 'N: reject foo/ syntax in ls argument' ' INPUT_END ' -test_expect_success 'N: copy to root by id and modify' ' - echo "hello, world" >expect.foo && - echo hello >expect.bar && - git fast-import <<-SETUP_END && - commit refs/heads/N7 - committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - data <<COMMIT - hello, tree - COMMIT - - deleteall - M 644 inline foo/bar - data <<EOF - hello - EOF - SETUP_END - - tree=$(git rev-parse --verify N7:) && - git fast-import <<-INPUT_END && - commit refs/heads/N8 - committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - data <<COMMIT - copy to root by id and modify - COMMIT +for root in '""' '' +do + test_expect_success "N: copy to root ($root) by id and modify" ' + echo "hello, world" >expect.foo && + echo hello >expect.bar && + git fast-import <<-SETUP_END && + commit refs/heads/N7 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + hello, tree + COMMIT - M 040000 $tree "" - M 644 inline foo/foo - data <<EOF - hello, world - EOF - INPUT_END - git show N8:foo/foo >actual.foo && - git show N8:foo/bar >actual.bar && - test_cmp expect.foo actual.foo && - test_cmp expect.bar actual.bar -' + deleteall + M 644 inline foo/bar + data <<EOF + hello + EOF + SETUP_END -test_expect_success 'N: extract subtree' ' - branch=$(git rev-parse --verify refs/heads/branch^{tree}) && - cat >input <<-INPUT_END && - commit refs/heads/N9 - committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - data <<COMMIT - extract subtree branch:newdir - COMMIT + tree=$(git rev-parse --verify N7:) && + git fast-import <<-INPUT_END && + commit refs/heads/N8 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + copy to root by id and modify + COMMIT - M 040000 $branch "" - C "newdir" "" - INPUT_END - git fast-import <input && - git diff --exit-code branch:newdir N9 -' + M 040000 $tree $root + M 644 inline foo/foo + data <<EOF + hello, world + EOF + INPUT_END + git show N8:foo/foo >actual.foo && + git show N8:foo/bar >actual.bar && + test_cmp expect.foo actual.foo && + test_cmp expect.bar actual.bar + ' + + test_expect_success "N: extract subtree to the root ($root)" ' + branch=$(git rev-parse --verify refs/heads/branch^{tree}) && + cat >input <<-INPUT_END && + commit refs/heads/N9 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + extract subtree branch:newdir + COMMIT -test_expect_success 'N: modify subtree, extract it, and modify again' ' - echo hello >expect.baz && - echo hello, world >expect.qux && - git fast-import <<-SETUP_END && - commit refs/heads/N10 - committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - data <<COMMIT - hello, tree - COMMIT + M 040000 $branch $root + C "newdir" $root + INPUT_END + git fast-import <input && + git diff --exit-code branch:newdir N9 + ' + + test_expect_success "N: modify subtree, extract it to the root ($root), and modify again" ' + echo hello >expect.baz && + echo hello, world >expect.qux && + git fast-import <<-SETUP_END && + commit refs/heads/N10 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + hello, tree + COMMIT - deleteall - M 644 inline foo/bar/baz - data <<EOF - hello - EOF - SETUP_END + deleteall + M 644 inline foo/bar/baz + data <<EOF + hello + EOF + SETUP_END - tree=$(git rev-parse --verify N10:) && - git fast-import <<-INPUT_END && - commit refs/heads/N11 - committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - data <<COMMIT - copy to root by id and modify - COMMIT + tree=$(git rev-parse --verify N10:) && + git fast-import <<-INPUT_END && + commit refs/heads/N11 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + copy to root by id and modify + COMMIT - M 040000 $tree "" - M 100644 inline foo/bar/qux - data <<EOF - hello, world - EOF - R "foo" "" - C "bar/qux" "bar/quux" - INPUT_END - git show N11:bar/baz >actual.baz && - git show N11:bar/qux >actual.qux && - git show N11:bar/quux >actual.quux && - test_cmp expect.baz actual.baz && - test_cmp expect.qux actual.qux && - test_cmp expect.qux actual.quux' + M 040000 $tree $root + M 100644 inline foo/bar/qux + data <<EOF + hello, world + EOF + R "foo" $root + C "bar/qux" "bar/quux" + INPUT_END + git show N11:bar/baz >actual.baz && + git show N11:bar/qux >actual.qux && + git show N11:bar/quux >actual.quux && + test_cmp expect.baz actual.baz && + test_cmp expect.qux actual.qux && + test_cmp expect.qux actual.quux + ' +done ### ### series O @@ -2007,12 +2017,11 @@ test_expect_success 'Q: verify first notes commit' ' ' test_expect_success 'Q: verify first notes tree' ' - cat >expect.unsorted <<-EOF && + sort >expect <<-EOF && 100644 blob $commit1 100644 blob $commit2 100644 blob $commit3 EOF - cat expect.unsorted | sort >expect && git cat-file -p refs/notes/foobar~2^{tree} | sed "s/ [0-9a-f]* / /" >actual && test_cmp expect actual ' @@ -2048,12 +2057,11 @@ test_expect_success 'Q: verify second notes commit' ' ' test_expect_success 'Q: verify second notes tree' ' - cat >expect.unsorted <<-EOF && + sort >expect <<-EOF && 100644 blob $commit1 100644 blob $commit2 100644 blob $commit3 EOF - cat expect.unsorted | sort >expect && git cat-file -p refs/notes/foobar^^{tree} | sed "s/ [0-9a-f]* / /" >actual && test_cmp expect actual ' @@ -2088,10 +2096,9 @@ test_expect_success 'Q: verify third notes commit' ' ' test_expect_success 'Q: verify third notes tree' ' - cat >expect.unsorted <<-EOF && + sort >expect <<-EOF && 100644 blob $commit1 EOF - cat expect.unsorted | sort >expect && git cat-file -p refs/notes/foobar2^{tree} | sed "s/ [0-9a-f]* / /" >actual && test_cmp expect actual ' @@ -2115,10 +2122,9 @@ test_expect_success 'Q: verify fourth notes commit' ' ' test_expect_success 'Q: verify fourth notes tree' ' - cat >expect.unsorted <<-EOF && + sort >expect <<-EOF && 100644 blob $commit2 EOF - cat expect.unsorted | sort >expect && git cat-file -p refs/notes/foobar^{tree} | sed "s/ [0-9a-f]* / /" >actual && test_cmp expect actual ' @@ -2146,6 +2152,7 @@ test_expect_success 'Q: deny note on empty branch' ' EOF test_must_fail git fast-import <input ' + ### ### series R (feature and option) ### @@ -2794,7 +2801,7 @@ test_expect_success 'R: blob appears only once' ' ' ### -### series S +### series S (mark and path parsing) ### # # Make sure missing spaces and EOLs after mark references @@ -3064,21 +3071,283 @@ test_expect_success 'S: ls with garbage after sha1 must fail' ' test_grep "space after tree-ish" err ' +# +# Path parsing +# +# There are two sorts of ways a path can be parsed, depending on whether it is +# the last field on the line. Additionally, ls without a <dataref> has a special +# case. Test every occurrence of <path> in the grammar against every error case. +# Paths for the root (empty strings) are tested elsewhere. +# + +# +# Valid paths at the end of a line: filemodify, filedelete, filecopy (dest), +# filerename (dest), and ls. +# +# commit :301 from root -- modify hello.c (for setup) +# commit :302 from :301 -- modify $path +# commit :303 from :302 -- delete $path +# commit :304 from :301 -- copy hello.c $path +# commit :305 from :301 -- rename hello.c $path +# ls :305 $path +# +test_path_eol_success () { + local test="$1" path="$2" unquoted_path="$3" + test_expect_success "S: paths at EOL with $test must work" ' + test_when_finished "git branch -D S-path-eol" && + + git fast-import --export-marks=marks.out <<-EOF >out 2>err && + blob + mark :401 + data <<BLOB + hello world + BLOB + + blob + mark :402 + data <<BLOB + hallo welt + BLOB + + commit refs/heads/S-path-eol + mark :301 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + initial commit + COMMIT + M 100644 :401 hello.c + + commit refs/heads/S-path-eol + mark :302 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + commit filemodify + COMMIT + from :301 + M 100644 :402 $path + + commit refs/heads/S-path-eol + mark :303 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + commit filedelete + COMMIT + from :302 + D $path + + commit refs/heads/S-path-eol + mark :304 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + commit filecopy dest + COMMIT + from :301 + C hello.c $path + + commit refs/heads/S-path-eol + mark :305 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + commit filerename dest + COMMIT + from :301 + R hello.c $path + + ls :305 $path + EOF + + commit_m=$(grep :302 marks.out | cut -d\ -f2) && + commit_d=$(grep :303 marks.out | cut -d\ -f2) && + commit_c=$(grep :304 marks.out | cut -d\ -f2) && + commit_r=$(grep :305 marks.out | cut -d\ -f2) && + blob1=$(grep :401 marks.out | cut -d\ -f2) && + blob2=$(grep :402 marks.out | cut -d\ -f2) && + + ( + printf "100644 blob $blob2\t$unquoted_path\n" && + printf "100644 blob $blob1\thello.c\n" + ) | sort >tree_m.exp && + git ls-tree $commit_m | sort >tree_m.out && + test_cmp tree_m.exp tree_m.out && + + printf "100644 blob $blob1\thello.c\n" >tree_d.exp && + git ls-tree $commit_d >tree_d.out && + test_cmp tree_d.exp tree_d.out && + + ( + printf "100644 blob $blob1\t$unquoted_path\n" && + printf "100644 blob $blob1\thello.c\n" + ) | sort >tree_c.exp && + git ls-tree $commit_c | sort >tree_c.out && + test_cmp tree_c.exp tree_c.out && + + printf "100644 blob $blob1\t$unquoted_path\n" >tree_r.exp && + git ls-tree $commit_r >tree_r.out && + test_cmp tree_r.exp tree_r.out && + + test_cmp out tree_r.exp + ' +} + +test_path_eol_success 'quoted spaces' '" hello world.c "' ' hello world.c ' +test_path_eol_success 'unquoted spaces' ' hello world.c ' ' hello world.c ' +test_path_eol_success 'octal escapes' '"\150\151\056\143"' 'hi.c' + +# +# Valid paths before a space: filecopy (source) and filerename (source). +# +# commit :301 from root -- modify $path (for setup) +# commit :302 from :301 -- copy $path hello2.c +# commit :303 from :301 -- rename $path hello2.c +# +test_path_space_success () { + local test="$1" path="$2" unquoted_path="$3" + test_expect_success "S: paths before space with $test must work" ' + test_when_finished "git branch -D S-path-space" && + + git fast-import --export-marks=marks.out <<-EOF 2>err && + blob + mark :401 + data <<BLOB + hello world + BLOB + + commit refs/heads/S-path-space + mark :301 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + initial commit + COMMIT + M 100644 :401 $path + + commit refs/heads/S-path-space + mark :302 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + commit filecopy source + COMMIT + from :301 + C $path hello2.c + + commit refs/heads/S-path-space + mark :303 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + commit filerename source + COMMIT + from :301 + R $path hello2.c + + EOF + + commit_c=$(grep :302 marks.out | cut -d\ -f2) && + commit_r=$(grep :303 marks.out | cut -d\ -f2) && + blob=$(grep :401 marks.out | cut -d\ -f2) && + + ( + printf "100644 blob $blob\t$unquoted_path\n" && + printf "100644 blob $blob\thello2.c\n" + ) | sort >tree_c.exp && + git ls-tree $commit_c | sort >tree_c.out && + test_cmp tree_c.exp tree_c.out && + + printf "100644 blob $blob\thello2.c\n" >tree_r.exp && + git ls-tree $commit_r >tree_r.out && + test_cmp tree_r.exp tree_r.out + ' +} + +test_path_space_success 'quoted spaces' '" hello world.c "' ' hello world.c ' +test_path_space_success 'no unquoted spaces' 'hello_world.c' 'hello_world.c' +test_path_space_success 'octal escapes' '"\150\151\056\143"' 'hi.c' + +# +# Test a single commit change with an invalid path. Run it with all occurrences +# of <path> in the grammar against all error kinds. +# +test_path_fail () { + local change="$1" what="$2" prefix="$3" path="$4" suffix="$5" err_grep="$6" + test_expect_success "S: $change with $what must fail" ' + test_must_fail git fast-import <<-EOF 2>err && + blob + mark :1 + data <<BLOB + hello world + BLOB + + commit refs/heads/S-path-fail + mark :2 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + commit setup + COMMIT + M 100644 :1 hello.c + + commit refs/heads/S-path-fail + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + commit with bad path + COMMIT + from :2 + $prefix$path$suffix + EOF + + test_grep "$err_grep" err + ' +} + +test_path_base_fail () { + local change="$1" prefix="$2" field="$3" suffix="$4" + test_path_fail "$change" 'unclosed " in '"$field" "$prefix" '"hello.c' "$suffix" "Invalid $field" + test_path_fail "$change" "invalid escape in quoted $field" "$prefix" '"hello\xff"' "$suffix" "Invalid $field" + test_path_fail "$change" "escaped NUL in quoted $field" "$prefix" '"hello\000"' "$suffix" "NUL in $field" +} +test_path_eol_quoted_fail () { + local change="$1" prefix="$2" field="$3" + test_path_base_fail "$change" "$prefix" "$field" '' + test_path_fail "$change" "garbage after quoted $field" "$prefix" '"hello.c"' 'x' "Garbage after $field" + test_path_fail "$change" "space after quoted $field" "$prefix" '"hello.c"' ' ' "Garbage after $field" +} +test_path_eol_fail () { + local change="$1" prefix="$2" field="$3" + test_path_eol_quoted_fail "$change" "$prefix" "$field" +} +test_path_space_fail () { + local change="$1" prefix="$2" field="$3" + test_path_base_fail "$change" "$prefix" "$field" ' world.c' + test_path_fail "$change" "missing space after quoted $field" "$prefix" '"hello.c"' 'x world.c' "Missing space after $field" + test_path_fail "$change" "missing space after unquoted $field" "$prefix" 'hello.c' '' "Missing space after $field" +} + +test_path_eol_fail filemodify 'M 100644 :1 ' path +test_path_eol_fail filedelete 'D ' path +test_path_space_fail filecopy 'C ' source +test_path_eol_fail filecopy 'C hello.c ' dest +test_path_space_fail filerename 'R ' source +test_path_eol_fail filerename 'R hello.c ' dest +test_path_eol_fail 'ls (in commit)' 'ls :2 ' path + +# When 'ls' has no <dataref>, the <path> must be quoted. +test_path_eol_quoted_fail 'ls (without dataref in commit)' 'ls ' path + ### ### series T (ls) ### # Setup is carried over from series S. -test_expect_success 'T: ls root tree' ' - sed -e "s/Z\$//" >expect <<-EOF && - 040000 tree $(git rev-parse S^{tree}) Z - EOF - sha1=$(git rev-parse --verify S) && - git fast-import --import-marks=marks <<-EOF >actual && - ls $sha1 "" - EOF - test_cmp expect actual -' +for root in '""' '' +do + test_expect_success "T: ls root ($root) tree" ' + sed -e "s/Z\$//" >expect <<-EOF && + 040000 tree $(git rev-parse S^{tree}) Z + EOF + sha1=$(git rev-parse --verify S) && + git fast-import --import-marks=marks <<-EOF >actual && + ls $sha1 $root + EOF + test_cmp expect actual + ' +done test_expect_success 'T: delete branch' ' git branch to-delete && @@ -3180,30 +3449,33 @@ test_expect_success 'U: validate directory delete result' ' compare_diff_raw expect actual ' -test_expect_success 'U: filedelete root succeeds' ' - cat >input <<-INPUT_END && - commit refs/heads/U - committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE - data <<COMMIT - must succeed - COMMIT - from refs/heads/U^0 - D "" +for root in '""' '' +do + test_expect_success "U: filedelete root ($root) succeeds" ' + cat >input <<-INPUT_END && + commit refs/heads/U-delete-root + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + must succeed + COMMIT + from refs/heads/U^0 + D $root - INPUT_END + INPUT_END - git fast-import <input -' + git fast-import <input + ' -test_expect_success 'U: validate root delete result' ' - cat >expect <<-EOF && - :100644 000000 $f7id $ZERO_OID D hello.c - EOF + test_expect_success "U: validate root ($root) delete result" ' + cat >expect <<-EOF && + :100644 000000 $f7id $ZERO_OID D hello.c + EOF - git diff-tree -M -r U^1 U >actual && + git diff-tree -M -r U U-delete-root >actual && - compare_diff_raw expect actual -' + compare_diff_raw expect actual + ' +done ### ### series V (checkpoint) diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh index e9a12c18bb..1eb035ee4c 100755 --- a/t/t9350-fast-export.sh +++ b/t/t9350-fast-export.sh @@ -236,7 +236,7 @@ EOF test_expect_success 'set up faked signed tag' ' - cat signed-tag-import | git fast-import + git fast-import <signed-tag-import ' @@ -537,7 +537,7 @@ test_expect_success 'full-tree re-shows unmodified files' ' test_expect_success 'set-up a few more tags for tag export tests' ' git checkout -f main && - HEAD_TREE=$(git show -s --pretty=raw HEAD | grep tree | sed "s/tree //") && + HEAD_TREE=$(git show -s --pretty=raw HEAD | sed -n "/tree/s/tree //p") && git tag tree_tag -m "tagging a tree" $HEAD_TREE && git tag -a tree_tag-obj -m "tagging a tree" $HEAD_TREE && git tag tag-obj_tag -m "tagging a tag" tree_tag-obj && diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh index 003c0b61d0..e499c7f955 100755 --- a/t/t9400-git-cvsserver-server.sh +++ b/t/t9400-git-cvsserver-server.sh @@ -117,12 +117,12 @@ END VERIFICATION REQUEST EOF test_expect_success 'pserver authentication' ' - cat request-anonymous | git-cvsserver pserver >log 2>&1 && + git-cvsserver pserver <request-anonymous >log 2>&1 && sed -ne \$p log | grep "^I LOVE YOU\$" ' test_expect_success 'pserver authentication failure (non-anonymous user)' ' - if cat request-git | git-cvsserver pserver >log 2>&1 + if git-cvsserver pserver <request-git >log 2>&1 then false else @@ -132,17 +132,17 @@ test_expect_success 'pserver authentication failure (non-anonymous user)' ' ' test_expect_success 'pserver authentication success (non-anonymous user with password)' ' - cat login-git-ok | git-cvsserver pserver >log 2>&1 && + git-cvsserver pserver <login-git-ok >log 2>&1 && sed -ne \$p log | grep "^I LOVE YOU\$" ' test_expect_success 'pserver authentication (login)' ' - cat login-anonymous | git-cvsserver pserver >log 2>&1 && + git-cvsserver pserver <login-anonymous >log 2>&1 && sed -ne \$p log | grep "^I LOVE YOU\$" ' test_expect_success 'pserver authentication failure (login/non-anonymous user)' ' - if cat login-git | git-cvsserver pserver >log 2>&1 + if git-cvsserver pserver <login-git >log 2>&1 then false else @@ -172,7 +172,7 @@ Root $WORKDIR EOF test_expect_success 'req_Root failure (relative pathname)' ' - if cat request-relative | git-cvsserver pserver >log 2>&1 + if git-cvsserver pserver <request-relative >log 2>&1 then echo unexpected success false @@ -183,28 +183,26 @@ test_expect_success 'req_Root failure (relative pathname)' ' ' test_expect_success 'req_Root failure (conflicting roots)' ' - cat request-conflict | git-cvsserver pserver >log 2>&1 && + git-cvsserver pserver <request-conflict >log 2>&1 && tail log | grep "^error 1 Conflicting roots specified$" ' test_expect_success 'req_Root (strict paths)' ' - cat request-anonymous | git-cvsserver --strict-paths pserver "$SERVERDIR" >log 2>&1 && + git-cvsserver --strict-paths pserver "$SERVERDIR" <request-anonymous >log 2>&1 && sed -ne \$p log | grep "^I LOVE YOU\$" ' test_expect_success 'req_Root failure (strict-paths)' ' - ! cat request-anonymous | - git-cvsserver --strict-paths pserver "$WORKDIR" >log 2>&1 + ! git-cvsserver --strict-paths pserver "$WORKDIR" <request-anonymous >log 2>&1 ' test_expect_success 'req_Root (w/o strict-paths)' ' - cat request-anonymous | git-cvsserver pserver "$WORKDIR/" >log 2>&1 && + git-cvsserver pserver "$WORKDIR/" <request-anonymous >log 2>&1 && sed -ne \$p log | grep "^I LOVE YOU\$" ' test_expect_success 'req_Root failure (w/o strict-paths)' ' - ! cat request-anonymous | - git-cvsserver pserver "$WORKDIR/gitcvs" >log 2>&1 + ! git-cvsserver pserver "$WORKDIR/gitcvs" <request-anonymous >log 2>&1 ' cat >request-base <<EOF @@ -217,27 +215,26 @@ Root /gitcvs.git EOF test_expect_success 'req_Root (base-path)' ' - cat request-base | git-cvsserver --strict-paths --base-path "$WORKDIR/" pserver "$SERVERDIR" >log 2>&1 && + git-cvsserver --strict-paths --base-path "$WORKDIR/" pserver "$SERVERDIR" <request-base >log 2>&1 && sed -ne \$p log | grep "^I LOVE YOU\$" ' test_expect_success 'req_Root failure (base-path)' ' - ! cat request-anonymous | - git-cvsserver --strict-paths --base-path "$WORKDIR" pserver "$SERVERDIR" >log 2>&1 + ! git-cvsserver --strict-paths --base-path "$WORKDIR" pserver "$SERVERDIR" <request-anonymous >log 2>&1 ' GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled false || exit 1 test_expect_success 'req_Root (export-all)' ' - cat request-anonymous | git-cvsserver --export-all pserver "$WORKDIR" >log 2>&1 && + git-cvsserver --export-all pserver "$WORKDIR" <request-anonymous >log 2>&1 && sed -ne \$p log | grep "^I LOVE YOU\$" ' test_expect_success 'req_Root failure (export-all w/o directory list)' ' - ! (cat request-anonymous | git-cvsserver --export-all pserver >log 2>&1 || false)' + ! (git-cvsserver --export-all pserver <request-anonymous >log 2>&1 || false)' test_expect_success 'req_Root (everything together)' ' - cat request-base | git-cvsserver --export-all --strict-paths --base-path "$WORKDIR/" pserver "$SERVERDIR" >log 2>&1 && + git-cvsserver --export-all --strict-paths --base-path "$WORKDIR/" pserver "$SERVERDIR" <request-base >log 2>&1 && sed -ne \$p log | grep "^I LOVE YOU\$" ' diff --git a/t/t9604-cvsimport-timestamps.sh b/t/t9604-cvsimport-timestamps.sh index 2ff4aa932d..2d03259729 100755 --- a/t/t9604-cvsimport-timestamps.sh +++ b/t/t9604-cvsimport-timestamps.sh @@ -3,11 +3,28 @@ test_description='git cvsimport timestamps' . ./lib-cvs.sh +test_lazy_prereq POSIX_TIMEZONE ' + local tz=XST-1XDT,M3.5.0,M11.1.0 + echo "1711846799 -> 2024-03-31 01:59:59 +0100" >expected && + TZ="$tz" test-tool date show:iso-local 1711846799 >actual && + test_cmp expected actual && + echo "1711846800 -> 2024-03-31 03:00:00 +0200" >expected && + TZ="$tz" test-tool date show:iso-local 1711846800 >actual && + test_cmp expected actual && + echo "1730591999 -> 2024-11-03 01:59:59 +0200" >expected && + TZ="$tz" test-tool date show:iso-local 1730591999 >actual && + test_cmp expected actual && + echo "1730592000 -> 2024-11-03 01:00:00 +0100" >expected && + TZ="$tz" test-tool date show:iso-local 1730592000 >actual && + test_cmp expected actual +' + setup_cvs_test_repository t9604 -test_expect_success PERL 'check timestamps are UTC (TZ=CST6CDT)' ' +test_expect_success PERL,POSIX_TIMEZONE 'check timestamps are UTC' ' - TZ=CST6CDT git cvsimport -p"-x" -C module-1 module && + TZ=CST6CDT,M4.1.0,M10.5.0 \ + git cvsimport -p"-x" -C module-1 module && git cvsimport -p"-x" -C module-1 module && ( cd module-1 && @@ -34,13 +51,13 @@ test_expect_success PERL 'check timestamps are UTC (TZ=CST6CDT)' ' test_cmp expect-1 actual-1 ' -test_expect_success PERL 'check timestamps with author-specific timezones' ' +test_expect_success PERL,POSIX_TIMEZONE 'check timestamps with author-specific timezones' ' cat >cvs-authors <<-EOF && user1=User One <user1@domain.org> - user2=User Two <user2@domain.org> CST6CDT - user3=User Three <user3@domain.org> EST5EDT - user4=User Four <user4@domain.org> MST7MDT + user2=User Two <user2@domain.org> CST6CDT,M4.1.0,M10.5.0 + user3=User Three <user3@domain.org> EST5EDT,M4.1.0,M10.5.0 + user4=User Four <user4@domain.org> MST7MDT,M4.1.0,M10.5.0 EOF git cvsimport -p"-x" -A cvs-authors -C module-2 module && ( diff --git a/t/t9802-git-p4-filetype.sh b/t/t9802-git-p4-filetype.sh index 2a6ee2a467..bb236cd2b5 100755 --- a/t/t9802-git-p4-filetype.sh +++ b/t/t9802-git-p4-filetype.sh @@ -175,7 +175,7 @@ test_expect_success 'keyword file create' ' cp k-text-k k-text-ko && p4 add -t text+ko k-text-ko && - cat k-text-k | iconv -f ascii -t utf-16 >k-utf16-k && + iconv -f ascii -t utf-16 <k-text-k >k-utf16-k && p4 add -t utf16+k k-utf16-k && cp k-utf16-k k-utf16-ko && diff --git a/t/t9807-git-p4-submit.sh b/t/t9807-git-p4-submit.sh index af4b286f9d..6ae7ced51b 100755 --- a/t/t9807-git-p4-submit.sh +++ b/t/t9807-git-p4-submit.sh @@ -418,7 +418,7 @@ test_expect_success 'description with Jobs and values on separate lines' ' marshal_dump job0 <change && marshal_dump job1 <change ) | sort >jobs && - cat jobname1 jobname2 | sort >expected && + sort jobname1 jobname2 >expected && test_cmp expected jobs ) ' diff --git a/t/t9824-git-p4-git-lfs.sh b/t/t9824-git-p4-git-lfs.sh index a28dbbdd56..80c8c31e32 100755 --- a/t/t9824-git-p4-git-lfs.sh +++ b/t/t9824-git-p4-git-lfs.sh @@ -17,8 +17,8 @@ test_file_in_lfs () { sed -n '2,2 p' "$FILE" | grep "^oid " && sed -n '3,3 p' "$FILE" | grep "^size " && test_line_count = 3 "$FILE" && - cat "$FILE" | grep "size $SIZE" && - HASH=$(cat "$FILE" | grep "oid sha256:" | sed -e "s/oid sha256://g") && + grep "size $SIZE" "$FILE" && + HASH=$(sed -ne "/oid sha256:/s/oid sha256://gp" "$FILE") && LFS_FILE=".git/lfs/objects/$(echo "$HASH" | cut -c1-2)/$(echo "$HASH" | cut -c3-4)/$HASH" && echo $EXPECTED_CONTENT >expect && test_path_is_file "$FILE" && diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index b16c284181..569cf23104 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -1263,6 +1263,29 @@ test_expect_success '__git_complete_fetch_refspecs - fully qualified & prefix' ' test_cmp expected out ' +test_expect_success '__git_complete_worktree_paths' ' + test_when_finished "git worktree remove other_wt" && + git worktree add --orphan other_wt && + run_completion "git worktree remove " && + grep other_wt out +' + +test_expect_success '__git_complete_worktree_paths - not a git repository' ' + ( + cd non-repo && + GIT_CEILING_DIRECTORIES="$ROOT" && + export GIT_CEILING_DIRECTORIES && + test_completion "git worktree remove " "" + ) +' + +test_expect_success '__git_complete_worktree_paths with -C' ' + test_when_finished "git -C otherrepo worktree remove otherrepo_wt" && + git -C otherrepo worktree add --orphan otherrepo_wt && + run_completion "git -C otherrepo worktree remove " && + grep otherrepo_wt out +' + test_expect_success 'git switch - with no options, complete local branches and unique remote branch names for DWIM logic' ' test_completion "git switch " <<-\EOF branch-in-other Z @@ -2804,6 +2827,20 @@ test_expect_success 'git clone --config= - value' ' EOF ' +test_expect_success 'git reflog show' ' + test_when_finished "git checkout - && git branch -d shown" && + git checkout -b shown && + test_completion "git reflog sho" <<-\EOF && + show Z + shown Z + EOF + test_completion "git reflog show sho" "shown " && + test_completion "git reflog shown sho" "shown " && + test_completion "git reflog --unt" "--until=" && + test_completion "git reflog show --unt" "--until=" && + test_completion "git reflog shown --unt" "--until=" +' + test_expect_success 'options with value' ' test_completion "git merge -X diff-algorithm=" <<-\EOF diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index b5eaf7fdc1..862d80c974 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -385,7 +385,7 @@ test_commit () { shift done && indir=${indir:+"$indir"/} && - local file=${2:-"$1.t"} && + local file="${2:-"$1.t"}" && if test -n "$append" then $echo "${3-$1}" >>"$indir$file" @@ -1263,9 +1263,8 @@ test_cmp_bin () { cmp "$@" } -# Deprecated - do not use this in new code test_i18ngrep () { - test_grep "$@" + BUG "do not use test_i18ngrep---use test_grep instead" } test_grep () { @@ -1656,7 +1655,16 @@ test_set_hash () { # Detect the hash algorithm in use. test_detect_hash () { - test_hash_algo="${GIT_TEST_DEFAULT_HASH:-sha1}" + case "$GIT_TEST_DEFAULT_HASH" in + "sha256") + test_hash_algo=sha256 + test_compat_hash_algo=sha1 + ;; + *) + test_hash_algo=sha1 + test_compat_hash_algo=sha256 + ;; + esac } # Detect the hash algorithm in use. @@ -1713,6 +1721,12 @@ test_oid () { local algo="${test_hash_algo}" && case "$1" in + --hash=storage) + algo="$test_hash_algo" && + shift;; + --hash=compat) + algo="$test_compat_hash_algo" && + shift;; --hash=*) algo="${1#--hash=}" && shift;; @@ -1734,7 +1748,7 @@ test_oid () { # Insert a slash into an object ID so it can be used to reference a location # under ".git/objects". For example, "deadbeef..." becomes "de/adbeef..". test_oid_to_path () { - local basename=${1#??} + local basename="${1#??}" echo "${1%$basename}/$basename" } @@ -1751,7 +1765,7 @@ test_parse_ls_tree_oids () { # Choose a port number based on the test script's number and store it in # the given variable name, unless that variable already contains a number. test_set_port () { - local var=$1 port + local var="$1" port if test $# -ne 1 || test -z "$var" then @@ -1826,7 +1840,7 @@ test_subcommand () { shift fi - local expr=$(printf '"%s",' "$@") + local expr="$(printf '"%s",' "$@")" expr="${expr%,}" if test -n "$negate" @@ -1916,7 +1930,7 @@ test_readlink () { # An optional increment to the magic timestamp may be specified as second # argument. test_set_magic_mtime () { - local inc=${2:-0} && + local inc="${2:-0}" && local mtime=$((1234567890 + $inc)) && test-tool chmtime =$mtime "$1" && test_is_magic_mtime "$1" $inc @@ -1929,7 +1943,7 @@ test_set_magic_mtime () { # argument. Usually, this should be the same increment which was used for # the associated test_set_magic_mtime. test_is_magic_mtime () { - local inc=${2:-0} && + local inc="${2:-0}" && local mtime=$((1234567890 + $inc)) && echo $mtime >.git/test-mtime-expect && test-tool chmtime --get "$1" >.git/test-mtime-actual && diff --git a/t/test-lib.sh b/t/test-lib.sh index 042f557a6f..79d3e0e7d9 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -1755,6 +1755,8 @@ esac case "$GIT_DEFAULT_REF_FORMAT" in files) test_set_prereq REFFILES;; +reftable) + test_set_prereq REFTABLE;; *) echo 2>&1 "error: unknown ref format $GIT_DEFAULT_REF_FORMAT" exit 1 @@ -1960,6 +1962,7 @@ test_lazy_prereq DEFAULT_REPO_FORMAT ' # Tests that verify the scheduler integration must set this locally # to avoid errors. GIT_TEST_MAINT_SCHEDULER="none:exit 1" +export GIT_TEST_MAINT_SCHEDULER # Does this platform support `git fsmonitor--daemon` # diff --git a/t/unit-tests/t-ctype.c b/t/unit-tests/t-ctype.c index f315489984..d6ac1fe678 100644 --- a/t/unit-tests/t-ctype.c +++ b/t/unit-tests/t-ctype.c @@ -1,30 +1,19 @@ #include "test-lib.h" -static int is_in(const char *s, int ch) -{ - /* - * We can't find NUL using strchr. Accept it as the first - * character in the spec -- there are no empty classes. - */ - if (ch == '\0') - return ch == *s; - if (*s == '\0') - s++; - return !!strchr(s, ch); -} - -/* Macro to test a character type */ -#define TEST_CTYPE_FUNC(func, string) \ -static void test_ctype_##func(void) { \ - for (int i = 0; i < 256; i++) { \ - if (!check_int(func(i), ==, is_in(string, i))) \ - test_msg(" i: 0x%02x", i); \ +#define TEST_CHAR_CLASS(class, string) do { \ + size_t len = ARRAY_SIZE(string) - 1 + \ + BUILD_ASSERT_OR_ZERO(ARRAY_SIZE(string) > 0) + \ + BUILD_ASSERT_OR_ZERO(sizeof(string[0]) == sizeof(char)); \ + int skip = test__run_begin(); \ + if (!skip) { \ + for (int i = 0; i < 256; i++) { \ + if (!check_int(class(i), ==, !!memchr(string, i, len)))\ + test_msg(" i: 0x%02x", i); \ + } \ + check(!class(EOF)); \ } \ - if (!check(!func(EOF))) \ - test_msg(" i: 0x%02x (EOF)", EOF); \ -} - -#define TEST_CHAR_CLASS(class) TEST(test_ctype_##class(), #class " works") + test__run_end(!skip, TEST_LOCATION(), #class " works"); \ +} while (0) #define DIGIT "0123456789" #define LOWER "abcdefghijklmnopqrstuvwxyz" @@ -44,37 +33,21 @@ static void test_ctype_##func(void) { \ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \ "\x7f" -TEST_CTYPE_FUNC(isdigit, DIGIT) -TEST_CTYPE_FUNC(isspace, " \n\r\t") -TEST_CTYPE_FUNC(isalpha, LOWER UPPER) -TEST_CTYPE_FUNC(isalnum, LOWER UPPER DIGIT) -TEST_CTYPE_FUNC(is_glob_special, "*?[\\") -TEST_CTYPE_FUNC(is_regex_special, "$()*+.?[\\^{|") -TEST_CTYPE_FUNC(is_pathspec_magic, "!\"#%&',-/:;<=>@_`~") -TEST_CTYPE_FUNC(isascii, ASCII) -TEST_CTYPE_FUNC(islower, LOWER) -TEST_CTYPE_FUNC(isupper, UPPER) -TEST_CTYPE_FUNC(iscntrl, CNTRL) -TEST_CTYPE_FUNC(ispunct, PUNCT) -TEST_CTYPE_FUNC(isxdigit, DIGIT "abcdefABCDEF") -TEST_CTYPE_FUNC(isprint, LOWER UPPER DIGIT PUNCT " ") - int cmd_main(int argc, const char **argv) { - /* Run all character type tests */ - TEST_CHAR_CLASS(isspace); - TEST_CHAR_CLASS(isdigit); - TEST_CHAR_CLASS(isalpha); - TEST_CHAR_CLASS(isalnum); - TEST_CHAR_CLASS(is_glob_special); - TEST_CHAR_CLASS(is_regex_special); - TEST_CHAR_CLASS(is_pathspec_magic); - TEST_CHAR_CLASS(isascii); - TEST_CHAR_CLASS(islower); - TEST_CHAR_CLASS(isupper); - TEST_CHAR_CLASS(iscntrl); - TEST_CHAR_CLASS(ispunct); - TEST_CHAR_CLASS(isxdigit); - TEST_CHAR_CLASS(isprint); + TEST_CHAR_CLASS(isspace, " \n\r\t"); + TEST_CHAR_CLASS(isdigit, DIGIT); + TEST_CHAR_CLASS(isalpha, LOWER UPPER); + TEST_CHAR_CLASS(isalnum, LOWER UPPER DIGIT); + TEST_CHAR_CLASS(is_glob_special, "*?[\\"); + TEST_CHAR_CLASS(is_regex_special, "$()*+.?[\\^{|"); + TEST_CHAR_CLASS(is_pathspec_magic, "!\"#%&',-/:;<=>@_`~"); + TEST_CHAR_CLASS(isascii, ASCII); + TEST_CHAR_CLASS(islower, LOWER); + TEST_CHAR_CLASS(isupper, UPPER); + TEST_CHAR_CLASS(iscntrl, CNTRL); + TEST_CHAR_CLASS(ispunct, PUNCT); + TEST_CHAR_CLASS(isxdigit, DIGIT "abcdefABCDEF"); + TEST_CHAR_CLASS(isprint, LOWER UPPER DIGIT PUNCT " "); return test_done(); } diff --git a/t/unit-tests/t-prio-queue.c b/t/unit-tests/t-prio-queue.c index d78b002f9e..7a4e5780e1 100644 --- a/t/unit-tests/t-prio-queue.c +++ b/t/unit-tests/t-prio-queue.c @@ -19,11 +19,13 @@ static int show(int *v) return v ? *v : MISSING; } -static void test_prio_queue(int *input, int *result, size_t input_size) +static void test_prio_queue(int *input, size_t input_size, + int *result, size_t result_size) { struct prio_queue pq = { intcmp }; + int j = 0; - for (int i = 0, j = 0; i < input_size; i++) { + for (int i = 0; i < input_size; i++) { void *peek, *get; switch(input[i]) { case GET: @@ -31,16 +33,22 @@ static void test_prio_queue(int *input, int *result, size_t input_size) get = prio_queue_get(&pq); if (!check(peek == get)) return; - if(!check_int(result[j++], ==, show(get))) - test_msg("failed at result[] index %d", j-1); + if (!check_uint(j, <, result_size)) + break; + if (!check_int(result[j], ==, show(get))) + test_msg(" j: %d", j); + j++; break; case DUMP: while ((peek = prio_queue_peek(&pq))) { get = prio_queue_get(&pq); if (!check(peek == get)) return; - if(!check_int(result[j++], ==, show(get))) - test_msg("failed at result[] index %d", j-1); + if (!check_uint(j, <, result_size)) + break; + if (!check_int(result[j], ==, show(get))) + test_msg(" j: %d", j); + j++; } break; case STACK: @@ -54,45 +62,30 @@ static void test_prio_queue(int *input, int *result, size_t input_size) break; } } + check_uint(j, ==, result_size); clear_prio_queue(&pq); } -#define BASIC_INPUT 2, 6, 3, 10, 9, 5, 7, 4, 5, 8, 1, DUMP -#define BASIC_RESULT 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10 - -#define MIXED_PUT_GET_INPUT 6, 2, 4, GET, 5, 3, GET, GET, 1, DUMP -#define MIXED_PUT_GET_RESULT 2, 3, 4, 1, 5, 6 - -#define EMPTY_QUEUE_INPUT 1, 2, GET, GET, GET, 1, 2, GET, GET, GET -#define EMPTY_QUEUE_RESULT 1, 2, MISSING, 1, 2, MISSING - -#define STACK_INPUT STACK, 8, 1, 5, 4, 6, 2, 3, DUMP -#define STACK_RESULT 3, 2, 6, 4, 5, 1, 8 - -#define REVERSE_STACK_INPUT STACK, 1, 2, 3, 4, 5, 6, REVERSE, DUMP -#define REVERSE_STACK_RESULT 1, 2, 3, 4, 5, 6 - -#define TEST_INPUT(INPUT, RESULT, name) \ - static void test_##name(void) \ -{ \ - int input[] = {INPUT}; \ - int result[] = {RESULT}; \ - test_prio_queue(input, result, ARRAY_SIZE(input)); \ -} - -TEST_INPUT(BASIC_INPUT, BASIC_RESULT, basic) -TEST_INPUT(MIXED_PUT_GET_INPUT, MIXED_PUT_GET_RESULT, mixed) -TEST_INPUT(EMPTY_QUEUE_INPUT, EMPTY_QUEUE_RESULT, empty) -TEST_INPUT(STACK_INPUT, STACK_RESULT, stack) -TEST_INPUT(REVERSE_STACK_INPUT, REVERSE_STACK_RESULT, reverse) +#define TEST_INPUT(input, result) \ + test_prio_queue(input, ARRAY_SIZE(input), result, ARRAY_SIZE(result)) int cmd_main(int argc, const char **argv) { - TEST(test_basic(), "prio-queue works for basic input"); - TEST(test_mixed(), "prio-queue works for mixed put & get commands"); - TEST(test_empty(), "prio-queue works when queue is empty"); - TEST(test_stack(), "prio-queue works when used as a LIFO stack"); - TEST(test_reverse(), "prio-queue works when LIFO stack is reversed"); + 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 })), + "prio-queue works for basic input"); + TEST(TEST_INPUT(((int []){ 6, 2, 4, GET, 5, 3, GET, GET, 1, DUMP }), + ((int []){ 2, 3, 4, 1, 5, 6 })), + "prio-queue works for mixed put & get commands"); + TEST(TEST_INPUT(((int []){ 1, 2, GET, GET, GET, 1, 2, GET, GET, GET }), + ((int []){ 1, 2, MISSING, 1, 2, MISSING })), + "prio-queue works when queue is empty"); + TEST(TEST_INPUT(((int []){ STACK, 8, 1, 5, 4, 6, 2, 3, DUMP }), + ((int []){ 3, 2, 6, 4, 5, 1, 8 })), + "prio-queue works when used as a LIFO stack"); + TEST(TEST_INPUT(((int []){ STACK, 1, 2, 3, 4, 5, 6, REVERSE, DUMP }), + ((int []){ 1, 2, 3, 4, 5, 6 })), + "prio-queue works when LIFO stack is reversed"); return test_done(); } |
