diff options
Diffstat (limited to 't')
449 files changed, 8985 insertions, 2164 deletions
diff --git a/t/.gitattributes b/t/.gitattributes index b9cea1795d..7664c6e027 100644 --- a/t/.gitattributes +++ b/t/.gitattributes @@ -1,5 +1,5 @@ t[0-9][0-9][0-9][0-9]/* -whitespace -/chainlint/*.expect eol=lf +/chainlint/*.expect eol=lf -whitespace /t0110/url-* binary /t3206/* eol=lf /t3900/*.txt eol=lf diff --git a/t/Makefile b/t/Makefile index 2d95046f26..4c30e7c06f 100644 --- a/t/Makefile +++ b/t/Makefile @@ -48,7 +48,8 @@ CHAINLINTTESTS = $(sort $(patsubst chainlint/%.test,%,$(wildcard chainlint/*.tes CHAINLINT = '$(PERL_PATH_SQ)' chainlint.pl UNIT_TEST_SOURCES = $(wildcard unit-tests/t-*.c) UNIT_TEST_PROGRAMS = $(patsubst unit-tests/%.c,unit-tests/bin/%$(X),$(UNIT_TEST_SOURCES)) -UNIT_TESTS = $(sort $(filter-out unit-tests/bin/t-basic%,$(UNIT_TEST_PROGRAMS))) +UNIT_TESTS = $(sort $(UNIT_TEST_PROGRAMS)) +UNIT_TESTS_NO_DIR = $(notdir $(UNIT_TESTS)) # `test-chainlint` (which is a dependency of `test-lint`, `test` and `prove`) # checks all tests in all scripts via a single invocation, so tell individual @@ -67,7 +68,7 @@ failed: test -z "$$failed" || $(MAKE) $$failed prove: pre-clean check-chainlint $(TEST_LINT) - @echo "*** prove ***"; $(CHAINLINTSUPPRESS) $(PROVE) --exec '$(TEST_SHELL_PATH_SQ)' $(GIT_PROVE_OPTS) $(T) :: $(GIT_TEST_OPTS) + @echo "*** prove (shell & unit tests) ***"; $(CHAINLINTSUPPRESS) TEST_SHELL_PATH='$(TEST_SHELL_PATH_SQ)' $(PROVE) --exec ./run-test.sh $(GIT_PROVE_OPTS) $(T) $(UNIT_TESTS) :: $(GIT_TEST_OPTS) $(MAKE) clean-except-prove-cache $(T): @@ -76,7 +77,7 @@ $(T): $(UNIT_TESTS): @echo "*** $@ ***"; $@ -.PHONY: unit-tests unit-tests-raw unit-tests-prove +.PHONY: unit-tests unit-tests-raw unit-tests-prove unit-tests-test-tool unit-tests: $(DEFAULT_UNIT_TEST_TARGET) unit-tests-raw: $(UNIT_TESTS) @@ -84,6 +85,13 @@ unit-tests-raw: $(UNIT_TESTS) unit-tests-prove: @echo "*** prove - unit tests ***"; $(PROVE) $(GIT_PROVE_OPTS) $(UNIT_TESTS) +unit-tests-test-tool: + @echo "*** test-tool - unit tests **" + ( \ + cd unit-tests/bin && \ + ../../helper/test-tool$X run-command testsuite $(UNIT_TESTS_NO_DIR)\ + ) + pre-clean: $(RM) -r '$(TEST_RESULTS_DIRECTORY_SQ)' @@ -100,20 +108,8 @@ clean-chainlint: check-chainlint: @mkdir -p '$(CHAINLINTTMP_SQ)' && \ - for i in $(CHAINLINTTESTS); do \ - echo "test_expect_success '$$i' '" && \ - sed -e '/^# LINT: /d' chainlint/$$i.test && \ - echo "'"; \ - done >'$(CHAINLINTTMP_SQ)'/tests && \ - { \ - echo "# chainlint: $(CHAINLINTTMP_SQ)/tests" && \ - for i in $(CHAINLINTTESTS); do \ - echo "# chainlint: $$i" && \ - cat chainlint/$$i.expect; \ - done \ - } >'$(CHAINLINTTMP_SQ)'/expect && \ - $(CHAINLINT) --emit-all '$(CHAINLINTTMP_SQ)'/tests | \ - sed -e 's/^[1-9][0-9]* //' >'$(CHAINLINTTMP_SQ)'/actual && \ + '$(PERL_PATH_SQ)' chainlint-cat.pl '$(CHAINLINTTMP_SQ)' $(CHAINLINTTESTS) && \ + { $(CHAINLINT) --emit-all '$(CHAINLINTTMP_SQ)'/tests >'$(CHAINLINTTMP_SQ)'/actual || true; } && \ diff -u '$(CHAINLINTTMP_SQ)'/expect '$(CHAINLINTTMP_SQ)'/actual test-lint: test-lint-duplicates test-lint-executable test-lint-shell-syntax \ @@ -382,33 +382,9 @@ mapping between "TEST_PASSES_SANITIZE_LEAK=true" and those tests that pass under "SANITIZE=leak". This is especially useful when testing a series that fixes various memory leaks with "git rebase -x". -GIT_TEST_SANITIZE_LEAK_LOG=true will log memory leaks to -"test-results/$TEST_NAME.leak/trace.*" files. The logs include a -"dedup_token" (see +"ASAN_OPTIONS=help=1 ./git") and other options to -make logs +machine-readable. - -With GIT_TEST_SANITIZE_LEAK_LOG=true we'll look at the leak logs -before exiting and exit on failure if the logs showed that we had a -memory leak, even if the test itself would have otherwise passed. This -allows us to catch e.g. missing &&-chaining. This is especially useful -when combined with "GIT_TEST_PASSING_SANITIZE_LEAK", see below. - GIT_TEST_PASSING_SANITIZE_LEAK=check when combined with "--immediate" will run to completion faster, and result in the same failing -tests. The only practical reason to run -GIT_TEST_PASSING_SANITIZE_LEAK=check without "--immediate" is to -combine it with "GIT_TEST_SANITIZE_LEAK_LOG=true". If we stop at the -first failing test case our leak logs won't show subsequent leaks we -might have run into. - -GIT_TEST_PASSING_SANITIZE_LEAK=(true|check) will not catch all memory -leaks unless combined with GIT_TEST_SANITIZE_LEAK_LOG=true. Some tests -run "git" (or "test-tool" etc.) without properly checking the exit -code, or git will invoke itself and fail to ferry the abort() exit -code to the original caller. When the two modes are combined we'll -look at the "test-results/$TEST_NAME.leak/trace.*" files at the end of -the test run to see if had memory leaks which the test itself didn't -catch. +tests. GIT_TEST_PROTOCOL_VERSION=<n>, when set, makes 'protocol.version' default to n. @@ -906,6 +882,14 @@ see test-lib-functions.sh for the full list and their options. 'git-write-tree should be able to write an empty tree.' \ 'tree=$(git-write-tree)' + If <script> is `-` (a single dash), then the script to run is read + from stdin. This lets you more easily use single quotes within the + script by using a here-doc. For example: + + test_expect_success 'output contains expected string' - <<\EOT + grep "this string has 'quotes' in it" output + EOT + If you supply three parameters the first will be taken to be a prerequisite; see the test_set_prereq and test_have_prereq documentation below: diff --git a/t/chainlint-cat.pl b/t/chainlint-cat.pl new file mode 100644 index 0000000000..388f6e1e41 --- /dev/null +++ b/t/chainlint-cat.pl @@ -0,0 +1,29 @@ +#!/usr/bin/env perl + +my $outdir = shift; +open(my $tests, '>', "$outdir/tests") + or die "unable to open $outdir/tests: $!"; +open(my $expect, '>', "$outdir/expect") + or die "unable to open $outdir/expect: $!"; + +print $expect "# chainlint: $outdir/tests\n"; + +my $offset = 0; +for my $script (@ARGV) { + print $expect "# chainlint: $script\n"; + + open(my $expect_in, '<', "chainlint/$script.expect") + or die "unable to open chainlint/$script.expect: $!"; + while (<$expect_in>) { + s/^\d+/$& + $offset/e; + print $expect $_; + } + + open(my $test_in, '<', "chainlint/$script.test") + or die "unable to open chainlint/$script.test: $!"; + while (<$test_in>) { + /^# LINT: / and next; + print $tests $_; + $offset++; + } +} diff --git a/t/chainlint.pl b/t/chainlint.pl index 556ee91a15..5361f23b1d 100755 --- a/t/chainlint.pl +++ b/t/chainlint.pl @@ -174,6 +174,10 @@ sub swallow_heredocs { $$b =~ /(?:\G|\n)$indent\Q$$tag[0]\E(?:\n|\z)/gc; if (pos($$b) > $start) { my $body = substr($$b, $start, pos($$b) - $start); + $self->{parser}->{heredocs}->{$$tag[0]} = { + content => substr($body, 0, length($body) - length($&)), + start_line => $self->{lineno}, + }; $self->{lineno} += () = $body =~ /\n/sg; next; } @@ -232,7 +236,8 @@ sub new { my $self = bless { buff => [], stop => [], - output => [] + output => [], + heredocs => {}, } => $class; $self->{lexer} = Lexer->new($self, $s); return $self; @@ -616,14 +621,21 @@ sub unwrap { sub check_test { my $self = shift @_; - my ($title, $body) = map(unwrap, @_); + my $title = unwrap(shift @_); + my $body = shift @_; + my $lineno = $body->[3]; + $body = unwrap($body); + if ($body eq '-') { + my $herebody = shift @_; + $body = $herebody->{content}; + $lineno = $herebody->{start_line}; + } $self->{ntests}++; my $parser = TestParser->new(\$body); my @tokens = $parser->parse(); my $problems = $parser->{problems}; return unless $emit_all || @$problems; my $c = main::fd_colors(1); - my $lineno = $_[1]->[3]; my $start = 0; my $checked = ''; for (sort {$a->[1]->[2] <=> $b->[1]->[2]} @$problems) { @@ -649,8 +661,13 @@ sub parse_cmd { return @tokens unless @tokens && $tokens[0]->[0] =~ /^test_expect_(?:success|failure)$/; my $n = $#tokens; $n-- while $n >= 0 && $tokens[$n]->[0] =~ /^(?:[;&\n|]|&&|\|\|)$/; - $self->check_test($tokens[1], $tokens[2]) if $n == 2; # title body - $self->check_test($tokens[2], $tokens[3]) if $n > 2; # prereq title body + my $herebody; + if ($n >= 2 && $tokens[$n-1]->[0] eq '-' && $tokens[$n]->[0] =~ /^<<-?(.+)$/) { + $herebody = $self->{heredocs}->{$1}; + $n--; + } + $self->check_test($tokens[1], $tokens[2], $herebody) if $n == 2; # title body + $self->check_test($tokens[2], $tokens[3], $herebody) if $n > 2; # prereq title body return @tokens; } @@ -716,11 +733,25 @@ sub fd_colors { sub ncores { # Windows - return $ENV{NUMBER_OF_PROCESSORS} if exists($ENV{NUMBER_OF_PROCESSORS}); + if (exists($ENV{NUMBER_OF_PROCESSORS})) { + my $ncpu = $ENV{NUMBER_OF_PROCESSORS}; + return $ncpu > 0 ? $ncpu : 1; + } # Linux / MSYS2 / Cygwin / WSL - do { local @ARGV='/proc/cpuinfo'; return scalar(grep(/^processor[\s\d]*:/, <>)); } if -r '/proc/cpuinfo'; + if (open my $fh, '<', '/proc/cpuinfo') { + my $cpuinfo = do { local $/; <$fh> }; + close($fh); + if ($cpuinfo =~ /^n?cpus active\s*:\s*(\d+)/m) { + return $1 if $1 > 0; + } + my @matches = ($cpuinfo =~ /^(processor|CPU)[\s\d]*:/mg); + return @matches ? scalar(@matches) : 1; + } # macOS & BSD - return qx/sysctl -n hw.ncpu/ if $^O =~ /(?:^darwin$|bsd)/; + if ($^O =~ /(?:^darwin$|bsd)/) { + my $ncpu = qx/sysctl -n hw.ncpu/; + return $ncpu > 0 ? $ncpu : 1; + } return 1; } @@ -748,7 +779,7 @@ sub check_script { while (my $path = $next_script->()) { $nscripts++; my $fh; - unless (open($fh, "<", $path)) { + unless (open($fh, "<:unix:crlf", $path)) { $emit->("?!ERR?! $path: $!\n"); next; } @@ -792,8 +823,10 @@ unless (@scripts) { show_stats($start_time, \@stats) if $show_stats; exit; } +$jobs = @scripts if @scripts < $jobs; -unless ($Config{useithreads} && eval { +unless ($jobs > 1 && + $Config{useithreads} && eval { require threads; threads->import(); require Thread::Queue; Thread::Queue->import(); 1; diff --git a/t/chainlint/arithmetic-expansion.expect b/t/chainlint/arithmetic-expansion.expect index 46ee1046af..338ecd5861 100644 --- a/t/chainlint/arithmetic-expansion.expect +++ b/t/chainlint/arithmetic-expansion.expect @@ -1,9 +1,9 @@ -( - foo && - bar=$((42 + 1)) && - baz -) && -( - bar=$((42 + 1)) ?!AMP?! - baz -) +2 ( +3 foo && +4 bar=$((42 + 1)) && +5 baz +6 ) && +7 ( +8 bar=$((42 + 1)) ?!AMP?! +9 baz +10 ) diff --git a/t/chainlint/arithmetic-expansion.test b/t/chainlint/arithmetic-expansion.test index 16206960d8..7b4c5c9a41 100644 --- a/t/chainlint/arithmetic-expansion.test +++ b/t/chainlint/arithmetic-expansion.test @@ -1,3 +1,4 @@ +test_expect_success 'arithmetic-expansion' ' ( foo && # LINT: closing ")" of $((...)) not misinterpreted as subshell-closing ")" @@ -9,3 +10,4 @@ bar=$((42 + 1)) baz ) +' diff --git a/t/chainlint/bash-array.expect b/t/chainlint/bash-array.expect index 4c34eaee45..435dc8bdc8 100644 --- a/t/chainlint/bash-array.expect +++ b/t/chainlint/bash-array.expect @@ -1,10 +1,10 @@ -( - foo && - bar=(gumbo stumbo wumbo) && - baz -) && -( - foo && - bar=${#bar[@]} && - baz -) +2 ( +3 foo && +4 bar=(gumbo stumbo wumbo) && +5 baz +6 ) && +7 ( +8 foo && +9 bar=${#bar[@]} && +10 baz +11 ) diff --git a/t/chainlint/bash-array.test b/t/chainlint/bash-array.test index 92bbb777b8..4ca977d299 100644 --- a/t/chainlint/bash-array.test +++ b/t/chainlint/bash-array.test @@ -1,3 +1,4 @@ +test_expect_success 'bash-array' ' ( foo && # LINT: ")" in Bash array assignment not misinterpreted as subshell-closing ")" @@ -10,3 +11,4 @@ bar=${#bar[@]} && baz ) +' diff --git a/t/chainlint/blank-line-before-esac.expect b/t/chainlint/blank-line-before-esac.expect index 056e03003d..b88ba919eb 100644 --- a/t/chainlint/blank-line-before-esac.expect +++ b/t/chainlint/blank-line-before-esac.expect @@ -1,18 +1,18 @@ -test_done () { - case "$test_failure" in - 0) - test_at_end_hook_ - - exit 0 ;; - - *) - if test $test_external_has_tap -eq 0 - then - say_color error "# failed $test_failure among $msg" - say "1..$test_count" - fi - - exit 1 ;; - - esac -} +2 test_done () { +3 case "$test_failure" in +4 0) +5 test_at_end_hook_ +6 +7 exit 0 ;; +8 +9 *) +10 if test $test_external_has_tap -eq 0 +11 then +12 say_color error "# failed $test_failure among $msg" +13 say "1..$test_count" +14 fi +15 +16 exit 1 ;; +17 +18 esac +19 } diff --git a/t/chainlint/blank-line-before-esac.test b/t/chainlint/blank-line-before-esac.test index cecccad19f..51f02ea0c5 100644 --- a/t/chainlint/blank-line-before-esac.test +++ b/t/chainlint/blank-line-before-esac.test @@ -1,3 +1,4 @@ +test_expect_success 'blank-line-before-esac' ' # LINT: blank line before "esac" test_done () { case "$test_failure" in @@ -17,3 +18,4 @@ test_done () { esac } +' diff --git a/t/chainlint/blank-line.expect b/t/chainlint/blank-line.expect index b47827d749..6ae39dd174 100644 --- a/t/chainlint/blank-line.expect +++ b/t/chainlint/blank-line.expect @@ -1,8 +1,8 @@ -( - - nothing && - - something - - -) +2 ( +3 +4 nothing && +5 +6 something +7 +8 +9 ) diff --git a/t/chainlint/blank-line.test b/t/chainlint/blank-line.test index 0fdf15b3e1..6f29a491de 100644 --- a/t/chainlint/blank-line.test +++ b/t/chainlint/blank-line.test @@ -1,3 +1,4 @@ +test_expect_success 'blank-line' ' ( nothing && @@ -8,3 +9,4 @@ ) +' diff --git a/t/chainlint/block-comment.expect b/t/chainlint/block-comment.expect index df2beea888..7926936c18 100644 --- a/t/chainlint/block-comment.expect +++ b/t/chainlint/block-comment.expect @@ -1,8 +1,8 @@ -( - { - # show a - echo a && - # show b - echo b - } -) +2 ( +3 { +4 # show a +5 echo a && +6 # show b +7 echo b +8 } +9 ) diff --git a/t/chainlint/block-comment.test b/t/chainlint/block-comment.test index df2beea888..934ef4113a 100644 --- a/t/chainlint/block-comment.test +++ b/t/chainlint/block-comment.test @@ -1,3 +1,4 @@ +test_expect_success 'block-comment' ' ( { # show a @@ -6,3 +7,4 @@ echo b } ) +' diff --git a/t/chainlint/block.expect b/t/chainlint/block.expect index 1c87326364..b62e3d58c3 100644 --- a/t/chainlint/block.expect +++ b/t/chainlint/block.expect @@ -1,23 +1,23 @@ -( - foo && - { - echo a ?!AMP?! - echo b - } && - bar && - { - echo c - } ?!AMP?! - baz -) && - -{ - echo a; ?!AMP?! echo b -} && -{ echo a; ?!AMP?! echo b; } && - -{ - echo "${var}9" && - echo "done" -} && -finis +2 ( +3 foo && +4 { +5 echo a ?!AMP?! +6 echo b +7 } && +8 bar && +9 { +10 echo c +11 } ?!AMP?! +12 baz +13 ) && +14 +15 { +16 echo a; ?!AMP?! echo b +17 } && +18 { echo a; ?!AMP?! echo b; } && +19 +20 { +21 echo "${var}9" && +22 echo "done" +23 } && +24 finis diff --git a/t/chainlint/block.test b/t/chainlint/block.test index 4ab69a4afc..a1b6b4dd32 100644 --- a/t/chainlint/block.test +++ b/t/chainlint/block.test @@ -1,3 +1,4 @@ +test_expect_success 'block' ' ( # LINT: missing "&&" after first "echo" foo && @@ -25,3 +26,4 @@ echo "done" } && finis +' diff --git a/t/chainlint/broken-chain.expect b/t/chainlint/broken-chain.expect index cfb58fb6b9..9a1838736f 100644 --- a/t/chainlint/broken-chain.expect +++ b/t/chainlint/broken-chain.expect @@ -1,6 +1,6 @@ -( - foo && - bar ?!AMP?! - baz && - wop -) +2 ( +3 foo && +4 bar ?!AMP?! +5 baz && +6 wop +7 ) diff --git a/t/chainlint/broken-chain.test b/t/chainlint/broken-chain.test index 2a44aa73b7..1966499ef9 100644 --- a/t/chainlint/broken-chain.test +++ b/t/chainlint/broken-chain.test @@ -1,3 +1,4 @@ +test_expect_success 'broken-chain' ' ( foo && # LINT: missing "&&" from "bar" @@ -6,3 +7,4 @@ # LINT: final statement before closing ")" legitimately lacks "&&" wop ) +' diff --git a/t/chainlint/case-comment.expect b/t/chainlint/case-comment.expect index 641c157b98..2442dd5f25 100644 --- a/t/chainlint/case-comment.expect +++ b/t/chainlint/case-comment.expect @@ -1,11 +1,11 @@ -( - case "$x" in - # found foo - x) foo ;; - # found other - *) - # treat it as bar - bar - ;; - esac -) +2 ( +3 case "$x" in +4 # found foo +5 x) foo ;; +6 # found other +7 *) +8 # treat it as bar +9 bar +10 ;; +11 esac +12 ) diff --git a/t/chainlint/case-comment.test b/t/chainlint/case-comment.test index 641c157b98..3f31ae9010 100644 --- a/t/chainlint/case-comment.test +++ b/t/chainlint/case-comment.test @@ -1,3 +1,4 @@ +test_expect_success 'case-comment' ' ( case "$x" in # found foo @@ -9,3 +10,4 @@ ;; esac ) +' diff --git a/t/chainlint/case.expect b/t/chainlint/case.expect index 31f280d8ce..c04c61ff36 100644 --- a/t/chainlint/case.expect +++ b/t/chainlint/case.expect @@ -1,19 +1,19 @@ -( - case "$x" in - x) foo ;; - *) bar ;; - esac && - foobar -) && -( - case "$x" in - x) foo ;; - *) bar ;; - esac ?!AMP?! - foobar -) && -( - case "$x" in 1) true;; esac && - case "$y" in 2) false;; esac ?!AMP?! - foobar -) +2 ( +3 case "$x" in +4 x) foo ;; +5 *) bar ;; +6 esac && +7 foobar +8 ) && +9 ( +10 case "$x" in +11 x) foo ;; +12 *) bar ;; +13 esac ?!AMP?! +14 foobar +15 ) && +16 ( +17 case "$x" in 1) true;; esac && +18 case "$y" in 2) false;; esac ?!AMP?! +19 foobar +20 ) diff --git a/t/chainlint/case.test b/t/chainlint/case.test index 4cb086bf87..bea21fee4f 100644 --- a/t/chainlint/case.test +++ b/t/chainlint/case.test @@ -1,3 +1,4 @@ +test_expect_success 'case' ' ( # LINT: "...)" arms in "case" not misinterpreted as subshell-closing ")" case "$x" in @@ -21,3 +22,4 @@ case "$y" in 2) false;; esac foobar ) +' diff --git a/t/chainlint/chain-break-background.expect b/t/chainlint/chain-break-background.expect index 20d0bb5333..d06deadae7 100644 --- a/t/chainlint/chain-break-background.expect +++ b/t/chainlint/chain-break-background.expect @@ -1,9 +1,9 @@ -JGIT_DAEMON_PID= && -git init --bare empty.git && ->empty.git/git-daemon-export-ok && -mkfifo jgit_daemon_output && -{ - jgit daemon --port="$JGIT_DAEMON_PORT" . >jgit_daemon_output & - JGIT_DAEMON_PID=$! -} && -test_expect_code 2 git ls-remote --exit-code git://localhost:$JGIT_DAEMON_PORT/empty.git +2 JGIT_DAEMON_PID= && +3 git init --bare empty.git && +4 >empty.git/git-daemon-export-ok && +5 mkfifo jgit_daemon_output && +6 { +7 jgit daemon --port="$JGIT_DAEMON_PORT" . >jgit_daemon_output & +8 JGIT_DAEMON_PID=$! +9 } && +10 test_expect_code 2 git ls-remote --exit-code git://localhost:$JGIT_DAEMON_PORT/empty.git diff --git a/t/chainlint/chain-break-background.test b/t/chainlint/chain-break-background.test index e10f656b05..c68e1b04d5 100644 --- a/t/chainlint/chain-break-background.test +++ b/t/chainlint/chain-break-background.test @@ -1,3 +1,4 @@ +test_expect_success 'chain-break-background' ' JGIT_DAEMON_PID= && git init --bare empty.git && >empty.git/git-daemon-export-ok && @@ -8,3 +9,4 @@ mkfifo jgit_daemon_output && JGIT_DAEMON_PID=$! } && test_expect_code 2 git ls-remote --exit-code git://localhost:$JGIT_DAEMON_PORT/empty.git +' diff --git a/t/chainlint/chain-break-continue.expect b/t/chainlint/chain-break-continue.expect index 47a3457710..4bb60aae25 100644 --- a/t/chainlint/chain-break-continue.expect +++ b/t/chainlint/chain-break-continue.expect @@ -1,12 +1,12 @@ -git ls-tree --name-only -r refs/notes/many_notes | -while read path -do - test "$path" = "foobar/non-note.txt" && continue - test "$path" = "deadbeef" && continue - test "$path" = "de/adbeef" && continue - - if test $(expr length "$path") -ne $hexsz - then - return 1 - fi -done +2 git ls-tree --name-only -r refs/notes/many_notes | +3 while read path +4 do +5 test "$path" = "foobar/non-note.txt" && continue +6 test "$path" = "deadbeef" && continue +7 test "$path" = "de/adbeef" && continue +8 +9 if test $(expr length "$path") -ne $hexsz +10 then +11 return 1 +12 fi +13 done diff --git a/t/chainlint/chain-break-continue.test b/t/chainlint/chain-break-continue.test index f0af71d8bd..de8119b204 100644 --- a/t/chainlint/chain-break-continue.test +++ b/t/chainlint/chain-break-continue.test @@ -1,3 +1,4 @@ +test_expect_success 'chain-break-continue' ' git ls-tree --name-only -r refs/notes/many_notes | while read path do @@ -11,3 +12,4 @@ do return 1 fi done +' diff --git a/t/chainlint/chain-break-false.expect b/t/chainlint/chain-break-false.expect index 989766fb85..4f815f8e14 100644 --- a/t/chainlint/chain-break-false.expect +++ b/t/chainlint/chain-break-false.expect @@ -1,9 +1,9 @@ -if condition not satisified -then - echo it did not work... - echo failed! - false -else - echo it went okay ?!AMP?! - congratulate user -fi +2 if condition not satisified +3 then +4 echo it did not work... +5 echo failed! +6 false +7 else +8 echo it went okay ?!AMP?! +9 congratulate user +10 fi diff --git a/t/chainlint/chain-break-false.test b/t/chainlint/chain-break-false.test index a5aaff8c8a..f78ad911fc 100644 --- a/t/chainlint/chain-break-false.test +++ b/t/chainlint/chain-break-false.test @@ -1,3 +1,4 @@ +test_expect_success 'chain-break-false' ' # LINT: broken &&-chain okay if explicit "false" signals failure if condition not satisified then @@ -8,3 +9,4 @@ else echo it went okay congratulate user fi +' diff --git a/t/chainlint/chain-break-return-exit.expect b/t/chainlint/chain-break-return-exit.expect index 4cd18e2edf..ba0ec51aa0 100644 --- a/t/chainlint/chain-break-return-exit.expect +++ b/t/chainlint/chain-break-return-exit.expect @@ -1,19 +1,19 @@ -case "$(git ls-files)" in -one) echo pass one ;; -*) echo bad one; return 1 ;; -esac && -( - case "$(git ls-files)" in - two) echo pass two ;; - *) echo bad two; exit 1 ;; - esac -) && -case "$(git ls-files)" in -dir/two"$LF"one) echo pass both ;; -*) echo bad; return 1 ;; -esac && - -for i in 1 2 3 4 ; do - git checkout main -b $i || return $? - test_commit $i $i $i tag$i || return $? -done +2 case "$(git ls-files)" in +3 one) echo pass one ;; +4 *) echo bad one; return 1 ;; +5 esac && +6 ( +7 case "$(git ls-files)" in +8 two) echo pass two ;; +9 *) echo bad two; exit 1 ;; +10 esac +11 ) && +12 case "$(git ls-files)" in +13 dir/two"$LF"one) echo pass both ;; +14 *) echo bad; return 1 ;; +15 esac && +16 +17 for i in 1 2 3 4 ; do +18 git checkout main -b $i || return $? +19 test_commit $i $i $i tag$i || return $? +20 done diff --git a/t/chainlint/chain-break-return-exit.test b/t/chainlint/chain-break-return-exit.test index 46542edf88..b6f519bb4d 100644 --- a/t/chainlint/chain-break-return-exit.test +++ b/t/chainlint/chain-break-return-exit.test @@ -1,3 +1,4 @@ +test_expect_success 'chain-break-return-exit' ' case "$(git ls-files)" in one) echo pass one ;; # LINT: broken &&-chain okay if explicit "return 1" signals failuire @@ -21,3 +22,4 @@ for i in 1 2 3 4 ; do git checkout main -b $i || return $? test_commit $i $i $i tag$i || return $? done +' diff --git a/t/chainlint/chain-break-status.expect b/t/chainlint/chain-break-status.expect index e6b3b2193e..23c0caa7d8 100644 --- a/t/chainlint/chain-break-status.expect +++ b/t/chainlint/chain-break-status.expect @@ -1,9 +1,9 @@ -OUT=$( ((large_git; echo $? 1>&3) | :) 3>&1 ) && -test_match_signal 13 "$OUT" && - -{ test-tool sigchain >actual; ret=$?; } && -{ - test_match_signal 15 "$ret" || - test "$ret" = 3 -} && -test_cmp expect actual +2 OUT=$( ((large_git; echo $? 1>&3) | :) 3>&1 ) && +3 test_match_signal 13 "$OUT" && +4 +5 { test-tool sigchain >actual; ret=$?; } && +6 { +7 test_match_signal 15 "$ret" || +8 test "$ret" = 3 +9 } && +10 test_cmp expect actual diff --git a/t/chainlint/chain-break-status.test b/t/chainlint/chain-break-status.test index a6602a7b99..d9fee190d9 100644 --- a/t/chainlint/chain-break-status.test +++ b/t/chainlint/chain-break-status.test @@ -1,3 +1,4 @@ +test_expect_success 'chain-break-status' ' # LINT: broken &&-chain okay if next command handles "$?" explicitly OUT=$( ((large_git; echo $? 1>&3) | :) 3>&1 ) && test_match_signal 13 "$OUT" && @@ -9,3 +10,4 @@ test_match_signal 13 "$OUT" && test "$ret" = 3 } && test_cmp expect actual +' diff --git a/t/chainlint/chained-block.expect b/t/chainlint/chained-block.expect index 574cdceb07..a546b714a6 100644 --- a/t/chainlint/chained-block.expect +++ b/t/chainlint/chained-block.expect @@ -1,9 +1,9 @@ -echo nobody home && { - test the doohicky ?!AMP?! - right now -} && - -GIT_EXTERNAL_DIFF=echo git diff | { - read path oldfile oldhex oldmode newfile newhex newmode && - test "z$oh" = "z$oldhex" -} +2 echo nobody home && { +3 test the doohicky ?!AMP?! +4 right now +5 } && +6 +7 GIT_EXTERNAL_DIFF=echo git diff | { +8 read path oldfile oldhex oldmode newfile newhex newmode && +9 test "z$oh" = "z$oldhex" +10 } diff --git a/t/chainlint/chained-block.test b/t/chainlint/chained-block.test index 86f81ece63..71ef1d0b7f 100644 --- a/t/chainlint/chained-block.test +++ b/t/chainlint/chained-block.test @@ -1,3 +1,4 @@ +test_expect_success 'chained-block' ' # LINT: start of block chained to preceding command echo nobody home && { test the doohicky @@ -9,3 +10,4 @@ GIT_EXTERNAL_DIFF=echo git diff | { read path oldfile oldhex oldmode newfile newhex newmode && test "z$oh" = "z$oldhex" } +' diff --git a/t/chainlint/chained-subshell.expect b/t/chainlint/chained-subshell.expect index 83810ea7ec..f78b268291 100644 --- a/t/chainlint/chained-subshell.expect +++ b/t/chainlint/chained-subshell.expect @@ -1,10 +1,10 @@ -mkdir sub && ( - cd sub && - foo the bar ?!AMP?! - nuff said -) && - -cut "-d " -f actual | (read s1 s2 s3 && -test -f $s1 ?!AMP?! -test $(cat $s2) = tree2path1 && -test $(cat $s3) = tree3path1) +2 mkdir sub && ( +3 cd sub && +4 foo the bar ?!AMP?! +5 nuff said +6 ) && +7 +8 cut "-d " -f actual | (read s1 s2 s3 && +9 test -f $s1 ?!AMP?! +10 test $(cat $s2) = tree2path1 && +11 test $(cat $s3) = tree3path1) diff --git a/t/chainlint/chained-subshell.test b/t/chainlint/chained-subshell.test index 4ff6ddd8cb..1f11f65398 100644 --- a/t/chainlint/chained-subshell.test +++ b/t/chainlint/chained-subshell.test @@ -1,3 +1,4 @@ +test_expect_success 'chained-subshell' ' # LINT: start of subshell chained to preceding command mkdir sub && ( cd sub && @@ -11,3 +12,4 @@ test -f $s1 test $(cat $s2) = tree2path1 && # LINT: closing subshell ")" correctly detected on same line as "$(...)" test $(cat $s3) = tree3path1) +' diff --git a/t/chainlint/close-nested-and-parent-together.expect b/t/chainlint/close-nested-and-parent-together.expect index 72d482f76d..4167e54a59 100644 --- a/t/chainlint/close-nested-and-parent-together.expect +++ b/t/chainlint/close-nested-and-parent-together.expect @@ -1,3 +1,3 @@ -(cd foo && - (bar && - baz)) +2 (cd foo && +3 (bar && +4 baz)) diff --git a/t/chainlint/close-nested-and-parent-together.test b/t/chainlint/close-nested-and-parent-together.test index 72d482f76d..56b28b186b 100644 --- a/t/chainlint/close-nested-and-parent-together.test +++ b/t/chainlint/close-nested-and-parent-together.test @@ -1,3 +1,5 @@ +test_expect_success 'close-nested-and-parent-together' ' (cd foo && (bar && baz)) +' diff --git a/t/chainlint/close-subshell.expect b/t/chainlint/close-subshell.expect index 2192a2870a..a272cfe72e 100644 --- a/t/chainlint/close-subshell.expect +++ b/t/chainlint/close-subshell.expect @@ -1,26 +1,26 @@ -( - foo -) && -( - bar -) >out && -( - baz -) 2>err && -( - boo -) <input && -( - bip -) | wuzzle && -( - bop -) | fazz \ - fozz && -( - bup -) | -fuzzle && -( - yop -) +2 ( +3 foo +4 ) && +5 ( +6 bar +7 ) >out && +8 ( +9 baz +10 ) 2>err && +11 ( +12 boo +13 ) <input && +14 ( +15 bip +16 ) | wuzzle && +17 ( +18 bop +19 ) | fazz \ +20 fozz && +21 ( +22 bup +23 ) | +24 fuzzle && +25 ( +26 yop +27 ) diff --git a/t/chainlint/close-subshell.test b/t/chainlint/close-subshell.test index 508ca447fd..b99f80569d 100644 --- a/t/chainlint/close-subshell.test +++ b/t/chainlint/close-subshell.test @@ -1,3 +1,4 @@ +test_expect_success 'close-subshell' ' # LINT: closing ")" with various decorations ("&&", ">", "|", etc.) ( foo @@ -25,3 +26,4 @@ fuzzle && ( yop ) +' diff --git a/t/chainlint/command-substitution-subsubshell.expect b/t/chainlint/command-substitution-subsubshell.expect index ec42f2c30c..f2a9312dc8 100644 --- a/t/chainlint/command-substitution-subsubshell.expect +++ b/t/chainlint/command-substitution-subsubshell.expect @@ -1,2 +1,2 @@ -OUT=$( ((large_git 1>&3) | :) 3>&1 ) && -test_match_signal 13 "$OUT" +2 OUT=$( ((large_git 1>&3) | :) 3>&1 ) && +3 test_match_signal 13 "$OUT" diff --git a/t/chainlint/command-substitution-subsubshell.test b/t/chainlint/command-substitution-subsubshell.test index 321de2951c..4ea772d60a 100644 --- a/t/chainlint/command-substitution-subsubshell.test +++ b/t/chainlint/command-substitution-subsubshell.test @@ -1,3 +1,5 @@ +test_expect_success 'command-substitution-subsubshell' ' # LINT: subshell nested in subshell nested in command substitution OUT=$( ((large_git 1>&3) | :) 3>&1 ) && test_match_signal 13 "$OUT" +' diff --git a/t/chainlint/command-substitution.expect b/t/chainlint/command-substitution.expect index c72e4df9e7..5e31b36db6 100644 --- a/t/chainlint/command-substitution.expect +++ b/t/chainlint/command-substitution.expect @@ -1,9 +1,9 @@ -( - foo && - bar=$(gobble) && - baz -) && -( - bar=$(gobble blocks) ?!AMP?! - baz -) +2 ( +3 foo && +4 bar=$(gobble) && +5 baz +6 ) && +7 ( +8 bar=$(gobble blocks) ?!AMP?! +9 baz +10 ) diff --git a/t/chainlint/command-substitution.test b/t/chainlint/command-substitution.test index 3bbb002a4c..494d671e80 100644 --- a/t/chainlint/command-substitution.test +++ b/t/chainlint/command-substitution.test @@ -1,3 +1,4 @@ +test_expect_success 'command-substitution' ' ( foo && # LINT: closing ")" of $(...) not misinterpreted as subshell-closing ")" @@ -9,3 +10,4 @@ bar=$(gobble blocks) baz ) +' diff --git a/t/chainlint/comment.expect b/t/chainlint/comment.expect index a68f1f9d7c..584098d6ba 100644 --- a/t/chainlint/comment.expect +++ b/t/chainlint/comment.expect @@ -1,8 +1,8 @@ -( - # comment 1 - nothing && - # comment 2 - something - # comment 3 - # comment 4 -) +2 ( +3 # comment 1 +4 nothing && +5 # comment 2 +6 something +7 # comment 3 +8 # comment 4 +9 ) diff --git a/t/chainlint/comment.test b/t/chainlint/comment.test index 113c0c466f..c488beac0d 100644 --- a/t/chainlint/comment.test +++ b/t/chainlint/comment.test @@ -1,3 +1,4 @@ +test_expect_success 'comment' ' ( # LINT: swallow comment lines # comment 1 @@ -9,3 +10,4 @@ # comment 3 # comment 4 ) +' diff --git a/t/chainlint/complex-if-in-cuddled-loop.expect b/t/chainlint/complex-if-in-cuddled-loop.expect index dac2d0fd1d..3a740103db 100644 --- a/t/chainlint/complex-if-in-cuddled-loop.expect +++ b/t/chainlint/complex-if-in-cuddled-loop.expect @@ -1,9 +1,9 @@ -(for i in a b c; do - if test "$(echo $(waffle bat))" = "eleventeen" && - test "$x" = "$y"; then - : - else - echo >file - fi ?!LOOP?! - done) && -test ! -f file +2 (for i in a b c; do +3 if test "$(echo $(waffle bat))" = "eleventeen" && +4 test "$x" = "$y"; then +5 : +6 else +7 echo >file +8 fi ?!LOOP?! +9 done) && +10 test ! -f file diff --git a/t/chainlint/complex-if-in-cuddled-loop.test b/t/chainlint/complex-if-in-cuddled-loop.test index 5efeda58b2..f98ae4c42d 100644 --- a/t/chainlint/complex-if-in-cuddled-loop.test +++ b/t/chainlint/complex-if-in-cuddled-loop.test @@ -1,3 +1,4 @@ +test_expect_success 'complex-if-in-cuddled-loop' ' # LINT: "for" loop cuddled with "(" and ")" and nested "if" with complex # LINT: multi-line condition; indented with spaces, not tabs (for i in a b c; do @@ -9,3 +10,4 @@ fi done) && test ! -f file +' diff --git a/t/chainlint/cuddled-if-then-else.expect b/t/chainlint/cuddled-if-then-else.expect index 1d8ed58c49..72da8794cb 100644 --- a/t/chainlint/cuddled-if-then-else.expect +++ b/t/chainlint/cuddled-if-then-else.expect @@ -1,6 +1,6 @@ -(if test -z ""; then - echo empty - else - echo bizzy - fi) && -echo foobar +2 (if test -z ""; then +3 echo empty +4 else +5 echo bizzy +6 fi) && +7 echo foobar diff --git a/t/chainlint/cuddled-if-then-else.test b/t/chainlint/cuddled-if-then-else.test index 7c53f4efe3..b1b42e1aac 100644 --- a/t/chainlint/cuddled-if-then-else.test +++ b/t/chainlint/cuddled-if-then-else.test @@ -1,3 +1,4 @@ +test_expect_success 'cuddled-if-then-else' ' # LINT: "if" cuddled with "(" and ")"; indented with spaces, not tabs (if test -z ""; then echo empty @@ -5,3 +6,4 @@ echo bizzy fi) && echo foobar +' diff --git a/t/chainlint/cuddled-loop.expect b/t/chainlint/cuddled-loop.expect index 9cf260708e..c38585c756 100644 --- a/t/chainlint/cuddled-loop.expect +++ b/t/chainlint/cuddled-loop.expect @@ -1,4 +1,4 @@ -( while read x - do foobar bop || exit 1 - done <file ) && -outside subshell +2 ( while read x +3 do foobar bop || exit 1 +4 done <file ) && +5 outside subshell diff --git a/t/chainlint/cuddled-loop.test b/t/chainlint/cuddled-loop.test index 3c2a62f751..6fccb6ac22 100644 --- a/t/chainlint/cuddled-loop.test +++ b/t/chainlint/cuddled-loop.test @@ -1,3 +1,4 @@ +test_expect_success 'cuddled-loop' ' # LINT: "while" loop cuddled with "(" and ")", with embedded (allowed) # LINT: "|| exit {n}" to exit loop early, and using redirection "<" to feed # LINT: loop; indented with spaces, not tabs @@ -5,3 +6,4 @@ do foobar bop || exit 1 done <file ) && outside subshell +' diff --git a/t/chainlint/cuddled.expect b/t/chainlint/cuddled.expect index c3e0be4047..b06d638311 100644 --- a/t/chainlint/cuddled.expect +++ b/t/chainlint/cuddled.expect @@ -1,17 +1,17 @@ -(cd foo && - bar -) && - -(cd foo ?!AMP?! - bar -) && - -( - cd foo && - bar) && - -(cd foo && - bar) && - -(cd foo ?!AMP?! - bar) +2 (cd foo && +3 bar +4 ) && +5 +6 (cd foo ?!AMP?! +7 bar +8 ) && +9 +10 ( +11 cd foo && +12 bar) && +13 +14 (cd foo && +15 bar) && +16 +17 (cd foo ?!AMP?! +18 bar) diff --git a/t/chainlint/cuddled.test b/t/chainlint/cuddled.test index 257b5b5eed..5a6ef7a4a6 100644 --- a/t/chainlint/cuddled.test +++ b/t/chainlint/cuddled.test @@ -1,3 +1,4 @@ +test_expect_success 'cuddled' ' # LINT: first subshell statement cuddled with opening "(" (cd foo && bar @@ -20,3 +21,4 @@ # LINT: same with missing "&&" (cd foo bar) +' diff --git a/t/chainlint/double-here-doc.expect b/t/chainlint/double-here-doc.expect index cd584a4357..48c04ecd58 100644 --- a/t/chainlint/double-here-doc.expect +++ b/t/chainlint/double-here-doc.expect @@ -1,12 +1,12 @@ -run_sub_test_lib_test_err run-inv-range-start \ - "--run invalid range start" \ - --run="a-5" <<-\EOF && -test_expect_success "passing test #1" "true" -test_done -EOF -check_sub_test_lib_test_err run-inv-range-start \ - <<-\EOF_OUT 3<<-EOF_ERR -> FATAL: Unexpected exit with code 1 -EOF_OUT -> error: --run: invalid non-numeric in range start: ${SQ}a-5${SQ} -EOF_ERR +2 run_sub_test_lib_test_err run-inv-range-start \ +3 "--run invalid range start" \ +4 --run="a-5" <<-\EOF && +5 test_expect_success "passing test #1" "true" +6 test_done +7 EOF +8 check_sub_test_lib_test_err run-inv-range-start \ +9 <<-\EOF_OUT 3<<-EOF_ERR +10 > FATAL: Unexpected exit with code 1 +11 EOF_OUT +12 > error: --run: invalid non-numeric in range start: ${SQ}a-5${SQ} +13 EOF_ERR diff --git a/t/chainlint/double-here-doc.test b/t/chainlint/double-here-doc.test index cd584a4357..1b69b7a651 100644 --- a/t/chainlint/double-here-doc.test +++ b/t/chainlint/double-here-doc.test @@ -1,3 +1,4 @@ +test_expect_success 'double-here-doc' ' run_sub_test_lib_test_err run-inv-range-start \ "--run invalid range start" \ --run="a-5" <<-\EOF && @@ -10,3 +11,4 @@ check_sub_test_lib_test_err run-inv-range-start \ EOF_OUT > error: --run: invalid non-numeric in range start: ${SQ}a-5${SQ} EOF_ERR +' diff --git a/t/chainlint/dqstring-line-splice.expect b/t/chainlint/dqstring-line-splice.expect index 37eab80738..2ca1c92cd6 100644 --- a/t/chainlint/dqstring-line-splice.expect +++ b/t/chainlint/dqstring-line-splice.expect @@ -1,5 +1,5 @@ - -echo 'fatal: reword option of --fixup is mutually exclusive with' '--patch/--interactive/--all/--include/--only' >expect && -test_must_fail git commit --fixup=reword:HEAD~ $1 2>actual && -test_cmp expect actual - +2 +3 echo 'fatal: reword option of --fixup is mutually exclusive with' '--patch/--interactive/--all/--include/--only' >expect && +4 test_must_fail git commit --fixup=reword:HEAD~ $1 2>actual && +5 test_cmp expect actual +6 diff --git a/t/chainlint/dqstring-line-splice.test b/t/chainlint/dqstring-line-splice.test index b40714439f..f6aa637be8 100644 --- a/t/chainlint/dqstring-line-splice.test +++ b/t/chainlint/dqstring-line-splice.test @@ -1,3 +1,4 @@ +test_expect_success 'dqstring-line-splice' ' # LINT: line-splice within DQ-string '" echo 'fatal: reword option of --fixup is mutually exclusive with'\ @@ -5,3 +6,4 @@ echo 'fatal: reword option of --fixup is mutually exclusive with'\ test_must_fail git commit --fixup=reword:HEAD~ $1 2>actual && test_cmp expect actual "' +' diff --git a/t/chainlint/dqstring-no-interpolate.expect b/t/chainlint/dqstring-no-interpolate.expect index 087eda15e4..c9f75849c5 100644 --- a/t/chainlint/dqstring-no-interpolate.expect +++ b/t/chainlint/dqstring-no-interpolate.expect @@ -1,12 +1,12 @@ -grep "^ ! [rejected][ ]*$BRANCH -> $BRANCH (non-fast-forward)$" out && - -grep "^\.git$" output.txt && - - -( - cd client$version && - GIT_TEST_PROTOCOL_VERSION=$version git fetch-pack --no-progress .. $(cat ../input) -) >output && - cut -d ' ' -f 2 <output | sort >actual && - test_cmp expect actual - +2 grep "^ ! [rejected][ ]*$BRANCH -> $BRANCH (non-fast-forward)$" out && +3 +4 grep "^\.git$" output.txt && +5 +6 +7 ( +8 cd client$version && +9 GIT_TEST_PROTOCOL_VERSION=$version git fetch-pack --no-progress .. $(cat ../input) +10 ) >output && +11 cut -d ' ' -f 2 <output | sort >actual && +12 test_cmp expect actual +13 diff --git a/t/chainlint/dqstring-no-interpolate.test b/t/chainlint/dqstring-no-interpolate.test index d2f4219cbb..7ae079b558 100644 --- a/t/chainlint/dqstring-no-interpolate.test +++ b/t/chainlint/dqstring-no-interpolate.test @@ -1,3 +1,4 @@ +test_expect_success 'dqstring-no-interpolate' ' # LINT: regex dollar-sign eol anchor in double-quoted string not special grep "^ ! \[rejected\][ ]*$BRANCH -> $BRANCH (non-fast-forward)$" out && @@ -13,3 +14,4 @@ grep "^\\.git\$" output.txt && cut -d ' ' -f 2 <output | sort >actual && test_cmp expect actual "' +' diff --git a/t/chainlint/empty-here-doc.expect b/t/chainlint/empty-here-doc.expect index 8507721192..54b33f823a 100644 --- a/t/chainlint/empty-here-doc.expect +++ b/t/chainlint/empty-here-doc.expect @@ -1,4 +1,4 @@ -git ls-tree $tree path >current && -cat >expected <<\EOF && -EOF -test_output +2 git ls-tree $tree path >current && +3 cat >expected <<\EOF && +4 EOF +5 test_output diff --git a/t/chainlint/empty-here-doc.test b/t/chainlint/empty-here-doc.test index 24fc165de3..8b7ab6eb5f 100644 --- a/t/chainlint/empty-here-doc.test +++ b/t/chainlint/empty-here-doc.test @@ -1,5 +1,7 @@ +test_expect_success 'empty-here-doc' ' git ls-tree $tree path >current && # LINT: empty here-doc cat >expected <<\EOF && EOF test_output +' diff --git a/t/chainlint/exclamation.expect b/t/chainlint/exclamation.expect index 765a35bb4c..078744b61b 100644 --- a/t/chainlint/exclamation.expect +++ b/t/chainlint/exclamation.expect @@ -1,4 +1,4 @@ -if ! condition; then echo nope; else yep; fi && -test_prerequisite !MINGW && -mail uucp!address && -echo !whatever! +2 if ! condition; then echo nope; else yep; fi && +3 test_prerequisite !MINGW && +4 mail uucp!address && +5 echo !whatever! diff --git a/t/chainlint/exclamation.test b/t/chainlint/exclamation.test index 323595b5bd..796de21b7c 100644 --- a/t/chainlint/exclamation.test +++ b/t/chainlint/exclamation.test @@ -1,3 +1,4 @@ +test_expect_success 'exclamation' ' # LINT: "! word" is two tokens if ! condition; then echo nope; else yep; fi && # LINT: "!word" is single token, not two tokens "!" and "word" @@ -6,3 +7,4 @@ test_prerequisite !MINGW && mail uucp!address && # LINT: "!word!" is single token, not three tokens "!", "word", and "!" echo !whatever! +' diff --git a/t/chainlint/exit-loop.expect b/t/chainlint/exit-loop.expect index f76aa60466..407278094c 100644 --- a/t/chainlint/exit-loop.expect +++ b/t/chainlint/exit-loop.expect @@ -1,24 +1,24 @@ -( - for i in a b c - do - foo || exit 1 - bar && - baz - done -) && -( - while true - do - foo || exit 1 - bar && - baz - done -) && -( - i=0 && - while test $i -lt 10 - do - echo $i || exit - i=$(($i + 1)) - done -) +2 ( +3 for i in a b c +4 do +5 foo || exit 1 +6 bar && +7 baz +8 done +9 ) && +10 ( +11 while true +12 do +13 foo || exit 1 +14 bar && +15 baz +16 done +17 ) && +18 ( +19 i=0 && +20 while test $i -lt 10 +21 do +22 echo $i || exit +23 i=$(($i + 1)) +24 done +25 ) diff --git a/t/chainlint/exit-loop.test b/t/chainlint/exit-loop.test index 2f038207e1..7e8b68b465 100644 --- a/t/chainlint/exit-loop.test +++ b/t/chainlint/exit-loop.test @@ -1,3 +1,4 @@ +test_expect_success 'exit-loop' ' ( for i in a b c do @@ -25,3 +26,4 @@ i=$(($i + 1)) done ) +' diff --git a/t/chainlint/exit-subshell.expect b/t/chainlint/exit-subshell.expect index da80339f78..793db12453 100644 --- a/t/chainlint/exit-subshell.expect +++ b/t/chainlint/exit-subshell.expect @@ -1,5 +1,5 @@ -( - foo || exit 1 - bar && - baz -) +2 ( +3 foo || exit 1 +4 bar && +5 baz +6 ) diff --git a/t/chainlint/exit-subshell.test b/t/chainlint/exit-subshell.test index 4e6ab69b88..05dff55cd7 100644 --- a/t/chainlint/exit-subshell.test +++ b/t/chainlint/exit-subshell.test @@ -1,6 +1,8 @@ +test_expect_success 'exit-subshell' ' ( # LINT: "|| exit {n}" valid subshell escape without hurting &&-chain foo || exit 1 bar && baz ) +' diff --git a/t/chainlint/for-loop-abbreviated.expect b/t/chainlint/for-loop-abbreviated.expect index 02c0d15cca..5574831976 100644 --- a/t/chainlint/for-loop-abbreviated.expect +++ b/t/chainlint/for-loop-abbreviated.expect @@ -1,5 +1,5 @@ -for it -do - path=$(expr "$it" : ([^:]*)) && - git update-index --add "$path" || exit -done +2 for it +3 do +4 path=$(expr "$it" : ([^:]*)) && +5 git update-index --add "$path" || exit +6 done diff --git a/t/chainlint/for-loop-abbreviated.test b/t/chainlint/for-loop-abbreviated.test index 1084eccb89..1dd14f2a44 100644 --- a/t/chainlint/for-loop-abbreviated.test +++ b/t/chainlint/for-loop-abbreviated.test @@ -1,6 +1,8 @@ +test_expect_success 'for-loop-abbreviated' ' # LINT: for-loop lacking optional "in [word...]" before "do" for it do path=$(expr "$it" : '\([^:]*\)') && git update-index --add "$path" || exit done +' diff --git a/t/chainlint/for-loop.expect b/t/chainlint/for-loop.expect index d2237f1e38..908aeedf96 100644 --- a/t/chainlint/for-loop.expect +++ b/t/chainlint/for-loop.expect @@ -1,14 +1,14 @@ -( - for i in a b c - do - echo $i ?!AMP?! - cat <<-\EOF ?!LOOP?! - bar - EOF - done ?!AMP?! - - for i in a b c; do - echo $i && - cat $i ?!LOOP?! - done -) +2 ( +3 for i in a b c +4 do +5 echo $i ?!AMP?! +6 cat <<-\EOF ?!LOOP?! +7 bar +8 EOF +9 done ?!AMP?! +10 +11 for i in a b c; do +12 echo $i && +13 cat $i ?!LOOP?! +14 done +15 ) diff --git a/t/chainlint/for-loop.test b/t/chainlint/for-loop.test index 6cb3428158..6f2489eb19 100644 --- a/t/chainlint/for-loop.test +++ b/t/chainlint/for-loop.test @@ -1,3 +1,4 @@ +test_expect_success 'for-loop' ' ( # LINT: "for", "do", "done" do not need "&&" for i in a b c @@ -17,3 +18,4 @@ cat $i done ) +' diff --git a/t/chainlint/function.expect b/t/chainlint/function.expect index dd7c997a3c..c226246b25 100644 --- a/t/chainlint/function.expect +++ b/t/chainlint/function.expect @@ -1,11 +1,11 @@ -sha1_file() { - echo "$*" | sed "s#..#.git/objects/&/#" -} && - -remove_object() { - file=$(sha1_file "$*") && - test -e "$file" ?!AMP?! - rm -f "$file" -} ?!AMP?! - -sha1_file arg && remove_object arg +2 sha1_file() { +3 echo "$*" | sed "s#..#.git/objects/&/#" +4 } && +5 +6 remove_object() { +7 file=$(sha1_file "$*") && +8 test -e "$file" ?!AMP?! +9 rm -f "$file" +10 } ?!AMP?! +11 +12 sha1_file arg && remove_object arg diff --git a/t/chainlint/function.test b/t/chainlint/function.test index 5ee59562c9..763fcf3f87 100644 --- a/t/chainlint/function.test +++ b/t/chainlint/function.test @@ -1,3 +1,4 @@ +test_expect_success 'function' ' # LINT: "()" in function definition not mistaken for subshell sha1_file() { echo "$*" | sed "s#..#.git/objects/&/#" @@ -11,3 +12,4 @@ remove_object() { } sha1_file arg && remove_object arg +' diff --git a/t/chainlint/here-doc-body-indent.expect b/t/chainlint/here-doc-body-indent.expect new file mode 100644 index 0000000000..4323acc93d --- /dev/null +++ b/t/chainlint/here-doc-body-indent.expect @@ -0,0 +1,2 @@ +2 echo "we should find this" ?!AMP?! +3 echo "even though our heredoc has its indent stripped" diff --git a/t/chainlint/here-doc-body-indent.test b/t/chainlint/here-doc-body-indent.test new file mode 100644 index 0000000000..39ff970ef3 --- /dev/null +++ b/t/chainlint/here-doc-body-indent.test @@ -0,0 +1,4 @@ +test_expect_success 'here-doc-body-indent' - <<-\EOT + echo "we should find this" + echo "even though our heredoc has its indent stripped" +EOT diff --git a/t/chainlint/here-doc-body-pathological.expect b/t/chainlint/here-doc-body-pathological.expect new file mode 100644 index 0000000000..a93a1fa3aa --- /dev/null +++ b/t/chainlint/here-doc-body-pathological.expect @@ -0,0 +1,7 @@ +2 echo "outer here-doc does not allow indented end-tag" ?!AMP?! +3 cat >file <<-\EOF && +4 but this inner here-doc +5 does allow indented EOF +6 EOF +7 echo "missing chain after" ?!AMP?! +8 echo "but this line is OK because it's the end" diff --git a/t/chainlint/here-doc-body-pathological.test b/t/chainlint/here-doc-body-pathological.test new file mode 100644 index 0000000000..7d2daa44f9 --- /dev/null +++ b/t/chainlint/here-doc-body-pathological.test @@ -0,0 +1,9 @@ +test_expect_success 'here-doc-body-pathological' - <<\EOF + echo "outer here-doc does not allow indented end-tag" + cat >file <<-\EOF && + but this inner here-doc + does allow indented EOF + EOF + echo "missing chain after" + echo "but this line is OK because it's the end" +EOF diff --git a/t/chainlint/here-doc-body.expect b/t/chainlint/here-doc-body.expect new file mode 100644 index 0000000000..ddf1c412af --- /dev/null +++ b/t/chainlint/here-doc-body.expect @@ -0,0 +1,7 @@ +2 echo "missing chain before" ?!AMP?! +3 cat >file <<-\EOF && +4 inside inner here-doc +5 these are not shell commands +6 EOF +7 echo "missing chain after" ?!AMP?! +8 echo "but this line is OK because it's the end" diff --git a/t/chainlint/here-doc-body.test b/t/chainlint/here-doc-body.test new file mode 100644 index 0000000000..989ac2f4e1 --- /dev/null +++ b/t/chainlint/here-doc-body.test @@ -0,0 +1,9 @@ +test_expect_success 'here-doc-body' - <<\EOT + echo "missing chain before" + cat >file <<-\EOF && + inside inner here-doc + these are not shell commands + EOF + echo "missing chain after" + echo "but this line is OK because it's the end" +EOT diff --git a/t/chainlint/here-doc-close-subshell.expect b/t/chainlint/here-doc-close-subshell.expect index 7d9c2b5607..965813f463 100644 --- a/t/chainlint/here-doc-close-subshell.expect +++ b/t/chainlint/here-doc-close-subshell.expect @@ -1,4 +1,4 @@ -( - cat <<-\INPUT) - fizz - INPUT +2 ( +3 cat <<-\INPUT) +4 fizz +5 INPUT diff --git a/t/chainlint/here-doc-close-subshell.test b/t/chainlint/here-doc-close-subshell.test index b857ff5467..2458f3323b 100644 --- a/t/chainlint/here-doc-close-subshell.test +++ b/t/chainlint/here-doc-close-subshell.test @@ -1,5 +1,7 @@ +test_expect_success 'here-doc-close-subshell' ' ( # LINT: line contains here-doc and closes nested subshell cat <<-\INPUT) fizz INPUT +' diff --git a/t/chainlint/here-doc-double.expect b/t/chainlint/here-doc-double.expect new file mode 100644 index 0000000000..20dba4b452 --- /dev/null +++ b/t/chainlint/here-doc-double.expect @@ -0,0 +1,2 @@ +8 echo "actual test commands" ?!AMP?! +9 echo "that should be checked" diff --git a/t/chainlint/here-doc-double.test b/t/chainlint/here-doc-double.test new file mode 100644 index 0000000000..777389f0d9 --- /dev/null +++ b/t/chainlint/here-doc-double.test @@ -0,0 +1,10 @@ +# This is obviously a ridiculous thing to do, but we should be able +# to handle two here-docs on the same line, and attribute them +# correctly. +test_expect_success "$(cat <<END_OF_PREREQS)" 'here-doc-double' - <<\EOT +SOME +PREREQS +END_OF_PREREQS + echo "actual test commands" + echo "that should be checked" +EOT diff --git a/t/chainlint/here-doc-indent-operator.expect b/t/chainlint/here-doc-indent-operator.expect index f92a7ce999..277a11202d 100644 --- a/t/chainlint/here-doc-indent-operator.expect +++ b/t/chainlint/here-doc-indent-operator.expect @@ -1,11 +1,11 @@ -cat >expect <<- EOF && -header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0 -num_commits: $1 -chunks: oid_fanout oid_lookup commit_metadata generation_data bloom_indexes bloom_data -EOF - -cat >expect << -EOF ?!AMP?! -this is not indented --EOF - -cleanup +2 cat >expect <<- EOF && +3 header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0 +4 num_commits: $1 +5 chunks: oid_fanout oid_lookup commit_metadata generation_data bloom_indexes bloom_data +6 EOF +7 +8 cat >expect << -EOF ?!AMP?! +9 this is not indented +10 -EOF +11 +12 cleanup diff --git a/t/chainlint/here-doc-indent-operator.test b/t/chainlint/here-doc-indent-operator.test index c8a6f18eb4..a2656f47c1 100644 --- a/t/chainlint/here-doc-indent-operator.test +++ b/t/chainlint/here-doc-indent-operator.test @@ -1,3 +1,4 @@ +test_expect_success 'here-doc-indent-operator' ' # LINT: whitespace between operator "<<-" and tag legal cat >expect <<- EOF && header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0 @@ -11,3 +12,4 @@ this is not indented -EOF cleanup +' diff --git a/t/chainlint/here-doc-multi-line-command-subst.expect b/t/chainlint/here-doc-multi-line-command-subst.expect index b7364c82c8..41b55f6437 100644 --- a/t/chainlint/here-doc-multi-line-command-subst.expect +++ b/t/chainlint/here-doc-multi-line-command-subst.expect @@ -1,8 +1,8 @@ -( - x=$(bobble <<-\END && - fossil - vegetable - END - wiffle) ?!AMP?! - echo $x -) +2 ( +3 x=$(bobble <<-\END && +4 fossil +5 vegetable +6 END +7 wiffle) ?!AMP?! +8 echo $x +9 ) diff --git a/t/chainlint/here-doc-multi-line-command-subst.test b/t/chainlint/here-doc-multi-line-command-subst.test index 899bc5de8b..8710a8c483 100644 --- a/t/chainlint/here-doc-multi-line-command-subst.test +++ b/t/chainlint/here-doc-multi-line-command-subst.test @@ -1,3 +1,4 @@ +test_expect_success 'here-doc-multi-line-command-subst' ' ( # LINT: line contains here-doc and opens multi-line $(...) x=$(bobble <<-\END && @@ -7,3 +8,4 @@ wiffle) echo $x ) +' diff --git a/t/chainlint/here-doc-multi-line-string.expect b/t/chainlint/here-doc-multi-line-string.expect index 6c13bdcbfb..c71828589e 100644 --- a/t/chainlint/here-doc-multi-line-string.expect +++ b/t/chainlint/here-doc-multi-line-string.expect @@ -1,7 +1,7 @@ -( - cat <<-\TXT && echo "multi-line - string" ?!AMP?! - fizzle - TXT - bap -) +2 ( +3 cat <<-\TXT && echo "multi-line +4 string" ?!AMP?! +5 fizzle +6 TXT +7 bap +8 ) diff --git a/t/chainlint/here-doc-multi-line-string.test b/t/chainlint/here-doc-multi-line-string.test index a53edbcc8d..2f496002fd 100644 --- a/t/chainlint/here-doc-multi-line-string.test +++ b/t/chainlint/here-doc-multi-line-string.test @@ -1,3 +1,4 @@ +test_expect_success 'here-doc-multi-line-string' ' ( # LINT: line contains here-doc and opens multi-line string cat <<-\TXT && echo "multi-line @@ -6,3 +7,4 @@ TXT bap ) +' diff --git a/t/chainlint/here-doc.expect b/t/chainlint/here-doc.expect index 91b961242a..2c382dd8eb 100644 --- a/t/chainlint/here-doc.expect +++ b/t/chainlint/here-doc.expect @@ -1,25 +1,25 @@ -boodle wobba \ - gorgo snoot \ - wafta snurb <<EOF && -quoth the raven, -nevermore... -EOF - -cat <<-Arbitrary_Tag_42 >foo && -snoz -boz -woz -Arbitrary_Tag_42 - -cat <<"zump" >boo && -snoz -boz -woz -zump - -horticulture <<\EOF -gomez -morticia -wednesday -pugsly -EOF +2 boodle wobba \ +3 gorgo snoot \ +4 wafta snurb <<EOF && +5 quoth the raven, +6 nevermore... +7 EOF +8 +9 cat <<-Arbitrary_Tag_42 >foo && +10 snoz +11 boz +12 woz +13 Arbitrary_Tag_42 +14 +15 cat <<"zump" >boo && +16 snoz +17 boz +18 woz +19 zump +20 +21 horticulture <<\EOF +22 gomez +23 morticia +24 wednesday +25 pugsly +26 EOF diff --git a/t/chainlint/here-doc.test b/t/chainlint/here-doc.test index 3f5f92cad3..c91b695319 100644 --- a/t/chainlint/here-doc.test +++ b/t/chainlint/here-doc.test @@ -1,3 +1,4 @@ +test_expect_success 'here-doc' ' # LINT: stitch together incomplete \-ending lines # LINT: swallow here-doc to avoid false positives in content boodle wobba \ @@ -28,3 +29,4 @@ morticia wednesday pugsly EOF +' diff --git a/t/chainlint/if-condition-split.expect b/t/chainlint/if-condition-split.expect index ee745ef8d7..9daf3d294a 100644 --- a/t/chainlint/if-condition-split.expect +++ b/t/chainlint/if-condition-split.expect @@ -1,7 +1,7 @@ -if bob && - marcia || - kevin -then - echo "nomads" ?!AMP?! - echo "for sure" -fi +2 if bob && +3 marcia || +4 kevin +5 then +6 echo "nomads" ?!AMP?! +7 echo "for sure" +8 fi diff --git a/t/chainlint/if-condition-split.test b/t/chainlint/if-condition-split.test index 240daa9fd5..9a3b3ed04a 100644 --- a/t/chainlint/if-condition-split.test +++ b/t/chainlint/if-condition-split.test @@ -1,3 +1,4 @@ +test_expect_success 'if-condition-split' ' # LINT: "if" condition split across multiple lines at "&&" or "||" if bob && marcia || @@ -6,3 +7,4 @@ then echo "nomads" echo "for sure" fi +' diff --git a/t/chainlint/if-in-loop.expect b/t/chainlint/if-in-loop.expect index d6514ae749..ff8c60dbdb 100644 --- a/t/chainlint/if-in-loop.expect +++ b/t/chainlint/if-in-loop.expect @@ -1,12 +1,12 @@ -( - for i in a b c - do - if false - then - echo "err" - exit 1 - fi ?!AMP?! - foo - done ?!AMP?! - bar -) +2 ( +3 for i in a b c +4 do +5 if false +6 then +7 echo "err" +8 exit 1 +9 fi ?!AMP?! +10 foo +11 done ?!AMP?! +12 bar +13 ) diff --git a/t/chainlint/if-in-loop.test b/t/chainlint/if-in-loop.test index 90c23976fe..5be9d1cfa5 100644 --- a/t/chainlint/if-in-loop.test +++ b/t/chainlint/if-in-loop.test @@ -1,3 +1,4 @@ +test_expect_success 'if-in-loop' ' ( for i in a b c do @@ -13,3 +14,4 @@ done bar ) +' diff --git a/t/chainlint/if-then-else.expect b/t/chainlint/if-then-else.expect index cbaaf857d4..965d7e41a2 100644 --- a/t/chainlint/if-then-else.expect +++ b/t/chainlint/if-then-else.expect @@ -1,22 +1,22 @@ -( - if test -n "" - then - echo very ?!AMP?! - echo empty - elif test -z "" - then - echo foo - else - echo foo && - cat <<-\EOF - bar - EOF - fi ?!AMP?! - echo poodle -) && -( - if test -n ""; then - echo very && - echo empty - fi -) +2 ( +3 if test -n "" +4 then +5 echo very ?!AMP?! +6 echo empty +7 elif test -z "" +8 then +9 echo foo +10 else +11 echo foo && +12 cat <<-\EOF +13 bar +14 EOF +15 fi ?!AMP?! +16 echo poodle +17 ) && +18 ( +19 if test -n ""; then +20 echo very && +21 echo empty +22 fi +23 ) diff --git a/t/chainlint/if-then-else.test b/t/chainlint/if-then-else.test index 2055336c2b..6582a7f440 100644 --- a/t/chainlint/if-then-else.test +++ b/t/chainlint/if-then-else.test @@ -1,3 +1,4 @@ +test_expect_success 'if-then-else' ' ( # LINT: "if", "then", "elif", "else", "fi" do not need "&&" if test -n "" @@ -27,3 +28,4 @@ echo empty fi ) +' diff --git a/t/chainlint/incomplete-line.expect b/t/chainlint/incomplete-line.expect index 134d3a14f5..b15e00b901 100644 --- a/t/chainlint/incomplete-line.expect +++ b/t/chainlint/incomplete-line.expect @@ -1,10 +1,10 @@ -line 1 \ -line 2 \ -line 3 \ -line 4 && -( - line 5 \ - line 6 \ - line 7 \ - line 8 -) +2 line 1 \ +3 line 2 \ +4 line 3 \ +5 line 4 && +6 ( +7 line 5 \ +8 line 6 \ +9 line 7 \ +10 line 8 +11 ) diff --git a/t/chainlint/incomplete-line.test b/t/chainlint/incomplete-line.test index d856658083..74a93021eb 100644 --- a/t/chainlint/incomplete-line.test +++ b/t/chainlint/incomplete-line.test @@ -1,3 +1,4 @@ +test_expect_success 'incomplete-line' ' # LINT: stitch together all incomplete \-ending lines line 1 \ line 2 \ @@ -10,3 +11,4 @@ line 4 && line 7 \ line 8 ) +' diff --git a/t/chainlint/inline-comment.expect b/t/chainlint/inline-comment.expect index 6bad218530..0285c0b22c 100644 --- a/t/chainlint/inline-comment.expect +++ b/t/chainlint/inline-comment.expect @@ -1,8 +1,8 @@ -( - foobar && # comment 1 - barfoo ?!AMP?! # wrong position for && - flibble "not a # comment" -) && - -(cd foo && - flibble "not a # comment") +2 ( +3 foobar && # comment 1 +4 barfoo ?!AMP?! # wrong position for && +5 flibble "not a # comment" +6 ) && +7 +8 (cd foo && +9 flibble "not a # comment") diff --git a/t/chainlint/inline-comment.test b/t/chainlint/inline-comment.test index 8f26856e77..4fbbf1058a 100644 --- a/t/chainlint/inline-comment.test +++ b/t/chainlint/inline-comment.test @@ -1,3 +1,4 @@ +test_expect_success 'inline-comment' ' ( # LINT: swallow inline comment (leaving command intact) foobar && # comment 1 @@ -10,3 +11,4 @@ # LINT: "#" in string in cuddled subshell not misinterpreted as comment (cd foo && flibble "not a # comment") +' diff --git a/t/chainlint/loop-detect-failure.expect b/t/chainlint/loop-detect-failure.expect index a66025c39d..40c06f0d53 100644 --- a/t/chainlint/loop-detect-failure.expect +++ b/t/chainlint/loop-detect-failure.expect @@ -1,15 +1,15 @@ -git init r1 && -for n in 1 2 3 4 5 -do - echo "This is file: $n" > r1/file.$n && - git -C r1 add file.$n && - git -C r1 commit -m "$n" || return 1 -done && - -git init r2 && -for n in 1000 10000 -do - printf "%"$n"s" X > r2/large.$n && - git -C r2 add large.$n && - git -C r2 commit -m "$n" ?!LOOP?! -done +2 git init r1 && +3 for n in 1 2 3 4 5 +4 do +5 echo "This is file: $n" > r1/file.$n && +6 git -C r1 add file.$n && +7 git -C r1 commit -m "$n" || return 1 +8 done && +9 +10 git init r2 && +11 for n in 1000 10000 +12 do +13 printf "%"$n"s" X > r2/large.$n && +14 git -C r2 add large.$n && +15 git -C r2 commit -m "$n" ?!LOOP?! +16 done diff --git a/t/chainlint/loop-detect-failure.test b/t/chainlint/loop-detect-failure.test index b9791cc802..44673aa394 100644 --- a/t/chainlint/loop-detect-failure.test +++ b/t/chainlint/loop-detect-failure.test @@ -1,3 +1,4 @@ +test_expect_success 'loop-detect-failure' ' git init r1 && # LINT: loop handles failure explicitly with "|| return 1" for n in 1 2 3 4 5 @@ -15,3 +16,4 @@ do git -C r2 add large.$n && git -C r2 commit -m "$n" done +' diff --git a/t/chainlint/loop-detect-status.expect b/t/chainlint/loop-detect-status.expect index 7ce3a34806..0f180b08de 100644 --- a/t/chainlint/loop-detect-status.expect +++ b/t/chainlint/loop-detect-status.expect @@ -1,18 +1,18 @@ -(while test $i -le $blobcount - do - printf "Generating blob $i/$blobcount\r" >&2 && - printf "blob\nmark :$i\ndata $blobsize\n" && - #test-tool genrandom $i $blobsize && - printf "%-${blobsize}s" $i && - echo "M 100644 :$i $i" >> commit && - i=$(($i+1)) || - echo $? > exit-status - done && - echo "commit refs/heads/main" && - echo "author A U Thor <author@email.com> 123456789 +0000" && - echo "committer C O Mitter <committer@email.com> 123456789 +0000" && - echo "data 5" && - echo ">2gb" && - cat commit) | -git fast-import --big-file-threshold=2 && -test ! -f exit-status +2 (while test $i -le $blobcount +3 do +4 printf "Generating blob $i/$blobcount\r" >&2 && +5 printf "blob\nmark :$i\ndata $blobsize\n" && +6 #test-tool genrandom $i $blobsize && +7 printf "%-${blobsize}s" $i && +8 echo "M 100644 :$i $i" >> commit && +9 i=$(($i+1)) || +10 echo $? > exit-status +11 done && +12 echo "commit refs/heads/main" && +13 echo "author A U Thor <author@email.com> 123456789 +0000" && +14 echo "committer C O Mitter <committer@email.com> 123456789 +0000" && +15 echo "data 5" && +16 echo ">2gb" && +17 cat commit) | +18 git fast-import --big-file-threshold=2 && +19 test ! -f exit-status diff --git a/t/chainlint/loop-detect-status.test b/t/chainlint/loop-detect-status.test index 1c6c23cfc9..8b639be073 100644 --- a/t/chainlint/loop-detect-status.test +++ b/t/chainlint/loop-detect-status.test @@ -1,3 +1,4 @@ +test_expect_success 'loop-detect-status' ' # LINT: "$?" handled explicitly within loop body (while test $i -le $blobcount do @@ -17,3 +18,4 @@ cat commit) | git fast-import --big-file-threshold=2 && test ! -f exit-status +' diff --git a/t/chainlint/loop-in-if.expect b/t/chainlint/loop-in-if.expect index 6c5d6e5b24..4e8c67c914 100644 --- a/t/chainlint/loop-in-if.expect +++ b/t/chainlint/loop-in-if.expect @@ -1,12 +1,12 @@ -( - if true - then - while true - do - echo "pop" ?!AMP?! - echo "glup" ?!LOOP?! - done ?!AMP?! - foo - fi ?!AMP?! - bar -) +2 ( +3 if true +4 then +5 while true +6 do +7 echo "pop" ?!AMP?! +8 echo "glup" ?!LOOP?! +9 done ?!AMP?! +10 foo +11 fi ?!AMP?! +12 bar +13 ) diff --git a/t/chainlint/loop-in-if.test b/t/chainlint/loop-in-if.test index dfcc3f98fb..b0d0d393cf 100644 --- a/t/chainlint/loop-in-if.test +++ b/t/chainlint/loop-in-if.test @@ -1,3 +1,4 @@ +test_expect_success 'loop-in-if' ' ( if true then @@ -13,3 +14,4 @@ fi bar ) +' diff --git a/t/chainlint/loop-upstream-pipe.expect b/t/chainlint/loop-upstream-pipe.expect index 0b82ecc4b9..bef82479ca 100644 --- a/t/chainlint/loop-upstream-pipe.expect +++ b/t/chainlint/loop-upstream-pipe.expect @@ -1,10 +1,10 @@ -( - git rev-list --objects --no-object-names base..loose | - while read oid - do - path="$objdir/$(test_oid_to_path "$oid")" && - printf "%s %d\n" "$oid" "$(test-tool chmtime --get "$path")" || - echo "object list generation failed for $oid" - done | - sort -k1 -) >expect && +2 ( +3 git rev-list --objects --no-object-names base..loose | +4 while read oid +5 do +6 path="$objdir/$(test_oid_to_path "$oid")" && +7 printf "%s %d\n" "$oid" "$(test-tool chmtime --get "$path")" || +8 echo "object list generation failed for $oid" +9 done | +10 sort -k1 +11 ) >expect && diff --git a/t/chainlint/loop-upstream-pipe.test b/t/chainlint/loop-upstream-pipe.test index efb77da897..8415a4db27 100644 --- a/t/chainlint/loop-upstream-pipe.test +++ b/t/chainlint/loop-upstream-pipe.test @@ -1,3 +1,4 @@ +test_expect_success 'loop-upstream-pipe' ' ( git rev-list --objects --no-object-names base..loose | while read oid @@ -9,3 +10,4 @@ done | sort -k1 ) >expect && +' diff --git a/t/chainlint/multi-line-nested-command-substitution.expect b/t/chainlint/multi-line-nested-command-substitution.expect index 300058341b..ad27e43e05 100644 --- a/t/chainlint/multi-line-nested-command-substitution.expect +++ b/t/chainlint/multi-line-nested-command-substitution.expect @@ -1,18 +1,18 @@ -( - foo && - x=$( - echo bar | - cat - ) && - echo ok -) | -sort && -( - bar && - x=$(echo bar | - cat - ) && - y=$(echo baz | - fip) && - echo fail -) +2 ( +3 foo && +4 x=$( +5 echo bar | +6 cat +7 ) && +8 echo ok +9 ) | +10 sort && +11 ( +12 bar && +13 x=$(echo bar | +14 cat +15 ) && +16 y=$(echo baz | +17 fip) && +18 echo fail +19 ) diff --git a/t/chainlint/multi-line-nested-command-substitution.test b/t/chainlint/multi-line-nested-command-substitution.test index 300058341b..e811c63f2b 100644 --- a/t/chainlint/multi-line-nested-command-substitution.test +++ b/t/chainlint/multi-line-nested-command-substitution.test @@ -1,3 +1,4 @@ +test_expect_success 'multi-line-nested-command-substitution' ' ( foo && x=$( @@ -16,3 +17,4 @@ sort && fip) && echo fail ) +' diff --git a/t/chainlint/multi-line-string.expect b/t/chainlint/multi-line-string.expect index 27ff95218e..62c54e3a5e 100644 --- a/t/chainlint/multi-line-string.expect +++ b/t/chainlint/multi-line-string.expect @@ -1,14 +1,14 @@ -( - x="line 1 - line 2 - line 3" && - y="line 1 - line2" ?!AMP?! - foobar -) && -( - echo "xyz" "abc - def - ghi" && - barfoo -) +2 ( +3 x="line 1 +4 line 2 +5 line 3" && +6 y="line 1 +7 line2" ?!AMP?! +8 foobar +9 ) && +10 ( +11 echo "xyz" "abc +12 def +13 ghi" && +14 barfoo +15 ) diff --git a/t/chainlint/multi-line-string.test b/t/chainlint/multi-line-string.test index 4a0af2107d..7b5048d2ea 100644 --- a/t/chainlint/multi-line-string.test +++ b/t/chainlint/multi-line-string.test @@ -1,3 +1,4 @@ +test_expect_success 'multi-line-string' ' ( x="line 1 line 2 @@ -13,3 +14,4 @@ ghi" && barfoo ) +' diff --git a/t/chainlint/negated-one-liner.expect b/t/chainlint/negated-one-liner.expect index ad4c2d949e..a6ce52a1da 100644 --- a/t/chainlint/negated-one-liner.expect +++ b/t/chainlint/negated-one-liner.expect @@ -1,5 +1,5 @@ -! (foo && bar) && -! (foo && bar) >baz && - -! (foo; ?!AMP?! bar) && -! (foo; ?!AMP?! bar) >baz +2 ! (foo && bar) && +3 ! (foo && bar) >baz && +4 +5 ! (foo; ?!AMP?! bar) && +6 ! (foo; ?!AMP?! bar) >baz diff --git a/t/chainlint/negated-one-liner.test b/t/chainlint/negated-one-liner.test index c9598e9153..30f4cc5a9b 100644 --- a/t/chainlint/negated-one-liner.test +++ b/t/chainlint/negated-one-liner.test @@ -1,3 +1,4 @@ +test_expect_success 'negated-one-liner' ' # LINT: top-level one-liner subshell ! (foo && bar) && ! (foo && bar) >baz && @@ -5,3 +6,4 @@ # LINT: top-level one-liner subshell missing internal "&&" ! (foo; bar) && ! (foo; bar) >baz +' diff --git a/t/chainlint/nested-cuddled-subshell.expect b/t/chainlint/nested-cuddled-subshell.expect index 3836049cc4..0191c9c294 100644 --- a/t/chainlint/nested-cuddled-subshell.expect +++ b/t/chainlint/nested-cuddled-subshell.expect @@ -1,25 +1,25 @@ -( - (cd foo && - bar - ) && - - (cd foo && - bar - ) ?!AMP?! - - ( - cd foo && - bar) && - - ( - cd foo && - bar) ?!AMP?! - - (cd foo && - bar) && - - (cd foo && - bar) ?!AMP?! - - foobar -) +2 ( +3 (cd foo && +4 bar +5 ) && +6 +7 (cd foo && +8 bar +9 ) ?!AMP?! +10 +11 ( +12 cd foo && +13 bar) && +14 +15 ( +16 cd foo && +17 bar) ?!AMP?! +18 +19 (cd foo && +20 bar) && +21 +22 (cd foo && +23 bar) ?!AMP?! +24 +25 foobar +26 ) diff --git a/t/chainlint/nested-cuddled-subshell.test b/t/chainlint/nested-cuddled-subshell.test index 8fd656c7b5..31e92d3be4 100644 --- a/t/chainlint/nested-cuddled-subshell.test +++ b/t/chainlint/nested-cuddled-subshell.test @@ -1,3 +1,4 @@ +test_expect_success 'nested-cuddled-subshell' ' ( # LINT: opening "(" cuddled with first nested subshell statement (cd foo && @@ -29,3 +30,4 @@ foobar ) +' diff --git a/t/chainlint/nested-here-doc.expect b/t/chainlint/nested-here-doc.expect index 29b3832a98..70d9b68dc9 100644 --- a/t/chainlint/nested-here-doc.expect +++ b/t/chainlint/nested-here-doc.expect @@ -1,30 +1,30 @@ -cat <<ARBITRARY >foop && -naddle -fub <<EOF - nozzle - noodle -EOF -formp -ARBITRARY - -( - cat <<-\INPUT_END && - fish are mice - but geese go slow - data <<EOF - perl is lerp - and nothing else - EOF - toink - INPUT_END - - cat <<-\EOT ?!AMP?! - text goes here - data <<EOF - data goes here - EOF - more test here - EOT - - foobar -) +2 cat <<ARBITRARY >foop && +3 naddle +4 fub <<EOF +5 nozzle +6 noodle +7 EOF +8 formp +9 ARBITRARY +10 +11 ( +12 cat <<-\INPUT_END && +13 fish are mice +14 but geese go slow +15 data <<EOF +16 perl is lerp +17 and nothing else +18 EOF +19 toink +20 INPUT_END +21 +22 cat <<-\EOT ?!AMP?! +23 text goes here +24 data <<EOF +25 data goes here +26 EOF +27 more test here +28 EOT +29 +30 foobar +31 ) diff --git a/t/chainlint/nested-here-doc.test b/t/chainlint/nested-here-doc.test index f35404bf0f..9505c47a34 100644 --- a/t/chainlint/nested-here-doc.test +++ b/t/chainlint/nested-here-doc.test @@ -1,3 +1,4 @@ +test_expect_success 'nested-here-doc' ' # LINT: inner "EOF" not misintrepreted as closing ARBITRARY here-doc cat <<ARBITRARY >foop && naddle @@ -31,3 +32,4 @@ ARBITRARY foobar ) +' diff --git a/t/chainlint/nested-loop-detect-failure.expect b/t/chainlint/nested-loop-detect-failure.expect index 3461df40e5..c13c4d2f90 100644 --- a/t/chainlint/nested-loop-detect-failure.expect +++ b/t/chainlint/nested-loop-detect-failure.expect @@ -1,31 +1,31 @@ -for i in 0 1 2 3 4 5 6 7 8 9; -do - for j in 0 1 2 3 4 5 6 7 8 9; - do - echo "$i$j" >"path$i$j" ?!LOOP?! - done ?!LOOP?! -done && - -for i in 0 1 2 3 4 5 6 7 8 9; -do - for j in 0 1 2 3 4 5 6 7 8 9; - do - echo "$i$j" >"path$i$j" || return 1 - done -done && - -for i in 0 1 2 3 4 5 6 7 8 9; -do - for j in 0 1 2 3 4 5 6 7 8 9; - do - echo "$i$j" >"path$i$j" ?!LOOP?! - done || return 1 -done && - -for i in 0 1 2 3 4 5 6 7 8 9; -do - for j in 0 1 2 3 4 5 6 7 8 9; - do - echo "$i$j" >"path$i$j" || return 1 - done || return 1 -done +2 for i in 0 1 2 3 4 5 6 7 8 9; +3 do +4 for j in 0 1 2 3 4 5 6 7 8 9; +5 do +6 echo "$i$j" >"path$i$j" ?!LOOP?! +7 done ?!LOOP?! +8 done && +9 +10 for i in 0 1 2 3 4 5 6 7 8 9; +11 do +12 for j in 0 1 2 3 4 5 6 7 8 9; +13 do +14 echo "$i$j" >"path$i$j" || return 1 +15 done +16 done && +17 +18 for i in 0 1 2 3 4 5 6 7 8 9; +19 do +20 for j in 0 1 2 3 4 5 6 7 8 9; +21 do +22 echo "$i$j" >"path$i$j" ?!LOOP?! +23 done || return 1 +24 done && +25 +26 for i in 0 1 2 3 4 5 6 7 8 9; +27 do +28 for j in 0 1 2 3 4 5 6 7 8 9; +29 do +30 echo "$i$j" >"path$i$j" || return 1 +31 done || return 1 +32 done diff --git a/t/chainlint/nested-loop-detect-failure.test b/t/chainlint/nested-loop-detect-failure.test index e6f0c1acfb..3d4b657412 100644 --- a/t/chainlint/nested-loop-detect-failure.test +++ b/t/chainlint/nested-loop-detect-failure.test @@ -1,3 +1,4 @@ +test_expect_success 'nested-loop-detect-failure' ' # LINT: neither loop handles failure explicitly with "|| return 1" for i in 0 1 2 3 4 5 6 7 8 9; do @@ -33,3 +34,4 @@ do echo "$i$j" >"path$i$j" || return 1 done || return 1 done +' diff --git a/t/chainlint/nested-subshell-comment.expect b/t/chainlint/nested-subshell-comment.expect index 9138cf386d..f89a8d03a8 100644 --- a/t/chainlint/nested-subshell-comment.expect +++ b/t/chainlint/nested-subshell-comment.expect @@ -1,11 +1,11 @@ -( - foo && - ( - bar && - # bottles wobble while fiddles gobble - # minor numbers of cows (or do they?) - baz && - snaff - ) ?!AMP?! - fuzzy -) +2 ( +3 foo && +4 ( +5 bar && +6 # bottles wobble while fiddles gobble +7 # minor numbers of cows (or do they?) +8 baz && +9 snaff +10 ) ?!AMP?! +11 fuzzy +12 ) diff --git a/t/chainlint/nested-subshell-comment.test b/t/chainlint/nested-subshell-comment.test index 0215cdb192..b430580ce0 100644 --- a/t/chainlint/nested-subshell-comment.test +++ b/t/chainlint/nested-subshell-comment.test @@ -1,3 +1,4 @@ +test_expect_success 'nested-subshell-comment' ' ( foo && ( @@ -11,3 +12,4 @@ ) fuzzy ) +' diff --git a/t/chainlint/nested-subshell.expect b/t/chainlint/nested-subshell.expect index 73ff28546a..811e8a7912 100644 --- a/t/chainlint/nested-subshell.expect +++ b/t/chainlint/nested-subshell.expect @@ -1,13 +1,13 @@ -( - cd foo && - ( - echo a && - echo b - ) >file && - - cd foo && - ( - echo a ?!AMP?! - echo b - ) >file -) +2 ( +3 cd foo && +4 ( +5 echo a && +6 echo b +7 ) >file && +8 +9 cd foo && +10 ( +11 echo a ?!AMP?! +12 echo b +13 ) >file +14 ) diff --git a/t/chainlint/nested-subshell.test b/t/chainlint/nested-subshell.test index 440ee9992d..c31da34b73 100644 --- a/t/chainlint/nested-subshell.test +++ b/t/chainlint/nested-subshell.test @@ -1,3 +1,4 @@ +test_expect_success 'nested-subshell' ' ( cd foo && ( @@ -11,3 +12,4 @@ echo b ) >file ) +' diff --git a/t/chainlint/not-heredoc.expect b/t/chainlint/not-heredoc.expect index 2e9bb135fe..611b7b75cb 100644 --- a/t/chainlint/not-heredoc.expect +++ b/t/chainlint/not-heredoc.expect @@ -1,14 +1,14 @@ -echo "<<<<<<< ours" && -echo ourside && -echo "=======" && -echo theirside && -echo ">>>>>>> theirs" && - -( - echo "<<<<<<< ours" && - echo ourside && - echo "=======" && - echo theirside && - echo ">>>>>>> theirs" ?!AMP?! - poodle -) >merged +2 echo "<<<<<<< ours" && +3 echo ourside && +4 echo "=======" && +5 echo theirside && +6 echo ">>>>>>> theirs" && +7 +8 ( +9 echo "<<<<<<< ours" && +10 echo ourside && +11 echo "=======" && +12 echo theirside && +13 echo ">>>>>>> theirs" ?!AMP?! +14 poodle +15 ) >merged diff --git a/t/chainlint/not-heredoc.test b/t/chainlint/not-heredoc.test index 9aa57346cd..09711e45e0 100644 --- a/t/chainlint/not-heredoc.test +++ b/t/chainlint/not-heredoc.test @@ -1,3 +1,4 @@ +test_expect_success 'not-heredoc' ' # LINT: "<< ours" inside string is not here-doc echo "<<<<<<< ours" && echo ourside && @@ -14,3 +15,4 @@ echo ">>>>>>> theirs" && echo ">>>>>>> theirs" poodle ) >merged +' diff --git a/t/chainlint/one-liner-for-loop.expect b/t/chainlint/one-liner-for-loop.expect index 51a3dc7c54..49dcf065ef 100644 --- a/t/chainlint/one-liner-for-loop.expect +++ b/t/chainlint/one-liner-for-loop.expect @@ -1,9 +1,9 @@ -git init dir-rename-and-content && -( - cd dir-rename-and-content && - test_write_lines 1 2 3 4 5 >foo && - mkdir olddir && - for i in a b c; do echo $i >olddir/$i; ?!LOOP?! done ?!AMP?! - git add foo olddir && - git commit -m "original" && -) +2 git init dir-rename-and-content && +3 ( +4 cd dir-rename-and-content && +5 test_write_lines 1 2 3 4 5 >foo && +6 mkdir olddir && +7 for i in a b c; do echo $i >olddir/$i; ?!LOOP?! done ?!AMP?! +8 git add foo olddir && +9 git commit -m "original" && +10 ) diff --git a/t/chainlint/one-liner-for-loop.test b/t/chainlint/one-liner-for-loop.test index 4bd8c066c7..00afd7ef76 100644 --- a/t/chainlint/one-liner-for-loop.test +++ b/t/chainlint/one-liner-for-loop.test @@ -1,3 +1,4 @@ +test_expect_success 'one-liner-for-loop' ' git init dir-rename-and-content && ( cd dir-rename-and-content && @@ -8,3 +9,4 @@ git init dir-rename-and-content && git add foo olddir && git commit -m "original" && ) +' diff --git a/t/chainlint/one-liner.expect b/t/chainlint/one-liner.expect index 57a7a444c1..9861811283 100644 --- a/t/chainlint/one-liner.expect +++ b/t/chainlint/one-liner.expect @@ -1,9 +1,9 @@ -(foo && bar) && -(foo && bar) | -(foo && bar) >baz && - -(foo; ?!AMP?! bar) && -(foo; ?!AMP?! bar) | -(foo; ?!AMP?! bar) >baz && - -(foo "bar; baz") +2 (foo && bar) && +3 (foo && bar) | +4 (foo && bar) >baz && +5 +6 (foo; ?!AMP?! bar) && +7 (foo; ?!AMP?! bar) | +8 (foo; ?!AMP?! bar) >baz && +9 +10 (foo "bar; baz") diff --git a/t/chainlint/one-liner.test b/t/chainlint/one-liner.test index be9858fa29..6e42ee1b5e 100644 --- a/t/chainlint/one-liner.test +++ b/t/chainlint/one-liner.test @@ -1,3 +1,4 @@ +test_expect_success 'one-liner' ' # LINT: top-level one-liner subshell (foo && bar) && (foo && bar) | @@ -10,3 +11,4 @@ # LINT: ";" in string not misinterpreted as broken &&-chain (foo "bar; baz") +' diff --git a/t/chainlint/p4-filespec.expect b/t/chainlint/p4-filespec.expect index 1290fd1ff2..cff3e4e3d1 100644 --- a/t/chainlint/p4-filespec.expect +++ b/t/chainlint/p4-filespec.expect @@ -1,4 +1,4 @@ -( - p4 print -1 //depot/fiddle#42 >file && - foobar -) +2 ( +3 p4 print -1 //depot/fiddle#42 >file && +4 foobar +5 ) diff --git a/t/chainlint/p4-filespec.test b/t/chainlint/p4-filespec.test index 4fd2d6e2b8..8ba6b911dc 100644 --- a/t/chainlint/p4-filespec.test +++ b/t/chainlint/p4-filespec.test @@ -1,5 +1,7 @@ +test_expect_success 'p4-filespec' ' ( # LINT: Perforce revspec in filespec not misinterpreted as in-line comment p4 print -1 //depot/fiddle#42 >file && foobar ) +' diff --git a/t/chainlint/pipe.expect b/t/chainlint/pipe.expect index 811971b1a3..1bbe5a2ce1 100644 --- a/t/chainlint/pipe.expect +++ b/t/chainlint/pipe.expect @@ -1,10 +1,10 @@ -( - foo | - bar | - baz && - - fish | - cow ?!AMP?! - - sunder -) +2 ( +3 foo | +4 bar | +5 baz && +6 +7 fish | +8 cow ?!AMP?! +9 +10 sunder +11 ) diff --git a/t/chainlint/pipe.test b/t/chainlint/pipe.test index dd82534c66..1af81c243b 100644 --- a/t/chainlint/pipe.test +++ b/t/chainlint/pipe.test @@ -1,3 +1,4 @@ +test_expect_success 'pipe' ' ( # LINT: no "&&" needed on line ending with "|" foo | @@ -10,3 +11,4 @@ sunder ) +' diff --git a/t/chainlint/return-loop.expect b/t/chainlint/return-loop.expect index cfc0549bef..da8f9abea3 100644 --- a/t/chainlint/return-loop.expect +++ b/t/chainlint/return-loop.expect @@ -1,5 +1,5 @@ -while test $i -lt $((num - 5)) -do - git notes add -m "notes for commit$i" HEAD~$i || return 1 - i=$((i + 1)) -done +2 while test $i -lt $((num - 5)) +3 do +4 git notes add -m "notes for commit$i" HEAD~$i || return 1 +5 i=$((i + 1)) +6 done diff --git a/t/chainlint/return-loop.test b/t/chainlint/return-loop.test index f90b171300..ea76c3593a 100644 --- a/t/chainlint/return-loop.test +++ b/t/chainlint/return-loop.test @@ -1,6 +1,8 @@ +test_expect_success 'return-loop' ' while test $i -lt $((num - 5)) do # LINT: "|| return {n}" valid loop escape outside subshell; no "&&" needed git notes add -m "notes for commit$i" HEAD~$i || return 1 i=$((i + 1)) done +' diff --git a/t/chainlint/semicolon.expect b/t/chainlint/semicolon.expect index 3aa2259f36..866438310c 100644 --- a/t/chainlint/semicolon.expect +++ b/t/chainlint/semicolon.expect @@ -1,19 +1,19 @@ -( - cat foo ; ?!AMP?! echo bar ?!AMP?! - cat foo ; ?!AMP?! echo bar -) && -( - cat foo ; ?!AMP?! echo bar && - cat foo ; ?!AMP?! echo bar -) && -( - echo "foo; bar" && - cat foo; ?!AMP?! echo bar -) && -( - foo; -) && -(cd foo && - for i in a b c; do - echo; ?!LOOP?! - done) +2 ( +3 cat foo ; ?!AMP?! echo bar ?!AMP?! +4 cat foo ; ?!AMP?! echo bar +5 ) && +6 ( +7 cat foo ; ?!AMP?! echo bar && +8 cat foo ; ?!AMP?! echo bar +9 ) && +10 ( +11 echo "foo; bar" && +12 cat foo; ?!AMP?! echo bar +13 ) && +14 ( +15 foo; +16 ) && +17 (cd foo && +18 for i in a b c; do +19 echo; ?!LOOP?! +20 done) diff --git a/t/chainlint/semicolon.test b/t/chainlint/semicolon.test index 67e1192c50..fc0ba1b539 100644 --- a/t/chainlint/semicolon.test +++ b/t/chainlint/semicolon.test @@ -1,3 +1,4 @@ +test_expect_success 'semicolon' ' ( # LINT: missing internal "&&" and ending "&&" cat foo ; echo bar @@ -23,3 +24,4 @@ # LINT: semicolon unnecessary but legitimate echo; done) +' diff --git a/t/chainlint/sqstring-in-sqstring.expect b/t/chainlint/sqstring-in-sqstring.expect index cf0b591cf7..ba5d3c3a6d 100644 --- a/t/chainlint/sqstring-in-sqstring.expect +++ b/t/chainlint/sqstring-in-sqstring.expect @@ -1,4 +1,4 @@ -perl -e ' - defined($_ = -s $_) or die for @ARGV; - exit 1 if $ARGV[0] <= $ARGV[1]; -' test-2-$packname_2.pack test-3-$packname_3.pack +2 perl -e ' +3 defined($_ = -s $_) or die for @ARGV; +4 exit 1 if $ARGV[0] <= $ARGV[1]; +5 ' test-2-$packname_2.pack test-3-$packname_3.pack diff --git a/t/chainlint/sqstring-in-sqstring.test b/t/chainlint/sqstring-in-sqstring.test index 77a425e0c7..24169724a5 100644 --- a/t/chainlint/sqstring-in-sqstring.test +++ b/t/chainlint/sqstring-in-sqstring.test @@ -1,5 +1,7 @@ +test_expect_success 'sqstring-in-sqstring' ' # LINT: SQ-string Perl code fragment within SQ-string perl -e '\'' defined($_ = -s $_) or die for @ARGV; exit 1 if $ARGV[0] <= $ARGV[1]; '\'' test-2-$packname_2.pack test-3-$packname_3.pack +' diff --git a/t/chainlint/subshell-here-doc.expect b/t/chainlint/subshell-here-doc.expect index 75d6f607e2..5647500c82 100644 --- a/t/chainlint/subshell-here-doc.expect +++ b/t/chainlint/subshell-here-doc.expect @@ -1,30 +1,30 @@ -( - echo wobba \ - gorgo snoot \ - wafta snurb <<-EOF && - quoth the raven, - nevermore... - EOF - - cat <<EOF >bip ?!AMP?! - fish fly high -EOF - - echo <<-\EOF >bop - gomez - morticia - wednesday - pugsly - EOF -) && -( - cat <<-\ARBITRARY >bup && - glink - FIZZ - ARBITRARY - cat <<-"ARBITRARY3" >bup3 && - glink - FIZZ - ARBITRARY3 - meep -) +2 ( +3 echo wobba \ +4 gorgo snoot \ +5 wafta snurb <<-EOF && +6 quoth the raven, +7 nevermore... +8 EOF +9 +10 cat <<EOF >bip ?!AMP?! +11 fish fly high +12 EOF +13 +14 echo <<-\EOF >bop +15 gomez +16 morticia +17 wednesday +18 pugsly +19 EOF +20 ) && +21 ( +22 cat <<-\ARBITRARY >bup && +23 glink +24 FIZZ +25 ARBITRARY +26 cat <<-"ARBITRARY3" >bup3 && +27 glink +28 FIZZ +29 ARBITRARY3 +30 meep +31 ) diff --git a/t/chainlint/subshell-here-doc.test b/t/chainlint/subshell-here-doc.test index d40eb65583..4a38f47f01 100644 --- a/t/chainlint/subshell-here-doc.test +++ b/t/chainlint/subshell-here-doc.test @@ -1,3 +1,4 @@ +test_expect_success 'subshell-here-doc' ' ( # LINT: stitch together incomplete \-ending lines # LINT: swallow here-doc to avoid false positives in content @@ -33,3 +34,4 @@ EOF ARBITRARY3 meep ) +' diff --git a/t/chainlint/subshell-one-liner.expect b/t/chainlint/subshell-one-liner.expect index 8f694990e8..214316c6a0 100644 --- a/t/chainlint/subshell-one-liner.expect +++ b/t/chainlint/subshell-one-liner.expect @@ -1,19 +1,19 @@ -( - (foo && bar) && - (foo && bar) | - (foo && bar) >baz && - - (foo; ?!AMP?! bar) && - (foo; ?!AMP?! bar) | - (foo; ?!AMP?! bar) >baz && - - (foo || exit 1) && - (foo || exit 1) | - (foo || exit 1) >baz && - - (foo && bar) ?!AMP?! - - (foo && bar; ?!AMP?! baz) ?!AMP?! - - foobar -) +2 ( +3 (foo && bar) && +4 (foo && bar) | +5 (foo && bar) >baz && +6 +7 (foo; ?!AMP?! bar) && +8 (foo; ?!AMP?! bar) | +9 (foo; ?!AMP?! bar) >baz && +10 +11 (foo || exit 1) && +12 (foo || exit 1) | +13 (foo || exit 1) >baz && +14 +15 (foo && bar) ?!AMP?! +16 +17 (foo && bar; ?!AMP?! baz) ?!AMP?! +18 +19 foobar +20 ) diff --git a/t/chainlint/subshell-one-liner.test b/t/chainlint/subshell-one-liner.test index 37fa643c20..dac536afcc 100644 --- a/t/chainlint/subshell-one-liner.test +++ b/t/chainlint/subshell-one-liner.test @@ -1,3 +1,4 @@ +test_expect_success 'subshell-one-liner' ' ( # LINT: nested one-liner subshell (foo && bar) && @@ -22,3 +23,4 @@ foobar ) +' diff --git a/t/chainlint/t7900-subtree.expect b/t/chainlint/t7900-subtree.expect index 02f3129232..9e60338bcf 100644 --- a/t/chainlint/t7900-subtree.expect +++ b/t/chainlint/t7900-subtree.expect @@ -1,22 +1,22 @@ -( - chks="sub1 -sub2 -sub3 -sub4" && - chks_sub=$(cat <<TXT | sed "s,^,sub dir/," -$chks -TXT -) && - chkms="main-sub1 -main-sub2 -main-sub3 -main-sub4" && - chkms_sub=$(cat <<TXT | sed "s,^,sub dir/," -$chkms -TXT -) && - - subfiles=$(git ls-files) && - check_equal "$subfiles" "$chkms -$chks" -) +2 ( +3 chks="sub1 +4 sub2 +5 sub3 +6 sub4" && +7 chks_sub=$(cat <<TXT | sed "s,^,sub dir/," +8 $chks +9 TXT +10 ) && +11 chkms="main-sub1 +12 main-sub2 +13 main-sub3 +14 main-sub4" && +15 chkms_sub=$(cat <<TXT | sed "s,^,sub dir/," +16 $chkms +17 TXT +18 ) && +19 +20 subfiles=$(git ls-files) && +21 check_equal "$subfiles" "$chkms +22 $chks" +23 ) diff --git a/t/chainlint/t7900-subtree.test b/t/chainlint/t7900-subtree.test index 02f3129232..1f4f03300f 100644 --- a/t/chainlint/t7900-subtree.test +++ b/t/chainlint/t7900-subtree.test @@ -1,3 +1,4 @@ +test_expect_success 't7900-subtree' ' ( chks="sub1 sub2 @@ -20,3 +21,4 @@ TXT check_equal "$subfiles" "$chkms $chks" ) +' diff --git a/t/chainlint/token-pasting.expect b/t/chainlint/token-pasting.expect index 6a387917a7..64f3235d26 100644 --- a/t/chainlint/token-pasting.expect +++ b/t/chainlint/token-pasting.expect @@ -1,27 +1,27 @@ -git config filter.rot13.smudge ./rot13.sh && -git config filter.rot13.clean ./rot13.sh && - -{ - echo "*.t filter=rot13" ?!AMP?! - echo "*.i ident" -} >.gitattributes && - -{ - echo a b c d e f g h i j k l m ?!AMP?! - echo n o p q r s t u v w x y z ?!AMP?! - echo '$Id$' -} >test && -cat test >test.t && -cat test >test.o && -cat test >test.i && -git add test test.t test.i && -rm -f test test.t test.i && -git checkout -- test test.t test.i && - -echo "content-test2" >test2.o && -echo "content-test3 - filename with special characters" >"test3 'sq',$x=.o" ?!AMP?! - -downstream_url_for_sed=$( - printf "%sn" "$downstream_url" | - sed -e 's/\/\\/g' -e 's/[[/.*^$]/\&/g' -) +2 git config filter.rot13.smudge ./rot13.sh && +3 git config filter.rot13.clean ./rot13.sh && +4 +5 { +6 echo "*.t filter=rot13" ?!AMP?! +7 echo "*.i ident" +8 } >.gitattributes && +9 +10 { +11 echo a b c d e f g h i j k l m ?!AMP?! +12 echo n o p q r s t u v w x y z ?!AMP?! +13 echo '$Id$' +14 } >test && +15 cat test >test.t && +16 cat test >test.o && +17 cat test >test.i && +18 git add test test.t test.i && +19 rm -f test test.t test.i && +20 git checkout -- test test.t test.i && +21 +22 echo "content-test2" >test2.o && +23 echo "content-test3 - filename with special characters" >"test3 'sq',$x=.o" ?!AMP?! +24 +25 downstream_url_for_sed=$( +26 printf "%sn" "$downstream_url" | +27 sed -e 's/\/\\/g' -e 's/[[/.*^$]/\&/g' +28 ) diff --git a/t/chainlint/token-pasting.test b/t/chainlint/token-pasting.test index b4610ce815..590914b733 100644 --- a/t/chainlint/token-pasting.test +++ b/t/chainlint/token-pasting.test @@ -1,3 +1,4 @@ +test_expect_success 'token-pasting' ' # LINT: single token; composite of multiple strings git config filter.rot13.smudge ./rot13.sh && git config filter.rot13.clean ./rot13.sh && @@ -30,3 +31,4 @@ downstream_url_for_sed=$( # LINT: exit/enter string context; "&" inside string not command terminator sed -e '\''s/\\/\\\\/g'\'' -e '\''s/[[/.*^$]/\\&/g'\'' ) +' diff --git a/t/chainlint/unclosed-here-doc-indent.expect b/t/chainlint/unclosed-here-doc-indent.expect index 7c30a1a024..f78e23cb63 100644 --- a/t/chainlint/unclosed-here-doc-indent.expect +++ b/t/chainlint/unclosed-here-doc-indent.expect @@ -1,4 +1,4 @@ -command_which_is_run && -cat >expect <<-\EOF ?!UNCLOSED-HEREDOC?! && -we forget to end the here-doc -command_which_is_gobbled +2 command_which_is_run && +3 cat >expect <<-\EOF ?!UNCLOSED-HEREDOC?! && +4 we forget to end the here-doc +5 command_which_is_gobbled diff --git a/t/chainlint/unclosed-here-doc-indent.test b/t/chainlint/unclosed-here-doc-indent.test index 5c841a9dfd..7ac9d0f7d7 100644 --- a/t/chainlint/unclosed-here-doc-indent.test +++ b/t/chainlint/unclosed-here-doc-indent.test @@ -1,4 +1,6 @@ +test_expect_success 'unclosed-here-doc-indent' ' command_which_is_run && cat >expect <<-\EOF && we forget to end the here-doc command_which_is_gobbled +' diff --git a/t/chainlint/unclosed-here-doc.expect b/t/chainlint/unclosed-here-doc.expect index d65e50f78d..51304672cf 100644 --- a/t/chainlint/unclosed-here-doc.expect +++ b/t/chainlint/unclosed-here-doc.expect @@ -1,7 +1,7 @@ -command_which_is_run && -cat >expect <<\EOF ?!UNCLOSED-HEREDOC?! && - we try to end the here-doc below, - but the indentation throws us off - since the operator is not "<<-". - EOF -command_which_is_gobbled +2 command_which_is_run && +3 cat >expect <<\EOF ?!UNCLOSED-HEREDOC?! && +4 we try to end the here-doc below, +5 but the indentation throws us off +6 since the operator is not "<<-". +7 EOF +8 command_which_is_gobbled diff --git a/t/chainlint/unclosed-here-doc.test b/t/chainlint/unclosed-here-doc.test index 69d3786c34..68e78f06f3 100644 --- a/t/chainlint/unclosed-here-doc.test +++ b/t/chainlint/unclosed-here-doc.test @@ -1,3 +1,4 @@ +test_expect_success 'unclosed-here-doc' ' command_which_is_run && cat >expect <<\EOF && we try to end the here-doc below, @@ -5,3 +6,4 @@ cat >expect <<\EOF && since the operator is not "<<-". EOF command_which_is_gobbled +' diff --git a/t/chainlint/while-loop.expect b/t/chainlint/while-loop.expect index 06c1567f48..5ffabd5a93 100644 --- a/t/chainlint/while-loop.expect +++ b/t/chainlint/while-loop.expect @@ -1,14 +1,14 @@ -( - while true - do - echo foo ?!AMP?! - cat <<-\EOF ?!LOOP?! - bar - EOF - done ?!AMP?! - - while true; do - echo foo && - cat bar ?!LOOP?! - done -) +2 ( +3 while true +4 do +5 echo foo ?!AMP?! +6 cat <<-\EOF ?!LOOP?! +7 bar +8 EOF +9 done ?!AMP?! +10 +11 while true; do +12 echo foo && +13 cat bar ?!LOOP?! +14 done +15 ) diff --git a/t/chainlint/while-loop.test b/t/chainlint/while-loop.test index d09fb016e4..33a201906a 100644 --- a/t/chainlint/while-loop.test +++ b/t/chainlint/while-loop.test @@ -1,3 +1,4 @@ +test_expect_success 'while-loop' ' ( # LINT: "while", "do", "done" do not need "&&" while true @@ -17,3 +18,4 @@ cat bar done ) +' diff --git a/t/helper/test-bitmap.c b/t/helper/test-bitmap.c index af43ee1cb5..3f23f21072 100644 --- a/t/helper/test-bitmap.c +++ b/t/helper/test-bitmap.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "git-compat-util.h" #include "pack-bitmap.h" @@ -13,21 +15,41 @@ static int bitmap_dump_hashes(void) return test_bitmap_hashes(the_repository); } +static int bitmap_dump_pseudo_merges(void) +{ + return test_bitmap_pseudo_merges(the_repository); +} + +static int bitmap_dump_pseudo_merge_commits(uint32_t n) +{ + return test_bitmap_pseudo_merge_commits(the_repository, n); +} + +static int bitmap_dump_pseudo_merge_objects(uint32_t n) +{ + return test_bitmap_pseudo_merge_objects(the_repository, n); +} + int cmd__bitmap(int argc, const char **argv) { setup_git_directory(); - if (argc != 2) - goto usage; - - if (!strcmp(argv[1], "list-commits")) + if (argc == 2 && !strcmp(argv[1], "list-commits")) return bitmap_list_commits(); - if (!strcmp(argv[1], "dump-hashes")) + if (argc == 2 && !strcmp(argv[1], "dump-hashes")) return bitmap_dump_hashes(); + if (argc == 2 && !strcmp(argv[1], "dump-pseudo-merges")) + return bitmap_dump_pseudo_merges(); + if (argc == 3 && !strcmp(argv[1], "dump-pseudo-merge-commits")) + return bitmap_dump_pseudo_merge_commits(atoi(argv[2])); + if (argc == 3 && !strcmp(argv[1], "dump-pseudo-merge-objects")) + return bitmap_dump_pseudo_merge_objects(atoi(argv[2])); -usage: usage("\ttest-tool bitmap list-commits\n" - "\ttest-tool bitmap dump-hashes"); + "\ttest-tool bitmap dump-hashes\n" + "\ttest-tool bitmap dump-pseudo-merges\n" + "\ttest-tool bitmap dump-pseudo-merge-commits <n>\n" + "\ttest-tool bitmap dump-pseudo-merge-objects <n>"); return -1; } diff --git a/t/helper/test-bloom.c b/t/helper/test-bloom.c index 1281e66876..97541daf71 100644 --- a/t/helper/test-bloom.c +++ b/t/helper/test-bloom.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "bloom.h" #include "hex.h" @@ -49,6 +51,7 @@ static void get_bloom_filter_for_commit(const struct object_id *commit_oid) static const char *bloom_usage = "\n" " test-tool bloom get_murmur3 <string>\n" +" test-tool bloom get_murmur3_seven_highbit\n" " test-tool bloom generate_filter <string> [<string>...]\n" " test-tool bloom get_filter_for_commit <commit-hex>\n"; @@ -63,7 +66,13 @@ int cmd__bloom(int argc, const char **argv) uint32_t hashed; if (argc < 3) usage(bloom_usage); - hashed = murmur3_seeded(0, argv[2], strlen(argv[2])); + hashed = murmur3_seeded_v2(0, argv[2], strlen(argv[2])); + printf("Murmur3 Hash with seed=0:0x%08x\n", hashed); + } + + if (!strcmp(argv[1], "get_murmur3_seven_highbit")) { + uint32_t hashed; + hashed = murmur3_seeded_v2(0, "\x99\xaa\xbb\xcc\xdd\xee\xff", 7); printf("Murmur3 Hash with seed=0:0x%08x\n", hashed); } diff --git a/t/helper/test-bundle-uri.c b/t/helper/test-bundle-uri.c index 09dc78733c..0c5fa723d8 100644 --- a/t/helper/test-bundle-uri.c +++ b/t/helper/test-bundle-uri.c @@ -88,8 +88,6 @@ static int cmd_ls_remote(int argc, const char **argv) die(_("bad repository '%s'"), dest); die(_("no remote configured to get bundle URIs from")); } - if (!remote->url_nr) - die(_("remote '%s' has no configured URL"), dest); transport = transport_get(remote, NULL); if (transport_get_remote_bundle_uri(transport) < 0) { diff --git a/t/helper/test-cache-tree.c b/t/helper/test-cache-tree.c index e7236392c8..5cdef3ebef 100644 --- a/t/helper/test-cache-tree.c +++ b/t/helper/test-cache-tree.c @@ -1,4 +1,5 @@ -#define USE_THE_INDEX_VARIABLE +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "gettext.h" #include "hex.h" @@ -38,29 +39,29 @@ int cmd__cache_tree(int argc, const char **argv) if (repo_read_index(the_repository) < 0) die(_("unable to read index file")); - oidcpy(&oid, &the_index.cache_tree->oid); + oidcpy(&oid, &the_repository->index->cache_tree->oid); tree = parse_tree_indirect(&oid); if (!tree) die(_("not a tree object: %s"), oid_to_hex(&oid)); if (empty) { /* clear the cache tree & allocate a new one */ - cache_tree_free(&the_index.cache_tree); - the_index.cache_tree = cache_tree(); + cache_tree_free(&the_repository->index->cache_tree); + the_repository->index->cache_tree = cache_tree(); } else if (invalidate_qty) { /* invalidate the specified number of unique paths */ - float f_interval = (float)the_index.cache_nr / invalidate_qty; + float f_interval = (float)the_repository->index->cache_nr / invalidate_qty; int interval = f_interval < 1.0 ? 1 : (int)f_interval; - for (i = 0; i < invalidate_qty && i * interval < the_index.cache_nr; i++) - cache_tree_invalidate_path(&the_index, the_index.cache[i * interval]->name); + for (i = 0; i < invalidate_qty && i * interval < the_repository->index->cache_nr; i++) + cache_tree_invalidate_path(the_repository->index, the_repository->index->cache[i * interval]->name); } if (argc != 1) usage_with_options(test_cache_tree_usage, options); else if (!strcmp(argv[0], "prime")) - prime_cache_tree(the_repository, &the_index, tree); + prime_cache_tree(the_repository, the_repository->index, tree); else if (!strcmp(argv[0], "update")) - cache_tree_update(&the_index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR); + cache_tree_update(the_repository->index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR); /* use "control" subcommand to specify no-op */ else if (!!strcmp(argv[0], "control")) die(_("Unhandled subcommand '%s'"), argv[0]); diff --git a/t/helper/test-dump-cache-tree.c b/t/helper/test-dump-cache-tree.c index c38f546e4f..3f0c7d0ed0 100644 --- a/t/helper/test-dump-cache-tree.c +++ b/t/helper/test-dump-cache-tree.c @@ -1,4 +1,5 @@ -#define USE_THE_INDEX_VARIABLE +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "hash.h" #include "hex.h" @@ -68,10 +69,10 @@ int cmd__dump_cache_tree(int ac UNUSED, const char **av UNUSED) setup_git_directory(); if (repo_read_index(the_repository) < 0) die("unable to read index file"); - istate = the_index; + istate = *the_repository->index; istate.cache_tree = another; cache_tree_update(&istate, WRITE_TREE_DRY_RUN); - ret = dump_cache_tree(the_index.cache_tree, another, ""); + ret = dump_cache_tree(the_repository->index->cache_tree, another, ""); cache_tree_free(&another); return ret; diff --git a/t/helper/test-dump-fsmonitor.c b/t/helper/test-dump-fsmonitor.c index 4f215fea02..1b7f37a84f 100644 --- a/t/helper/test-dump-fsmonitor.c +++ b/t/helper/test-dump-fsmonitor.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "read-cache-ll.h" #include "repository.h" diff --git a/t/helper/test-dump-split-index.c b/t/helper/test-dump-split-index.c index f29d18ef94..a6720faf9c 100644 --- a/t/helper/test-dump-split-index.c +++ b/t/helper/test-dump-split-index.c @@ -1,4 +1,5 @@ -#define USE_THE_INDEX_VARIABLE +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "hex.h" #include "read-cache-ll.h" @@ -19,16 +20,16 @@ int cmd__dump_split_index(int ac UNUSED, const char **av) setup_git_directory(); - do_read_index(&the_index, av[1], 1); - printf("own %s\n", oid_to_hex(&the_index.oid)); - si = the_index.split_index; + do_read_index(the_repository->index, av[1], 1); + printf("own %s\n", oid_to_hex(&the_repository->index->oid)); + si = the_repository->index->split_index; if (!si) { printf("not a split index\n"); return 0; } printf("base %s\n", oid_to_hex(&si->base_oid)); - for (i = 0; i < the_index.cache_nr; i++) { - struct cache_entry *ce = the_index.cache[i]; + for (i = 0; i < the_repository->index->cache_nr; i++) { + struct cache_entry *ce = the_repository->index->cache[i]; printf("%06o %s %d\t%s\n", ce->ce_mode, oid_to_hex(&ce->oid), ce_stage(ce), ce->name); } diff --git a/t/helper/test-dump-untracked-cache.c b/t/helper/test-dump-untracked-cache.c index b4af9712fe..4f010d5324 100644 --- a/t/helper/test-dump-untracked-cache.c +++ b/t/helper/test-dump-untracked-cache.c @@ -1,4 +1,5 @@ -#define USE_THE_INDEX_VARIABLE +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "dir.h" #include "hex.h" @@ -56,7 +57,7 @@ int cmd__dump_untracked_cache(int ac UNUSED, const char **av UNUSED) setup_git_directory(); if (repo_read_index(the_repository) < 0) die("unable to read index file"); - uc = the_index.untracked; + uc = the_repository->index->untracked; if (!uc) { printf("no untracked cache\n"); return 0; diff --git a/t/helper/test-example-decorate.c b/t/helper/test-example-decorate.c deleted file mode 100644 index 8f59f6be4c..0000000000 --- a/t/helper/test-example-decorate.c +++ /dev/null @@ -1,78 +0,0 @@ -#include "test-tool.h" -#include "git-compat-util.h" -#include "object.h" -#include "decorate.h" -#include "repository.h" - -int cmd__example_decorate(int argc UNUSED, const char **argv UNUSED) -{ - struct decoration n; - struct object_id one_oid = { {1} }; - struct object_id two_oid = { {2} }; - struct object_id three_oid = { {3} }; - struct object *one, *two, *three; - - int decoration_a, decoration_b; - - void *ret; - - int i, objects_noticed = 0; - - /* - * The struct must be zero-initialized. - */ - memset(&n, 0, sizeof(n)); - - /* - * Add 2 objects, one with a non-NULL decoration and one with a NULL - * decoration. - */ - one = lookup_unknown_object(the_repository, &one_oid); - two = lookup_unknown_object(the_repository, &two_oid); - ret = add_decoration(&n, one, &decoration_a); - if (ret) - BUG("when adding a brand-new object, NULL should be returned"); - ret = add_decoration(&n, two, NULL); - if (ret) - BUG("when adding a brand-new object, NULL should be returned"); - - /* - * When re-adding an already existing object, the old decoration is - * returned. - */ - ret = add_decoration(&n, one, NULL); - if (ret != &decoration_a) - BUG("when readding an already existing object, existing decoration should be returned"); - ret = add_decoration(&n, two, &decoration_b); - if (ret) - BUG("when readding an already existing object, existing decoration should be returned"); - - /* - * Lookup returns the added declarations, or NULL if the object was - * never added. - */ - ret = lookup_decoration(&n, one); - if (ret) - BUG("lookup should return added declaration"); - ret = lookup_decoration(&n, two); - if (ret != &decoration_b) - BUG("lookup should return added declaration"); - three = lookup_unknown_object(the_repository, &three_oid); - ret = lookup_decoration(&n, three); - if (ret) - BUG("lookup for unknown object should return NULL"); - - /* - * The user can also loop through all entries. - */ - for (i = 0; i < n.size; i++) { - if (n.entries[i].base) - objects_noticed++; - } - if (objects_noticed != 2) - BUG("should have 2 objects"); - - clear_decoration(&n, NULL); - - return 0; -} diff --git a/t/unit-tests/t-basic.c b/t/helper/test-example-tap.c index fda1ae59a6..d072ad559f 100644 --- a/t/unit-tests/t-basic.c +++ b/t/helper/test-example-tap.c @@ -1,4 +1,5 @@ -#include "test-lib.h" +#include "test-tool.h" +#include "t/unit-tests/test-lib.h" /* * The purpose of this "unit test" is to verify a few invariants of the unit @@ -69,7 +70,7 @@ static void t_empty(void) ; /* empty */ } -int cmd_main(int argc, const char **argv) +int cmd__example_tap(int argc, const char **argv) { test_res = TEST(check_res = check_int(1, ==, 1), "passing test"); TEST(t_res(1), "passing test and assertion return 1"); diff --git a/t/helper/test-find-pack.c b/t/helper/test-find-pack.c index e8bd793e58..14b2b0c12c 100644 --- a/t/helper/test-find-pack.c +++ b/t/helper/test-find-pack.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "object-name.h" #include "object-store.h" diff --git a/t/helper/test-fsmonitor-client.c b/t/helper/test-fsmonitor-client.c index 8280984d08..02bfe92e8d 100644 --- a/t/helper/test-fsmonitor-client.c +++ b/t/helper/test-fsmonitor-client.c @@ -3,6 +3,8 @@ * a `git fsmonitor--daemon` daemon. */ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "parse-options.h" #include "fsmonitor-ipc.h" diff --git a/t/helper/test-hash-speed.c b/t/helper/test-hash-speed.c index b235da594f..7de822af51 100644 --- a/t/helper/test-hash-speed.c +++ b/t/helper/test-hash-speed.c @@ -1,5 +1,5 @@ #include "test-tool.h" -#include "hash-ll.h" +#include "hash.h" #define NUM_SECONDS 3 diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c index 0eb0b3d49c..2912899558 100644 --- a/t/helper/test-hashmap.c +++ b/t/helper/test-hashmap.c @@ -36,7 +36,8 @@ static int test_entry_cmp(const void *cmp_data, } static struct test_entry *alloc_test_entry(unsigned int hash, - char *key, char *value) + const char *key, + const char *value) { size_t klen = strlen(key); size_t vlen = strlen(value); diff --git a/t/helper/test-json-writer.c b/t/helper/test-json-writer.c index afe393f597..ed52eb76bf 100644 --- a/t/helper/test-json-writer.c +++ b/t/helper/test-json-writer.c @@ -174,7 +174,7 @@ static void make_arr4(int pretty) jw_end(&arr4); } -static char *expect_nest1 = +static const char *expect_nest1 = "{\"obj1\":{\"a\":\"abc\",\"b\":42,\"c\":true},\"arr1\":[\"abc\",42,true]}"; static struct json_writer nest1 = JSON_WRITER_INIT; @@ -195,10 +195,10 @@ static void make_nest1(int pretty) jw_release(&arr1); } -static char *expect_inline1 = +static const char *expect_inline1 = "{\"obj1\":{\"a\":\"abc\",\"b\":42,\"c\":true},\"arr1\":[\"abc\",42,true]}"; -static char *pretty_inline1 = +static const char *pretty_inline1 = ("{\n" " \"obj1\": {\n" " \"a\": \"abc\",\n" @@ -236,10 +236,10 @@ static void make_inline1(int pretty) jw_end(&inline1); } -static char *expect_inline2 = +static const char *expect_inline2 = "[[1,2],[3,4],{\"a\":\"abc\"}]"; -static char *pretty_inline2 = +static const char *pretty_inline2 = ("[\n" " [\n" " 1,\n" diff --git a/t/helper/test-lazy-init-name-hash.c b/t/helper/test-lazy-init-name-hash.c index 187a115d57..40f5df4412 100644 --- a/t/helper/test-lazy-init-name-hash.c +++ b/t/helper/test-lazy-init-name-hash.c @@ -1,4 +1,5 @@ -#define USE_THE_INDEX_VARIABLE +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "environment.h" #include "name-hash.h" @@ -40,22 +41,22 @@ static void dump_run(void) repo_read_index(the_repository); if (single) { - test_lazy_init_name_hash(&the_index, 0); + test_lazy_init_name_hash(the_repository->index, 0); } else { - int nr_threads_used = test_lazy_init_name_hash(&the_index, 1); + int nr_threads_used = test_lazy_init_name_hash(the_repository->index, 1); if (!nr_threads_used) die("non-threaded code path used"); } - hashmap_for_each_entry(&the_index.dir_hash, &iter_dir, dir, + hashmap_for_each_entry(&the_repository->index->dir_hash, &iter_dir, dir, ent /* member name */) printf("dir %08x %7d %s\n", dir->ent.hash, dir->nr, dir->name); - hashmap_for_each_entry(&the_index.name_hash, &iter_cache, ce, + hashmap_for_each_entry(&the_repository->index->name_hash, &iter_cache, ce, ent /* member name */) printf("name %08x %s\n", ce->ent.hash, ce->name); - discard_index(&the_index); + discard_index(the_repository->index); } /* @@ -74,7 +75,7 @@ static uint64_t time_runs(int try_threaded) t0 = getnanotime(); repo_read_index(the_repository); t1 = getnanotime(); - nr_threads_used = test_lazy_init_name_hash(&the_index, try_threaded); + nr_threads_used = test_lazy_init_name_hash(the_repository->index, try_threaded); t2 = getnanotime(); sum += (t2 - t1); @@ -86,16 +87,16 @@ static uint64_t time_runs(int try_threaded) printf("%f %f %d multi %d\n", ((double)(t1 - t0))/1000000000, ((double)(t2 - t1))/1000000000, - the_index.cache_nr, + the_repository->index->cache_nr, nr_threads_used); else printf("%f %f %d single\n", ((double)(t1 - t0))/1000000000, ((double)(t2 - t1))/1000000000, - the_index.cache_nr); + the_repository->index->cache_nr); fflush(stdout); - discard_index(&the_index); + discard_index(the_repository->index); } avg = sum / count; @@ -120,8 +121,8 @@ static void analyze_run(void) int nr; repo_read_index(the_repository); - cache_nr_limit = the_index.cache_nr; - discard_index(&the_index); + cache_nr_limit = the_repository->index->cache_nr; + discard_index(the_repository->index); nr = analyze; while (1) { @@ -135,22 +136,22 @@ static void analyze_run(void) for (i = 0; i < count; i++) { repo_read_index(the_repository); - the_index.cache_nr = nr; /* cheap truncate of index */ + the_repository->index->cache_nr = nr; /* cheap truncate of index */ t1s = getnanotime(); - test_lazy_init_name_hash(&the_index, 0); + test_lazy_init_name_hash(the_repository->index, 0); t2s = getnanotime(); sum_single += (t2s - t1s); - the_index.cache_nr = cache_nr_limit; - discard_index(&the_index); + the_repository->index->cache_nr = cache_nr_limit; + discard_index(the_repository->index); repo_read_index(the_repository); - the_index.cache_nr = nr; /* cheap truncate of index */ + the_repository->index->cache_nr = nr; /* cheap truncate of index */ t1m = getnanotime(); - nr_threads_used = test_lazy_init_name_hash(&the_index, 1); + nr_threads_used = test_lazy_init_name_hash(the_repository->index, 1); t2m = getnanotime(); sum_multi += (t2m - t1m); - the_index.cache_nr = cache_nr_limit; - discard_index(&the_index); + the_repository->index->cache_nr = cache_nr_limit; + discard_index(the_repository->index); if (!nr_threads_used) printf(" [size %8d] [single %f] non-threaded code path used\n", diff --git a/t/helper/test-match-trees.c b/t/helper/test-match-trees.c index d0db5ff26f..e0e2048320 100644 --- a/t/helper/test-match-trees.c +++ b/t/helper/test-match-trees.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "hex.h" #include "match-trees.h" diff --git a/t/helper/test-oid-array.c b/t/helper/test-oid-array.c index aafe398ef0..076b849cbf 100644 --- a/t/helper/test-oid-array.c +++ b/t/helper/test-oid-array.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "hex.h" #include "oid-array.h" @@ -17,6 +19,8 @@ int cmd__oid_array(int argc UNUSED, const char **argv UNUSED) int nongit_ok; setup_git_directory_gently(&nongit_ok); + if (nongit_ok) + repo_set_hash_algo(the_repository, GIT_HASH_SHA1); while (strbuf_getline(&line, stdin) != EOF) { const char *arg; diff --git a/t/helper/test-oidmap.c b/t/helper/test-oidmap.c deleted file mode 100644 index bd30244a54..0000000000 --- a/t/helper/test-oidmap.c +++ /dev/null @@ -1,123 +0,0 @@ -#include "test-tool.h" -#include "hex.h" -#include "object-name.h" -#include "oidmap.h" -#include "repository.h" -#include "setup.h" -#include "strbuf.h" -#include "string-list.h" - -/* key is an oid and value is a name (could be a refname for example) */ -struct test_entry { - struct oidmap_entry entry; - char name[FLEX_ARRAY]; -}; - -#define DELIM " \t\r\n" - -/* - * Read stdin line by line and print result of commands to stdout: - * - * hash oidkey -> sha1hash(oidkey) - * put oidkey namevalue -> NULL / old namevalue - * get oidkey -> NULL / namevalue - * remove oidkey -> NULL / old namevalue - * iterate -> oidkey1 namevalue1\noidkey2 namevalue2\n... - * - */ -int cmd__oidmap(int argc UNUSED, const char **argv UNUSED) -{ - struct string_list parts = STRING_LIST_INIT_NODUP; - struct strbuf line = STRBUF_INIT; - struct oidmap map = OIDMAP_INIT; - - setup_git_directory(); - - /* init oidmap */ - oidmap_init(&map, 0); - - /* process commands from stdin */ - while (strbuf_getline(&line, stdin) != EOF) { - char *cmd, *p1, *p2; - struct test_entry *entry; - struct object_id oid; - - /* break line into command and up to two parameters */ - string_list_setlen(&parts, 0); - string_list_split_in_place(&parts, line.buf, DELIM, 2); - string_list_remove_empty_items(&parts, 0); - - /* ignore empty lines */ - if (!parts.nr) - continue; - if (!*parts.items[0].string || *parts.items[0].string == '#') - continue; - - cmd = parts.items[0].string; - p1 = parts.nr >= 1 ? parts.items[1].string : NULL; - p2 = parts.nr >= 2 ? parts.items[2].string : NULL; - - if (!strcmp("put", cmd) && p1 && p2) { - - if (repo_get_oid(the_repository, p1, &oid)) { - printf("Unknown oid: %s\n", p1); - continue; - } - - /* create entry with oid_key = p1, name_value = p2 */ - FLEX_ALLOC_STR(entry, name, p2); - oidcpy(&entry->entry.oid, &oid); - - /* add / replace entry */ - entry = oidmap_put(&map, entry); - - /* print and free replaced entry, if any */ - puts(entry ? entry->name : "NULL"); - free(entry); - - } else if (!strcmp("get", cmd) && p1) { - - if (repo_get_oid(the_repository, p1, &oid)) { - printf("Unknown oid: %s\n", p1); - continue; - } - - /* lookup entry in oidmap */ - entry = oidmap_get(&map, &oid); - - /* print result */ - puts(entry ? entry->name : "NULL"); - - } else if (!strcmp("remove", cmd) && p1) { - - if (repo_get_oid(the_repository, p1, &oid)) { - printf("Unknown oid: %s\n", p1); - continue; - } - - /* remove entry from oidmap */ - entry = oidmap_remove(&map, &oid); - - /* print result and free entry*/ - puts(entry ? entry->name : "NULL"); - free(entry); - - } else if (!strcmp("iterate", cmd)) { - - struct oidmap_iter iter; - oidmap_iter_init(&map, &iter); - while ((entry = oidmap_iter_next(&iter))) - printf("%s %s\n", oid_to_hex(&entry->entry.oid), entry->name); - - } else { - - printf("Unknown command %s\n", cmd); - - } - } - - string_list_clear(&parts, 0); - strbuf_release(&line); - oidmap_free(&map, 1); - return 0; -} diff --git a/t/helper/test-oidtree.c b/t/helper/test-oidtree.c deleted file mode 100644 index c7a1d4c642..0000000000 --- a/t/helper/test-oidtree.c +++ /dev/null @@ -1,54 +0,0 @@ -#include "test-tool.h" -#include "hex.h" -#include "oidtree.h" -#include "setup.h" -#include "strbuf.h" - -static enum cb_next print_oid(const struct object_id *oid, void *data UNUSED) -{ - puts(oid_to_hex(oid)); - return CB_CONTINUE; -} - -int cmd__oidtree(int argc UNUSED, const char **argv UNUSED) -{ - struct oidtree ot; - struct strbuf line = STRBUF_INIT; - int nongit_ok; - int algo = GIT_HASH_UNKNOWN; - - oidtree_init(&ot); - setup_git_directory_gently(&nongit_ok); - - while (strbuf_getline(&line, stdin) != EOF) { - const char *arg; - struct object_id oid; - - if (skip_prefix(line.buf, "insert ", &arg)) { - if (get_oid_hex_any(arg, &oid) == GIT_HASH_UNKNOWN) - die("insert not a hexadecimal oid: %s", arg); - algo = oid.algo; - oidtree_insert(&ot, &oid); - } else if (skip_prefix(line.buf, "contains ", &arg)) { - if (get_oid_hex(arg, &oid)) - die("contains not a hexadecimal oid: %s", arg); - printf("%d\n", oidtree_contains(&ot, &oid)); - } else if (skip_prefix(line.buf, "each ", &arg)) { - char buf[GIT_MAX_HEXSZ + 1] = { '0' }; - memset(&oid, 0, sizeof(oid)); - memcpy(buf, arg, strlen(arg)); - buf[hash_algos[algo].hexsz] = '\0'; - get_oid_hex_any(buf, &oid); - oid.algo = algo; - oidtree_each(&ot, &oid, strlen(arg), print_oid, NULL); - } else if (!strcmp(line.buf, "clear")) { - oidtree_clear(&ot); - } else { - die("unknown command: %s", line.buf); - } - } - - strbuf_release(&line); - - return 0; -} diff --git a/t/helper/test-pack-mtimes.c b/t/helper/test-pack-mtimes.c index 67a964ef90..f8f9afbb5b 100644 --- a/t/helper/test-pack-mtimes.c +++ b/t/helper/test-pack-mtimes.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "hex.h" #include "strbuf.h" diff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c index ded8116cc5..5250913d99 100644 --- a/t/helper/test-parse-options.c +++ b/t/helper/test-parse-options.c @@ -207,6 +207,7 @@ int cmd__parse_options(int argc, const char **argv) expect.strdup_strings = 1; string_list_clear(&expect, 0); string_list_clear(&list, 0); + free(file); return ret; } diff --git a/t/helper/test-partial-clone.c b/t/helper/test-partial-clone.c index 910a128614..0ead529167 100644 --- a/t/helper/test-partial-clone.c +++ b/t/helper/test-partial-clone.c @@ -21,7 +21,7 @@ static void object_info(const char *gitdir, const char *oid_hex) if (repo_init(&r, gitdir, NULL)) die("could not init repo"); - if (parse_oid_hex(oid_hex, &oid, &p)) + if (parse_oid_hex_algop(oid_hex, &oid, &p, r.hash_algo)) die("could not parse oid"); if (oid_object_info_extended(&r, &oid, &oi, 0)) die("could not obtain object info"); diff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c index 70396fa384..bf0e23ed50 100644 --- a/t/helper/test-path-utils.c +++ b/t/helper/test-path-utils.c @@ -7,6 +7,7 @@ #include "string-list.h" #include "trace.h" #include "utf8.h" +#include "copy.h" /* * A "string_list_each_func_t" function that normalizes an entry from diff --git a/t/helper/test-proc-receive.c b/t/helper/test-proc-receive.c index f30022d222..29361c7aab 100644 --- a/t/helper/test-proc-receive.c +++ b/t/helper/test-proc-receive.c @@ -3,8 +3,8 @@ #include "hex.h" #include "parse-options.h" #include "pkt-line.h" -#include "setup.h" #include "sigchain.h" +#include "string-list.h" static const char *proc_receive_usage[] = { "test-tool proc-receive [<options>]", @@ -92,9 +92,9 @@ static void proc_receive_read_commands(struct packet_reader *reader, if (die_read_commands) die("die with the --die-read-commands option"); - if (parse_oid_hex(reader->line, &old_oid, &p) || + if (parse_oid_hex_any(reader->line, &old_oid, &p) == GIT_HASH_UNKNOWN || *p++ != ' ' || - parse_oid_hex(p, &new_oid, &p) || + parse_oid_hex_any(p, &new_oid, &p) == GIT_HASH_UNKNOWN || *p++ != ' ') die("protocol error: expected 'old new ref', got '%s'", reader->line); @@ -128,7 +128,6 @@ static void proc_receive_read_push_options(struct packet_reader *reader, int cmd__proc_receive(int argc, const char **argv) { - int nongit_ok = 0; struct packet_reader reader; struct command *commands = NULL; struct string_list push_options = STRING_LIST_INIT_DUP; @@ -154,8 +153,6 @@ int cmd__proc_receive(int argc, const char **argv) OPT_END() }; - setup_git_directory_gently(&nongit_ok); - argc = parse_options(argc, argv, "test-tools", options, proc_receive_usage, 0); if (argc > 0) usage_msg_opt("Too many arguments.", proc_receive_usage, options); diff --git a/t/helper/test-reach.c b/t/helper/test-reach.c index 1e3b431e3e..5dd374379c 100644 --- a/t/helper/test-reach.c +++ b/t/helper/test-reach.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "commit.h" #include "commit-reach.h" @@ -62,7 +64,7 @@ int cmd__reach(int ac, const char **av) die("failed to resolve %s", buf.buf + 2); orig = parse_object(r, &oid); - peeled = deref_tag_noverify(orig); + peeled = deref_tag_noverify(the_repository, orig); if (!peeled) die("failed to load commit for input %s resulting in oid %s\n", diff --git a/t/helper/test-read-cache.c b/t/helper/test-read-cache.c index 1acd362346..d285c656bd 100644 --- a/t/helper/test-read-cache.c +++ b/t/helper/test-read-cache.c @@ -1,4 +1,5 @@ -#define USE_THE_INDEX_VARIABLE +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "config.h" #include "read-cache-ll.h" @@ -10,7 +11,7 @@ int cmd__read_cache(int argc, const char **argv) int i, cnt = 1; const char *name = NULL; - initialize_the_repository(); + initialize_repository(the_repository); if (argc > 1 && skip_prefix(argv[1], "--print-and-refresh=", &name)) { argc--; @@ -27,16 +28,16 @@ int cmd__read_cache(int argc, const char **argv) if (name) { int pos; - refresh_index(&the_index, REFRESH_QUIET, + refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL); - pos = index_name_pos(&the_index, name, strlen(name)); + pos = index_name_pos(the_repository->index, name, strlen(name)); if (pos < 0) die("%s not in index", name); printf("%s is%s up to date\n", name, - ce_uptodate(the_index.cache[pos]) ? "" : " not"); + ce_uptodate(the_repository->index->cache[pos]) ? "" : " not"); write_file(name, "%d\n", i); } - discard_index(&the_index); + discard_index(the_repository->index); } return 0; } diff --git a/t/helper/test-read-graph.c b/t/helper/test-read-graph.c index 8c7a83f578..9018c9f541 100644 --- a/t/helper/test-read-graph.c +++ b/t/helper/test-read-graph.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "commit-graph.h" #include "repository.h" @@ -5,20 +7,8 @@ #include "bloom.h" #include "setup.h" -int cmd__read_graph(int argc UNUSED, const char **argv UNUSED) +static void dump_graph_info(struct commit_graph *graph) { - struct commit_graph *graph = NULL; - struct object_directory *odb; - - setup_git_directory(); - odb = the_repository->objects->odb; - - prepare_repo_settings(the_repository); - - graph = read_commit_graph_one(the_repository, odb); - if (!graph) - return 1; - printf("header: %08x %d %d %d %d\n", ntohl(*(uint32_t*)graph->data), *(unsigned char*)(graph->data + 4), @@ -57,8 +47,57 @@ int cmd__read_graph(int argc UNUSED, const char **argv UNUSED) if (graph->topo_levels) printf(" topo_levels"); printf("\n"); +} + +static void dump_graph_bloom_filters(struct commit_graph *graph) +{ + uint32_t i; + + for (i = 0; i < graph->num_commits + graph->num_commits_in_base; i++) { + struct bloom_filter filter = { 0 }; + size_t j; + + if (load_bloom_filter_from_graph(graph, &filter, i) < 0) { + fprintf(stderr, "missing Bloom filter for graph " + "position %"PRIu32"\n", i); + continue; + } + + for (j = 0; j < filter.len; j++) + printf("%02x", filter.data[j]); + if (filter.len) + printf("\n"); + } +} + +int cmd__read_graph(int argc, const char **argv) +{ + struct commit_graph *graph = NULL; + struct object_directory *odb; + int ret = 0; + + setup_git_directory(); + odb = the_repository->objects->odb; + + prepare_repo_settings(the_repository); + + graph = read_commit_graph_one(the_repository, odb); + if (!graph) { + ret = 1; + goto done; + } + + if (argc <= 1) + dump_graph_info(graph); + else if (!strcmp(argv[1], "bloom-filters")) + dump_graph_bloom_filters(graph); + else { + fprintf(stderr, "unknown sub-command: '%s'\n", argv[1]); + ret = 1; + } +done: UNLEAK(graph); - return 0; + return ret; } diff --git a/t/helper/test-read-midx.c b/t/helper/test-read-midx.c index 4acae41bb9..83effc2b5f 100644 --- a/t/helper/test-read-midx.c +++ b/t/helper/test-read-midx.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "hex.h" #include "midx.h" diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c index 82bbf6e2e6..637b8b294e 100644 --- a/t/helper/test-ref-store.c +++ b/t/helper/test-ref-store.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "hex.h" #include "refs.h" @@ -82,7 +84,7 @@ static const char **get_store(const char **argv, struct ref_store **refs) add_to_alternates_memory(sb.buf); strbuf_release(&sb); - *refs = get_submodule_ref_store(gitdir); + *refs = repo_get_submodule_ref_store(the_repository, gitdir); } else if (skip_prefix(argv[0], "worktree:", &gitdir)) { struct worktree **p, **worktrees = get_worktrees(); @@ -118,7 +120,7 @@ static int cmd_create_symref(struct ref_store *refs, const char **argv) const char *target = notnull(*argv++, "target"); const char *logmsg = *argv++; - return refs_create_symref(refs, refname, target, logmsg); + return refs_update_symref(refs, refname, target, logmsg); } static struct flag_definition transaction_flags[] = { @@ -126,6 +128,7 @@ static struct flag_definition transaction_flags[] = { FLAG_DEF(REF_FORCE_CREATE_REFLOG), FLAG_DEF(REF_SKIP_OID_VERIFICATION), FLAG_DEF(REF_SKIP_REFNAME_VERIFICATION), + FLAG_DEF(REF_SKIP_CREATE_REFLOG), { NULL, 0 } }; diff --git a/t/helper/test-reftable.c b/t/helper/test-reftable.c index 00237ef0d9..aa6538a8da 100644 --- a/t/helper/test-reftable.c +++ b/t/helper/test-reftable.c @@ -5,15 +5,12 @@ int cmd__reftable(int argc, const char **argv) { /* test from simple to complex. */ - basics_test_main(argc, argv); - record_test_main(argc, argv); block_test_main(argc, argv); tree_test_main(argc, argv); pq_test_main(argc, argv); readwrite_test_main(argc, argv); merged_test_main(argc, argv); stack_test_main(argc, argv); - refname_test_main(argc, argv); return 0; } diff --git a/t/helper/test-regex.c b/t/helper/test-regex.c index 80042eafc2..366bd70976 100644 --- a/t/helper/test-regex.c +++ b/t/helper/test-regex.c @@ -20,8 +20,8 @@ static struct reg_flag reg_flags[] = { static int test_regex_bug(void) { - char *pat = "[^={} \t]+"; - char *str = "={}\nfred"; + const char *pat = "[^={} \t]+"; + const char *str = "={}\nfred"; regex_t r; regmatch_t m[1]; diff --git a/t/helper/test-repository.c b/t/helper/test-repository.c index 0c7c5aa4dd..c6a074df3d 100644 --- a/t/helper/test-repository.c +++ b/t/helper/test-repository.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "commit-graph.h" #include "commit.h" diff --git a/t/helper/test-revision-walking.c b/t/helper/test-revision-walking.c index f346951bc2..071f5bd1e2 100644 --- a/t/helper/test-revision-walking.c +++ b/t/helper/test-revision-walking.c @@ -8,6 +8,8 @@ * published by the Free Software Foundation. */ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "commit.h" #include "diff.h" diff --git a/t/helper/test-rot13-filter.c b/t/helper/test-rot13-filter.c index f8d564c622..7e1d9e0ee4 100644 --- a/t/helper/test-rot13-filter.c +++ b/t/helper/test-rot13-filter.c @@ -136,7 +136,7 @@ static void free_delay_entries(void) strmap_clear(&delay, 0); } -static void add_delay_entry(char *pathname, int count, int requested) +static void add_delay_entry(const char *pathname, int count, int requested) { struct delay_entry *entry = xcalloc(1, sizeof(*entry)); entry->count = count; @@ -189,7 +189,8 @@ static void reply_list_available_blobs_cmd(void) static void command_loop(void) { for (;;) { - char *buf, *output; + char *buf; + const char *output; char *pathname; struct delay_entry *entry; struct strbuf input = STRBUF_INIT; diff --git a/t/helper/test-run-command.c b/t/helper/test-run-command.c index c0ed8722c8..61eb1175fe 100644 --- a/t/helper/test-run-command.c +++ b/t/helper/test-run-command.c @@ -65,6 +65,7 @@ struct testsuite { struct string_list tests, failed; int next; int quiet, immediate, verbose, verbose_log, trace, write_junit_xml; + const char *shell_path; }; #define TESTSUITE_INIT { \ .tests = STRING_LIST_INIT_DUP, \ @@ -80,7 +81,9 @@ static int next_test(struct child_process *cp, struct strbuf *err, void *cb, return 0; test = suite->tests.items[suite->next++].string; - strvec_pushl(&cp->args, "sh", test, NULL); + if (suite->shell_path) + strvec_push(&cp->args, suite->shell_path); + strvec_push(&cp->args, test); if (suite->quiet) strvec_push(&cp->args, "--quiet"); if (suite->immediate) @@ -155,6 +158,8 @@ static int testsuite(int argc, const char **argv) .task_finished = test_finished, .data = &suite, }; + struct strbuf progpath = STRBUF_INIT; + size_t path_prefix_len; argc = parse_options(argc, argv, NULL, options, testsuite_usage, PARSE_OPT_STOP_AT_NON_OPTION); @@ -162,26 +167,36 @@ static int testsuite(int argc, const char **argv) if (max_jobs <= 0) max_jobs = online_cpus(); + /* + * If we run without a shell, execute the programs directly from CWD. + */ + suite.shell_path = getenv("TEST_SHELL_PATH"); + if (!suite.shell_path) + strbuf_addstr(&progpath, "./"); + path_prefix_len = progpath.len; + dir = opendir("."); if (!dir) die("Could not open the current directory"); while ((d = readdir(dir))) { const char *p = d->d_name; - if (*p != 't' || !isdigit(p[1]) || !isdigit(p[2]) || - !isdigit(p[3]) || !isdigit(p[4]) || p[5] != '-' || - !ends_with(p, ".sh")) + if (!strcmp(p, ".") || !strcmp(p, "..")) continue; /* No pattern: match all */ if (!argc) { - string_list_append(&suite.tests, p); + strbuf_setlen(&progpath, path_prefix_len); + strbuf_addstr(&progpath, p); + string_list_append(&suite.tests, progpath.buf); continue; } for (i = 0; i < argc; i++) if (!wildmatch(argv[i], p, 0)) { - string_list_append(&suite.tests, p); + strbuf_setlen(&progpath, path_prefix_len); + strbuf_addstr(&progpath, p); + string_list_append(&suite.tests, progpath.buf); break; } } @@ -208,6 +223,7 @@ static int testsuite(int argc, const char **argv) string_list_clear(&suite.tests, 0); string_list_clear(&suite.failed, 0); + strbuf_release(&progpath); return ret; } diff --git a/t/helper/test-scrap-cache-tree.c b/t/helper/test-scrap-cache-tree.c index 0a816a96e2..64fff6e9e3 100644 --- a/t/helper/test-scrap-cache-tree.c +++ b/t/helper/test-scrap-cache-tree.c @@ -1,4 +1,5 @@ -#define USE_THE_INDEX_VARIABLE +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "lockfile.h" #include "read-cache-ll.h" @@ -15,9 +16,9 @@ int cmd__scrap_cache_tree(int ac UNUSED, const char **av UNUSED) repo_hold_locked_index(the_repository, &index_lock, LOCK_DIE_ON_ERROR); if (repo_read_index(the_repository) < 0) die("unable to read index file"); - cache_tree_free(&the_index.cache_tree); - the_index.cache_tree = NULL; - if (write_locked_index(&the_index, &index_lock, COMMIT_LOCK)) + cache_tree_free(&the_repository->index->cache_tree); + the_repository->index->cache_tree = NULL; + if (write_locked_index(the_repository->index, &index_lock, COMMIT_LOCK)) die("unable to write index file"); return 0; } diff --git a/t/helper/test-sha1.c b/t/helper/test-sha1.c index dcb7f6c003..e60d000c03 100644 --- a/t/helper/test-sha1.c +++ b/t/helper/test-sha1.c @@ -1,5 +1,5 @@ #include "test-tool.h" -#include "hash-ll.h" +#include "hash.h" int cmd__sha1(int ac, const char **av) { diff --git a/t/helper/test-sha256.c b/t/helper/test-sha256.c index 08cf149001..2fb20438f3 100644 --- a/t/helper/test-sha256.c +++ b/t/helper/test-sha256.c @@ -1,5 +1,5 @@ #include "test-tool.h" -#include "hash-ll.h" +#include "hash.h" int cmd__sha256(int ac, const char **av) { diff --git a/t/helper/test-strcmp-offset.c b/t/helper/test-strcmp-offset.c deleted file mode 100644 index d8473cf2fc..0000000000 --- a/t/helper/test-strcmp-offset.c +++ /dev/null @@ -1,23 +0,0 @@ -#include "test-tool.h" -#include "read-cache-ll.h" - -int cmd__strcmp_offset(int argc UNUSED, const char **argv) -{ - int result; - size_t offset; - - if (!argv[1] || !argv[2]) - die("usage: %s <string1> <string2>", argv[0]); - - result = strcmp_offset(argv[1], argv[2], &offset); - - /* - * Because different CRTs behave differently, only rely on signs - * of the result values. - */ - result = (result < 0 ? -1 : - result > 0 ? 1 : - 0); - printf("%d %"PRIuMAX"\n", result, (uintmax_t)offset); - return 0; -} diff --git a/t/helper/test-submodule-config.c b/t/helper/test-submodule-config.c index 9df2f03ac8..cbe93f2f9e 100644 --- a/t/helper/test-submodule-config.c +++ b/t/helper/test-submodule-config.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "config.h" #include "hash.h" @@ -44,7 +46,7 @@ int cmd__submodule_config(int argc, const char **argv) path_or_name = arg[1]; if (commit[0] == '\0') - oidclr(&commit_oid); + oidclr(&commit_oid, the_repository->hash_algo); else if (repo_get_oid(the_repository, commit, &commit_oid) < 0) die_usage(argc, argv, "Commit not found."); diff --git a/t/helper/test-submodule-nested-repo-config.c b/t/helper/test-submodule-nested-repo-config.c index ecd40ded99..6ca069ce63 100644 --- a/t/helper/test-submodule-nested-repo-config.c +++ b/t/helper/test-submodule-nested-repo-config.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "repository.h" #include "setup.h" diff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c index 7197969a08..22e518d229 100644 --- a/t/helper/test-submodule.c +++ b/t/helper/test-submodule.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "test-tool-utils.h" #include "parse-options.h" diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c index 80a946b847..da3e69128a 100644 --- a/t/helper/test-tool.c +++ b/t/helper/test-tool.c @@ -29,7 +29,7 @@ static struct test_cmd cmds[] = { { "dump-split-index", cmd__dump_split_index }, { "dump-untracked-cache", cmd__dump_untracked_cache }, { "env-helper", cmd__env_helper }, - { "example-decorate", cmd__example_decorate }, + { "example-tap", cmd__example_tap }, { "find-pack", cmd__find_pack }, { "fsmonitor-client", cmd__fsmonitor_client }, { "genrandom", cmd__genrandom }, @@ -44,8 +44,6 @@ static struct test_cmd cmds[] = { { "mergesort", cmd__mergesort }, { "mktemp", cmd__mktemp }, { "oid-array", cmd__oid_array }, - { "oidmap", cmd__oidmap }, - { "oidtree", cmd__oidtree }, { "online-cpus", cmd__online_cpus }, { "pack-mtimes", cmd__pack_mtimes }, { "parse-options", cmd__parse_options }, @@ -77,7 +75,6 @@ static struct test_cmd cmds[] = { { "sha256", cmd__sha256 }, { "sigchain", cmd__sigchain }, { "simple-ipc", cmd__simple_ipc }, - { "strcmp-offset", cmd__strcmp_offset }, { "string-list", cmd__string_list }, { "submodule", cmd__submodule }, { "submodule-config", cmd__submodule_config }, diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h index 2808b92419..642a34578c 100644 --- a/t/helper/test-tool.h +++ b/t/helper/test-tool.h @@ -23,7 +23,7 @@ int cmd__dump_split_index(int argc, const char **argv); int cmd__dump_untracked_cache(int argc, const char **argv); int cmd__dump_reftable(int argc, const char **argv); int cmd__env_helper(int argc, const char **argv); -int cmd__example_decorate(int argc, const char **argv); +int cmd__example_tap(int argc, const char **argv); int cmd__find_pack(int argc, const char **argv); int cmd__fsmonitor_client(int argc, const char **argv); int cmd__genrandom(int argc, const char **argv); @@ -37,8 +37,6 @@ int cmd__lazy_init_name_hash(int argc, const char **argv); int cmd__match_trees(int argc, const char **argv); int cmd__mergesort(int argc, const char **argv); int cmd__mktemp(int argc, const char **argv); -int cmd__oidmap(int argc, const char **argv); -int cmd__oidtree(int argc, const char **argv); int cmd__online_cpus(int argc, const char **argv); int cmd__pack_mtimes(int argc, const char **argv); int cmd__parse_options(int argc, const char **argv); @@ -70,7 +68,6 @@ int cmd__oid_array(int argc, const char **argv); int cmd__sha256(int argc, const char **argv); int cmd__sigchain(int argc, const char **argv); int cmd__simple_ipc(int argc, const char **argv); -int cmd__strcmp_offset(int argc, const char **argv); int cmd__string_list(int argc, const char **argv); int cmd__submodule(int argc, const char **argv); int cmd__submodule_config(int argc, const char **argv); diff --git a/t/helper/test-trace2.c b/t/helper/test-trace2.c index 1adac29a57..cd955ec63e 100644 --- a/t/helper/test-trace2.c +++ b/t/helper/test-trace2.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "strvec.h" #include "run-command.h" diff --git a/t/helper/test-write-cache.c b/t/helper/test-write-cache.c index f084034d38..b37dd2c5d6 100644 --- a/t/helper/test-write-cache.c +++ b/t/helper/test-write-cache.c @@ -1,4 +1,5 @@ -#define USE_THE_INDEX_VARIABLE +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "lockfile.h" #include "read-cache-ll.h" @@ -16,7 +17,7 @@ int cmd__write_cache(int argc, const char **argv) for (i = 0; i < cnt; i++) { repo_hold_locked_index(the_repository, &index_lock, LOCK_DIE_ON_ERROR); - if (write_locked_index(&the_index, &index_lock, COMMIT_LOCK)) + if (write_locked_index(the_repository->index, &index_lock, COMMIT_LOCK)) die("unable to write index file"); } diff --git a/t/lib-bundle-uri-protocol.sh b/t/lib-bundle-uri-protocol.sh index a4a1af8d02..de09b6b02e 100644 --- a/t/lib-bundle-uri-protocol.sh +++ b/t/lib-bundle-uri-protocol.sh @@ -18,7 +18,7 @@ git) start_git_daemon --export-all --enable=receive-pack BUNDLE_URI_PARENT="$GIT_DAEMON_DOCUMENT_ROOT_PATH/parent" BUNDLE_URI_REPO_URI="$GIT_DAEMON_URL/parent" - BUNDLE_URI_BUNDLE_URI="https://example.com/fake.bdl" + BUNDLE_URI_BUNDLE_URI="$BUNDLE_URI_REPO_URI/fake.bdl" test_set_prereq BUNDLE_URI_GIT ;; http) @@ -26,7 +26,7 @@ http) start_httpd BUNDLE_URI_PARENT="$HTTPD_DOCUMENT_ROOT_PATH/http_parent" BUNDLE_URI_REPO_URI="$HTTPD_URL/smart/http_parent" - BUNDLE_URI_BUNDLE_URI="https://example.com/fake.bdl" + BUNDLE_URI_BUNDLE_URI="$BUNDLE_URI_REPO_URL/fake.bdl" test_set_prereq BUNDLE_URI_HTTP ;; *) diff --git a/t/lib-chunk.sh b/t/lib-chunk.sh index a7cd9c3c6d..9f01df190b 100644 --- a/t/lib-chunk.sh +++ b/t/lib-chunk.sh @@ -13,5 +13,6 @@ corrupt_chunk_file () { fn=$1; shift perl "$TEST_DIRECTORY"/lib-chunk/corrupt-chunk-file.pl \ "$@" <"$fn" >"$fn.tmp" && - mv "$fn.tmp" "$fn" + # some vintages of macOS 'mv' fails to overwrite a read-only file. + mv -f "$fn.tmp" "$fn" } diff --git a/t/lib-credential.sh b/t/lib-credential.sh index 44799c0d38..58b9c74060 100644 --- a/t/lib-credential.sh +++ b/t/lib-credential.sh @@ -538,6 +538,129 @@ helper_test_oauth_refresh_token() { ' } +helper_test_authtype() { + HELPER=$1 + + test_expect_success "helper ($HELPER) stores authtype and credential" ' + check approve $HELPER <<-\EOF + capability[]=authtype + authtype=Bearer + credential=random-token + protocol=https + host=git.example.com + EOF + ' + + test_expect_success "helper ($HELPER) gets authtype and credential" ' + check fill $HELPER <<-\EOF + capability[]=authtype + protocol=https + host=git.example.com + -- + capability[]=authtype + authtype=Bearer + credential=random-token + protocol=https + host=git.example.com + -- + EOF + ' + + test_expect_success "helper ($HELPER) stores authtype and credential with username" ' + check approve $HELPER <<-\EOF + capability[]=authtype + authtype=Bearer + credential=other-token + protocol=https + host=git.example.com + username=foobar + EOF + ' + + test_expect_success "helper ($HELPER) gets authtype and credential with username" ' + check fill $HELPER <<-\EOF + capability[]=authtype + protocol=https + host=git.example.com + username=foobar + -- + capability[]=authtype + authtype=Bearer + credential=other-token + protocol=https + host=git.example.com + username=foobar + -- + EOF + ' + + test_expect_success "helper ($HELPER) does not get authtype and credential with different username" ' + check fill $HELPER <<-\EOF + capability[]=authtype + protocol=https + host=git.example.com + username=barbaz + -- + protocol=https + host=git.example.com + username=barbaz + password=askpass-password + -- + askpass: Password for '\''https://barbaz@git.example.com'\'': + EOF + ' + + test_expect_success "helper ($HELPER) does not store ephemeral authtype and credential" ' + check approve $HELPER <<-\EOF && + capability[]=authtype + authtype=Bearer + credential=git2-token + protocol=https + host=git2.example.com + ephemeral=1 + EOF + + check fill $HELPER <<-\EOF + capability[]=authtype + protocol=https + host=git2.example.com + -- + protocol=https + host=git2.example.com + username=askpass-username + password=askpass-password + -- + askpass: Username for '\''https://git2.example.com'\'': + askpass: Password for '\''https://askpass-username@git2.example.com'\'': + EOF + ' + + test_expect_success "helper ($HELPER) does not store ephemeral username and password" ' + check approve $HELPER <<-\EOF && + capability[]=authtype + protocol=https + host=git2.example.com + user=barbaz + password=secret + ephemeral=1 + EOF + + check fill $HELPER <<-\EOF + capability[]=authtype + protocol=https + host=git2.example.com + -- + protocol=https + host=git2.example.com + username=askpass-username + password=askpass-password + -- + askpass: Username for '\''https://git2.example.com'\'': + askpass: Password for '\''https://askpass-username@git2.example.com'\'': + EOF + ' +} + write_script askpass <<\EOF echo >&2 askpass: $* what=$(echo $1 | cut -d" " -f1 | tr A-Z a-z | tr -cd a-z) diff --git a/t/lib-httpd/nph-custom-auth.sh b/t/lib-httpd/nph-custom-auth.sh index f5345e775e..d408d2caad 100644 --- a/t/lib-httpd/nph-custom-auth.sh +++ b/t/lib-httpd/nph-custom-auth.sh @@ -19,21 +19,30 @@ CHALLENGE_FILE=custom-auth.challenge # if test -n "$HTTP_AUTHORIZATION" && \ - grep -Fqsx "${HTTP_AUTHORIZATION}" "$VALID_CREDS_FILE" + grep -Fqs "creds=${HTTP_AUTHORIZATION}" "$VALID_CREDS_FILE" then + idno=$(grep -F "creds=${HTTP_AUTHORIZATION}" "$VALID_CREDS_FILE" | sed -e 's/^id=\([a-z0-9-][a-z0-9-]*\) .*$/\1/') + status=$(sed -ne "s/^id=$idno.*status=\\([0-9][0-9][0-9]\\).*\$/\\1/p" "$CHALLENGE_FILE" | head -n1) # Note that although git-http-backend returns a status line, it # does so using a CGI 'Status' header. Because this script is an # No Parsed Headers (NPH) script, we must return a real HTTP # status line. # This is only a test script, so we don't bother to check for # the actual status from git-http-backend and always return 200. - echo 'HTTP/1.1 200 OK' - exec "$GIT_EXEC_PATH"/git-http-backend + echo "HTTP/1.1 $status Nonspecific Reason Phrase" + if test "$status" -eq 200 + then + exec "$GIT_EXEC_PATH"/git-http-backend + else + sed -ne "s/^id=$idno.*response=//p" "$CHALLENGE_FILE" + echo + exit + fi fi echo 'HTTP/1.1 401 Authorization Required' if test -f "$CHALLENGE_FILE" then - cat "$CHALLENGE_FILE" + sed -ne 's/^id=default.*response=//p' "$CHALLENGE_FILE" fi echo diff --git a/t/perf/p5333-pseudo-merge-bitmaps.sh b/t/perf/p5333-pseudo-merge-bitmaps.sh new file mode 100755 index 0000000000..2e8b1d2635 --- /dev/null +++ b/t/perf/p5333-pseudo-merge-bitmaps.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +test_description='pseudo-merge bitmaps' +. ./perf-lib.sh + +test_perf_large_repo + +test_expect_success 'setup' ' + git \ + -c bitmapPseudoMerge.all.pattern="refs/" \ + -c bitmapPseudoMerge.all.threshold=now \ + -c bitmapPseudoMerge.all.stableThreshold=never \ + -c bitmapPseudoMerge.all.maxMerges=64 \ + -c pack.writeBitmapLookupTable=true \ + repack -adb +' + +test_perf 'git rev-list --count --all --objects (no bitmaps)' ' + git rev-list --objects --all +' + +test_perf 'git rev-list --count --all --objects (no pseudo-merges)' ' + GIT_TEST_USE_PSEUDO_MERGES=0 \ + git rev-list --objects --all --use-bitmap-index +' + +test_perf 'git rev-list --count --all --objects (with pseudo-merges)' ' + GIT_TEST_USE_PSEUDO_MERGES=1 \ + git rev-list --objects --all --use-bitmap-index +' + +test_done diff --git a/t/run-test.sh b/t/run-test.sh new file mode 100755 index 0000000000..13c353b91b --- /dev/null +++ b/t/run-test.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +# A simple wrapper to run shell tests via TEST_SHELL_PATH, +# or exec unit tests directly. + +case "$1" in +*.sh) + if test -z "${TEST_SHELL_PATH}" + then + echo >&2 "ERROR: TEST_SHELL_PATH is empty or not set" + exit 1 + fi + exec "${TEST_SHELL_PATH}" "$@" + ;; +*) + exec "$@" + ;; +esac diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 6e300be2ac..98b81e4d63 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -1201,6 +1201,34 @@ test_expect_success 'very long name in the index handled sanely' ' test $len = 4098 ' +# D/F conflict checking uses an optimization when adding to the end. +# make sure it does not get confused by `a-` sorting _between_ +# `a` and `a/`. +test_expect_success 'more update-index D/F conflicts' ' + # empty the index to make sure our entry is last + git read-tree --empty && + cacheinfo=100644,$(test_oid empty_blob) && + git update-index --add --cacheinfo $cacheinfo,path5/a && + + test_must_fail git update-index --add --cacheinfo $cacheinfo,path5/a/file && + test_must_fail git update-index --add --cacheinfo $cacheinfo,path5/a/b/file && + test_must_fail git update-index --add --cacheinfo $cacheinfo,path5/a/b/c/file && + + # "a-" sorts between "a" and "a/" + git update-index --add --cacheinfo $cacheinfo,path5/a- && + + test_must_fail git update-index --add --cacheinfo $cacheinfo,path5/a/file && + test_must_fail git update-index --add --cacheinfo $cacheinfo,path5/a/b/file && + test_must_fail git update-index --add --cacheinfo $cacheinfo,path5/a/b/c/file && + + cat >expected <<-\EOF && + path5/a + path5/a- + EOF + git ls-files >actual && + test_cmp expected actual +' + test_expect_success 'test_must_fail on a failing git command' ' test_must_fail git notacommand ' diff --git a/t/t0001-init.sh b/t/t0001-init.sh index b131d665db..49e9bf77c6 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -584,14 +584,39 @@ test_expect_success 'init with --ref-format=files' ' test_cmp expect actual ' -test_expect_success 're-init with same format' ' - test_when_finished "rm -rf refformat" && - git init --ref-format=files refformat && - git init --ref-format=files refformat && - echo files >expect && - git -C refformat rev-parse --show-ref-format >actual && - test_cmp expect actual -' +backends="files reftable" +for from_format in $backends +do + test_expect_success "re-init with same format ($from_format)" ' + test_when_finished "rm -rf refformat" && + git init --ref-format=$from_format refformat && + git init --ref-format=$from_format refformat && + echo $from_format >expect && + git -C refformat rev-parse --show-ref-format >actual && + test_cmp expect actual + ' + + for to_format in $backends + do + if test "$from_format" = "$to_format" + then + continue + fi + + test_expect_success "re-init with different format fails ($from_format -> $to_format)" ' + test_when_finished "rm -rf refformat" && + git init --ref-format=$from_format refformat && + cat >expect <<-EOF && + fatal: attempt to reinitialize repository with different reference storage format + EOF + test_must_fail git init --ref-format=$to_format refformat 2>err && + test_cmp expect err && + echo $from_format >expect && + git -C refformat rev-parse --show-ref-format >actual && + test_cmp expect actual + ' + done +done test_expect_success 'init with --ref-format=garbage' ' test_when_finished "rm -rf refformat" && @@ -678,4 +703,64 @@ test_expect_success 'branch -m with the initial branch' ' test_cmp expect actual ' +test_expect_success 'init with includeIf.onbranch condition' ' + test_when_finished "rm -rf repo" && + git -c includeIf.onbranch:main.path=nonexistent init repo && + echo $GIT_DEFAULT_REF_FORMAT >expect && + git -C repo rev-parse --show-ref-format >actual && + test_cmp expect actual +' + +test_expect_success 'init with includeIf.onbranch condition with existing directory' ' + test_when_finished "rm -rf repo" && + mkdir repo && + git -c includeIf.onbranch:nonexistent.path=/does/not/exist init repo && + echo $GIT_DEFAULT_REF_FORMAT >expect && + git -C repo rev-parse --show-ref-format >actual && + test_cmp expect actual +' + +test_expect_success 're-init with includeIf.onbranch condition' ' + test_when_finished "rm -rf repo" && + git init repo && + git -c includeIf.onbranch:nonexistent.path=/does/not/exist init repo && + echo $GIT_DEFAULT_REF_FORMAT >expect && + git -C repo rev-parse --show-ref-format >actual && + test_cmp expect actual +' + +test_expect_success 're-init with includeIf.onbranch condition' ' + test_when_finished "rm -rf repo" && + git init repo && + git -c includeIf.onbranch:nonexistent.path=/does/not/exist init repo && + echo $GIT_DEFAULT_REF_FORMAT >expect && + git -C repo rev-parse --show-ref-format >actual && + test_cmp expect actual +' + +test_expect_success 're-init skips non-matching includeIf.onbranch' ' + test_when_finished "rm -rf repo config" && + cat >config <<-EOF && + [ + garbage + EOF + git init repo && + git -c includeIf.onbranch:nonexistent.path="$(test-tool path-utils absolute_path config)" init repo +' + +test_expect_success 're-init reads matching includeIf.onbranch' ' + test_when_finished "rm -rf repo config" && + cat >config <<-EOF && + [ + garbage + EOF + path="$(test-tool path-utils absolute_path config)" && + git init --initial-branch=branch repo && + cat >expect <<-EOF && + fatal: bad config line 1 in file $path + EOF + test_must_fail git -c includeIf.onbranch:branch.path="$path" init repo 2>err && + test_cmp expect err +' + test_done diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh index 774b52c298..66ccb5889d 100755 --- a/t/t0003-attributes.sh +++ b/t/t0003-attributes.sh @@ -398,13 +398,19 @@ test_expect_success 'bad attr source defaults to reading .gitattributes file' ' ) ' -test_expect_success 'bare repo defaults to reading .gitattributes from HEAD' ' +test_expect_success 'bare repo no longer defaults to reading .gitattributes from HEAD' ' test_when_finished rm -rf test bare_with_gitattribute && git init test && test_commit -C test gitattributes .gitattributes "f/path test=val" && git clone --bare test bare_with_gitattribute && - echo "f/path: test: val" >expect && + + echo "f/path: test: unspecified" >expect && git -C bare_with_gitattribute check-attr test -- f/path >actual && + test_cmp expect actual && + + echo "f/path: test: val" >expect && + git -C bare_with_gitattribute -c attr.tree=HEAD \ + check-attr test -- f/path >actual && test_cmp expect actual ' @@ -428,6 +434,21 @@ test_expect_success 'precedence of --attr-source, GIT_ATTR_SOURCE, then attr.tre ) ' +test_expect_success 'diff without repository with attr source' ' + mkdir -p "$TRASH_DIRECTORY/outside/nongit" && + ( + cd "$TRASH_DIRECTORY/outside/nongit" && + GIT_CEILING_DIRECTORIES="$TRASH_DIRECTORY/outside" && + export GIT_CEILING_DIRECTORIES && + touch file && + cat >expect <<-EOF && + fatal: cannot use --attr-source or GIT_ATTR_SOURCE without repo + EOF + test_must_fail env GIT_ATTR_SOURCE=HEAD git grep --no-index foo file 2>err && + test_cmp expect err + ) +' + test_expect_success 'bare repository: with --source' ' ( cd bare.git && @@ -572,6 +593,16 @@ test_expect_success EXPENSIVE 'large attributes file ignored in index' ' test_cmp expect err ' +test_expect_success EXPENSIVE 'large attributes blob ignored' ' + test_when_finished "git update-index --remove .gitattributes" && + blob=$(dd if=/dev/zero bs=1048576 count=101 2>/dev/null | git hash-object -w --stdin) && + git update-index --add --cacheinfo 100644,$blob,.gitattributes && + tree="$(git write-tree)" && + git check-attr --cached --all --source="$tree" path >/dev/null 2>err && + echo "warning: ignoring overly large gitattributes blob ${SQ}.gitattributes${SQ}" >expect && + test_cmp expect err +' + test_expect_success 'builtin object mode attributes work (dir and regular paths)' ' >normal && attr_check_object_mode normal 100644 && diff --git a/t/t0006-date.sh b/t/t0006-date.sh index 3031256d14..fd373e1b39 100755 --- a/t/t0006-date.sh +++ b/t/t0006-date.sh @@ -8,6 +8,11 @@ TEST_PASSES_SANITIZE_LEAK=true # arbitrary reference time: 2009-08-30 19:20:00 GIT_TEST_DATE_NOW=1251660000; export GIT_TEST_DATE_NOW +if test_have_prereq TIME_IS_64BIT,TIME_T_IS_64BIT +then + test_set_prereq HAVE_64BIT_TIME +fi + check_relative() { t=$(($GIT_TEST_DATE_NOW - $1)) echo "$t -> $2" >expect @@ -80,14 +85,15 @@ 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 -check_show iso-local "$FUTURE" "2152-06-19 22:24:56 +0000" TIME_IS_64BIT,TIME_T_IS_64BIT +check_show iso "$FUTURE" "2152-06-19 18:24:56 -0400" HAVE_64BIT_TIME +check_show iso-local "$FUTURE" "2152-06-19 22:24:56 +0000" HAVE_64BIT_TIME -check_parse() { +REQUIRE_64BIT_TIME= +check_parse () { echo "$1 -> $2" >expect - test_expect_${4:-success} "parse date ($1${3:+ TZ=$3})" " - TZ=${3:-$TZ} test-tool date parse '$1' >actual && - test_cmp expect actual + test_expect_success $REQUIRE_64BIT_TIME "parse date ($1${3:+ TZ=$3}) -> $2" " + TZ=${3:-$TZ} test-tool date parse '$1' >actual && + test_cmp expect actual " } @@ -117,6 +123,39 @@ check_parse '2008-02-14 20:30:45 -05:00' '2008-02-14 20:30:45 -0500' check_parse '2008-02-14 20:30:45' '2008-02-14 20:30:45 -0500' EST5 check_parse 'Thu, 7 Apr 2005 15:14:13 -0700' '2005-04-07 15:14:13 -0700' +check_parse '1970-01-01 00:00:00' '1970-01-01 00:00:00 +0000' +check_parse '1970-01-01 00:00:00 +00' '1970-01-01 00:00:00 +0000' +check_parse '1970-01-01 00:00:00 Z' '1970-01-01 00:00:00 +0000' +check_parse '1970-01-01 00:00:00 -01' '1970-01-01 00:00:00 -0100' +check_parse '1970-01-01 00:00:00 +01' bad +check_parse '1970-01-01 00:00:00 +11' bad +check_parse '1970-01-01 00:59:59 +01' bad +check_parse '1970-01-01 01:00:00 +01' '1970-01-01 01:00:00 +0100' +check_parse '1970-01-01 01:00:00 +11' bad +check_parse '1970-01-02 00:00:00 +11' '1970-01-02 00:00:00 +1100' +check_parse '1969-12-31 23:59:59' bad +check_parse '1969-12-31 23:59:59 +00' bad +check_parse '1969-12-31 23:59:59 Z' bad +check_parse '1969-12-31 23:59:59 +11' bad +check_parse '1969-12-31 23:59:59 -11' bad + +REQUIRE_64BIT_TIME=HAVE_64BIT_TIME +check_parse '2099-12-31 23:59:59' '2099-12-31 23:59:59 +0000' +check_parse '2099-12-31 23:59:59 +00' '2099-12-31 23:59:59 +0000' +check_parse '2099-12-31 23:59:59 Z' '2099-12-31 23:59:59 +0000' +check_parse '2099-12-31 23:59:59 +01' '2099-12-31 23:59:59 +0100' +check_parse '2099-12-31 23:59:59 -01' bad +check_parse '2099-12-31 23:59:59 -11' bad +check_parse '2099-12-31 23:00:00 -01' bad +check_parse '2099-12-31 22:59:59 -01' '2099-12-31 22:59:59 -0100' +check_parse '2100-00-00 00:00:00' bad +check_parse '2099-12-30 00:00:00 -11' '2099-12-30 00:00:00 -1100' +check_parse '2100-00-00 00:00:00 +00' bad +check_parse '2100-00-00 00:00:00 Z' bad +check_parse '2100-00-00 00:00:00 -11' bad +check_parse '2100-00-00 00:00:00 +11' bad +REQUIRE_64BIT_TIME= + check_approxidate() { echo "$1 -> $2 +0000" >expect test_expect_${3:-success} "parse approxidate ($1)" " diff --git a/t/t0007-git-var.sh b/t/t0007-git-var.sh index ff4fd9348c..9fc5882387 100755 --- a/t/t0007-git-var.sh +++ b/t/t0007-git-var.sh @@ -157,7 +157,7 @@ test_expect_success POSIXPERM 'GIT_SHELL_PATH points to a valid executable' ' test_expect_success MINGW 'GIT_SHELL_PATH points to a suitable shell' ' shellpath=$(git var GIT_SHELL_PATH) && case "$shellpath" in - *sh) ;; + [A-Z]:/*/sh.exe) test -f "$shellpath";; *) return 1;; esac ' diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh index 361446b2f4..02a18d4fdb 100755 --- a/t/t0008-ignores.sh +++ b/t/t0008-ignores.sh @@ -945,4 +945,12 @@ test_expect_success SYMLINKS 'symlinks not respected in-tree' ' test_grep "unable to access.*gitignore" err ' +test_expect_success EXPENSIVE 'large exclude file ignored in tree' ' + test_when_finished "rm .gitignore" && + dd if=/dev/zero of=.gitignore bs=101M count=1 && + git ls-files -o --exclude-standard 2>err && + echo "warning: ignoring excessively large pattern file: .gitignore" >expect && + test_cmp expect err +' + test_done diff --git a/t/t0014-alias.sh b/t/t0014-alias.sh index 95568342be..854d59ec58 100755 --- a/t/t0014-alias.sh +++ b/t/t0014-alias.sh @@ -44,4 +44,15 @@ test_expect_success 'run-command formats empty args properly' ' test_cmp expect actual ' +test_expect_success 'tracing a shell alias with arguments shows trace of prepared command' ' + cat >expect <<-EOF && + trace: start_command: SHELL -c ${SQ}echo \$* "\$@"${SQ} ${SQ}echo \$*${SQ} arg + EOF + git config alias.echo "!echo \$*" && + env GIT_TRACE=1 git echo arg 2>output && + # redact platform differences + sed -n -e "s/^\(trace: start_command:\) .* -c /\1 SHELL -c /p" output >actual && + test_cmp expect actual +' + test_done diff --git a/t/t0015-hash.sh b/t/t0015-hash.sh deleted file mode 100755 index 0a087a1983..0000000000 --- a/t/t0015-hash.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/sh - -test_description='test basic hash implementation' - -TEST_PASSES_SANITIZE_LEAK=true -. ./test-lib.sh - -test_expect_success 'test basic SHA-1 hash values' ' - test-tool sha1 </dev/null >actual && - grep da39a3ee5e6b4b0d3255bfef95601890afd80709 actual && - printf "a" | test-tool sha1 >actual && - grep 86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 actual && - printf "abc" | test-tool sha1 >actual && - grep a9993e364706816aba3e25717850c26c9cd0d89d actual && - printf "message digest" | test-tool sha1 >actual && - grep c12252ceda8be8994d5fa0290a47231c1d16aae3 actual && - printf "abcdefghijklmnopqrstuvwxyz" | test-tool sha1 >actual && - grep 32d10c7b8cf96570ca04ce37f2a19d84240d3a89 actual && - perl -e "$| = 1; print q{aaaaaaaaaa} for 1..100000;" | - test-tool sha1 >actual && - grep 34aa973cd4c4daa4f61eeb2bdbad27316534016f actual && - printf "blob 0\0" | test-tool sha1 >actual && - grep e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 actual && - printf "blob 3\0abc" | test-tool sha1 >actual && - grep f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f actual && - printf "tree 0\0" | test-tool sha1 >actual && - grep 4b825dc642cb6eb9a060e54bf8d69288fbee4904 actual -' - -test_expect_success 'test basic SHA-256 hash values' ' - test-tool sha256 </dev/null >actual && - grep e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 actual && - printf "a" | test-tool sha256 >actual && - grep ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb actual && - printf "abc" | test-tool sha256 >actual && - grep ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad actual && - printf "message digest" | test-tool sha256 >actual && - grep f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650 actual && - printf "abcdefghijklmnopqrstuvwxyz" | test-tool sha256 >actual && - grep 71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73 actual && - # Try to exercise the chunking code by turning autoflush on. - perl -e "$| = 1; print q{aaaaaaaaaa} for 1..100000;" | - test-tool sha256 >actual && - grep cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0 actual && - perl -e "$| = 1; print q{abcdefghijklmnopqrstuvwxyz} for 1..100000;" | - test-tool sha256 >actual && - grep e406ba321ca712ad35a698bf0af8d61fc4dc40eca6bdcea4697962724ccbde35 actual && - printf "blob 0\0" | test-tool sha256 >actual && - grep 473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813 actual && - printf "blob 3\0abc" | test-tool sha256 >actual && - grep c1cf6e465077930e88dc5136641d402f72a229ddd996f627d60e9639eaba35a6 actual && - printf "tree 0\0" | test-tool sha256 >actual && - grep 6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321 actual -' - -test_done diff --git a/t/t0016-oidmap.sh b/t/t0016-oidmap.sh deleted file mode 100755 index 0faef1f4f1..0000000000 --- a/t/t0016-oidmap.sh +++ /dev/null @@ -1,112 +0,0 @@ -#!/bin/sh - -test_description='test oidmap' - -TEST_PASSES_SANITIZE_LEAK=true -. ./test-lib.sh - -# This purposefully is very similar to t0011-hashmap.sh - -test_oidmap () { - echo "$1" | test-tool oidmap $3 >actual && - echo "$2" >expect && - test_cmp expect actual -} - - -test_expect_success 'setup' ' - - test_commit one && - test_commit two && - test_commit three && - test_commit four - -' - -test_expect_success 'put' ' - -test_oidmap "put one 1 -put two 2 -put invalidOid 4 -put three 3" "NULL -NULL -Unknown oid: invalidOid -NULL" - -' - -test_expect_success 'replace' ' - -test_oidmap "put one 1 -put two 2 -put three 3 -put invalidOid 4 -put two deux -put one un" "NULL -NULL -NULL -Unknown oid: invalidOid -2 -1" - -' - -test_expect_success 'get' ' - -test_oidmap "put one 1 -put two 2 -put three 3 -get two -get four -get invalidOid -get one" "NULL -NULL -NULL -2 -NULL -Unknown oid: invalidOid -1" - -' - -test_expect_success 'remove' ' - -test_oidmap "put one 1 -put two 2 -put three 3 -remove one -remove two -remove invalidOid -remove four" "NULL -NULL -NULL -1 -2 -Unknown oid: invalidOid -NULL" - -' - -test_expect_success 'iterate' ' - test-tool oidmap >actual.raw <<-\EOF && - put one 1 - put two 2 - put three 3 - iterate - EOF - - # sort "expect" too so we do not rely on the order of particular oids - sort >expect <<-EOF && - NULL - NULL - NULL - $(git rev-parse one) 1 - $(git rev-parse two) 2 - $(git rev-parse three) 3 - EOF - - sort <actual.raw >actual && - test_cmp expect actual -' - -test_done diff --git a/t/t0017-env-helper.sh b/t/t0017-env-helper.sh index fc14ba091c..f3a16859cc 100755 --- a/t/t0017-env-helper.sh +++ b/t/t0017-env-helper.sh @@ -91,9 +91,16 @@ test_expect_success 'test-tool env-helper reads config thanks to trace2' ' git config -l 2>err && grep "exceeded maximum include depth" err && + # This validates that the assumption that we attempt to + # read the configuration and fail very early in the start-up + # sequence (due to trace2 subsystem), even before we notice + # that the directory named with "test-tool -C" does not exist + # and die. It is a dubious thing to test, though. test_must_fail \ env HOME="$(pwd)/home" GIT_TEST_ENV_HELPER=true \ - test-tool -C cycle env-helper --type=bool --default=0 --exit-code GIT_TEST_ENV_HELPER 2>err && + test-tool -C no-such-directory \ + env-helper --type=bool --default=0 \ + --exit-code GIT_TEST_ENV_HELPER 2>err && grep "exceeded maximum include depth" err ' diff --git a/t/t0018-advice.sh b/t/t0018-advice.sh index 0dcfb760a2..29306b367c 100755 --- a/t/t0018-advice.sh +++ b/t/t0018-advice.sh @@ -2,6 +2,9 @@ test_description='Test advise_if_enabled functionality' +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=trunk +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh @@ -29,4 +32,72 @@ test_expect_success 'advice should not be printed when config variable is set to test_must_be_empty actual ' +test_expect_success 'advice should not be printed when --no-advice is used' ' + q_to_tab >expect <<-\EOF && + On branch trunk + + No commits yet + + Untracked files: + QREADME + + nothing added to commit but untracked files present + EOF + + test_when_finished "rm -fr advice-test" && + git init advice-test && + ( + cd advice-test && + >README && + git --no-advice status + ) >actual && + test_cmp expect actual +' + +test_expect_success 'advice should not be printed when GIT_ADVICE is set to false' ' + q_to_tab >expect <<-\EOF && + On branch trunk + + No commits yet + + Untracked files: + QREADME + + nothing added to commit but untracked files present + EOF + + test_when_finished "rm -fr advice-test" && + git init advice-test && + ( + cd advice-test && + >README && + GIT_ADVICE=false git status + ) >actual && + test_cmp expect actual +' + +test_expect_success 'advice should be printed when GIT_ADVICE is set to true' ' + q_to_tab >expect <<-\EOF && + On branch trunk + + No commits yet + + Untracked files: + (use "git add <file>..." to include in what will be committed) + QREADME + + nothing added to commit but untracked files present (use "git add" to track) + EOF + + test_when_finished "rm -fr advice-test" && + git init advice-test && + ( + cd advice-test && + >README && + GIT_ADVICE=true git status + ) >actual && + cat actual > /tmp/actual && + test_cmp expect actual +' + test_done diff --git a/t/t0033-safe-directory.sh b/t/t0033-safe-directory.sh index dc3496897a..5fe61f1291 100755 --- a/t/t0033-safe-directory.sh +++ b/t/t0033-safe-directory.sh @@ -71,7 +71,22 @@ test_expect_success 'safe.directory=*, but is reset' ' expect_rejected_dir ' +test_expect_success 'safe.directory with matching glob' ' + git config --global --unset-all safe.directory && + p=$(pwd) && + git config --global safe.directory "${p%/*}/*" && + git status +' + +test_expect_success 'safe.directory with unmatching glob' ' + git config --global --unset-all safe.directory && + p=$(pwd) && + git config --global safe.directory "${p%/*}no/*" && + expect_rejected_dir +' + test_expect_success 'safe.directory in included file' ' + git config --global --unset-all safe.directory && cat >gitconfig-include <<-EOF && [safe] directory = "$(pwd)" @@ -80,4 +95,28 @@ test_expect_success 'safe.directory in included file' ' git status ' +test_expect_success 'local clone of unowned repo refused in unsafe directory' ' + test_when_finished "rm -rf source" && + git init source && + ( + sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER && + test_commit -C source initial + ) && + test_must_fail git clone --local source target && + test_path_is_missing target +' + +test_expect_success 'local clone of unowned repo accepted in safe directory' ' + test_when_finished "rm -rf source" && + git init source && + ( + sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER && + test_commit -C source initial + ) && + test_must_fail git clone --local source target && + git config --global --add safe.directory "$(pwd)/source/.git" && + git clone --local source target && + test_path_is_dir target +' + test_done diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index 8bb2a8b453..45a773642f 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -176,6 +176,23 @@ test_expect_success 'long options' ' test_cmp expect output ' +test_expect_success 'abbreviate to something longer than SHA1 length' ' + cat >expect <<-EOF && + boolean: 0 + integer: 0 + magnitude: 0 + timestamp: 0 + string: (not set) + abbrev: 100 + verbose: -1 + quiet: 0 + dry run: no + file: (not set) + EOF + test-tool parse-options --abbrev=100 >output && + test_cmp expect output +' + test_expect_success 'missing required value' ' cat >expect <<-\EOF && error: switch `s'\'' requires a value diff --git a/t/t0064-oid-array.sh b/t/t0064-oid-array.sh index 88c89e8f48..de74b692d0 100755 --- a/t/t0064-oid-array.sh +++ b/t/t0064-oid-array.sh @@ -15,6 +15,24 @@ echoid () { done } +test_expect_success 'without repository' ' + cat >expect <<-EOF && + 4444444444444444444444444444444444444444 + 5555555555555555555555555555555555555555 + 8888888888888888888888888888888888888888 + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + EOF + cat >input <<-EOF && + append 4444444444444444444444444444444444444444 + append 5555555555555555555555555555555555555555 + append 8888888888888888888888888888888888888888 + append aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + for_each_unique + EOF + nongit test-tool oid-array <input >actual && + test_cmp expect actual +' + test_expect_success 'ordered enumeration' ' echoid "" 44 55 88 aa >expect && { diff --git a/t/t0065-strcmp-offset.sh b/t/t0065-strcmp-offset.sh deleted file mode 100755 index 94e34c83ed..0000000000 --- a/t/t0065-strcmp-offset.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh - -test_description='Test strcmp_offset functionality' - -TEST_PASSES_SANITIZE_LEAK=true -. ./test-lib.sh - -while read s1 s2 expect -do - test_expect_success "strcmp_offset($s1, $s2)" ' - echo "$expect" >expect && - test-tool strcmp-offset "$s1" "$s2" >actual && - test_cmp expect actual - ' -done <<-EOF -abc abc 0 3 -abc def -1 0 -abc abz -1 2 -abc abcdef -1 3 -EOF - -test_done diff --git a/t/t0068-for-each-repo.sh b/t/t0068-for-each-repo.sh index 4b90b74d5d..95019e01ed 100755 --- a/t/t0068-for-each-repo.sh +++ b/t/t0068-for-each-repo.sh @@ -59,4 +59,20 @@ test_expect_success 'error on NULL value for config keys' ' test_cmp expect actual ' +test_expect_success '--keep-going' ' + git config keep.going non-existing && + git config --add keep.going . && + + test_must_fail git for-each-repo --config=keep.going \ + -- branch >out 2>err && + test_grep "cannot change to .*non-existing" err && + test_must_be_empty out && + + test_must_fail git for-each-repo --config=keep.going --keep-going \ + -- branch >out 2>err && + test_grep "cannot change to .*non-existing" err && + git branch >expect && + test_cmp expect out +' + test_done diff --git a/t/t0069-oidtree.sh b/t/t0069-oidtree.sh deleted file mode 100755 index 889db50818..0000000000 --- a/t/t0069-oidtree.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/sh - -test_description='basic tests for the oidtree implementation' -TEST_PASSES_SANITIZE_LEAK=true -. ./test-lib.sh - -maxhexsz=$(test_oid hexsz) -echoid () { - prefix="${1:+$1 }" - shift - while test $# -gt 0 - do - shortoid="$1" - shift - difference=$(($maxhexsz - ${#shortoid})) - printf "%s%s%0${difference}d\\n" "$prefix" "$shortoid" "0" - done -} - -test_expect_success 'oidtree insert and contains' ' - cat >expect <<-\EOF && - 0 - 0 - 0 - 1 - 1 - 0 - EOF - { - echoid insert 444 1 2 3 4 5 a b c d e && - echoid contains 44 441 440 444 4440 4444 && - echo clear - } | test-tool oidtree >actual && - test_cmp expect actual -' - -test_expect_success 'oidtree each' ' - echoid "" 123 321 321 >expect && - { - echoid insert f 9 8 123 321 a b c d e && - echo each 12300 && - echo each 3211 && - echo each 3210 && - echo each 32100 && - echo clear - } | test-tool oidtree >actual && - test_cmp expect actual -' - -test_done diff --git a/t/t0080-unit-test-output.sh b/t/t0080-unit-test-output.sh index 6657c114a3..7bbb065d58 100755 --- a/t/t0080-unit-test-output.sh +++ b/t/t0080-unit-test-output.sh @@ -9,50 +9,50 @@ test_expect_success 'TAP output from unit tests' ' cat >expect <<-EOF && ok 1 - passing test ok 2 - passing test and assertion return 1 - # check "1 == 2" failed at t/unit-tests/t-basic.c:76 + # check "1 == 2" failed at t/helper/test-example-tap.c:77 # left: 1 # right: 2 not ok 3 - failing test ok 4 - failing test and assertion return 0 not ok 5 - passing TEST_TODO() # TODO ok 6 - passing TEST_TODO() returns 1 - # todo check ${SQ}check(x)${SQ} succeeded at t/unit-tests/t-basic.c:25 + # todo check ${SQ}check(x)${SQ} succeeded at t/helper/test-example-tap.c:26 not ok 7 - failing TEST_TODO() ok 8 - failing TEST_TODO() returns 0 - # check "0" failed at t/unit-tests/t-basic.c:30 + # check "0" failed at t/helper/test-example-tap.c:31 # skipping test - missing prerequisite - # skipping check ${SQ}1${SQ} at t/unit-tests/t-basic.c:32 + # skipping check ${SQ}1${SQ} at t/helper/test-example-tap.c:33 ok 9 - test_skip() # SKIP ok 10 - skipped test returns 1 # skipping test - missing prerequisite ok 11 - test_skip() inside TEST_TODO() # SKIP ok 12 - test_skip() inside TEST_TODO() returns 1 - # check "0" failed at t/unit-tests/t-basic.c:48 + # check "0" failed at t/helper/test-example-tap.c:49 not ok 13 - TEST_TODO() after failing check ok 14 - TEST_TODO() after failing check returns 0 - # check "0" failed at t/unit-tests/t-basic.c:56 + # check "0" failed at t/helper/test-example-tap.c:57 not ok 15 - failing check after TEST_TODO() ok 16 - failing check after TEST_TODO() returns 0 - # check "!strcmp("\thello\\\\", "there\"\n")" failed at t/unit-tests/t-basic.c:61 + # check "!strcmp("\thello\\\\", "there\"\n")" failed at t/helper/test-example-tap.c:62 # left: "\011hello\\\\" # right: "there\"\012" - # check "!strcmp("NULL", NULL)" failed at t/unit-tests/t-basic.c:62 + # check "!strcmp("NULL", NULL)" failed at t/helper/test-example-tap.c:63 # left: "NULL" # right: NULL - # check "${SQ}a${SQ} == ${SQ}\n${SQ}" failed at t/unit-tests/t-basic.c:63 + # check "${SQ}a${SQ} == ${SQ}\n${SQ}" failed at t/helper/test-example-tap.c:64 # left: ${SQ}a${SQ} # right: ${SQ}\012${SQ} - # check "${SQ}\\\\${SQ} == ${SQ}\\${SQ}${SQ}" failed at t/unit-tests/t-basic.c:64 + # check "${SQ}\\\\${SQ} == ${SQ}\\${SQ}${SQ}" failed at t/helper/test-example-tap.c:65 # left: ${SQ}\\\\${SQ} # right: ${SQ}\\${SQ}${SQ} not ok 17 - messages from failing string and char comparison - # BUG: test has no checks at t/unit-tests/t-basic.c:91 + # BUG: test has no checks at t/helper/test-example-tap.c:92 not ok 18 - test with no checks ok 19 - test with no checks returns 0 1..19 EOF - ! "$GIT_BUILD_DIR"/t/unit-tests/bin/t-basic >actual && + ! test-tool example-tap >actual && test_cmp expect actual ' diff --git a/t/t0095-bloom.sh b/t/t0095-bloom.sh index b567383eb8..c8d84ab606 100755 --- a/t/t0095-bloom.sh +++ b/t/t0095-bloom.sh @@ -29,6 +29,14 @@ test_expect_success 'compute unseeded murmur3 hash for test string 2' ' test_cmp expect actual ' +test_expect_success 'compute unseeded murmur3 hash for test string 3' ' + cat >expect <<-\EOF && + Murmur3 Hash with seed=0:0xa183ccfd + EOF + test-tool bloom get_murmur3_seven_highbit >actual && + test_cmp expect actual +' + test_expect_success 'compute bloom key for empty string' ' cat >expect <<-\EOF && Hashes:0x5615800c|0x5b966560|0x61174ab4|0x66983008|0x6c19155c|0x7199fab0|0x771ae004| diff --git a/t/t0211-trace2-perf.sh b/t/t0211-trace2-perf.sh index 13ef69b92f..070fe7a5da 100755 --- a/t/t0211-trace2-perf.sh +++ b/t/t0211-trace2-perf.sh @@ -233,7 +233,7 @@ have_counter_event () { pattern="d0|${thread}|${event}||||${category}|name:${name} value:${value}" && - grep "${patern}" ${file} + grep "${pattern}" ${file} } test_expect_success 'global counter test/test1' ' diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh index 400f6bdbca..6a76b7fdbd 100755 --- a/t/t0300-credentials.sh +++ b/t/t0300-credentials.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='basic credential helper tests' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-credential.sh @@ -12,7 +14,13 @@ test_expect_success 'setup helper scripts' ' IFS== while read key value; do echo >&2 "$whoami: $key=$value" - eval "$key=$value" + if test -z "${key%%*\[\]}" + then + key=${key%%\[\]} + eval "$key=\"\$$key $value\"" + else + eval "$key=$value" + fi done IFS=$OIFS EOF @@ -35,6 +43,30 @@ test_expect_success 'setup helper scripts' ' test -z "$pass" || echo password=$pass EOF + write_script git-credential-verbatim-cred <<-\EOF && + authtype=$1; shift + credential=$1; shift + . ./dump + echo capability[]=authtype + echo capability[]=state + test -z "${capability##*authtype*}" || exit 0 + test -z "$authtype" || echo authtype=$authtype + test -z "$credential" || echo credential=$credential + test -z "${capability##*state*}" || exit 0 + echo state[]=verbatim-cred:foo + EOF + + write_script git-credential-verbatim-ephemeral <<-\EOF && + authtype=$1; shift + credential=$1; shift + . ./dump + echo capability[]=authtype + test -z "${capability##*authtype*}" || exit 0 + test -z "$authtype" || echo authtype=$authtype + test -z "$credential" || echo credential=$credential + echo "ephemeral=1" + EOF + write_script git-credential-verbatim-with-expiry <<-\EOF && user=$1; shift pass=$1; shift @@ -64,6 +96,67 @@ test_expect_success 'credential_fill invokes helper' ' EOF ' +test_expect_success 'credential_fill invokes helper with credential' ' + check fill "verbatim-cred Bearer token" <<-\EOF + capability[]=authtype + protocol=http + host=example.com + -- + capability[]=authtype + authtype=Bearer + credential=token + protocol=http + host=example.com + -- + verbatim-cred: get + verbatim-cred: capability[]=authtype + verbatim-cred: protocol=http + verbatim-cred: host=example.com + EOF +' + +test_expect_success 'credential_fill invokes helper with ephemeral credential' ' + check fill "verbatim-ephemeral Bearer token" <<-\EOF + capability[]=authtype + protocol=http + host=example.com + -- + capability[]=authtype + authtype=Bearer + credential=token + ephemeral=1 + protocol=http + host=example.com + -- + verbatim-ephemeral: get + verbatim-ephemeral: capability[]=authtype + verbatim-ephemeral: protocol=http + verbatim-ephemeral: host=example.com + EOF +' +test_expect_success 'credential_fill invokes helper with credential and state' ' + check fill "verbatim-cred Bearer token" <<-\EOF + capability[]=authtype + capability[]=state + protocol=http + host=example.com + -- + capability[]=authtype + capability[]=state + authtype=Bearer + credential=token + protocol=http + host=example.com + state[]=verbatim-cred:foo + -- + verbatim-cred: get + verbatim-cred: capability[]=authtype + verbatim-cred: capability[]=state + verbatim-cred: protocol=http + verbatim-cred: host=example.com + EOF +' + test_expect_success 'credential_fill invokes multiple helpers' ' check fill useless "verbatim foo bar" <<-\EOF protocol=http @@ -83,6 +176,45 @@ test_expect_success 'credential_fill invokes multiple helpers' ' EOF ' +test_expect_success 'credential_fill response does not get capabilities when helpers are incapable' ' + check fill useless "verbatim foo bar" <<-\EOF + capability[]=authtype + capability[]=state + protocol=http + host=example.com + -- + protocol=http + host=example.com + username=foo + password=bar + -- + useless: get + useless: capability[]=authtype + useless: capability[]=state + useless: protocol=http + useless: host=example.com + verbatim: get + verbatim: capability[]=authtype + verbatim: capability[]=state + verbatim: protocol=http + verbatim: host=example.com + EOF +' + +test_expect_success 'credential_fill response does not get capabilities when caller is incapable' ' + check fill "verbatim-cred Bearer token" <<-\EOF + protocol=http + host=example.com + -- + protocol=http + host=example.com + -- + verbatim-cred: get + verbatim-cred: protocol=http + verbatim-cred: host=example.com + EOF +' + test_expect_success 'credential_fill stops when we get a full response' ' check fill "verbatim one two" "verbatim three four" <<-\EOF protocol=http @@ -99,6 +231,25 @@ test_expect_success 'credential_fill stops when we get a full response' ' EOF ' +test_expect_success 'credential_fill thinks a credential is a full response' ' + check fill "verbatim-cred Bearer token" "verbatim three four" <<-\EOF + capability[]=authtype + protocol=http + host=example.com + -- + capability[]=authtype + authtype=Bearer + credential=token + protocol=http + host=example.com + -- + verbatim-cred: get + verbatim-cred: capability[]=authtype + verbatim-cred: protocol=http + verbatim-cred: host=example.com + EOF +' + test_expect_success 'credential_fill continues through partial response' ' check fill "verbatim one \"\"" "verbatim two three" <<-\EOF protocol=http @@ -175,6 +326,20 @@ test_expect_success 'credential_fill passes along metadata' ' EOF ' +test_expect_success 'credential_fill produces no credential without capability' ' + check fill "verbatim-cred Bearer token" <<-\EOF + protocol=http + host=example.com + -- + protocol=http + host=example.com + -- + verbatim-cred: get + verbatim-cred: protocol=http + verbatim-cred: host=example.com + EOF +' + test_expect_success 'credential_approve calls all helpers' ' check approve useless "verbatim one two" <<-\EOF protocol=http diff --git a/t/t0301-credential-cache.sh b/t/t0301-credential-cache.sh index f2c146fa2a..c10e35905e 100755 --- a/t/t0301-credential-cache.sh +++ b/t/t0301-credential-cache.sh @@ -39,6 +39,7 @@ test_atexit 'git credential-cache exit' helper_test cache helper_test_password_expiry_utc cache helper_test_oauth_refresh_token cache +helper_test_authtype cache test_expect_success 'socket defaults to ~/.cache/git/credential/socket' ' test_when_finished " diff --git a/t/t0410-partial-clone.sh b/t/t0410-partial-clone.sh index 88a66f0904..2c30c86e7b 100755 --- a/t/t0410-partial-clone.sh +++ b/t/t0410-partial-clone.sh @@ -3,6 +3,7 @@ test_description='partial clone' . ./test-lib.sh +. "$TEST_DIRECTORY"/lib-terminal.sh # missing promisor objects cause repacks which write bitmaps to fail GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 @@ -689,6 +690,67 @@ test_expect_success 'lazy-fetch when accessing object not in the_repository' ' ! grep "[?]$FILE_HASH" out ' +test_expect_success 'push should not fetch new commit objects' ' + rm -rf server client && + test_create_repo server && + test_config -C server uploadpack.allowfilter 1 && + test_config -C server uploadpack.allowanysha1inwant 1 && + test_commit -C server server1 && + + git clone --filter=blob:none "file://$(pwd)/server" client && + test_commit -C client client1 && + + test_commit -C server server2 && + COMMIT=$(git -C server rev-parse server2) && + + test_must_fail git -C client push 2>err && + grep "fetch first" err && + git -C client rev-list --objects --missing=print "$COMMIT" >objects && + grep "^[?]$COMMIT" objects +' + +test_expect_success 'setup for promisor.quiet tests' ' + rm -rf server && + test_create_repo server && + test_commit -C server foo && + git -C server rm foo.t && + git -C server commit -m remove && + git -C server config uploadpack.allowanysha1inwant 1 && + git -C server config uploadpack.allowfilter 1 +' + +test_expect_success TTY 'promisor.quiet=false shows progress messages' ' + rm -rf repo && + git clone --filter=blob:none "file://$(pwd)/server" repo && + git -C repo config promisor.quiet "false" && + + test_terminal git -C repo cat-file -p foo:foo.t 2>err && + + # Ensure that progress messages are written + grep "Receiving objects" err +' + +test_expect_success TTY 'promisor.quiet=true does not show progress messages' ' + rm -rf repo && + git clone --filter=blob:none "file://$(pwd)/server" repo && + git -C repo config promisor.quiet "true" && + + test_terminal git -C repo cat-file -p foo:foo.t 2>err && + + # Ensure that no progress messages are written + ! grep "Receiving objects" err +' + +test_expect_success TTY 'promisor.quiet=unconfigured shows progress messages' ' + rm -rf repo && + git clone --filter=blob:none "file://$(pwd)/server" repo && + + test_terminal git -C repo cat-file -p foo:foo.t 2>err && + + # Ensure that progress messages are written + grep "Receiving objects" err +' + . "$TEST_DIRECTORY"/lib-httpd.sh start_httpd diff --git a/t/t0411-clone-from-partial.sh b/t/t0411-clone-from-partial.sh new file mode 100755 index 0000000000..932bf2067d --- /dev/null +++ b/t/t0411-clone-from-partial.sh @@ -0,0 +1,79 @@ +#!/bin/sh + +test_description='check that local clone does not fetch from promisor remotes' + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +test_expect_success 'create evil repo' ' + git init tmp && + test_commit -C tmp a && + git -C tmp config uploadpack.allowfilter 1 && + git clone --filter=blob:none --no-local --no-checkout tmp evil && + rm -rf tmp && + + git -C evil config remote.origin.uploadpack \"\$TRASH_DIRECTORY/fake-upload-pack\" && + write_script fake-upload-pack <<-\EOF && + echo >&2 "fake-upload-pack running" + >"$TRASH_DIRECTORY/script-executed" + exit 1 + EOF + export TRASH_DIRECTORY && + + # empty shallow file disables local clone optimization + >evil/.git/shallow +' + +test_expect_success 'local clone must not fetch from promisor remote and execute script' ' + rm -f script-executed && + test_must_fail git clone \ + --upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \ + evil clone1 2>err && + test_grep "detected dubious ownership" err && + test_grep ! "fake-upload-pack running" err && + test_path_is_missing script-executed +' + +test_expect_success 'clone from file://... must not fetch from promisor remote and execute script' ' + rm -f script-executed && + test_must_fail git clone \ + --upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \ + "file://$(pwd)/evil" clone2 2>err && + test_grep "detected dubious ownership" err && + test_grep ! "fake-upload-pack running" err && + test_path_is_missing script-executed +' + +test_expect_success 'fetch from file://... must not fetch from promisor remote and execute script' ' + rm -f script-executed && + test_must_fail git fetch \ + --upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \ + "file://$(pwd)/evil" 2>err && + test_grep "detected dubious ownership" err && + test_grep ! "fake-upload-pack running" err && + test_path_is_missing script-executed +' + +test_expect_success 'pack-objects should fetch from promisor remote and execute script' ' + rm -f script-executed && + echo "HEAD" | test_must_fail git -C evil pack-objects --revs --stdout >/dev/null 2>err && + test_grep "fake-upload-pack running" err && + test_path_is_file script-executed +' + +test_expect_success 'clone from promisor remote does not lazy-fetch by default' ' + rm -f script-executed && + test_must_fail git clone evil no-lazy 2>err && + test_grep "lazy fetching disabled" err && + test_path_is_missing script-executed +' + +test_expect_success 'promisor lazy-fetching can be re-enabled' ' + rm -f script-executed && + test_must_fail env GIT_NO_LAZY_FETCH=0 \ + git clone evil lazy-ok 2>err && + test_grep "fake-upload-pack running" err && + test_path_is_file script-executed +' + +test_done diff --git a/t/t0450/txt-help-mismatches b/t/t0450/txt-help-mismatches index a0777acd66..28003f18c9 100644 --- a/t/t0450/txt-help-mismatches +++ b/t/t0450/txt-help-mismatches @@ -10,7 +10,6 @@ checkout checkout-index clone column -config credential credential-cache credential-store diff --git a/t/t0600-reffiles-backend.sh b/t/t0600-reffiles-backend.sh index 64214340e7..20df336cc3 100755 --- a/t/t0600-reffiles-backend.sh +++ b/t/t0600-reffiles-backend.sh @@ -4,16 +4,12 @@ test_description='Test reffiles backend' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +GIT_TEST_DEFAULT_REF_FORMAT=files +export GIT_TEST_DEFAULT_REF_FORMAT TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh -if ! test_have_prereq REFFILES -then - skip_all='skipping reffiles specific tests' - test_done -fi - test_expect_success 'setup' ' git commit --allow-empty -m Initial && C=$(git rev-parse HEAD) && @@ -95,82 +91,82 @@ test_expect_success 'empty directory should not fool 1-arg delete' ' git update-ref --stdin ' -test_expect_success 'non-empty directory blocks create' ' +test_expect_success 'non-empty directory blocks create' - <<\EOT prefix=refs/ne-create && mkdir -p .git/$prefix/foo/bar && : >.git/$prefix/foo/bar/baz.lock && test_when_finished "rm -f .git/$prefix/foo/bar/baz.lock" && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/foo$SQ: there is a non-empty directory $SQ.git/$prefix/foo$SQ blocking reference $SQ$prefix/foo$SQ + fatal: cannot lock ref '$prefix/foo': there is a non-empty directory '.git/$prefix/foo' blocking reference '$prefix/foo' EOF printf "%s\n" "update $prefix/foo $C" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/foo$SQ: unable to resolve reference $SQ$prefix/foo$SQ + fatal: cannot lock ref '$prefix/foo': unable to resolve reference '$prefix/foo' EOF printf "%s\n" "update $prefix/foo $D $C" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'broken reference blocks create' ' +test_expect_success 'broken reference blocks create' - <<\EOT prefix=refs/broken-create && mkdir -p .git/$prefix && echo "gobbledigook" >.git/$prefix/foo && test_when_finished "rm -f .git/$prefix/foo" && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/foo$SQ: unable to resolve reference $SQ$prefix/foo$SQ: reference broken + fatal: cannot lock ref '$prefix/foo': unable to resolve reference '$prefix/foo': reference broken EOF printf "%s\n" "update $prefix/foo $C" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/foo$SQ: unable to resolve reference $SQ$prefix/foo$SQ: reference broken + fatal: cannot lock ref '$prefix/foo': unable to resolve reference '$prefix/foo': reference broken EOF printf "%s\n" "update $prefix/foo $D $C" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'non-empty directory blocks indirect create' ' +test_expect_success 'non-empty directory blocks indirect create' - <<\EOT prefix=refs/ne-indirect-create && git symbolic-ref $prefix/symref $prefix/foo && mkdir -p .git/$prefix/foo/bar && : >.git/$prefix/foo/bar/baz.lock && test_when_finished "rm -f .git/$prefix/foo/bar/baz.lock" && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/symref$SQ: there is a non-empty directory $SQ.git/$prefix/foo$SQ blocking reference $SQ$prefix/foo$SQ + fatal: cannot lock ref '$prefix/symref': there is a non-empty directory '.git/$prefix/foo' blocking reference '$prefix/foo' EOF printf "%s\n" "update $prefix/symref $C" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/symref$SQ: unable to resolve reference $SQ$prefix/foo$SQ + fatal: cannot lock ref '$prefix/symref': unable to resolve reference '$prefix/foo' EOF printf "%s\n" "update $prefix/symref $D $C" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'broken reference blocks indirect create' ' +test_expect_success 'broken reference blocks indirect create' - <<\EOT prefix=refs/broken-indirect-create && git symbolic-ref $prefix/symref $prefix/foo && echo "gobbledigook" >.git/$prefix/foo && test_when_finished "rm -f .git/$prefix/foo" && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/symref$SQ: unable to resolve reference $SQ$prefix/foo$SQ: reference broken + fatal: cannot lock ref '$prefix/symref': unable to resolve reference '$prefix/foo': reference broken EOF printf "%s\n" "update $prefix/symref $C" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/symref$SQ: unable to resolve reference $SQ$prefix/foo$SQ: reference broken + fatal: cannot lock ref '$prefix/symref': unable to resolve reference '$prefix/foo': reference broken EOF printf "%s\n" "update $prefix/symref $D $C" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT test_expect_success 'no bogus intermediate values during delete' ' prefix=refs/slow-transaction && @@ -228,7 +224,7 @@ test_expect_success 'no bogus intermediate values during delete' ' test_must_fail git rev-parse --verify --quiet $prefix/foo ' -test_expect_success 'delete fails cleanly if packed-refs file is locked' ' +test_expect_success 'delete fails cleanly if packed-refs file is locked' - <<\EOT prefix=refs/locked-packed-refs && # Set up a reference with differing loose and packed versions: git update-ref $prefix/foo $C && @@ -240,9 +236,9 @@ test_expect_success 'delete fails cleanly if packed-refs file is locked' ' test_when_finished "rm -f .git/packed-refs.lock" && test_must_fail git update-ref -d $prefix/foo >out 2>err && git for-each-ref $prefix >actual && - test_grep "Unable to create $SQ.*packed-refs.lock$SQ: " err && + test_grep "Unable to create '.*packed-refs.lock': " err && test_cmp unchanged actual -' +EOT test_expect_success 'delete fails cleanly if packed-refs.new write fails' ' # Setup and expectations are similar to the test above. @@ -428,7 +424,7 @@ 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 && + rm -rf 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 && @@ -472,4 +468,36 @@ test_expect_success POSIXPERM 'git reflog expire honors core.sharedRepository' ' esac ' +test_expect_success SYMLINKS 'symref transaction supports symlinks' ' + test_when_finished "git symbolic-ref -d TEST_SYMREF_HEAD" && + git update-ref refs/heads/new @ && + test_config core.prefersymlinkrefs true && + cat >stdin <<-EOF && + start + symref-create TEST_SYMREF_HEAD refs/heads/new + prepare + commit + EOF + git update-ref --no-deref --stdin <stdin && + test_path_is_symlink .git/TEST_SYMREF_HEAD && + test "$(test_readlink .git/TEST_SYMREF_HEAD)" = refs/heads/new +' + +test_expect_success 'symref transaction supports false symlink config' ' + test_when_finished "git symbolic-ref -d TEST_SYMREF_HEAD" && + git update-ref refs/heads/new @ && + test_config core.prefersymlinkrefs false && + cat >stdin <<-EOF && + start + symref-create TEST_SYMREF_HEAD refs/heads/new + prepare + commit + EOF + git update-ref --no-deref --stdin <stdin && + test_path_is_file .git/TEST_SYMREF_HEAD && + git symbolic-ref TEST_SYMREF_HEAD >actual && + echo refs/heads/new >expect && + test_cmp expect actual +' + test_done diff --git a/t/t0601-reffiles-pack-refs.sh b/t/t0601-reffiles-pack-refs.sh index 7d4ab0b91a..60a544b8ee 100755 --- a/t/t0601-reffiles-pack-refs.sh +++ b/t/t0601-reffiles-pack-refs.sh @@ -9,18 +9,15 @@ test_description='git pack-refs should not change the branch semantic This test runs git pack-refs and git show-ref and checks that the branch semantic is still the same. ' + GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +GIT_TEST_DEFAULT_REF_FORMAT=files +export GIT_TEST_DEFAULT_REF_FORMAT TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh -if ! test_have_prereq REFFILES -then - skip_all='skipping reffiles specific tests' - test_done -fi - test_expect_success 'enable reflogs' ' git config core.logallrefupdates true ' diff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh index 178791e086..b06c46999d 100755 --- a/t/t0610-reftable-basics.sh +++ b/t/t0610-reftable-basics.sh @@ -4,17 +4,15 @@ # test_description='reftable basics' + GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +GIT_TEST_DEFAULT_REF_FORMAT=reftable +export GIT_TEST_DEFAULT_REF_FORMAT +TEST_PASSES_SANITIZE_LEAK=true . ./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' ' @@ -81,8 +79,8 @@ test_expect_success 'init: reinitializing reftable with files backend fails' ' ' test_expect_perms () { - local perms="$1" - local file="$2" + local perms="$1" && + local file="$2" && local actual="$(ls -l "$file")" && case "$actual" in @@ -286,7 +284,7 @@ test_expect_success 'ref transaction: creating symbolic ref fails with F/D confl git init repo && test_commit -C repo A && cat >expect <<-EOF && - error: unable to write symref for refs/heads: file/directory conflict + error: ${SQ}refs/heads/main${SQ} exists; cannot create ${SQ}refs/heads${SQ} EOF test_must_fail git -C repo symbolic-ref refs/heads refs/heads/foo 2>err && test_cmp expect err @@ -854,6 +852,39 @@ test_expect_success 'reflog: updates via HEAD update HEAD reflog' ' ) ' +test_expect_success 'branch: copying branch with D/F conflict' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit A && + git branch branch && + cat >expect <<-EOF && + error: ${SQ}refs/heads/branch${SQ} exists; cannot create ${SQ}refs/heads/branch/moved${SQ} + fatal: branch copy failed + EOF + test_must_fail git branch -c branch branch/moved 2>err && + test_cmp expect err + ) +' + +test_expect_success 'branch: moving branch with D/F conflict' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit A && + git branch branch && + git branch conflict && + cat >expect <<-EOF && + error: ${SQ}refs/heads/conflict${SQ} exists; cannot create ${SQ}refs/heads/conflict/moved${SQ} + fatal: branch rename failed + EOF + test_must_fail git branch -m branch conflict/moved 2>err && + test_cmp expect err + ) +' + test_expect_success 'worktree: adding worktree creates separate stack' ' test_when_finished "rm -rf repo worktree" && git init repo && diff --git a/t/t0611-reftable-httpd.sh b/t/t0611-reftable-httpd.sh index 5e05b9c1f2..2805995cc8 100755 --- a/t/t0611-reftable-httpd.sh +++ b/t/t0611-reftable-httpd.sh @@ -2,6 +2,7 @@ test_description='reftable HTTPD tests' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-httpd.sh diff --git a/t/t0612-reftable-jgit-compatibility.sh b/t/t0612-reftable-jgit-compatibility.sh new file mode 100755 index 0000000000..84922153ab --- /dev/null +++ b/t/t0612-reftable-jgit-compatibility.sh @@ -0,0 +1,133 @@ +#!/bin/sh + +test_description='reftables are compatible with JGit' + +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +GIT_TEST_DEFAULT_REF_FORMAT=reftable +export GIT_TEST_DEFAULT_REF_FORMAT + +# JGit does not support the 'link' DIRC extension. +GIT_TEST_SPLIT_INDEX=0 +export GIT_TEST_SPLIT_INDEX + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +if ! test_have_prereq JGIT +then + skip_all='skipping reftable JGit tests; JGit is not present in PATH' + test_done +fi + +if ! test_have_prereq SHA1 +then + skip_all='skipping reftable JGit tests; JGit does not support SHA256 reftables' + test_done +fi + +test_commit_jgit () { + touch "$1" && + jgit add "$1" && + jgit commit -m "$1" +} + +test_same_refs () { + git show-ref --head >cgit.actual && + jgit show-ref >jgit-tabs.actual && + tr "\t" " " <jgit-tabs.actual >jgit.actual && + test_cmp cgit.actual jgit.actual +} + +test_same_ref () { + git rev-parse "$1" >cgit.actual && + jgit rev-parse "$1" >jgit.actual && + test_cmp cgit.actual jgit.actual +} + +test_same_reflog () { + git reflog "$*" >cgit.actual && + jgit reflog "$*" >jgit-newline.actual && + sed '/^$/d' <jgit-newline.actual >jgit.actual && + test_cmp cgit.actual jgit.actual +} + +test_expect_success 'CGit repository can be read by JGit' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit A && + test_same_refs && + test_same_ref HEAD && + test_same_reflog HEAD + ) +' + +test_expect_success 'JGit repository can be read by CGit' ' + test_when_finished "rm -rf repo" && + jgit init repo && + ( + cd repo && + + touch file && + jgit add file && + jgit commit -m "initial commit" && + + # Note that we must convert the ref storage after we have + # written the default branch. Otherwise JGit will end up with + # no HEAD at all. + jgit convert-ref-storage --format=reftable && + + test_same_refs && + test_same_ref HEAD && + # Interestingly, JGit cannot read its own reflog here. CGit can + # though. + printf "%s HEAD@{0}: commit (initial): initial commit" "$(git rev-parse --short HEAD)" >expect && + git reflog HEAD >actual && + test_cmp expect actual + ) +' + +test_expect_success 'mixed writes from JGit and CGit' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + + test_commit A && + test_commit_jgit B && + test_commit C && + test_commit_jgit D && + + test_same_refs && + test_same_ref HEAD && + test_same_reflog HEAD + ) +' + +test_expect_success 'JGit can read multi-level index' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + + test_commit A && + awk " + BEGIN { + print \"start\"; + for (i = 0; i < 10000; i++) + printf \"create refs/heads/branch-%d HEAD\n\", i; + print \"commit\"; + } + " >input && + git update-ref --stdin <input && + + test_same_refs && + test_same_ref refs/heads/branch-1 && + test_same_ref refs/heads/branch-5738 && + test_same_ref refs/heads/branch-9999 + ) +' + +test_done diff --git a/t/t0613-reftable-write-options.sh b/t/t0613-reftable-write-options.sh new file mode 100755 index 0000000000..b1c6c97524 --- /dev/null +++ b/t/t0613-reftable-write-options.sh @@ -0,0 +1,287 @@ +#!/bin/sh + +test_description='reftable write options' + +GIT_TEST_DEFAULT_REF_FORMAT=reftable +export GIT_TEST_DEFAULT_REF_FORMAT +# Disable auto-compaction for all tests as we explicitly control repacking of +# refs. +GIT_TEST_REFTABLE_AUTOCOMPACTION=false +export GIT_TEST_REFTABLE_AUTOCOMPACTION +# Block sizes depend on the hash function, so we force SHA1 here. +GIT_TEST_DEFAULT_HASH=sha1 +export GIT_TEST_DEFAULT_HASH +# Block sizes also depend on the actual refs we write, so we force "master" to +# be the default initial branch name. +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +test_expect_success 'default write options' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit initial && + git pack-refs && + cat >expect <<-EOF && + header: + block_size: 4096 + ref: + - length: 129 + restarts: 2 + log: + - length: 262 + restarts: 2 + EOF + test-tool dump-reftable -b .git/reftable/*.ref >actual && + test_cmp expect actual + ) +' + +test_expect_success 'disabled reflog writes no log blocks' ' + test_config_global core.logAllRefUpdates false && + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit initial && + git pack-refs && + cat >expect <<-EOF && + header: + block_size: 4096 + ref: + - length: 129 + restarts: 2 + EOF + test-tool dump-reftable -b .git/reftable/*.ref >actual && + test_cmp expect actual + ) +' + +test_expect_success 'many refs results in multiple blocks' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit initial && + for i in $(test_seq 200) + do + printf "update refs/heads/branch-%d HEAD\n" "$i" || + return 1 + done >input && + git update-ref --stdin <input && + git pack-refs && + + cat >expect <<-EOF && + header: + block_size: 4096 + ref: + - length: 4049 + restarts: 11 + - length: 1136 + restarts: 3 + log: + - length: 4041 + restarts: 4 + - length: 4015 + restarts: 3 + - length: 4014 + restarts: 3 + - length: 4012 + restarts: 3 + - length: 3289 + restarts: 3 + EOF + test-tool dump-reftable -b .git/reftable/*.ref >actual && + test_cmp expect actual + ) +' + +test_expect_success 'tiny block size leads to error' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit initial && + cat >expect <<-EOF && + error: unable to compact stack: entry too large + EOF + test_must_fail git -c reftable.blockSize=50 pack-refs 2>err && + test_cmp expect err + ) +' + +test_expect_success 'small block size leads to multiple ref blocks' ' + test_config_global core.logAllRefUpdates false && + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit A && + test_commit B && + git -c reftable.blockSize=100 pack-refs && + + cat >expect <<-EOF && + header: + block_size: 100 + ref: + - length: 53 + restarts: 1 + - length: 74 + restarts: 1 + - length: 38 + restarts: 1 + EOF + test-tool dump-reftable -b .git/reftable/*.ref >actual && + test_cmp expect actual + ) +' + +test_expect_success 'small block size fails with large reflog message' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit A && + perl -e "print \"a\" x 500" >logmsg && + cat >expect <<-EOF && + fatal: update_ref failed for ref ${SQ}refs/heads/logme${SQ}: reftable: transaction failure: entry too large + EOF + test_must_fail git -c reftable.blockSize=100 \ + update-ref -m "$(cat logmsg)" refs/heads/logme HEAD 2>err && + test_cmp expect err + ) +' + +test_expect_success 'block size exceeding maximum supported size' ' + test_config_global core.logAllRefUpdates false && + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit A && + test_commit B && + cat >expect <<-EOF && + fatal: reftable block size cannot exceed 16MB + EOF + test_must_fail git -c reftable.blockSize=16777216 pack-refs 2>err && + test_cmp expect err + ) +' + +test_expect_success 'restart interval at every single record' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit initial && + for i in $(test_seq 10) + do + printf "update refs/heads/branch-%d HEAD\n" "$i" || + return 1 + done >input && + git update-ref --stdin <input && + git -c reftable.restartInterval=1 pack-refs && + + cat >expect <<-EOF && + header: + block_size: 4096 + ref: + - length: 566 + restarts: 13 + log: + - length: 1393 + restarts: 12 + EOF + test-tool dump-reftable -b .git/reftable/*.ref >actual && + test_cmp expect actual + ) +' + +test_expect_success 'restart interval exceeding maximum supported interval' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit initial && + cat >expect <<-EOF && + fatal: reftable block size cannot exceed 65535 + EOF + test_must_fail git -c reftable.restartInterval=65536 pack-refs 2>err && + test_cmp expect err + ) +' + +test_expect_success 'object index gets written by default with ref index' ' + test_config_global core.logAllRefUpdates false && + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit initial && + for i in $(test_seq 5) + do + printf "update refs/heads/branch-%d HEAD\n" "$i" || + return 1 + done >input && + git update-ref --stdin <input && + git -c reftable.blockSize=100 pack-refs && + + cat >expect <<-EOF && + header: + block_size: 100 + ref: + - length: 53 + restarts: 1 + - length: 95 + restarts: 1 + - length: 71 + restarts: 1 + - length: 80 + restarts: 1 + obj: + - length: 11 + restarts: 1 + EOF + test-tool dump-reftable -b .git/reftable/*.ref >actual && + test_cmp expect actual + ) +' + +test_expect_success 'object index can be disabled' ' + test_config_global core.logAllRefUpdates false && + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + test_commit initial && + for i in $(test_seq 5) + do + printf "update refs/heads/branch-%d HEAD\n" "$i" || + return 1 + done >input && + git update-ref --stdin <input && + git -c reftable.blockSize=100 -c reftable.indexObjects=false pack-refs && + + cat >expect <<-EOF && + header: + block_size: 100 + ref: + - length: 53 + restarts: 1 + - length: 95 + restarts: 1 + - length: 71 + restarts: 1 + - length: 80 + restarts: 1 + EOF + test-tool dump-reftable -b .git/reftable/*.ref >actual && + test_cmp expect actual + ) +' + +test_done diff --git a/t/t1004-read-tree-m-u-wf.sh b/t/t1004-read-tree-m-u-wf.sh index 11bf10424f..2b9720b0fe 100755 --- a/t/t1004-read-tree-m-u-wf.sh +++ b/t/t1004-read-tree-m-u-wf.sh @@ -5,6 +5,7 @@ test_description='read-tree -m -u checks working tree files' 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-read-tree.sh diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh index e12b221972..ff9bf213aa 100755 --- a/t/t1006-cat-file.sh +++ b/t/t1006-cat-file.sh @@ -1294,4 +1294,34 @@ test_expect_success 'batch-command flush without --buffer' ' grep "^fatal:.*flush is only for --buffer mode.*" err ' +script=' +use warnings; +use strict; +use IPC::Open2; +my ($opt, $oid, $expect, @pfx) = @ARGV; +my @cmd = (qw(git cat-file), $opt); +my $pid = open2(my $out, my $in, @cmd) or die "open2: @cmd"; +print $in @pfx, $oid, "\n" or die "print $!"; +my $rvec = ""; +vec($rvec, fileno($out), 1) = 1; +select($rvec, undef, undef, 30) or die "no response to `@pfx $oid` from @cmd"; +my $info = <$out>; +chop($info) eq "\n" or die "no LF"; +$info eq $expect or die "`$info` != `$expect`"; +close $in or die "close in $!"; +close $out or die "close out $!"; +waitpid $pid, 0; +$? == 0 or die "\$?=$?"; +' + +expect="$hello_oid blob $hello_size" + +test_expect_success PERL '--batch-check is unbuffered by default' ' + perl -e "$script" -- --batch-check $hello_oid "$expect" +' + +test_expect_success PERL '--batch-command info is unbuffered by default' ' + perl -e "$script" -- --batch-command $hello_oid "$expect" "info " +' + test_done diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh index 64aea38486..d73a5cc237 100755 --- a/t/t1007-hash-object.sh +++ b/t/t1007-hash-object.sh @@ -260,4 +260,10 @@ test_expect_success '--literally with extra-long type' ' echo example | git hash-object -t $t --literally --stdin ' +test_expect_success '--stdin outside of repository (uses SHA-1)' ' + nongit git hash-object --stdin <hello >actual && + echo "$(test_oid --hash=sha1 hello)" >expect && + test_cmp expect actual +' + test_done diff --git a/t/t1013-read-tree-submodule.sh b/t/t1013-read-tree-submodule.sh index bfc90d4cf2..cf8b94ebed 100755 --- a/t/t1013-read-tree-submodule.sh +++ b/t/t1013-read-tree-submodule.sh @@ -2,6 +2,7 @@ test_description='read-tree can handle submodules' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-submodule-update.sh diff --git a/t/t1015-read-index-unmerged.sh b/t/t1015-read-index-unmerged.sh index 55d22da32c..da737a32a2 100755 --- a/t/t1015-read-index-unmerged.sh +++ b/t/t1015-read-index-unmerged.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='Test various callers of read_index_unmerged' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup modify/delete + directory/file conflict' ' diff --git a/t/t1021-rerere-in-workdir.sh b/t/t1021-rerere-in-workdir.sh index 0b892894eb..69bf9476cb 100755 --- a/t/t1021-rerere-in-workdir.sh +++ b/t/t1021-rerere-in-workdir.sh @@ -4,6 +4,7 @@ test_description='rerere run in a workdir' 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 SYMLINKS setup ' diff --git a/t/t1090-sparse-checkout-scope.sh b/t/t1090-sparse-checkout-scope.sh index 3a14218b24..da0e7714d5 100755 --- a/t/t1090-sparse-checkout-scope.sh +++ b/t/t1090-sparse-checkout-scope.sh @@ -6,6 +6,7 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME TEST_CREATE_REPO_NO_TEMPLATE=1 +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t1091-sparse-checkout-builtin.sh b/t/t1091-sparse-checkout-builtin.sh index ab3a105fff..8c5cd651b4 100755 --- a/t/t1091-sparse-checkout-builtin.sh +++ b/t/t1091-sparse-checkout-builtin.sh @@ -8,6 +8,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME GIT_TEST_SPLIT_INDEX=false export GIT_TEST_SPLIT_INDEX +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh list_files() { diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh index 2f1ae5fd3b..a2c0e1b4dc 100755 --- a/t/t1092-sparse-checkout-compatibility.sh +++ b/t/t1092-sparse-checkout-compatibility.sh @@ -159,7 +159,10 @@ init_repos () { git -C sparse-checkout sparse-checkout set deep && git -C sparse-index sparse-checkout init --cone --sparse-index && test_cmp_config -C sparse-index true index.sparse && - git -C sparse-index sparse-checkout set deep + git -C sparse-index sparse-checkout set deep && + + # Disable this message to keep stderr the same. + git -C sparse-index config advice.sparseIndexExpanded false } init_repos_as_submodules () { @@ -2331,4 +2334,15 @@ test_expect_success 'sparse-index is not expanded: check-attr' ' ensure_not_expanded check-attr -a --cached -- folder1/a ' +test_expect_success 'advice.sparseIndexExpanded' ' + init_repos && + + git -C sparse-index config --unset advice.sparseIndexExpanded && + git -C sparse-index sparse-checkout set deep/deeper1 && + mkdir -p sparse-index/deep/deeper2/deepest && + touch sparse-index/deep/deeper2/deepest/bogus && + git -C sparse-index status 2>err && + grep "The sparse index is expanding to a full index" err +' + test_done diff --git a/t/t1300-config.sh b/t/t1300-config.sh index 9b65d9eaf5..9de2d95f06 100755 --- a/t/t1300-config.sh +++ b/t/t1300-config.sh @@ -11,6 +11,34 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh +for mode in legacy subcommands +do + +case "$mode" in +legacy) + mode_prefix="--" + mode_get="" + mode_get_all="--get-all" + mode_get_regexp="--get-regexp" + mode_set="" + mode_replace_all="--replace-all" + mode_unset="--unset" + mode_unset_all="--unset-all" + ;; +subcommands) + mode_prefix="" + mode_get="get" + mode_get_all="get --all" + mode_get_regexp="get --regexp --all --show-names" + mode_set="set" + mode_replace_all="set --all" + mode_unset="unset" + mode_unset_all="unset --all" + ;; +*) + BUG "unknown mode $mode";; +esac + test_expect_success 'setup whitespace config' ' sed -e "s/^|//" \ -e "s/[$]$//" \ @@ -112,7 +140,7 @@ cat > expect << EOF penguin = little blue EOF test_expect_success 'initial' ' - git config section.penguin "little blue" && + git config ${mode_set} section.penguin "little blue" && test_cmp expect .git/config ' @@ -122,7 +150,7 @@ cat > expect << EOF Movie = BadPhysics EOF test_expect_success 'mixed case' ' - git config Section.Movie BadPhysics && + git config ${mode_set} Section.Movie BadPhysics && test_cmp expect .git/config ' @@ -134,7 +162,7 @@ cat > expect << EOF WhatEver = Second EOF test_expect_success 'similar section' ' - git config Sections.WhatEver Second && + git config ${mode_set} Sections.WhatEver Second && test_cmp expect .git/config ' @@ -147,7 +175,7 @@ cat > expect << EOF WhatEver = Second EOF test_expect_success 'uppercase section' ' - git config SECTION.UPPERCASE true && + git config ${mode_set} SECTION.UPPERCASE true && test_cmp expect .git/config ' @@ -174,8 +202,8 @@ 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 ${mode_set} --comment="find fish" section.disposition peckish && + git config ${mode_set} --comment="#abc" section.foo bar && git config --comment="and comment" section.spsp value && git config --comment=" # and comment" section.htsp value && @@ -184,7 +212,7 @@ test_expect_success 'append comments' ' ' test_expect_success 'Prohibited LF in comment' ' - test_must_fail git config --comment="a${LF}b" section.k v + test_must_fail git config ${mode_set} --comment="a${LF}b" section.k v ' test_expect_success 'non-match result' 'test_cmp expect .git/config' @@ -235,7 +263,7 @@ foo = bar EOF test_expect_success 'unset with cont. lines' ' - git config --unset beta.baz + git config ${mode_unset} beta.baz ' cat > expect <<\EOF @@ -262,7 +290,7 @@ EOF cp .git/config .git/config2 test_expect_success 'multiple unset' ' - git config --unset-all beta.haha + git config ${mode_unset_all} beta.haha ' cat > expect << EOF @@ -281,14 +309,14 @@ test_expect_success 'multiple unset is correct' ' cp .git/config2 .git/config test_expect_success '--replace-all missing value' ' - test_must_fail git config --replace-all beta.haha && + test_must_fail git config ${mode_replace_all} beta.haha && test_cmp .git/config2 .git/config ' rm .git/config2 test_expect_success '--replace-all' ' - git config --replace-all beta.haha gamma + git config ${mode_replace_all} beta.haha gamma ' cat > expect << EOF @@ -315,7 +343,7 @@ noIndent= sillyValue ; 'nother silly comment [nextSection] noNewline = ouch EOF test_expect_success 'really mean test' ' - git config beta.haha alpha && + git config ${mode_set} beta.haha alpha && test_cmp expect .git/config ' @@ -330,7 +358,7 @@ noIndent= sillyValue ; 'nother silly comment nonewline = wow EOF test_expect_success 'really really mean test' ' - git config nextsection.nonewline wow && + git config ${mode_set} nextsection.nonewline wow && test_cmp expect .git/config ' @@ -348,7 +376,7 @@ noIndent= sillyValue ; 'nother silly comment nonewline = wow EOF test_expect_success 'unset' ' - git config --unset beta.haha && + git config ${mode_unset} beta.haha && test_cmp expect .git/config ' @@ -384,7 +412,7 @@ test_expect_success 'multi-valued get-all returns all' ' wow wow2 for me EOF - git config --get-all nextsection.nonewline >actual && + git config ${mode_get_all} nextsection.nonewline >actual && test_cmp expect actual ' @@ -404,11 +432,11 @@ test_expect_success 'multivar replace' ' ' test_expect_success 'ambiguous unset' ' - test_must_fail git config --unset nextsection.nonewline + test_must_fail git config ${mode_unset} nextsection.nonewline ' test_expect_success 'invalid unset' ' - test_must_fail git config --unset somesection.nonewline + test_must_fail git config ${mode_unset} somesection.nonewline ' cat > expect << EOF @@ -422,7 +450,12 @@ noIndent= sillyValue ; 'nother silly comment EOF test_expect_success 'multivar unset' ' - git config --unset nextsection.nonewline "wow3$" && + case "$mode" in + legacy) + git config --unset nextsection.nonewline "wow3$";; + subcommands) + git config unset --value="wow3$" nextsection.nonewline;; + esac && test_cmp expect .git/config ' @@ -460,11 +493,11 @@ version.1.2.3eX.alpha=beta EOF test_expect_success 'working --list' ' - git config --list > output && + git config ${mode_prefix}list > output && test_cmp expect output ' test_expect_success '--list without repo produces empty output' ' - git --git-dir=nonexistent config --list >output && + git --git-dir=nonexistent config ${mode_prefix}list >output && test_must_be_empty output ' @@ -476,7 +509,7 @@ version.1.2.3eX.alpha EOF test_expect_success '--name-only --list' ' - git config --name-only --list >output && + git config ${mode_prefix}list --name-only >output && test_cmp expect output ' @@ -486,7 +519,7 @@ nextsection.nonewline wow2 for me EOF test_expect_success '--get-regexp' ' - git config --get-regexp in >output && + git config ${mode_get_regexp} in >output && test_cmp expect output ' @@ -496,7 +529,7 @@ nextsection.nonewline EOF test_expect_success '--name-only --get-regexp' ' - git config --name-only --get-regexp in >output && + git config ${mode_get_regexp} --name-only in >output && test_cmp expect output ' @@ -507,7 +540,7 @@ EOF test_expect_success '--add' ' git config --add nextsection.nonewline "wow4 for you" && - git config --get-all nextsection.nonewline > output && + git config ${mode_get_all} nextsection.nonewline > output && test_cmp expect output ' @@ -529,21 +562,21 @@ test_expect_success 'get variable with empty value' ' echo novalue.variable > expect test_expect_success 'get-regexp variable with no value' ' - git config --get-regexp novalue > output && + git config ${mode_get_regexp} novalue > output && test_cmp expect output ' echo 'novalue.variable true' > expect test_expect_success 'get-regexp --bool variable with no value' ' - git config --bool --get-regexp novalue > output && + git config ${mode_get_regexp} --bool novalue > output && test_cmp expect output ' echo 'emptyvalue.variable ' > expect test_expect_success 'get-regexp variable with empty value' ' - git config --get-regexp emptyvalue > output && + git config ${mode_get_regexp} emptyvalue > output && test_cmp expect output ' @@ -563,7 +596,8 @@ test_expect_success 'get bool variable with empty value' ' test_expect_success 'no arguments, but no crash' ' test_must_fail git config >output 2>&1 && - test_grep usage output + echo "error: no action specified" >expect && + test_cmp expect output ' cat > .git/config << EOF @@ -614,17 +648,17 @@ ein.bahn=strasse EOF test_expect_success 'alternative GIT_CONFIG' ' - GIT_CONFIG=other-config git config --list >output && + GIT_CONFIG=other-config git config ${mode_prefix}list >output && test_cmp expect output ' test_expect_success 'alternative GIT_CONFIG (--file)' ' - git config --file other-config --list >output && + git config ${mode_prefix}list --file other-config >output && test_cmp expect output ' test_expect_success 'alternative GIT_CONFIG (--file=-)' ' - git config --file - --list <other-config >output && + git config ${mode_prefix}list --file - <other-config >output && test_cmp expect output ' @@ -633,10 +667,11 @@ test_expect_success 'setting a value in stdin is an error' ' ' test_expect_success 'editing stdin is an error' ' - test_must_fail git config --file - --edit + test_must_fail git config ${mode_prefix}edit --file - ' test_expect_success 'refer config from subdirectory' ' + test_when_finished "rm -r x" && mkdir x && test_cmp_config -C x strasse --file=../other-config --get ein.bahn ' @@ -665,7 +700,7 @@ weird EOF test_expect_success 'rename section' ' - git config --rename-section branch.eins branch.zwei + git config ${mode_prefix}rename-section branch.eins branch.zwei ' cat > expect << EOF @@ -684,7 +719,7 @@ test_expect_success 'rename succeeded' ' ' test_expect_success 'rename non-existing section' ' - test_must_fail git config --rename-section \ + test_must_fail git config ${mode_prefix}rename-section \ branch."world domination" branch.drei ' @@ -693,7 +728,7 @@ test_expect_success 'rename succeeded' ' ' test_expect_success 'rename another section' ' - git config --rename-section branch."1 234 blabl/a" branch.drei + git config ${mode_prefix}rename-section branch."1 234 blabl/a" branch.drei ' cat > expect << EOF @@ -716,7 +751,7 @@ cat >> .git/config << EOF EOF test_expect_success 'rename a section with a var on the same line' ' - git config --rename-section branch.vier branch.zwei + git config ${mode_prefix}rename-section branch.vier branch.zwei ' cat > expect << EOF @@ -737,11 +772,11 @@ test_expect_success 'rename succeeded' ' ' test_expect_success 'renaming empty section name is rejected' ' - test_must_fail git config --rename-section branch.zwei "" + test_must_fail git config ${mode_prefix}rename-section branch.zwei "" ' test_expect_success 'renaming to bogus section is rejected' ' - test_must_fail git config --rename-section branch.zwei "bogus name" + test_must_fail git config ${mode_prefix}rename-section branch.zwei "bogus name" ' test_expect_success 'renaming a section with a long line' ' @@ -750,7 +785,7 @@ test_expect_success 'renaming a section with a long line' ' printf " c = d %1024s [a] e = f\\n" " " && printf "[a] g = h\\n" } >y && - git config -f y --rename-section a xyz && + git config ${mode_prefix}rename-section -f y a xyz && test_must_fail git config -f y b.e ' @@ -760,7 +795,7 @@ test_expect_success 'renaming an embedded section with a long line' ' printf " c = d %1024s [a] [foo] e = f\\n" " " && printf "[a] g = h\\n" } >y && - git config -f y --rename-section a xyz && + git config ${mode_prefix}rename-section -f y a xyz && test_must_fail git config -f y foo.e ' @@ -770,7 +805,7 @@ test_expect_success 'renaming a section with an overly-long line' ' printf " c = d %525000s e" " " && printf "[a] g = h\\n" } >y && - test_must_fail git config -f y --rename-section a xyz 2>err && + test_must_fail git config ${mode_prefix}rename-section -f y a xyz 2>err && grep "refusing to work with overly long line in .y. on line 2" err ' @@ -779,7 +814,7 @@ cat >> .git/config << EOF EOF test_expect_success 'remove section' ' - git config --remove-section branch.zwei + git config ${mode_prefix}remove-section branch.zwei ' cat > expect << EOF @@ -803,16 +838,16 @@ EOF test_expect_success 'section ending' ' rm -f .git/config && - git config gitcvs.enabled true && - git config gitcvs.ext.dbname %Ggitcvs1.%a.%m.sqlite && - git config gitcvs.dbname %Ggitcvs2.%a.%m.sqlite && + git config ${mode_set} gitcvs.enabled true && + git config ${mode_set} gitcvs.ext.dbname %Ggitcvs1.%a.%m.sqlite && + git config ${mode_set} gitcvs.dbname %Ggitcvs2.%a.%m.sqlite && test_cmp expect .git/config ' test_expect_success numbers ' - git config kilo.gram 1k && - git config mega.ton 1m && + git config ${mode_set} kilo.gram 1k && + git config ${mode_set} mega.ton 1m && echo 1024 >expect && echo 1048576 >>expect && git config --int --get kilo.gram >actual && @@ -821,20 +856,20 @@ test_expect_success numbers ' ' test_expect_success '--int is at least 64 bits' ' - git config giga.watts 121g && + git config ${mode_set} giga.watts 121g && echo >expect && test_cmp_config 129922760704 --int --get giga.watts ' test_expect_success 'invalid unit' ' - git config aninvalid.unit "1auto" && + git config ${mode_set} aninvalid.unit "1auto" && test_cmp_config 1auto aninvalid.unit && test_must_fail git config --int --get aninvalid.unit 2>actual && test_grep "bad numeric config value .1auto. for .aninvalid.unit. in file .git/config: invalid unit" actual ' test_expect_success 'invalid unit boolean' ' - git config commit.gpgsign "1true" && + git config ${mode_set} commit.gpgsign "1true" && test_cmp_config 1true commit.gpgsign && test_must_fail git config --bool --get commit.gpgsign 2>actual && test_grep "bad boolean config value .1true. for .commit.gpgsign." actual @@ -847,7 +882,7 @@ test_expect_success 'line number is reported correctly' ' ' test_expect_success 'invalid stdin config' ' - echo "[broken" | test_must_fail git config --list --file - >output 2>&1 && + echo "[broken" | test_must_fail git config ${mode_prefix}list --file - >output 2>&1 && test_grep "bad config line 1 in standard input" output ' @@ -864,14 +899,14 @@ EOF test_expect_success bool ' - git config bool.true1 01 && - git config bool.true2 -1 && - git config bool.true3 YeS && - git config bool.true4 true && - git config bool.false1 000 && - git config bool.false2 "" && - git config bool.false3 nO && - git config bool.false4 FALSE && + git config ${mode_set} bool.true1 01 && + git config ${mode_set} bool.true2 -1 && + git config ${mode_set} bool.true3 YeS && + git config ${mode_set} bool.true4 true && + git config ${mode_set} bool.false1 000 && + git config ${mode_set} bool.false2 "" && + git config ${mode_set} bool.false3 nO && + git config ${mode_set} bool.false4 FALSE && rm -f result && for i in 1 2 3 4 do @@ -882,7 +917,7 @@ test_expect_success bool ' test_expect_success 'invalid bool (--get)' ' - git config bool.nobool foobar && + git config ${mode_set} bool.nobool foobar && test_must_fail git config --bool --get bool.nobool' test_expect_success 'invalid bool (set)' ' @@ -1071,7 +1106,7 @@ test_expect_success 'get --expiry-date' ' test_expect_success 'get --type=color' ' rm .git/config && - git config foo.color "red" && + git config ${mode_set} foo.color "red" && git config --get --type=color foo.color >actual.raw && test_decode_color <actual.raw >actual && echo "<RED>" >expect && @@ -1108,18 +1143,18 @@ cat > expect << EOF EOF test_expect_success 'quoting' ' rm -f .git/config && - git config quote.leading " test" && - git config quote.ending "test " && - git config quote.semicolon "test;test" && - git config quote.hash "test#test" && + git config ${mode_set} quote.leading " test" && + git config ${mode_set} quote.ending "test " && + git config ${mode_set} quote.semicolon "test;test" && + git config ${mode_set} quote.hash "test#test" && test_cmp expect .git/config ' test_expect_success 'key with newline' ' - test_must_fail git config "key.with + test_must_fail git config ${mode_get} "key.with newline" 123' -test_expect_success 'value with newline' 'git config key.sub value.with\\\ +test_expect_success 'value with newline' 'git config ${mode_set} key.sub value.with\\\ newline' cat > .git/config <<\EOF @@ -1139,7 +1174,7 @@ section.quotecont=cont;inued EOF test_expect_success 'value continued on next line' ' - git config --list > result && + git config ${mode_prefix}list > result && test_cmp expect result ' @@ -1163,14 +1198,14 @@ Qsection.sub=section.val4 Qsection.sub=section.val5Q EOF test_expect_success '--null --list' ' - git config --null --list >result.raw && + git config ${mode_prefix}list --null >result.raw && nul_to_q <result.raw >result && echo >>result && test_cmp expect result ' test_expect_success '--null --get-regexp' ' - git config --null --get-regexp "val[0-9]" >result.raw && + git config ${mode_get_regexp} --null "val[0-9]" >result.raw && nul_to_q <result.raw >result && echo >>result && test_cmp expect result @@ -1178,26 +1213,27 @@ test_expect_success '--null --get-regexp' ' 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 && + git config ${mode_set} section.val "foo bar" && + git config ${mode_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 && + git config ${mode_set} section.val "$(cat expect)" && + git config ${mode_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 && + git config ${mode_set} section.val "$(cat expect)" && + git config ${mode_get} section.val >actual && test_cmp expect actual ' test_expect_success SYMLINKS 'symlinked configuration' ' + test_when_finished "rm myconfig" && ln -s notyet myconfig && git config --file=myconfig test.frotz nitfol && test -h myconfig && @@ -1218,10 +1254,11 @@ test_expect_success SYMLINKS 'symlinked configuration' ' ' test_expect_success SYMLINKS 'symlink to nonexistent configuration' ' + test_when_finished "rm linktonada linktolinktonada" && ln -s doesnotexist linktonada && ln -s linktonada linktolinktonada && - test_must_fail git config --file=linktonada --list && - test_must_fail git config --file=linktolinktonada --list + test_must_fail git config ${mode_prefix}list --file=linktonada && + test_must_fail git config ${mode_prefix}list --file=linktolinktonada ' test_expect_success 'check split_cmdline return' ' @@ -1229,12 +1266,12 @@ test_expect_success 'check split_cmdline return' ' git init repo && ( cd repo && - git config alias.split-cmdline-fix "echo \"" && + git config ${mode_set} alias.split-cmdline-fix "echo \"" && test_must_fail git split-cmdline-fix && echo foo >foo && git add foo && git commit -m "initial commit" && - git config branch.main.mergeoptions "echo \"" && + git config ${mode_set} branch.main.mergeoptions "echo \"" && test_must_fail git merge main ) ' @@ -1266,18 +1303,18 @@ test_expect_success 'git -c can represent empty string' ' ' test_expect_success 'key sanity-checking' ' - test_must_fail git config foo=bar && - test_must_fail git config foo=.bar && - test_must_fail git config foo.ba=r && - test_must_fail git config foo.1bar && - test_must_fail git config foo."ba + test_must_fail git config ${mode_get} foo=bar && + test_must_fail git config ${mode_get} foo=.bar && + test_must_fail git config ${mode_get} foo.ba=r && + test_must_fail git config ${mode_get} foo.1bar && + test_must_fail git config ${mode_get} foo."ba z".bar && - test_must_fail git config . false && - test_must_fail git config .foo false && - test_must_fail git config foo. false && - test_must_fail git config .foo. false && - git config foo.bar true && - git config foo."ba =z".bar false + test_must_fail git config ${mode_set} . false && + test_must_fail git config ${mode_set} .foo false && + test_must_fail git config ${mode_set} foo. false && + test_must_fail git config ${mode_set} .foo. false && + git config ${mode_set} foo.bar true && + git config ${mode_set} foo."ba =z".bar false ' test_expect_success 'git -c works with aliases of builtins' ' @@ -1319,7 +1356,7 @@ test_expect_success 'git -c complains about empty key and value' ' ' test_expect_success 'multiple git -c appends config' ' - test_config alias.x "!git -c x.two=2 config --get-regexp ^x\.*" && + test_config alias.x "!git -c x.two=2 config ${mode_get_regexp} ^x\.*" && cat >expect <<-\EOF && x.one 1 x.two 2 @@ -1478,14 +1515,14 @@ do done test_expect_success 'git -c is not confused by empty environment' ' - GIT_CONFIG_PARAMETERS="" git -c x.one=1 config --list + GIT_CONFIG_PARAMETERS="" git -c x.one=1 config ${mode_prefix}list ' test_expect_success 'GIT_CONFIG_PARAMETERS handles old-style entries' ' v="${SQ}key.one=foo${SQ}" && v="$v ${SQ}key.two=bar${SQ}" && v="$v ${SQ}key.ambiguous=section.whatever=value${SQ}" && - GIT_CONFIG_PARAMETERS=$v git config --get-regexp "key.*" >actual && + GIT_CONFIG_PARAMETERS=$v git config ${mode_get_regexp} "key.*" >actual && cat >expect <<-EOF && key.one foo key.two bar @@ -1498,7 +1535,7 @@ test_expect_success 'GIT_CONFIG_PARAMETERS handles new-style entries' ' v="${SQ}key.one${SQ}=${SQ}foo${SQ}" && v="$v ${SQ}key.two${SQ}=${SQ}bar${SQ}" && v="$v ${SQ}key.ambiguous=section.whatever${SQ}=${SQ}value${SQ}" && - GIT_CONFIG_PARAMETERS=$v git config --get-regexp "key.*" >actual && + GIT_CONFIG_PARAMETERS=$v git config ${mode_get_regexp} "key.*" >actual && cat >expect <<-EOF && key.one foo key.two bar @@ -1512,7 +1549,7 @@ test_expect_success 'old and new-style entries can mix' ' v="$v ${SQ}key.newone${SQ}=${SQ}newfoo${SQ}" && v="$v ${SQ}key.oldtwo=oldbar${SQ}" && v="$v ${SQ}key.newtwo${SQ}=${SQ}newbar${SQ}" && - GIT_CONFIG_PARAMETERS=$v git config --get-regexp "key.*" >actual && + GIT_CONFIG_PARAMETERS=$v git config ${mode_get_regexp} "key.*" >actual && cat >expect <<-EOF && key.oldone oldfoo key.newone newfoo @@ -1525,7 +1562,7 @@ test_expect_success 'old and new-style entries can mix' ' test_expect_success 'old and new bools with ambiguous subsection' ' v="${SQ}key.with=equals.oldbool${SQ}" && v="$v ${SQ}key.with=equals.newbool${SQ}=" && - GIT_CONFIG_PARAMETERS=$v git config --get-regexp "key.*" >actual && + GIT_CONFIG_PARAMETERS=$v git config ${mode_get_regexp} "key.*" >actual && cat >expect <<-EOF && key.with equals.oldbool key.with=equals.newbool @@ -1539,7 +1576,7 @@ test_expect_success 'detect bogus GIT_CONFIG_PARAMETERS' ' env.two two EOF GIT_CONFIG_PARAMETERS="${SQ}env.one=one${SQ} ${SQ}env.two=two${SQ}" \ - git config --get-regexp "env.*" >actual && + git config ${mode_get_regexp} "env.*" >actual && test_cmp expect actual && cat >expect <<-EOF && @@ -1547,12 +1584,12 @@ test_expect_success 'detect bogus GIT_CONFIG_PARAMETERS' ' env.two two EOF GIT_CONFIG_PARAMETERS="${SQ}env.one=one${SQ}\\$SQ$SQ$SQ ${SQ}env.two=two${SQ}" \ - git config --get-regexp "env.*" >actual && + git config ${mode_get_regexp} "env.*" >actual && test_cmp expect actual && test_must_fail env \ GIT_CONFIG_PARAMETERS="${SQ}env.one=one${SQ}\\$SQ ${SQ}env.two=two${SQ}" \ - git config --get-regexp "env.*" + git config ${mode_get_regexp} "env.*" ' test_expect_success 'git --config-env=key=envvar support' ' @@ -1600,7 +1637,7 @@ test_expect_success 'git -c and --config-env work together' ' ENVVAR=env-value git \ -c bar.cmd=cmd-value \ --config-env=bar.env=ENVVAR \ - config --get-regexp "^bar.*" >actual && + config ${mode_get_regexp} "^bar.*" >actual && test_cmp expect actual ' @@ -1628,7 +1665,7 @@ test_expect_success 'git config handles environment config pairs' ' GIT_CONFIG_COUNT=2 \ GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="foo" \ GIT_CONFIG_KEY_1="pair.two" GIT_CONFIG_VALUE_1="bar" \ - git config --get-regexp "pair.*" >actual && + git config ${mode_get_regexp} "pair.*" >actual && cat >expect <<-EOF && pair.one foo pair.two bar @@ -1638,7 +1675,7 @@ test_expect_success 'git config handles environment config pairs' ' test_expect_success 'git config ignores pairs without count' ' test_must_fail env GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \ - git config pair.one 2>error && + git config ${mode_get} pair.one 2>error && test_must_be_empty error ' @@ -1646,7 +1683,7 @@ test_expect_success 'git config ignores pairs exceeding count' ' GIT_CONFIG_COUNT=1 \ GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \ GIT_CONFIG_KEY_1="pair.two" GIT_CONFIG_VALUE_1="value" \ - git config --get-regexp "pair.*" >actual 2>error && + git config ${mode_get_regexp} "pair.*" >actual 2>error && cat >expect <<-EOF && pair.one value EOF @@ -1657,43 +1694,43 @@ test_expect_success 'git config ignores pairs exceeding count' ' test_expect_success 'git config ignores pairs with zero count' ' test_must_fail env \ GIT_CONFIG_COUNT=0 GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \ - git config pair.one 2>error && + git config ${mode_get} pair.one 2>error && test_must_be_empty error ' test_expect_success 'git config ignores pairs with empty count' ' test_must_fail env \ GIT_CONFIG_COUNT= GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \ - git config pair.one 2>error && + git config ${mode_get} pair.one 2>error && test_must_be_empty error ' test_expect_success 'git config fails with invalid count' ' - test_must_fail env GIT_CONFIG_COUNT=10a git config --list 2>error && + test_must_fail env GIT_CONFIG_COUNT=10a git config ${mode_prefix}list 2>error && test_grep "bogus count" error && - test_must_fail env GIT_CONFIG_COUNT=9999999999999999 git config --list 2>error && + test_must_fail env GIT_CONFIG_COUNT=9999999999999999 git config ${mode_prefix}list 2>error && test_grep "too many entries" error ' test_expect_success 'git config fails with missing config key' ' test_must_fail env GIT_CONFIG_COUNT=1 GIT_CONFIG_VALUE_0="value" \ - git config --list 2>error && + git config ${mode_prefix}list 2>error && test_grep "missing config key" error ' test_expect_success 'git config fails with missing config value' ' test_must_fail env GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0="pair.one" \ - git config --list 2>error && + git config ${mode_prefix}list 2>error && test_grep "missing config value" error ' test_expect_success 'git config fails with invalid config pair key' ' test_must_fail env GIT_CONFIG_COUNT=1 \ GIT_CONFIG_KEY_0= GIT_CONFIG_VALUE_0=value \ - git config --list && + git config ${mode_prefix}list && test_must_fail env GIT_CONFIG_COUNT=1 \ GIT_CONFIG_KEY_0=missing-section GIT_CONFIG_VALUE_0=value \ - git config --list + git config ${mode_prefix}list ' test_expect_success 'environment overrides config file' ' @@ -1703,7 +1740,7 @@ test_expect_success 'environment overrides config file' ' one = value EOF GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=pair.one GIT_CONFIG_VALUE_0=override \ - git config pair.one >actual && + git config ${mode_get} pair.one >actual && cat >expect <<-EOF && override EOF @@ -1713,7 +1750,7 @@ test_expect_success 'environment overrides config file' ' test_expect_success 'GIT_CONFIG_PARAMETERS overrides environment config' ' GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=pair.one GIT_CONFIG_VALUE_0=value \ GIT_CONFIG_PARAMETERS="${SQ}pair.one=override${SQ}" \ - git config pair.one >actual && + git config ${mode_get} pair.one >actual && cat >expect <<-EOF && override EOF @@ -1732,8 +1769,8 @@ test_expect_success 'command line overrides environment config' ' test_expect_success 'git config --edit works' ' git config -f tmp test.value no && echo test.value=yes >expect && - GIT_EDITOR="echo [test]value=yes >" git config -f tmp --edit && - git config -f tmp --list >actual && + GIT_EDITOR="echo [test]value=yes >" git config ${mode_prefix}edit -f tmp && + git config ${mode_prefix}list -f tmp >actual && test_cmp expect actual ' @@ -1741,8 +1778,8 @@ test_expect_success 'git config --edit respects core.editor' ' git config -f tmp test.value no && echo test.value=yes >expect && test_config core.editor "echo [test]value=yes >" && - git config -f tmp --edit && - git config -f tmp --list >actual && + git config ${mode_prefix}edit -f tmp && + git config ${mode_prefix}list -f tmp >actual && test_cmp expect actual ' @@ -1788,20 +1825,28 @@ test_expect_success 'urlmatch' ' test_expect_code 1 git config --bool --get-urlmatch doesnt.exist https://good.example.com >actual && test_must_be_empty actual && + test_expect_code 1 git config get --url=https://good.example.com --bool doesnt.exist >actual && + test_must_be_empty actual && echo true >expect && git config --bool --get-urlmatch http.SSLverify https://good.example.com >actual && test_cmp expect actual && + git config get --bool --url=https://good.example.com http.SSLverify >actual && + test_cmp expect actual && echo false >expect && git config --bool --get-urlmatch http.sslverify https://weak.example.com >actual && test_cmp expect actual && + git config get --bool --url=https://weak.example.com http.sslverify >actual && + test_cmp expect actual && { echo http.cookiefile /tmp/cookie.txt && echo http.sslverify false } >expect && git config --get-urlmatch HTTP https://weak.example.com >actual && + test_cmp expect actual && + git config get --url=https://weak.example.com HTTP >actual && test_cmp expect actual ' @@ -1817,6 +1862,8 @@ test_expect_success 'urlmatch with --show-scope' ' local http.sslverify false EOF git config --get-urlmatch --show-scope HTTP https://weak.example.com >actual && + test_cmp expect actual && + git config get --url=https://weak.example.com --show-scope HTTP >actual && test_cmp expect actual ' @@ -1849,45 +1896,67 @@ test_expect_success 'urlmatch favors more specific URLs' ' echo http.cookiefile /tmp/root.txt >expect && git config --get-urlmatch HTTP https://example.com >actual && test_cmp expect actual && + git config get --url=https://example.com HTTP >actual && + test_cmp expect actual && echo http.cookiefile /tmp/subdirectory.txt >expect && git config --get-urlmatch HTTP https://example.com/subdirectory >actual && test_cmp expect actual && + git config get --url=https://example.com/subdirectory HTTP >actual && + test_cmp expect actual && echo http.cookiefile /tmp/subdirectory.txt >expect && git config --get-urlmatch HTTP https://example.com/subdirectory/nested >actual && test_cmp expect actual && + git config get --url=https://example.com/subdirectory/nested HTTP >actual && + test_cmp expect actual && echo http.cookiefile /tmp/user.txt >expect && git config --get-urlmatch HTTP https://user@example.com/ >actual && test_cmp expect actual && + git config get --url=https://user@example.com/ HTTP >actual && + test_cmp expect actual && echo http.cookiefile /tmp/subdirectory.txt >expect && git config --get-urlmatch HTTP https://averylonguser@example.com/subdirectory >actual && test_cmp expect actual && + git config get --url=https://averylonguser@example.com/subdirectory HTTP >actual && + test_cmp expect actual && echo http.cookiefile /tmp/preceding.txt >expect && git config --get-urlmatch HTTP https://preceding.example.com >actual && test_cmp expect actual && + git config get --url=https://preceding.example.com HTTP >actual && + test_cmp expect actual && echo http.cookiefile /tmp/wildcard.txt >expect && git config --get-urlmatch HTTP https://wildcard.example.com >actual && test_cmp expect actual && + git config get --url=https://wildcard.example.com HTTP >actual && + test_cmp expect actual && echo http.cookiefile /tmp/sub.txt >expect && git config --get-urlmatch HTTP https://sub.example.com/wildcardwithsubdomain >actual && test_cmp expect actual && + git config get --url=https://sub.example.com/wildcardwithsubdomain HTTP >actual && + test_cmp expect actual && echo http.cookiefile /tmp/trailing.txt >expect && git config --get-urlmatch HTTP https://trailing.example.com >actual && test_cmp expect actual && + git config get --url=https://trailing.example.com HTTP >actual && + test_cmp expect actual && echo http.cookiefile /tmp/sub.txt >expect && git config --get-urlmatch HTTP https://user@sub.example.com >actual && test_cmp expect actual && + git config get --url=https://user@sub.example.com HTTP >actual && + test_cmp expect actual && echo http.cookiefile /tmp/multiwildcard.txt >expect && git config --get-urlmatch HTTP https://wildcard.example.org >actual && + test_cmp expect actual && + git config get --url=https://wildcard.example.org HTTP >actual && test_cmp expect actual ' @@ -1954,7 +2023,7 @@ test_expect_success '--unset last key removes section (except if commented)' ' # please be careful when you update the above variable EOF - git config --unset section.key && + git config ${mode_unset} section.key && test_cmp expect .git/config && cat >.git/config <<-\EOF && @@ -1967,7 +2036,7 @@ test_expect_success '--unset last key removes section (except if commented)' ' [next-section] EOF - git config --unset section.key && + git config ${mode_unset} section.key && test_cmp expect .git/config && q_to_tab >.git/config <<-\EOF && @@ -1977,7 +2046,7 @@ test_expect_success '--unset last key removes section (except if commented)' ' [two] key = true EOF - git config --unset two.key && + git config ${mode_unset} two.key && ! grep two .git/config && q_to_tab >.git/config <<-\EOF && @@ -1987,7 +2056,7 @@ test_expect_success '--unset last key removes section (except if commented)' ' [one] key = true EOF - git config --unset-all one.key && + git config ${mode_unset_all} one.key && test_line_count = 0 .git/config && q_to_tab >.git/config <<-\EOF && @@ -1997,7 +2066,7 @@ test_expect_success '--unset last key removes section (except if commented)' ' [two] Qkey = true EOF - git config --unset two.key && + git config ${mode_unset} two.key && grep two .git/config && q_to_tab >.git/config <<-\EOF && @@ -2009,8 +2078,8 @@ test_expect_success '--unset last key removes section (except if commented)' ' [TWO "subsection"] [one] EOF - git config --unset two.subsection.key && - test "not [two subsection]" = "$(git config one.key)" && + git config ${mode_unset} two.subsection.key && + test "not [two subsection]" = "$(git config ${mode_get} one.key)" && test_line_count = 3 .git/config ' @@ -2021,7 +2090,7 @@ test_expect_success '--unset-all removes section if empty & uncommented' ' key = value2 EOF - git config --unset-all section.key && + git config ${mode_unset_all} section.key && test_line_count = 0 .git/config ' @@ -2044,7 +2113,7 @@ test_expect_success POSIXPERM,PERL 'preserves existing permissions' ' git config imap.pass Hunter2 && perl -e \ "die q(badset) if ((stat(q(.git/config)))[2] & 07777) != 0600" && - git config --rename-section imap pop && + git config ${mode_prefix}rename-section imap pop && perl -e \ "die q(badrename) if ((stat(q(.git/config)))[2] & 07777) != 0600" ' @@ -2093,7 +2162,7 @@ test_expect_success '--show-origin with --list' ' command line: user.cmdline=true EOF GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=user.environ GIT_CONFIG_VALUE_0=true\ - git -c user.cmdline=true config --list --show-origin >output && + git -c user.cmdline=true config ${mode_prefix}list --show-origin >output && test_cmp expect output ' @@ -2110,7 +2179,7 @@ test_expect_success '--show-origin with --list --null' ' includeQcommand line:Quser.cmdline trueQ EOF - git -c user.cmdline=true config --null --list --show-origin >output.raw && + git -c user.cmdline=true config ${mode_prefix}list --null --show-origin >output.raw && nul_to_q <output.raw >output && # The here-doc above adds a newline that the --null output would not # include. Add it here to make the two comparable. @@ -2124,7 +2193,7 @@ test_expect_success '--show-origin with single file' ' file:.git/config user.override=local file:.git/config include.path=../include/relative.include EOF - git config --local --list --show-origin >output && + git config ${mode_prefix}list --local --show-origin >output && test_cmp expect output ' @@ -2133,7 +2202,7 @@ test_expect_success '--show-origin with --get-regexp' ' file:$HOME/.gitconfig user.global true file:.git/config user.local true EOF - git config --show-origin --get-regexp "user\.[g|l].*" >output && + git config ${mode_get_regexp} --show-origin "user\.[g|l].*" >output && test_cmp expect output ' @@ -2141,7 +2210,7 @@ test_expect_success '--show-origin getting a single key' ' cat >expect <<-\EOF && file:.git/config local EOF - git config --show-origin user.override >output && + git config ${mode_get} --show-origin user.override >output && test_cmp expect output ' @@ -2162,7 +2231,7 @@ test_expect_success !MINGW '--show-origin escape special file name characters' ' cat >expect <<-\EOF && file:"file\" (dq) and spaces.conf" user.custom=true EOF - git config --file "$WEIRDLY_NAMED_FILE" --show-origin --list >output && + git config ${mode_prefix}list --file "$WEIRDLY_NAMED_FILE" --show-origin >output && test_cmp expect output ' @@ -2170,7 +2239,7 @@ test_expect_success '--show-origin stdin' ' cat >expect <<-\EOF && standard input: user.custom=true EOF - git config --file - --show-origin --list <"$CUSTOM_CONFIG_FILE" >output && + git config ${mode_prefix}list --file - --show-origin <"$CUSTOM_CONFIG_FILE" >output && test_cmp expect output ' @@ -2197,7 +2266,7 @@ test_expect_success '--show-origin blob' ' cat >expect <<-EOF && blob:$blob user.custom=true EOF - git config --blob=$blob --show-origin --list >output && + git config ${mode_prefix}list --blob=$blob --show-origin >output && test_cmp expect output ) ' @@ -2213,7 +2282,7 @@ test_expect_success '--show-origin blob ref' ' cp "$CUSTOM_CONFIG_FILE" custom.conf && git add custom.conf && git commit -m "new config file" && - git config --blob=main:custom.conf --show-origin --list >output && + git config ${mode_prefix}list --blob=main:custom.conf --show-origin >output && test_cmp expect output ) ' @@ -2239,13 +2308,14 @@ test_expect_success '--show-scope with --list' ' worktree user.worktree=true command user.cmdline=true EOF + test_when_finished "git worktree remove wt1" && git worktree add wt1 && # We need these to test for worktree scope, but outside of this # test, this is just noise test_config core.repositoryformatversion 1 && test_config extensions.worktreeConfig true && git config --worktree user.worktree true && - git -c user.cmdline=true config --list --show-scope >output && + git -c user.cmdline=true config ${mode_prefix}list --show-scope >output && test_cmp expect output ' @@ -2254,7 +2324,7 @@ test_expect_success !MINGW '--show-scope with --blob' ' cat >expect <<-EOF && command user.custom=true EOF - git config --blob=$blob --show-scope --list >output && + git config ${mode_prefix}list --blob=$blob --show-scope >output && test_cmp expect output ' @@ -2264,7 +2334,7 @@ test_expect_success '--show-scope with --local' ' local user.override=local local include.path=../include/relative.include EOF - git config --local --list --show-scope >output && + git config ${mode_prefix}list --local --show-scope >output && test_cmp expect output ' @@ -2272,7 +2342,7 @@ test_expect_success '--show-scope getting a single value' ' cat >expect <<-\EOF && local true EOF - git config --show-scope --get user.local >output && + git config ${mode_get} --show-scope user.local >output && test_cmp expect output ' @@ -2288,7 +2358,7 @@ test_expect_success '--show-scope with --show-origin' ' local file:.git/../include/relative.include user.relative=include command command line: user.cmdline=true EOF - git -c user.cmdline=true config --list --show-origin --show-scope >output && + git -c user.cmdline=true config ${mode_prefix}list --show-origin --show-scope >output && test_cmp expect output ' @@ -2329,7 +2399,7 @@ test_expect_success 'override global and system config' ' global home.config=true local local.config=true EOF - git config --show-scope --list >output && + git config ${mode_prefix}list --show-scope >output && test_cmp expect output && cat >expect <<-EOF && @@ -2338,20 +2408,20 @@ test_expect_success 'override global and system config' ' local local.config=true EOF GIT_CONFIG_NOSYSTEM=false GIT_CONFIG_SYSTEM=custom-system-config GIT_CONFIG_GLOBAL=custom-global-config \ - git config --show-scope --list >output && + git config ${mode_prefix}list --show-scope >output && test_cmp expect output && cat >expect <<-EOF && local local.config=true EOF GIT_CONFIG_NOSYSTEM=false GIT_CONFIG_SYSTEM=/dev/null GIT_CONFIG_GLOBAL=/dev/null \ - git config --show-scope --list >output && + git config ${mode_prefix}list --show-scope >output && test_cmp expect output ' test_expect_success 'override global and system config with missing file' ' - test_must_fail env GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=/dev/null git config --global --list && - test_must_fail env GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=does-not-exist git config --system --list && + test_must_fail env GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=/dev/null git config ${mode_prefix}list --global && + test_must_fail env GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=does-not-exist git config ${mode_prefix}list --system && GIT_CONFIG_GLOBAL=does-not-exist GIT_CONFIG_SYSTEM=does-not-exist git version ' @@ -2467,7 +2537,7 @@ test_expect_success '--replace-all does not invent newlines' ' [abc] Qkey = b EOF - git config --replace-all abc.key b && + git config ${mode_replace_all} abc.key b && test_cmp expect .git/config ' @@ -2478,7 +2548,7 @@ test_expect_success 'set all config with value-pattern' ' # no match => add new entry cp initial config && git config --file=config abc.key two a+ && - git config --file=config --list >actual && + git config ${mode_prefix}list --file=config >actual && cat >expect <<-\EOF && abc.key=one abc.key=two @@ -2491,7 +2561,7 @@ test_expect_success 'set all config with value-pattern' ' # multiple values, no match => add git config --file=config abc.key three a+ && - git config --file=config --list >actual && + git config ${mode_prefix}list --file=config >actual && cat >expect <<-\EOF && abc.key=one abc.key=two @@ -2501,7 +2571,7 @@ test_expect_success 'set all config with value-pattern' ' # single match => replace git config --file=config abc.key four h+ && - git config --file=config --list >actual && + git config ${mode_prefix}list --file=config >actual && cat >expect <<-\EOF && abc.key=one abc.key=two @@ -2516,7 +2586,7 @@ test_expect_success '--replace-all and value-pattern' ' git config --file=config --add abc.key two && git config --file=config --add abc.key three && git config --file=config --replace-all abc.key four "o+" && - git config --file=config --list >actual && + git config ${mode_prefix}list --file=config >actual && cat >expect <<-\EOF && abc.key=four abc.key=three @@ -2532,20 +2602,20 @@ test_expect_success 'refuse --fixed-value for incompatible actions' ' test_must_fail git config --file=config --fixed-value --add dev.null bogus && test_must_fail git config --file=config --fixed-value --get-urlmatch dev.null bogus && test_must_fail git config --file=config --fixed-value --get-urlmatch dev.null bogus && - test_must_fail git config --file=config --fixed-value --rename-section dev null && - test_must_fail git config --file=config --fixed-value --remove-section dev && - test_must_fail git config --file=config --fixed-value --list && + test_must_fail git config ${mode_prefix}rename-section --file=config --fixed-value dev null && + test_must_fail git config ${mode_prefix}remove-section --file=config --fixed-value dev && + test_must_fail git config ${mode_prefix}list --file=config --fixed-value && test_must_fail git config --file=config --fixed-value --get-color dev.null && test_must_fail git config --file=config --fixed-value --get-colorbool dev.null && # These modes complain when --fixed-value has no value-pattern - test_must_fail git config --file=config --fixed-value dev.null bogus && - test_must_fail git config --file=config --fixed-value --replace-all dev.null bogus && - test_must_fail git config --file=config --fixed-value --get dev.null && - test_must_fail git config --file=config --fixed-value --get-all dev.null && - test_must_fail git config --file=config --fixed-value --get-regexp "dev.*" && - test_must_fail git config --file=config --fixed-value --unset dev.null && - test_must_fail git config --file=config --fixed-value --unset-all dev.null + test_must_fail git config ${mode_set} --file=config --fixed-value dev.null bogus && + test_must_fail git config ${mode_replace_all} --file=config --fixed-value dev.null bogus && + test_must_fail git config ${mode_prefix}get --file=config --fixed-value dev.null && + test_must_fail git config ${mode_get_all} --file=config --fixed-value dev.null && + test_must_fail git config ${mode_get_regexp} --file=config --fixed-value "dev.*" && + test_must_fail git config ${mode_unset} --file=config --fixed-value dev.null && + test_must_fail git config ${mode_unset_all} --file=config --fixed-value dev.null ' test_expect_success '--fixed-value uses exact string matching' ' @@ -2555,7 +2625,7 @@ test_expect_success '--fixed-value uses exact string matching' ' cp initial config && git config --file=config fixed.test bogus "$META" && - git config --file=config --list >actual && + git config ${mode_prefix}list --file=config >actual && cat >expect <<-EOF && fixed.test=$META fixed.test=bogus @@ -2564,7 +2634,7 @@ test_expect_success '--fixed-value uses exact string matching' ' cp initial config && git config --file=config --fixed-value fixed.test bogus "$META" && - git config --file=config --list >actual && + git config ${mode_prefix}list --file=config >actual && cat >expect <<-\EOF && fixed.test=bogus EOF @@ -2573,16 +2643,21 @@ test_expect_success '--fixed-value uses exact string matching' ' cp initial config && test_must_fail git config --file=config --unset fixed.test "$META" && git config --file=config --fixed-value --unset fixed.test "$META" && - test_must_fail git config --file=config fixed.test && + test_must_fail git config ${mode_get} --file=config fixed.test && + + cp initial config && + test_must_fail git config unset --file=config --value="$META" fixed.test && + git config unset --file=config --fixed-value --value="$META" fixed.test && + test_must_fail git config ${mode_get} --file=config fixed.test && cp initial config && test_must_fail git config --file=config --unset-all fixed.test "$META" && git config --file=config --fixed-value --unset-all fixed.test "$META" && - test_must_fail git config --file=config fixed.test && + test_must_fail git config ${mode_get} --file=config fixed.test && cp initial config && - git config --file=config --replace-all fixed.test bogus "$META" && - git config --file=config --list >actual && + git config --file=config fixed.test bogus "$META" && + git config ${mode_prefix}list --file=config >actual && cat >expect <<-EOF && fixed.test=$META fixed.test=bogus @@ -2590,7 +2665,7 @@ test_expect_success '--fixed-value uses exact string matching' ' test_cmp expect actual && git config --file=config --fixed-value --replace-all fixed.test bogus "$META" && - git config --file=config --list >actual && + git config ${mode_prefix}list --file=config >actual && cat >expect <<-EOF && fixed.test=bogus fixed.test=bogus @@ -2605,18 +2680,27 @@ test_expect_success '--get and --get-all with --fixed-value' ' git config --file=config --add fixed.test "$META" && git config --file=config --get fixed.test bogus && + git config get --file=config --value=bogus fixed.test && test_must_fail git config --file=config --get fixed.test "$META" && + test_must_fail git config get --file=config --value="$META" fixed.test && git config --file=config --get --fixed-value fixed.test "$META" && + git config get --file=config --fixed-value --value="$META" fixed.test && test_must_fail git config --file=config --get --fixed-value fixed.test non-existent && git config --file=config --get-all fixed.test bogus && + git config get --all --file=config --value=bogus fixed.test && test_must_fail git config --file=config --get-all fixed.test "$META" && + test_must_fail git config get --all --file=config --value="$META" fixed.test && git config --file=config --get-all --fixed-value fixed.test "$META" && + git config get --all --file=config --value="$META" --fixed-value fixed.test && test_must_fail git config --file=config --get-all --fixed-value fixed.test non-existent && git config --file=config --get-regexp fixed+ bogus && + git config get --regexp --file=config --value=bogus fixed+ && test_must_fail git config --file=config --get-regexp fixed+ "$META" && + test_must_fail git config get --regexp --file=config --value="$META" fixed+ && git config --file=config --get-regexp --fixed-value fixed+ "$META" && + git config get --regexp --file=config --fixed-value --value="$META" fixed+ && test_must_fail git config --file=config --get-regexp --fixed-value fixed+ non-existent ' @@ -2738,4 +2822,25 @@ test_expect_success 'includeIf.hasconfig:remote.*.url forbids remote url in such grep "fatal: remote URLs cannot be configured in file directly or indirectly included by includeIf.hasconfig:remote.*.url" err ' +test_expect_success 'negated mode causes failure' ' + test_must_fail git config --no-get 2>err && + grep "unknown option \`no-get${SQ}" err +' + +test_expect_success 'specifying multiple modes causes failure' ' + cat >expect <<-EOF && + error: options ${SQ}--get-all${SQ} and ${SQ}--get${SQ} cannot be used together + EOF + test_must_fail git config --get --get-all 2>err && + test_cmp expect err +' + +test_expect_success 'writing to stdin is rejected' ' + echo "fatal: writing to stdin is not supported" >expect && + test_must_fail git config ${mode_set} --file - foo.bar baz 2>err && + test_cmp expect err +' + +done + test_done diff --git a/t/t1306-xdg-files.sh b/t/t1306-xdg-files.sh index 40d3c42618..53e5b290b9 100755 --- a/t/t1306-xdg-files.sh +++ b/t/t1306-xdg-files.sh @@ -7,6 +7,7 @@ test_description='Compatibility with $XDG_CONFIG_HOME/git/ files' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'read config: xdg file exists and ~/.gitconfig doesn'\''t' ' diff --git a/t/t1350-config-hooks-path.sh b/t/t1350-config-hooks-path.sh index f6dc83e2aa..ceeb7ac3a4 100755 --- a/t/t1350-config-hooks-path.sh +++ b/t/t1350-config-hooks-path.sh @@ -2,6 +2,7 @@ test_description='Test the core.hooksPath configuration variable' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'set up a pre-commit hook in core.hooksPath' ' @@ -41,4 +42,11 @@ test_expect_success 'git rev-parse --git-path hooks' ' test .git/custom-hooks/abc = "$(cat actual)" ' +test_expect_success 'core.hooksPath=/dev/null' ' + git clone -c core.hooksPath=/dev/null . no-templates && + value="$(git -C no-templates config --local core.hooksPath)" && + # The Bash used by Git for Windows rewrites `/dev/null` to `nul` + { test /dev/null = "$value" || test nul = "$value"; } +' + test_done diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh index ec3443cc87..eb1691860d 100755 --- a/t/t1400-update-ref.sh +++ b/t/t1400-update-ref.sh @@ -4,6 +4,8 @@ # test_description='Test git update-ref and basic ref logging' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh Z=$ZERO_OID @@ -890,17 +892,23 @@ test_expect_success 'stdin update/create/verify combination works' ' ' test_expect_success 'stdin verify succeeds for correct value' ' + test-tool ref-store main for-each-reflog-ent $m >before && git rev-parse $m >expect && echo "verify $m $m" >stdin && git update-ref --stdin <stdin && git rev-parse $m >actual && - test_cmp expect actual + test_cmp expect actual && + test-tool ref-store main for-each-reflog-ent $m >after && + test_cmp before after ' test_expect_success 'stdin verify succeeds for missing reference' ' + test-tool ref-store main for-each-reflog-ent $m >before && echo "verify refs/heads/missing $Z" >stdin && git update-ref --stdin <stdin && - test_must_fail git rev-parse --verify -q refs/heads/missing + test_must_fail git rev-parse --verify -q refs/heads/missing && + test-tool ref-store main for-each-reflog-ent $m >after && + test_cmp before after ' test_expect_success 'stdin verify treats no value as missing' ' @@ -1354,6 +1362,7 @@ test_expect_success 'fails with duplicate HEAD update' ' ' test_expect_success 'fails with duplicate ref update via symref' ' + test_when_finished "git symbolic-ref -d refs/heads/symref2" && git branch target2 $A && git symbolic-ref refs/heads/symref2 refs/heads/target2 && cat >stdin <<-EOF && @@ -1641,4 +1650,423 @@ test_expect_success PIPE 'transaction flushes status updates' ' test_cmp expected actual ' +format_command () { + if test "$1" = "-z" + then + shift + printf "$F" "$@" + else + echo "$@" + fi +} + +for type in "" "-z" +do + + test_expect_success "stdin $type symref-verify fails without --no-deref" ' + git symbolic-ref refs/heads/symref $a && + format_command $type "symref-verify refs/heads/symref" "$a" >stdin && + test_must_fail git update-ref --stdin $type <stdin 2>err && + grep "fatal: symref-verify: cannot operate with deref mode" err + ' + + test_expect_success "stdin $type symref-verify fails with too many arguments" ' + format_command $type "symref-verify refs/heads/symref" "$a" "$a" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err && + if test "$type" = "-z" + then + grep "fatal: unknown command: $a" err + else + grep "fatal: symref-verify refs/heads/symref: extra input: $a" err + fi + ' + + test_expect_success "stdin $type symref-verify succeeds for correct value" ' + git symbolic-ref refs/heads/symref >expect && + test-tool ref-store main for-each-reflog-ent refs/heads/symref >before && + format_command $type "symref-verify refs/heads/symref" "$a" >stdin && + git update-ref --stdin $type --no-deref <stdin && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual && + test-tool ref-store main for-each-reflog-ent refs/heads/symref >after && + test_cmp before after + ' + + test_expect_success "stdin $type symref-verify fails with no value" ' + git symbolic-ref refs/heads/symref >expect && + format_command $type "symref-verify refs/heads/symref" "" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin + ' + + test_expect_success "stdin $type symref-verify succeeds for dangling reference" ' + test_when_finished "git symbolic-ref -d refs/heads/symref2" && + test_must_fail git symbolic-ref refs/heads/nonexistent && + git symbolic-ref refs/heads/symref2 refs/heads/nonexistent && + format_command $type "symref-verify refs/heads/symref2" "refs/heads/nonexistent" >stdin && + git update-ref --stdin $type --no-deref <stdin + ' + + test_expect_success "stdin $type symref-verify fails for missing reference" ' + test-tool ref-store main for-each-reflog-ent refs/heads/symref >before && + format_command $type "symref-verify refs/heads/missing" "refs/heads/unknown" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err && + grep "fatal: cannot lock ref ${SQ}refs/heads/missing${SQ}: unable to resolve reference ${SQ}refs/heads/missing${SQ}" err && + test_must_fail git rev-parse --verify -q refs/heads/missing && + test-tool ref-store main for-each-reflog-ent refs/heads/symref >after && + test_cmp before after + ' + + test_expect_success "stdin $type symref-verify fails for wrong value" ' + git symbolic-ref refs/heads/symref >expect && + format_command $type "symref-verify refs/heads/symref" "$b" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-verify fails for mistaken null value" ' + git symbolic-ref refs/heads/symref >expect && + format_command $type "symref-verify refs/heads/symref" "$Z" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-delete fails without --no-deref" ' + git symbolic-ref refs/heads/symref $a && + format_command $type "symref-delete refs/heads/symref" "$a" >stdin && + test_must_fail git update-ref --stdin $type <stdin 2>err && + grep "fatal: symref-delete: cannot operate with deref mode" err + ' + + test_expect_success "stdin $type symref-delete fails with no ref" ' + format_command $type "symref-delete " >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err && + grep "fatal: symref-delete: missing <ref>" err + ' + + test_expect_success "stdin $type symref-delete fails deleting regular ref" ' + test_when_finished "git update-ref -d refs/heads/regularref" && + git update-ref refs/heads/regularref $a && + format_command $type "symref-delete refs/heads/regularref" "$a" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err && + grep "fatal: cannot lock ref ${SQ}refs/heads/regularref${SQ}: expected symref with target ${SQ}$a${SQ}: but is a regular ref" err + ' + + test_expect_success "stdin $type symref-delete fails with too many arguments" ' + format_command $type "symref-delete refs/heads/symref" "$a" "$a" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err && + if test "$type" = "-z" + then + grep "fatal: unknown command: $a" err + else + grep "fatal: symref-delete refs/heads/symref: extra input: $a" err + fi + ' + + test_expect_success "stdin $type symref-delete fails with wrong old value" ' + format_command $type "symref-delete refs/heads/symref" "$m" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err && + grep "fatal: verifying symref target: ${SQ}refs/heads/symref${SQ}: is at $a but expected refs/heads/main" err && + git symbolic-ref refs/heads/symref >expect && + echo $a >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-delete works with right old value" ' + format_command $type "symref-delete refs/heads/symref" "$a" >stdin && + git update-ref --stdin $type --no-deref <stdin && + test_must_fail git rev-parse --verify -q refs/heads/symref + ' + + test_expect_success "stdin $type symref-delete works with empty old value" ' + git symbolic-ref refs/heads/symref $a >stdin && + format_command $type "symref-delete refs/heads/symref" "" >stdin && + git update-ref --stdin $type --no-deref <stdin && + test_must_fail git rev-parse --verify -q $b + ' + + test_expect_success "stdin $type symref-delete succeeds for dangling reference" ' + test_must_fail git symbolic-ref refs/heads/nonexistent && + git symbolic-ref refs/heads/symref2 refs/heads/nonexistent && + format_command $type "symref-delete refs/heads/symref2" "refs/heads/nonexistent" >stdin && + git update-ref --stdin $type --no-deref <stdin && + test_must_fail git symbolic-ref -d refs/heads/symref2 + ' + + test_expect_success "stdin $type symref-delete deletes regular ref without target" ' + git update-ref refs/heads/regularref $a && + format_command $type "symref-delete refs/heads/regularref" >stdin && + git update-ref --stdin $type --no-deref <stdin + ' + + test_expect_success "stdin $type symref-create fails with too many arguments" ' + format_command $type "symref-create refs/heads/symref" "$a" "$a" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err && + if test "$type" = "-z" + then + grep "fatal: unknown command: $a" err + else + grep "fatal: symref-create refs/heads/symref: extra input: $a" err + fi + ' + + test_expect_success "stdin $type symref-create fails with no target" ' + format_command $type "symref-create refs/heads/symref" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin + ' + + test_expect_success "stdin $type symref-create fails with empty target" ' + format_command $type "symref-create refs/heads/symref" "" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin + ' + + test_expect_success "stdin $type symref-create works" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + format_command $type "symref-create refs/heads/symref" "$a" >stdin && + git update-ref --stdin $type --no-deref <stdin && + git symbolic-ref refs/heads/symref >expect && + echo $a >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-create works with --no-deref" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + format_command $type "symref-create refs/heads/symref" "$a" && + git update-ref --stdin $type <stdin 2>err + ' + + test_expect_success "stdin $type create dangling symref ref works" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + format_command $type "symref-create refs/heads/symref" "refs/heads/unkown" >stdin && + git update-ref --stdin $type --no-deref <stdin && + git symbolic-ref refs/heads/symref >expect && + echo refs/heads/unkown >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-create does not create reflogs by default" ' + test_when_finished "git symbolic-ref -d refs/symref" && + format_command $type "symref-create refs/symref" "$a" >stdin && + git update-ref --stdin $type --no-deref <stdin && + git symbolic-ref refs/symref >expect && + echo $a >actual && + test_cmp expect actual && + test_must_fail git reflog exists refs/symref + ' + + test_expect_success "stdin $type symref-create reflogs with --create-reflog" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + format_command $type "symref-create refs/heads/symref" "$a" >stdin && + git update-ref --create-reflog --stdin $type --no-deref <stdin && + git symbolic-ref refs/heads/symref >expect && + echo $a >actual && + test_cmp expect actual && + git reflog exists refs/heads/symref + ' + + test_expect_success "stdin $type symref-update fails with too many arguments" ' + format_command $type "symref-update refs/heads/symref" "$a" "ref" "$a" "$a" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err && + if test "$type" = "-z" + then + grep "fatal: unknown command: $a" err + else + grep "fatal: symref-update refs/heads/symref: extra input: $a" err + fi + ' + + test_expect_success "stdin $type symref-update fails with wrong old value argument" ' + format_command $type "symref-update refs/heads/symref" "$a" "foo" "$a" "$a" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err && + grep "fatal: symref-update refs/heads/symref: invalid arg ${SQ}foo${SQ} for old value" err + ' + + test_expect_success "stdin $type symref-update creates with zero old value" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + format_command $type "symref-update refs/heads/symref" "$a" "oid" "$Z" >stdin && + git update-ref --stdin $type --no-deref <stdin && + echo $a >expect && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-update creates with no old value" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + format_command $type "symref-update refs/heads/symref" "$a" >stdin && + git update-ref --stdin $type --no-deref <stdin && + echo $a >expect && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-update creates dangling" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + test_must_fail git rev-parse refs/heads/nonexistent && + format_command $type "symref-update refs/heads/symref" "refs/heads/nonexistent" >stdin && + git update-ref --stdin $type --no-deref <stdin && + echo refs/heads/nonexistent >expect && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-update fails with wrong old value" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + git symbolic-ref refs/heads/symref $a && + format_command $type "symref-update refs/heads/symref" "$m" "ref" "$b" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err && + grep "fatal: verifying symref target: ${SQ}refs/heads/symref${SQ}: is at $a but expected $b" err && + test_must_fail git rev-parse --verify -q $c + ' + + test_expect_success "stdin $type symref-update updates dangling ref" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + test_must_fail git rev-parse refs/heads/nonexistent && + git symbolic-ref refs/heads/symref refs/heads/nonexistent && + format_command $type "symref-update refs/heads/symref" "$a" >stdin && + git update-ref --stdin $type --no-deref <stdin && + echo $a >expect && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-update updates dangling ref with old value" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + test_must_fail git rev-parse refs/heads/nonexistent && + git symbolic-ref refs/heads/symref refs/heads/nonexistent && + format_command $type "symref-update refs/heads/symref" "$a" "ref" "refs/heads/nonexistent" >stdin && + git update-ref --stdin $type --no-deref <stdin && + echo $a >expect && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-update fails update dangling ref with wrong old value" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + test_must_fail git rev-parse refs/heads/nonexistent && + git symbolic-ref refs/heads/symref refs/heads/nonexistent && + format_command $type "symref-update refs/heads/symref" "$a" "ref" "refs/heads/wrongref" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin && + echo refs/heads/nonexistent >expect && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-update works with right old value" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + git symbolic-ref refs/heads/symref $a && + format_command $type "symref-update refs/heads/symref" "$m" "ref" "$a" >stdin && + git update-ref --stdin $type --no-deref <stdin && + echo $m >expect && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-update works with no old value" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + git symbolic-ref refs/heads/symref $a && + format_command $type "symref-update refs/heads/symref" "$m" >stdin && + git update-ref --stdin $type --no-deref <stdin && + echo $m >expect && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-update fails with empty old ref-target" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + git symbolic-ref refs/heads/symref $a && + format_command $type "symref-update refs/heads/symref" "$m" "ref" "" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin && + echo $a >expect && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-update creates (with deref)" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + format_command $type "symref-update refs/heads/symref" "$a" >stdin && + git update-ref --stdin $type <stdin && + echo $a >expect && + git symbolic-ref --no-recurse refs/heads/symref >actual && + test_cmp expect actual && + test-tool ref-store main for-each-reflog-ent refs/heads/symref >actual && + grep "$Z $(git rev-parse $a)" actual + ' + + test_expect_success "stdin $type symref-update regular ref to symref with correct old-oid" ' + test_when_finished "git symbolic-ref -d --no-recurse refs/heads/regularref" && + git update-ref --no-deref refs/heads/regularref $a && + format_command $type "symref-update refs/heads/regularref" "$a" "oid" "$(git rev-parse $a)" >stdin && + git update-ref --stdin $type <stdin && + echo $a >expect && + git symbolic-ref --no-recurse refs/heads/regularref >actual && + test_cmp expect actual && + test-tool ref-store main for-each-reflog-ent refs/heads/regularref >actual && + grep "$(git rev-parse $a) $(git rev-parse $a)" actual + ' + + test_expect_success "stdin $type symref-update regular ref to symref fails with wrong old-oid" ' + test_when_finished "git update-ref -d refs/heads/regularref" && + git update-ref --no-deref refs/heads/regularref $a && + format_command $type "symref-update refs/heads/regularref" "$a" "oid" "$(git rev-parse refs/heads/target2)" >stdin && + test_must_fail git update-ref --stdin $type <stdin 2>err && + grep "fatal: cannot lock ref ${SQ}refs/heads/regularref${SQ}: is at $(git rev-parse $a) but expected $(git rev-parse refs/heads/target2)" err && + echo $(git rev-parse $a) >expect && + git rev-parse refs/heads/regularref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-update regular ref to symref fails with invalid old-oid" ' + test_when_finished "git update-ref -d refs/heads/regularref" && + git update-ref --no-deref refs/heads/regularref $a && + format_command $type "symref-update refs/heads/regularref" "$a" "oid" "not-a-ref-oid" >stdin && + test_must_fail git update-ref --stdin $type <stdin 2>err && + grep "fatal: symref-update refs/heads/regularref: invalid oid: not-a-ref-oid" err && + echo $(git rev-parse $a) >expect && + git rev-parse refs/heads/regularref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-update existing symref with zero old-oid" ' + test_when_finished "git symbolic-ref -d --no-recurse refs/heads/symref" && + git symbolic-ref refs/heads/symref refs/heads/target2 && + format_command $type "symref-update refs/heads/symref" "$a" "oid" "$Z" >stdin && + test_must_fail git update-ref --stdin $type <stdin 2>err && + grep "fatal: cannot lock ref ${SQ}refs/heads/symref${SQ}: reference already exists" err && + echo refs/heads/target2 >expect && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-update regular ref to symref (with deref)" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + test_when_finished "git update-ref -d --no-deref refs/heads/symref2" && + git update-ref refs/heads/symref2 $a && + git symbolic-ref --no-recurse refs/heads/symref refs/heads/symref2 && + format_command $type "symref-update refs/heads/symref" "$a" >stdin && + git update-ref $type --stdin <stdin && + echo $a >expect && + git symbolic-ref --no-recurse refs/heads/symref2 >actual && + test_cmp expect actual && + echo refs/heads/symref2 >expect && + git symbolic-ref --no-recurse refs/heads/symref >actual && + test_cmp expect actual && + test-tool ref-store main for-each-reflog-ent refs/heads/symref >actual && + grep "$(git rev-parse $a) $(git rev-parse $a)" actual + ' + + test_expect_success "stdin $type symref-update regular ref to symref" ' + test_when_finished "git symbolic-ref -d --no-recurse refs/heads/regularref" && + git update-ref --no-deref refs/heads/regularref $a && + format_command $type "symref-update refs/heads/regularref" "$a" >stdin && + git update-ref $type --stdin <stdin && + echo $a >expect && + git symbolic-ref --no-recurse refs/heads/regularref >actual && + test_cmp expect actual && + test-tool ref-store main for-each-reflog-ent refs/heads/regularref >actual && + grep "$(git rev-parse $a) $(git rev-parse $a)" actual + ' + +done + test_done diff --git a/t/t1403-show-ref.sh b/t/t1403-show-ref.sh index 33fb7a38ff..403f6b8f7d 100755 --- a/t/t1403-show-ref.sh +++ b/t/t1403-show-ref.sh @@ -121,13 +121,13 @@ test_expect_success 'show-ref -d' ' ' -test_expect_success 'show-ref --heads, --tags, --head, pattern' ' +test_expect_success 'show-ref --branches, --tags, --head, pattern' ' for branch in B main side do echo $(git rev-parse refs/heads/$branch) refs/heads/$branch || return 1 - done >expect.heads && - git show-ref --heads >actual && - test_cmp expect.heads actual && + done >expect.branches && + git show-ref --branches >actual && + test_cmp expect.branches actual && for tag in A B C do @@ -136,15 +136,15 @@ test_expect_success 'show-ref --heads, --tags, --head, pattern' ' git show-ref --tags >actual && test_cmp expect.tags actual && - cat expect.heads expect.tags >expect && - git show-ref --heads --tags >actual && + cat expect.branches expect.tags >expect && + git show-ref --branches --tags >actual && test_cmp expect actual && { echo $(git rev-parse HEAD) HEAD && - cat expect.heads expect.tags + cat expect.branches expect.tags } >expect && - git show-ref --heads --tags --head >actual && + git show-ref --branches --tags --head >actual && test_cmp expect actual && { @@ -165,6 +165,14 @@ test_expect_success 'show-ref --heads, --tags, --head, pattern' ' test_cmp expect actual ' +test_expect_success 'show-ref --heads is deprecated and hidden' ' + test_expect_code 129 git show-ref -h >short-help && + test_grep ! -e --heads short-help && + git show-ref --heads >actual 2>warning && + test_grep ! deprecated warning && + test_cmp expect.branches actual +' + test_expect_success 'show-ref --verify HEAD' ' echo $(git rev-parse HEAD) HEAD >expect && git show-ref --verify HEAD >actual && diff --git a/t/t1404-update-ref-errors.sh b/t/t1404-update-ref-errors.sh index 98e9158bd2..df90112618 100755 --- a/t/t1404-update-ref-errors.sh +++ b/t/t1404-update-ref-errors.sh @@ -100,13 +100,13 @@ df_test() { printf "%s\n" "delete $delname" "create $addname $D" fi >commands && test_must_fail git update-ref --stdin <commands 2>output.err && - grep "fatal:\( cannot lock ref $SQ$addname$SQ:\)\? $SQ$delref$SQ exists; cannot create $SQ$addref$SQ" output.err && + grep -E "fatal:( cannot lock ref '$addname':)? '$delref' exists; cannot create '$addref'" 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 } -test_expect_success 'setup' ' +test_expect_success 'setup' - <<\EOT git commit --allow-empty -m Initial && C=$(git rev-parse HEAD) && @@ -114,283 +114,283 @@ test_expect_success 'setup' ' D=$(git rev-parse HEAD) && git commit --allow-empty -m Third && E=$(git rev-parse HEAD) -' +EOT -test_expect_success 'existing loose ref is a simple prefix of new' ' +test_expect_success 'existing loose ref is a simple prefix of new' - <<\EOT prefix=refs/1l && test_update_rejected "a c e" false "b c/x d" \ - "$SQ$prefix/c$SQ exists; cannot create $SQ$prefix/c/x$SQ" + "'$prefix/c' exists; cannot create '$prefix/c/x'" -' +EOT -test_expect_success 'existing packed ref is a simple prefix of new' ' +test_expect_success 'existing packed ref is a simple prefix of new' - <<\EOT prefix=refs/1p && test_update_rejected "a c e" true "b c/x d" \ - "$SQ$prefix/c$SQ exists; cannot create $SQ$prefix/c/x$SQ" + "'$prefix/c' exists; cannot create '$prefix/c/x'" -' +EOT -test_expect_success 'existing loose ref is a deeper prefix of new' ' +test_expect_success 'existing loose ref is a deeper prefix of new' - <<\EOT prefix=refs/2l && test_update_rejected "a c e" false "b c/x/y d" \ - "$SQ$prefix/c$SQ exists; cannot create $SQ$prefix/c/x/y$SQ" + "'$prefix/c' exists; cannot create '$prefix/c/x/y'" -' +EOT -test_expect_success 'existing packed ref is a deeper prefix of new' ' +test_expect_success 'existing packed ref is a deeper prefix of new' - <<\EOT prefix=refs/2p && test_update_rejected "a c e" true "b c/x/y d" \ - "$SQ$prefix/c$SQ exists; cannot create $SQ$prefix/c/x/y$SQ" + "'$prefix/c' exists; cannot create '$prefix/c/x/y'" -' +EOT -test_expect_success 'new ref is a simple prefix of existing loose' ' +test_expect_success 'new ref is a simple prefix of existing loose' - <<\EOT prefix=refs/3l && test_update_rejected "a c/x e" false "b c d" \ - "$SQ$prefix/c/x$SQ exists; cannot create $SQ$prefix/c$SQ" + "'$prefix/c/x' exists; cannot create '$prefix/c'" -' +EOT -test_expect_success 'new ref is a simple prefix of existing packed' ' +test_expect_success 'new ref is a simple prefix of existing packed' - <<\EOT prefix=refs/3p && test_update_rejected "a c/x e" true "b c d" \ - "$SQ$prefix/c/x$SQ exists; cannot create $SQ$prefix/c$SQ" + "'$prefix/c/x' exists; cannot create '$prefix/c'" -' +EOT -test_expect_success 'new ref is a deeper prefix of existing loose' ' +test_expect_success 'new ref is a deeper prefix of existing loose' - <<\EOT prefix=refs/4l && test_update_rejected "a c/x/y e" false "b c d" \ - "$SQ$prefix/c/x/y$SQ exists; cannot create $SQ$prefix/c$SQ" + "'$prefix/c/x/y' exists; cannot create '$prefix/c'" -' +EOT -test_expect_success 'new ref is a deeper prefix of existing packed' ' +test_expect_success 'new ref is a deeper prefix of existing packed' - <<\EOT prefix=refs/4p && test_update_rejected "a c/x/y e" true "b c d" \ - "$SQ$prefix/c/x/y$SQ exists; cannot create $SQ$prefix/c$SQ" + "'$prefix/c/x/y' exists; cannot create '$prefix/c'" -' +EOT -test_expect_success 'one new ref is a simple prefix of another' ' +test_expect_success 'one new ref is a simple prefix of another' - <<\EOT prefix=refs/5 && test_update_rejected "a e" false "b c c/x d" \ - "cannot process $SQ$prefix/c$SQ and $SQ$prefix/c/x$SQ at the same time" + "cannot process '$prefix/c' and '$prefix/c/x' at the same time" -' +EOT -test_expect_success 'D/F conflict prevents add long + delete short' ' +test_expect_success 'D/F conflict prevents add long + delete short' - <<\EOT df_test refs/df-al-ds --add-del foo/bar foo -' +EOT -test_expect_success 'D/F conflict prevents add short + delete long' ' +test_expect_success 'D/F conflict prevents add short + delete long' - <<\EOT df_test refs/df-as-dl --add-del foo foo/bar -' +EOT -test_expect_success 'D/F conflict prevents delete long + add short' ' +test_expect_success 'D/F conflict prevents delete long + add short' - <<\EOT df_test refs/df-dl-as --del-add foo/bar foo -' +EOT -test_expect_success 'D/F conflict prevents delete short + add long' ' +test_expect_success 'D/F conflict prevents delete short + add long' - <<\EOT df_test refs/df-ds-al --del-add foo foo/bar -' +EOT -test_expect_success 'D/F conflict prevents add long + delete short packed' ' +test_expect_success 'D/F conflict prevents add long + delete short packed' - <<\EOT df_test refs/df-al-dsp --pack --add-del foo/bar foo -' +EOT -test_expect_success 'D/F conflict prevents add short + delete long packed' ' +test_expect_success 'D/F conflict prevents add short + delete long packed' - <<\EOT df_test refs/df-as-dlp --pack --add-del foo foo/bar -' +EOT -test_expect_success 'D/F conflict prevents delete long packed + add short' ' +test_expect_success 'D/F conflict prevents delete long packed + add short' - <<\EOT df_test refs/df-dlp-as --pack --del-add foo/bar foo -' +EOT -test_expect_success 'D/F conflict prevents delete short packed + add long' ' +test_expect_success 'D/F conflict prevents delete short packed + add long' - <<\EOT df_test refs/df-dsp-al --pack --del-add foo foo/bar -' +EOT # Try some combinations involving symbolic refs... -test_expect_success 'D/F conflict prevents indirect add long + delete short' ' +test_expect_success 'D/F conflict prevents indirect add long + delete short' - <<\EOT df_test refs/df-ial-ds --sym-add --add-del foo/bar foo -' +EOT -test_expect_success 'D/F conflict prevents indirect add long + indirect delete short' ' +test_expect_success 'D/F conflict prevents indirect add long + indirect delete short' - <<\EOT df_test refs/df-ial-ids --sym-add --sym-del --add-del foo/bar foo -' +EOT -test_expect_success 'D/F conflict prevents indirect add short + indirect delete long' ' +test_expect_success 'D/F conflict prevents indirect add short + indirect delete long' - <<\EOT df_test refs/df-ias-idl --sym-add --sym-del --add-del foo foo/bar -' +EOT -test_expect_success 'D/F conflict prevents indirect delete long + indirect add short' ' +test_expect_success 'D/F conflict prevents indirect delete long + indirect add short' - <<\EOT df_test refs/df-idl-ias --sym-add --sym-del --del-add foo/bar foo -' +EOT -test_expect_success 'D/F conflict prevents indirect add long + delete short packed' ' +test_expect_success 'D/F conflict prevents indirect add long + delete short packed' - <<\EOT df_test refs/df-ial-dsp --sym-add --pack --add-del foo/bar foo -' +EOT -test_expect_success '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' - <<\EOT df_test refs/df-ial-idsp --sym-add --sym-del --pack --add-del foo/bar foo -' +EOT -test_expect_success 'D/F conflict prevents add long + indirect delete short packed' ' +test_expect_success 'D/F conflict prevents add long + indirect delete short packed' - <<\EOT df_test refs/df-al-idsp --sym-del --pack --add-del foo/bar foo -' +EOT -test_expect_success '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' - <<\EOT df_test refs/df-idlp-ias --sym-add --sym-del --pack --del-add foo/bar foo -' +EOT # Test various errors when reading the old values of references... -test_expect_success 'missing old value blocks update' ' +test_expect_success 'missing old value blocks update' - <<\EOT prefix=refs/missing-update && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/foo$SQ: unable to resolve reference $SQ$prefix/foo$SQ + fatal: cannot lock ref '$prefix/foo': unable to resolve reference '$prefix/foo' EOF printf "%s\n" "update $prefix/foo $E $D" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'incorrect old value blocks update' ' +test_expect_success 'incorrect old value blocks update' - <<\EOT prefix=refs/incorrect-update && git update-ref $prefix/foo $C && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/foo$SQ: is at $C but expected $D + fatal: cannot lock ref '$prefix/foo': is at $C but expected $D EOF printf "%s\n" "update $prefix/foo $E $D" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'existing old value blocks create' ' +test_expect_success 'existing old value blocks create' - <<\EOT prefix=refs/existing-create && git update-ref $prefix/foo $C && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/foo$SQ: reference already exists + fatal: cannot lock ref '$prefix/foo': reference already exists EOF printf "%s\n" "create $prefix/foo $E" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'incorrect old value blocks delete' ' +test_expect_success 'incorrect old value blocks delete' - <<\EOT prefix=refs/incorrect-delete && git update-ref $prefix/foo $C && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/foo$SQ: is at $C but expected $D + fatal: cannot lock ref '$prefix/foo': is at $C but expected $D EOF printf "%s\n" "delete $prefix/foo $D" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'missing old value blocks indirect update' ' +test_expect_success 'missing old value blocks indirect update' - <<\EOT prefix=refs/missing-indirect-update && git symbolic-ref $prefix/symref $prefix/foo && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/symref$SQ: unable to resolve reference $SQ$prefix/foo$SQ + fatal: cannot lock ref '$prefix/symref': unable to resolve reference '$prefix/foo' EOF printf "%s\n" "update $prefix/symref $E $D" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'incorrect old value blocks indirect update' ' +test_expect_success 'incorrect old value blocks indirect update' - <<\EOT prefix=refs/incorrect-indirect-update && git symbolic-ref $prefix/symref $prefix/foo && git update-ref $prefix/foo $C && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/symref$SQ: is at $C but expected $D + fatal: cannot lock ref '$prefix/symref': is at $C but expected $D EOF printf "%s\n" "update $prefix/symref $E $D" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'existing old value blocks indirect create' ' +test_expect_success 'existing old value blocks indirect create' - <<\EOT prefix=refs/existing-indirect-create && git symbolic-ref $prefix/symref $prefix/foo && git update-ref $prefix/foo $C && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/symref$SQ: reference already exists + fatal: cannot lock ref '$prefix/symref': reference already exists EOF printf "%s\n" "create $prefix/symref $E" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'incorrect old value blocks indirect delete' ' +test_expect_success 'incorrect old value blocks indirect delete' - <<\EOT prefix=refs/incorrect-indirect-delete && git symbolic-ref $prefix/symref $prefix/foo && git update-ref $prefix/foo $C && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/symref$SQ: is at $C but expected $D + fatal: cannot lock ref '$prefix/symref': is at $C but expected $D EOF printf "%s\n" "delete $prefix/symref $D" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'missing old value blocks indirect no-deref update' ' +test_expect_success 'missing old value blocks indirect no-deref update' - <<\EOT prefix=refs/missing-noderef-update && git symbolic-ref $prefix/symref $prefix/foo && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/symref$SQ: reference is missing but expected $D + fatal: cannot lock ref '$prefix/symref': reference is missing but expected $D EOF printf "%s\n" "option no-deref" "update $prefix/symref $E $D" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'incorrect old value blocks indirect no-deref update' ' +test_expect_success 'incorrect old value blocks indirect no-deref update' - <<\EOT prefix=refs/incorrect-noderef-update && git symbolic-ref $prefix/symref $prefix/foo && git update-ref $prefix/foo $C && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/symref$SQ: is at $C but expected $D + fatal: cannot lock ref '$prefix/symref': is at $C but expected $D EOF printf "%s\n" "option no-deref" "update $prefix/symref $E $D" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'existing old value blocks indirect no-deref create' ' +test_expect_success 'existing old value blocks indirect no-deref create' - <<\EOT prefix=refs/existing-noderef-create && git symbolic-ref $prefix/symref $prefix/foo && git update-ref $prefix/foo $C && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/symref$SQ: reference already exists + fatal: cannot lock ref '$prefix/symref': reference already exists EOF printf "%s\n" "option no-deref" "create $prefix/symref $E" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'incorrect old value blocks indirect no-deref delete' ' +test_expect_success 'incorrect old value blocks indirect no-deref delete' - <<\EOT prefix=refs/incorrect-noderef-delete && git symbolic-ref $prefix/symref $prefix/foo && git update-ref $prefix/foo $C && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/symref$SQ: is at $C but expected $D + fatal: cannot lock ref '$prefix/symref': is at $C but expected $D EOF printf "%s\n" "option no-deref" "delete $prefix/symref $D" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT test_done diff --git a/t/t1416-ref-transaction-hooks.sh b/t/t1416-ref-transaction-hooks.sh index 2092488090..5a812ca3c0 100755 --- a/t/t1416-ref-transaction-hooks.sh +++ b/t/t1416-ref-transaction-hooks.sh @@ -134,4 +134,81 @@ test_expect_success 'interleaving hook calls succeed' ' test_cmp expect target-repo.git/actual ' +test_expect_success 'hook captures git-symbolic-ref updates' ' + test_when_finished "rm actual" && + + test_hook reference-transaction <<-\EOF && + echo "$*" >>actual + while read -r line + do + printf "%s\n" "$line" + done >>actual + EOF + + git symbolic-ref refs/heads/symref refs/heads/main && + + cat >expect <<-EOF && + prepared + $ZERO_OID ref:refs/heads/main refs/heads/symref + committed + $ZERO_OID ref:refs/heads/main refs/heads/symref + EOF + + test_cmp expect actual +' + +test_expect_success 'hook gets all queued symref updates' ' + test_when_finished "rm actual" && + + git update-ref refs/heads/branch $POST_OID && + git symbolic-ref refs/heads/symref refs/heads/main && + git symbolic-ref refs/heads/symrefd refs/heads/main && + git symbolic-ref refs/heads/symrefu refs/heads/main && + + test_hook reference-transaction <<-\EOF && + echo "$*" >>actual + while read -r line + do + printf "%s\n" "$line" + done >>actual + EOF + + # In the files backend, "delete" also triggers an additional transaction + # update on the packed-refs backend, which constitutes additional reflog + # entries. + if test_have_prereq REFFILES + then + cat >expect <<-EOF + aborted + $ZERO_OID $ZERO_OID refs/heads/symrefd + EOF + else + >expect + fi && + + cat >>expect <<-EOF && + prepared + ref:refs/heads/main $ZERO_OID refs/heads/symref + ref:refs/heads/main $ZERO_OID refs/heads/symrefd + $ZERO_OID ref:refs/heads/main refs/heads/symrefc + ref:refs/heads/main ref:refs/heads/branch refs/heads/symrefu + committed + ref:refs/heads/main $ZERO_OID refs/heads/symref + ref:refs/heads/main $ZERO_OID refs/heads/symrefd + $ZERO_OID ref:refs/heads/main refs/heads/symrefc + ref:refs/heads/main ref:refs/heads/branch refs/heads/symrefu + EOF + + git update-ref --no-deref --stdin <<-EOF && + start + symref-verify refs/heads/symref refs/heads/main + symref-delete refs/heads/symrefd refs/heads/main + symref-create refs/heads/symrefc refs/heads/main + symref-update refs/heads/symrefu refs/heads/branch ref refs/heads/main + prepare + commit + EOF + test_cmp expect actual +' + test_done diff --git a/t/t1460-refs-migrate.sh b/t/t1460-refs-migrate.sh new file mode 100755 index 0000000000..f7c0783d30 --- /dev/null +++ b/t/t1460-refs-migrate.sh @@ -0,0 +1,243 @@ +#!/bin/sh + +test_description='migration of ref storage backends' + +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +test_migration () { + git -C "$1" for-each-ref --include-root-refs \ + --format='%(refname) %(objectname) %(symref)' >expect && + git -C "$1" refs migrate --ref-format="$2" && + git -C "$1" for-each-ref --include-root-refs \ + --format='%(refname) %(objectname) %(symref)' >actual && + test_cmp expect actual && + + git -C "$1" rev-parse --show-ref-format >actual && + echo "$2" >expect && + test_cmp expect actual +} + +test_expect_success 'setup' ' + rm -rf .git && + # The migration does not yet support reflogs. + git config --global core.logAllRefUpdates false +' + +test_expect_success "superfluous arguments" ' + test_when_finished "rm -rf repo" && + git init repo && + test_must_fail git -C repo refs migrate foo 2>err && + cat >expect <<-EOF && + usage: too many arguments + EOF + test_cmp expect err +' + +test_expect_success "missing ref storage format" ' + test_when_finished "rm -rf repo" && + git init repo && + test_must_fail git -C repo refs migrate 2>err && + cat >expect <<-EOF && + usage: missing --ref-format=<format> + EOF + test_cmp expect err +' + +test_expect_success "unknown ref storage format" ' + test_when_finished "rm -rf repo" && + git init repo && + test_must_fail git -C repo refs migrate \ + --ref-format=unknown 2>err && + cat >expect <<-EOF && + error: unknown ref storage format ${SQ}unknown${SQ} + EOF + test_cmp expect err +' + +ref_formats="files reftable" +for from_format in $ref_formats +do + for to_format in $ref_formats + do + if test "$from_format" = "$to_format" + then + continue + fi + + test_expect_success "$from_format: migration to same format fails" ' + test_when_finished "rm -rf repo" && + git init --ref-format=$from_format repo && + test_must_fail git -C repo refs migrate \ + --ref-format=$from_format 2>err && + cat >expect <<-EOF && + error: repository already uses ${SQ}$from_format${SQ} format + EOF + test_cmp expect err + ' + + test_expect_success "$from_format -> $to_format: migration with reflog fails" ' + test_when_finished "rm -rf repo" && + git init --ref-format=$from_format repo && + test_config -C repo core.logAllRefUpdates true && + test_commit -C repo logged && + test_must_fail git -C repo refs migrate \ + --ref-format=$to_format 2>err && + cat >expect <<-EOF && + error: migrating reflogs is not supported yet + EOF + test_cmp expect err + ' + + test_expect_success "$from_format -> $to_format: migration with worktree fails" ' + test_when_finished "rm -rf repo" && + git init --ref-format=$from_format repo && + git -C repo worktree add wt && + test_must_fail git -C repo refs migrate \ + --ref-format=$to_format 2>err && + cat >expect <<-EOF && + error: migrating repositories with worktrees is not supported yet + EOF + test_cmp expect err + ' + + test_expect_success "$from_format -> $to_format: unborn HEAD" ' + test_when_finished "rm -rf repo" && + git init --ref-format=$from_format repo && + test_migration repo "$to_format" + ' + + test_expect_success "$from_format -> $to_format: single ref" ' + test_when_finished "rm -rf repo" && + git init --ref-format=$from_format repo && + test_commit -C repo initial && + test_migration repo "$to_format" + ' + + test_expect_success "$from_format -> $to_format: bare repository" ' + test_when_finished "rm -rf repo repo.git" && + git init --ref-format=$from_format repo && + test_commit -C repo initial && + git clone --ref-format=$from_format --mirror repo repo.git && + test_migration repo.git "$to_format" + ' + + test_expect_success "$from_format -> $to_format: dangling symref" ' + test_when_finished "rm -rf repo" && + git init --ref-format=$from_format repo && + test_commit -C repo initial && + git -C repo symbolic-ref BROKEN_HEAD refs/heads/nonexistent && + test_migration repo "$to_format" && + echo refs/heads/nonexistent >expect && + git -C repo symbolic-ref BROKEN_HEAD >actual && + test_cmp expect actual + ' + + test_expect_success "$from_format -> $to_format: broken ref" ' + test_when_finished "rm -rf repo" && + git init --ref-format=$from_format repo && + test_commit -C repo initial && + test-tool -C repo ref-store main update-ref "" refs/heads/broken \ + "$(test_oid 001)" "$ZERO_OID" REF_SKIP_CREATE_REFLOG,REF_SKIP_OID_VERIFICATION && + test_migration repo "$to_format" && + test_oid 001 >expect && + git -C repo rev-parse refs/heads/broken >actual && + test_cmp expect actual + ' + + test_expect_success "$from_format -> $to_format: pseudo-refs" ' + test_when_finished "rm -rf repo" && + git init --ref-format=$from_format repo && + test_commit -C repo initial && + git -C repo update-ref FOO_HEAD HEAD && + test_migration repo "$to_format" + ' + + test_expect_success "$from_format -> $to_format: special refs are left alone" ' + test_when_finished "rm -rf repo" && + git init --ref-format=$from_format repo && + test_commit -C repo initial && + git -C repo rev-parse HEAD >repo/.git/MERGE_HEAD && + git -C repo rev-parse MERGE_HEAD && + test_migration repo "$to_format" && + test_path_is_file repo/.git/MERGE_HEAD + ' + + test_expect_success "$from_format -> $to_format: a bunch of refs" ' + test_when_finished "rm -rf repo" && + git init --ref-format=$from_format repo && + + test_commit -C repo initial && + cat >input <<-EOF && + create FOO_HEAD HEAD + create refs/heads/branch-1 HEAD + create refs/heads/branch-2 HEAD + create refs/heads/branch-3 HEAD + create refs/heads/branch-4 HEAD + create refs/tags/tag-1 HEAD + create refs/tags/tag-2 HEAD + EOF + git -C repo update-ref --stdin <input && + test_migration repo "$to_format" + ' + + test_expect_success "$from_format -> $to_format: dry-run migration does not modify repository" ' + test_when_finished "rm -rf repo" && + git init --ref-format=$from_format repo && + test_commit -C repo initial && + git -C repo refs migrate --dry-run \ + --ref-format=$to_format >output && + grep "Finished dry-run migration of refs" output && + test_path_is_dir repo/.git/ref_migration.* && + echo $from_format >expect && + git -C repo rev-parse --show-ref-format >actual && + test_cmp expect actual + ' + done +done + +test_expect_success 'migrating from files format deletes backend files' ' + test_when_finished "rm -rf repo" && + git init --ref-format=files repo && + test_commit -C repo first && + git -C repo pack-refs --all && + test_commit -C repo second && + git -C repo update-ref ORIG_HEAD HEAD && + git -C repo rev-parse HEAD >repo/.git/FETCH_HEAD && + + test_path_is_file repo/.git/HEAD && + test_path_is_file repo/.git/ORIG_HEAD && + test_path_is_file repo/.git/refs/heads/main && + test_path_is_file repo/.git/packed-refs && + + test_migration repo reftable && + + echo "ref: refs/heads/.invalid" >expect && + test_cmp expect repo/.git/HEAD && + echo "this repository uses the reftable format" >expect && + test_cmp expect repo/.git/refs/heads && + test_path_is_file repo/.git/FETCH_HEAD && + test_path_is_missing repo/.git/ORIG_HEAD && + test_path_is_missing repo/.git/refs/heads/main && + test_path_is_missing repo/.git/logs && + test_path_is_missing repo/.git/packed-refs +' + +test_expect_success 'migrating from reftable format deletes backend files' ' + test_when_finished "rm -rf repo" && + git init --ref-format=reftable repo && + test_commit -C repo first && + + test_path_is_dir repo/.git/reftable && + test_migration repo files && + + test_path_is_missing repo/.git/reftable && + echo "ref: refs/heads/main" >expect && + test_cmp expect repo/.git/HEAD && + test_path_is_file repo/.git/refs/heads/main +' + +test_done diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh index a669e592f1..30c31918fd 100755 --- a/t/t1500-rev-parse.sh +++ b/t/t1500-rev-parse.sh @@ -304,4 +304,10 @@ test_expect_success 'rev-parse --bisect includes bad, excludes good' ' test_cmp expect actual ' +test_expect_success '--short= truncates to the actual hash length' ' + git rev-parse HEAD >expect && + git rev-parse --short=100 HEAD >actual && + test_cmp expect actual +' + test_done diff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh index 70f1e0a998..f9d68ce74e 100755 --- a/t/t1512-rev-parse-disambiguation.sh +++ b/t/t1512-rev-parse-disambiguation.sh @@ -23,6 +23,7 @@ one tagged as v1.0.0. They all have one regular file each. GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_cmp_failed_rev_parse () { diff --git a/t/t1517-outside-repo.sh b/t/t1517-outside-repo.sh new file mode 100755 index 0000000000..990a036582 --- /dev/null +++ b/t/t1517-outside-repo.sh @@ -0,0 +1,111 @@ +#!/bin/sh + +test_description='check random commands outside repo' + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +test_expect_success 'set up a non-repo directory and test file' ' + GIT_CEILING_DIRECTORIES=$(pwd) && + export GIT_CEILING_DIRECTORIES && + mkdir non-repo && + ( + cd non-repo && + # confirm that git does not find a repo + test_must_fail git rev-parse --git-dir + ) && + test_write_lines one two three four >nums && + git add nums && + cp nums nums.old && + test_write_lines five >>nums && + git diff >sample.patch +' + +test_expect_success 'compute a patch-id outside repository (uses SHA-1)' ' + nongit env GIT_DEFAULT_HASH=sha1 \ + git patch-id <sample.patch >patch-id.expect && + nongit \ + git patch-id <sample.patch >patch-id.actual && + test_cmp patch-id.expect patch-id.actual +' + +test_expect_success 'hash-object outside repository (uses SHA-1)' ' + nongit env GIT_DEFAULT_HASH=sha1 \ + git hash-object --stdin <sample.patch >hash.expect && + nongit \ + git hash-object --stdin <sample.patch >hash.actual && + test_cmp hash.expect hash.actual +' + +test_expect_success 'apply a patch outside repository' ' + ( + cd non-repo && + cp ../nums.old nums && + git apply ../sample.patch + ) && + test_cmp nums non-repo/nums +' + +test_expect_success 'grep outside repository' ' + git grep --cached two >expect && + ( + cd non-repo && + cp ../nums.old nums && + git grep --no-index two >../actual + ) && + test_cmp expect actual +' + +test_expect_success 'imap-send outside repository' ' + test_config_global imap.host imaps://localhost && + test_config_global imap.folder Drafts && + + echo nothing to send >expect && + test_must_fail git imap-send -v </dev/null 2>actual && + test_cmp expect actual && + + ( + cd non-repo && + test_must_fail git imap-send -v </dev/null 2>../actual + ) && + test_cmp expect actual +' + +test_expect_success 'check-ref-format outside repository' ' + git check-ref-format --branch refs/heads/xyzzy >expect && + nongit git check-ref-format --branch refs/heads/xyzzy >actual && + test_cmp expect actual +' + +test_expect_success 'diff outside repository' ' + echo one >one && + echo two >two && + test_must_fail git diff --no-index one two >expect.raw && + ( + cd non-repo && + cp ../one . && + cp ../two . && + test_must_fail git diff one two >../actual.raw + ) && + # outside repository diff falls back to SHA-1 but + # GIT_DEFAULT_HASH may be set to sha256 on the in-repo side. + sed -e "/^index /d" expect.raw >expect && + sed -e "/^index /d" actual.raw >actual && + test_cmp expect actual +' + +test_expect_success 'stripspace outside repository' ' + nongit git stripspace -s </dev/null +' + +test_expect_success 'remote-http outside repository' ' + test_must_fail git remote-http 2>actual && + test_grep "^error: remote-curl" actual && + ( + cd non-repo && + test_must_fail git remote-http 2>../actual + ) && + test_grep "^error: remote-curl" actual +' + +test_done diff --git a/t/t1700-split-index.sh b/t/t1700-split-index.sh index a7b7263b35..ac4a5b2734 100755 --- a/t/t1700-split-index.sh +++ b/t/t1700-split-index.sh @@ -527,7 +527,7 @@ test_expect_success 'reading split index at alternate location' ' # ... and, for backwards compatibility, in the current GIT_DIR # as well. - mv -v ./reading-alternate-location/.git/sharedindex.* .git && + mv ./reading-alternate-location/.git/sharedindex.* .git && GIT_INDEX_FILE=./reading-alternate-location/.git/index \ git ls-files --cached >actual && test_cmp expect actual diff --git a/t/t2013-checkout-submodule.sh b/t/t2013-checkout-submodule.sh index b2bdd1fcb4..3c1d663d94 100755 --- a/t/t2013-checkout-submodule.sh +++ b/t/t2013-checkout-submodule.sh @@ -2,6 +2,7 @@ test_description='checkout can handle submodules' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-submodule-update.sh diff --git a/t/t2024-checkout-dwim.sh b/t/t2024-checkout-dwim.sh index a3b1449ef1..2caada3d83 100755 --- a/t/t2024-checkout-dwim.sh +++ b/t/t2024-checkout-dwim.sh @@ -4,6 +4,7 @@ test_description='checkout <branch> Ensures that checkout on an unborn branch does what the user expects' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Is the current branch "refs/heads/$1"? diff --git a/t/t2060-switch.sh b/t/t2060-switch.sh index c91c4db936..77b2346291 100755 --- a/t/t2060-switch.sh +++ b/t/t2060-switch.sh @@ -5,6 +5,7 @@ test_description='switch 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/t2405-worktree-submodule.sh b/t/t2405-worktree-submodule.sh index 11018f37c7..1d7f605633 100755 --- a/t/t2405-worktree-submodule.sh +++ b/t/t2405-worktree-submodule.sh @@ -5,6 +5,7 @@ test_description='Combination of submodules and multiple worktrees' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh base_path=$(pwd -P) diff --git a/t/t2500-untracked-overwriting.sh b/t/t2500-untracked-overwriting.sh index 5c0bf4d21f..714feb83be 100755 --- a/t/t2500-untracked-overwriting.sh +++ b/t/t2500-untracked-overwriting.sh @@ -2,6 +2,7 @@ test_description='Test handling of overwriting untracked files' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_setup_reset () { diff --git a/t/t3007-ls-files-recurse-submodules.sh b/t/t3007-ls-files-recurse-submodules.sh index 61771eec83..f04bdc8c78 100755 --- a/t/t3007-ls-files-recurse-submodules.sh +++ b/t/t3007-ls-files-recurse-submodules.sh @@ -6,6 +6,7 @@ This test verifies the recurse-submodules feature correctly lists files from submodules. ' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup directory structure and submodules' ' diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh index 758963b189..e627f08a17 100755 --- a/t/t3203-branch-output.sh +++ b/t/t3203-branch-output.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='git branch display tests' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-terminal.sh diff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh index 7b05bf3961..a767c3520e 100755 --- a/t/t3206-range-diff.sh +++ b/t/t3206-range-diff.sh @@ -545,6 +545,20 @@ do ' done +test_expect_success "--range-diff implies --cover-letter for multi-patch series" ' + test_when_finished "rm -f v2-000?-*" && + git format-patch -v2 --range-diff=topic main..unmodified && + test_grep "^Range-diff against v1:$" v2-0000-cover-letter.patch +' + +test_expect_success "explicit --no-cover-letter defeats implied --cover-letter" ' + test_when_finished "rm -f v2-000?-*" && + test_must_fail git format-patch --no-cover-letter \ + -v2 --range-diff=topic main..unmodified && + test_must_fail git -c format.coverLetter=no format-patch \ + -v2 --range-diff=topic main..unmodified +' + test_expect_success 'format-patch --range-diff as commentary' ' git format-patch --range-diff=HEAD~1 HEAD~1 >actual && test_when_finished "rm 0001-*" && diff --git a/t/t3301-notes.sh b/t/t3301-notes.sh index cf23c06c09..536bd11ff4 100755 --- a/t/t3301-notes.sh +++ b/t/t3301-notes.sh @@ -5,6 +5,7 @@ test_description='Test commit notes' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh write_script fake_editor <<\EOF diff --git a/t/t3306-notes-prune.sh b/t/t3306-notes-prune.sh index 8f4102ff9e..b6e9f643e3 100755 --- a/t/t3306-notes-prune.sh +++ b/t/t3306-notes-prune.sh @@ -2,6 +2,7 @@ test_description='Test git notes prune' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup: create a few commits with notes' ' diff --git a/t/t3308-notes-merge.sh b/t/t3308-notes-merge.sh index 202702be1a..e1d05ff6bc 100755 --- a/t/t3308-notes-merge.sh +++ b/t/t3308-notes-merge.sh @@ -5,6 +5,7 @@ test_description='Test merging of notes trees' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t3309-notes-merge-auto-resolve.sh b/t/t3309-notes-merge-auto-resolve.sh index 9bd5dbf341..f55277f499 100755 --- a/t/t3309-notes-merge-auto-resolve.sh +++ b/t/t3309-notes-merge-auto-resolve.sh @@ -5,6 +5,7 @@ test_description='Test notes merging with auto-resolving strategies' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Set up a notes merge scenario with all kinds of potential conflicts diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index e1c8c5f701..ae34bfad60 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -11,6 +11,7 @@ among other things. GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh GIT_AUTHOR_NAME=author@name diff --git a/t/t3401-rebase-and-am-rename.sh b/t/t3401-rebase-and-am-rename.sh index f18bae9450..328c1d3a3f 100755 --- a/t/t3401-rebase-and-am-rename.sh +++ b/t/t3401-rebase-and-am-rename.sh @@ -2,6 +2,7 @@ test_description='git rebase + directory rename tests' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-rebase.sh diff --git a/t/t3403-rebase-skip.sh b/t/t3403-rebase-skip.sh index a1911c4a9d..4f1d6e8ea6 100755 --- a/t/t3403-rebase-skip.sh +++ b/t/t3403-rebase-skip.sh @@ -8,6 +8,7 @@ test_description='git rebase --merge --skip 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-rebase.sh diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index d1bead61fa..f92baad138 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -2215,6 +2215,51 @@ test_expect_success 'bad labels and refs rejected when parsing todo list' ' test_path_is_missing execed ' +test_expect_success 'non-merge commands reject merge commits' ' + test_when_finished "test_might_fail git rebase --abort" && + git checkout E && + git merge I && + oid=$(git rev-parse HEAD) && + cat >todo <<-EOF && + pick $oid + reword $oid + edit $oid + fixup $oid + squash $oid + EOF + ( + set_replace_editor todo && + test_must_fail git rebase -i HEAD 2>actual + ) && + cat >expect <<-EOF && + error: ${SQ}pick${SQ} does not accept merge commits + hint: ${SQ}pick${SQ} does not take a merge commit. If you wanted to + hint: replay the merge, use ${SQ}merge -C${SQ} on the commit. + hint: Disable this message with "git config advice.rebaseTodoError false" + error: invalid line 1: pick $oid + error: ${SQ}reword${SQ} does not accept merge commits + hint: ${SQ}reword${SQ} does not take a merge commit. If you wanted to + hint: replay the merge and reword the commit message, use + hint: ${SQ}merge -c${SQ} on the commit + hint: Disable this message with "git config advice.rebaseTodoError false" + error: invalid line 2: reword $oid + error: ${SQ}edit${SQ} does not accept merge commits + hint: ${SQ}edit${SQ} does not take a merge commit. If you wanted to + hint: replay the merge, use ${SQ}merge -C${SQ} on the commit, and then + hint: ${SQ}break${SQ} to give the control back to you so that you can + hint: do ${SQ}git commit --amend && git rebase --continue${SQ}. + hint: Disable this message with "git config advice.rebaseTodoError false" + error: invalid line 3: edit $oid + error: cannot squash merge commit into another commit + error: invalid line 4: fixup $oid + error: cannot squash merge commit into another commit + error: invalid line 5: squash $oid + You can fix this with ${SQ}git rebase --edit-todo${SQ} and then run ${SQ}git rebase --continue${SQ}. + Or you can abort the rebase with ${SQ}git rebase --abort${SQ}. + EOF + test_cmp expect actual +' + # This must be the last test in this file test_expect_success '$EDITOR and friends are unchanged' ' test_editor_unchanged diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh index a1d7fa7f7c..82108b67e6 100755 --- a/t/t3406-rebase-message.sh +++ b/t/t3406-rebase-message.sh @@ -5,6 +5,7 @@ test_description='messages from rebase operation' 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/t3407-rebase-abort.sh b/t/t3407-rebase-abort.sh index 9f49c4228b..2c3f38d45a 100755 --- a/t/t3407-rebase-abort.sh +++ b/t/t3407-rebase-abort.sh @@ -5,6 +5,7 @@ test_description='git rebase --abort tests' 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/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh index fcc40d6fe1..22452ff84c 100755 --- a/t/t3415-rebase-autosquash.sh +++ b/t/t3415-rebase-autosquash.sh @@ -5,6 +5,7 @@ test_description='auto squash' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-rebase.sh diff --git a/t/t3417-rebase-whitespace-fix.sh b/t/t3417-rebase-whitespace-fix.sh index 96f2cf22fa..22ee3a2045 100755 --- a/t/t3417-rebase-whitespace-fix.sh +++ b/t/t3417-rebase-whitespace-fix.sh @@ -5,6 +5,7 @@ test_description='git rebase --whitespace=fix This test runs git rebase --whitespace=fix and make sure that it works. ' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # prepare initial revision of "file" with a blank line at the end diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh index 127216f722..c0d29c2154 100755 --- a/t/t3418-rebase-continue.sh +++ b/t/t3418-rebase-continue.sh @@ -5,6 +5,7 @@ test_description='git rebase --continue 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-rebase.sh diff --git a/t/t3420-rebase-autostash.sh b/t/t3420-rebase-autostash.sh index 1a820f1481..63e400b89f 100755 --- a/t/t3420-rebase-autostash.sh +++ b/t/t3420-rebase-autostash.sh @@ -7,6 +7,7 @@ test_description='git rebase --autostash tests' 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/t3421-rebase-topology-linear.sh b/t/t3421-rebase-topology-linear.sh index 62d86d557d..737af80bb3 100755 --- a/t/t3421-rebase-topology-linear.sh +++ b/t/t3421-rebase-topology-linear.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='basic rebase topology tests' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-rebase.sh diff --git a/t/t3424-rebase-empty.sh b/t/t3424-rebase-empty.sh index 1ee6b00fd5..515c949ae3 100755 --- a/t/t3424-rebase-empty.sh +++ b/t/t3424-rebase-empty.sh @@ -2,6 +2,7 @@ test_description='git rebase of commits that start or become empty' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup test repository' ' diff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh index ba069dccbd..94ea88e384 100755 --- a/t/t3426-rebase-submodule.sh +++ b/t/t3426-rebase-submodule.sh @@ -2,6 +2,7 @@ test_description='rebase can handle submodules' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-submodule-update.sh . "$TEST_DIRECTORY"/lib-rebase.sh diff --git a/t/t3428-rebase-signoff.sh b/t/t3428-rebase-signoff.sh index 1bebd1ce74..365436ebfc 100755 --- a/t/t3428-rebase-signoff.sh +++ b/t/t3428-rebase-signoff.sh @@ -7,10 +7,16 @@ This test runs git rebase --signoff and make sure that it works. TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh +. "$TEST_DIRECTORY"/lib-rebase.sh test_expect_success 'setup' ' git commit --allow-empty -m "Initial empty commit" && test_commit first file a && + test_commit second file && + git checkout -b conflict-branch first && + test_commit file-2 file-2 && + test_commit conflict file && + test_commit third file && ident="$GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" && @@ -28,6 +34,22 @@ test_expect_success 'setup' ' Signed-off-by: $ident EOF + # Expected commit message after conflict resolution for rebase --signoff + cat >expected-signed-conflict <<-EOF && + third + + Signed-off-by: $ident + + conflict + + Signed-off-by: $ident + + file-2 + + Signed-off-by: $ident + + EOF + # Expected commit message after rebase without --signoff (or with --no-signoff) cat >expected-unsigned <<-EOF && first @@ -39,8 +61,12 @@ test_expect_success 'setup' ' # 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 --apply --signoff adds a sign-off line' ' - git rbs --apply HEAD^ && - test_commit_message HEAD expected-signed + test_must_fail git rbs --apply second third && + git checkout --theirs file && + git add file && + git rebase --continue && + git log --format=%B -n3 >actual && + test_cmp expected-signed-conflict actual ' test_expect_success 'rebase --no-signoff does not add a sign-off line' ' @@ -51,28 +77,65 @@ test_expect_success 'rebase --no-signoff does not add a sign-off line' ' test_expect_success 'rebase --exec --signoff adds a sign-off line' ' test_when_finished "rm exec" && - git commit --amend -m "first" && - git rebase --exec "touch exec" --signoff HEAD^ && + git rebase --exec "touch exec" --signoff first^ first && test_path_is_file exec && test_commit_message HEAD expected-signed ' test_expect_success 'rebase --root --signoff adds a sign-off line' ' - git commit --amend -m "first" && + git checkout first && git rebase --root --keep-empty --signoff && 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^ && - test_commit_message HEAD expected-signed +test_expect_success 'rebase -m --signoff adds a sign-off line' ' + test_must_fail git rebase -m --signoff second third && + git checkout --theirs file && + git add file && + GIT_EDITOR="sed -n /Conflicts:/,/^\\\$/p >actual" \ + git rebase --continue && + cat >expect <<-\EOF && + # Conflicts: + # file + + EOF + test_cmp expect actual && + git log --format=%B -n3 >actual && + test_cmp expected-signed-conflict actual ' -test_expect_success 'rebase -m --signoff fails' ' - git commit --amend -m "first" && - git rebase -m --signoff HEAD^ && - test_commit_message HEAD expected-signed +test_expect_success 'rebase -i --signoff adds a sign-off line when editing commit' ' + ( + set_fake_editor && + FAKE_LINES="edit 1 edit 3 edit 2" \ + git rebase -i --signoff first third + ) && + echo a >a && + git add a && + test_must_fail git rebase --continue && + git checkout --ours file && + echo b >a && + git add a file && + git rebase --continue && + echo c >a && + git add a && + git log --format=%B -n3 >actual && + cat >expect <<-EOF && + conflict + + Signed-off-by: $ident + + third + + Signed-off-by: $ident + + file-2 + + Signed-off-by: $ident + + EOF + test_cmp expect actual ' + test_done diff --git a/t/t3430-rebase-merges.sh b/t/t3430-rebase-merges.sh index 59b5d6b6f2..36ca126bcd 100755 --- a/t/t3430-rebase-merges.sh +++ b/t/t3430-rebase-merges.sh @@ -21,6 +21,7 @@ Initial setup: GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-rebase.sh . "$TEST_DIRECTORY"/lib-log-graph.sh diff --git a/t/t3434-rebase-i18n.sh b/t/t3434-rebase-i18n.sh index e6fef696bb..26a48d6b10 100755 --- a/t/t3434-rebase-i18n.sh +++ b/t/t3434-rebase-i18n.sh @@ -17,6 +17,7 @@ Initial setup: GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh compare_msg () { @@ -71,7 +72,7 @@ test_rebase_continue_update_encode () { git config i18n.commitencoding $new && test_must_fail git rebase -m main && test -f .git/rebase-merge/message && - git stripspace <.git/rebase-merge/message >two.t && + git stripspace -s <.git/rebase-merge/message >two.t && git add two.t && git rebase --continue && compare_msg $msgfile $old $new && diff --git a/t/t3500-cherry.sh b/t/t3500-cherry.sh index 78c3eac54b..61ca87512d 100755 --- a/t/t3500-cherry.sh +++ b/t/t3500-cherry.sh @@ -11,6 +11,7 @@ checks that git cherry only returns the second patch in the local branch GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh GIT_AUTHOR_EMAIL=bogus_email_address diff --git a/t/t3504-cherry-pick-rerere.sh b/t/t3504-cherry-pick-rerere.sh index 4581ae98b8..597c98e9c5 100755 --- a/t/t3504-cherry-pick-rerere.sh +++ b/t/t3504-cherry-pick-rerere.sh @@ -5,6 +5,7 @@ test_description='cherry-pick should rerere for conflicts' 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/t3505-cherry-pick-empty.sh b/t/t3505-cherry-pick-empty.sh index 9748443530..ead3fb4680 100755 --- a/t/t3505-cherry-pick-empty.sh +++ b/t/t3505-cherry-pick-empty.sh @@ -5,6 +5,7 @@ test_description='test cherry-picking an empty commit' 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/t3508-cherry-pick-many-commits.sh b/t/t3508-cherry-pick-many-commits.sh index 2d53ce754c..afa7727a4a 100755 --- a/t/t3508-cherry-pick-many-commits.sh +++ b/t/t3508-cherry-pick-many-commits.sh @@ -5,6 +5,7 @@ test_description='test cherry-picking many commits' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh check_head_differs_from() { diff --git a/t/t3509-cherry-pick-merge-df.sh b/t/t3509-cherry-pick-merge-df.sh index f4159246e1..171cc6d76b 100755 --- a/t/t3509-cherry-pick-merge-df.sh +++ b/t/t3509-cherry-pick-merge-df.sh @@ -4,6 +4,7 @@ test_description='Test cherry-pick with directory/file conflicts' 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 'Initialize repository' ' diff --git a/t/t3512-cherry-pick-submodule.sh b/t/t3512-cherry-pick-submodule.sh index f22d1ddead..9387a22a9e 100755 --- a/t/t3512-cherry-pick-submodule.sh +++ b/t/t3512-cherry-pick-submodule.sh @@ -5,6 +5,7 @@ test_description='cherry-pick can handle submodules' 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-submodule-update.sh diff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh index 8bfe3ed246..e178968b40 100755 --- a/t/t3513-revert-submodule.sh +++ b/t/t3513-revert-submodule.sh @@ -2,6 +2,7 @@ test_description='revert can handle submodules' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-submodule-update.sh diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh index 98259e2ada..31ac31d4bc 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -8,6 +8,7 @@ test_description='Test of the various options to git rm.' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Setup some files to be removed, some with funny characters diff --git a/t/t3602-rm-sparse-checkout.sh b/t/t3602-rm-sparse-checkout.sh index 08580fd3dc..fcdefba48c 100755 --- a/t/t3602-rm-sparse-checkout.sh +++ b/t/t3602-rm-sparse-checkout.sh @@ -2,6 +2,7 @@ test_description='git rm in sparse checked out working trees' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' " diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh index 04d8333373..5d78868ac1 100755 --- a/t/t3701-add-interactive.sh +++ b/t/t3701-add-interactive.sh @@ -8,6 +8,8 @@ TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-terminal.sh +SP=" " + diff_cmp () { for x do @@ -41,19 +43,17 @@ force_color () { ) } -test_expect_success 'warn about add.interactive.useBuiltin' ' - cat >expect <<-\EOF && - warning: the add.interactive.useBuiltin setting has been removed! - See its entry in '\''git help config'\'' for details. - No changes. +test_expect_success 'unknown command' ' + test_when_finished "git reset --hard; rm -f command" && + echo W >command && + git add -N command && + git diff command >expect && + cat >>expect <<-EOF && + (1/1) Stage addition [y,n,q,a,d,e,p,?]? Unknown command ${SQ}W${SQ} (use ${SQ}?${SQ} for help) + (1/1) Stage addition [y,n,q,a,d,e,p,?]?$SP EOF - - for v in = =true =false - do - git -c "add.interactive.useBuiltin$v" add -p >out 2>actual && - test_must_be_empty out && - test_cmp expect actual || return 1 - done + git add -p -- command <command >actual 2>&1 && + test_cmp expect actual ' test_expect_success 'setup (initial)' ' @@ -145,6 +145,14 @@ test_expect_success 'revert works (commit)' ' grep "unchanged *+3/-0 file" output ' +test_expect_success 'reject multi-key input' ' + saved=$(git hash-object -w file) && + test_when_finished "git cat-file blob $saved >file" && + echo an extra line >>file && + test_write_lines aa | git add -p >actual && + test_grep "is expected, got ${SQ}aa${SQ}" actual +' + test_expect_success 'setup expected' ' cat >expected <<-\EOF EOF @@ -232,7 +240,6 @@ test_expect_success 'setup file' ' ' test_expect_success 'setup patch' ' - SP=" " && NULL="" && cat >patch <<-EOF @@ -1,4 +1,4 @@ @@ -335,13 +342,13 @@ test_expect_success 'different prompts for mode change/deleted' ' test_expect_success 'correct message when there is nothing to do' ' git reset --hard && - git add -p 2>err && - test_grep "No changes" err && + git add -p >out && + test_grep "No changes" out && printf "\\0123" >binary && git add binary && printf "\\0abc" >binary && - git add -p 2>err && - test_grep "Only binary files changed" err + git add -p >out && + test_grep "Only binary files changed" out ' test_expect_success 'setup again' ' @@ -512,7 +519,7 @@ test_expect_success 'split hunk setup' ' test_write_lines 10 15 20 21 22 23 24 30 40 50 60 >test ' -test_expect_success 'goto hunk' ' +test_expect_success 'goto hunk 1 with "g 1"' ' test_when_finished "git reset" && tr _ " " >expect <<-EOF && (2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,p,?]? + 1: -1,2 +1,3 +15 @@ -528,7 +535,20 @@ test_expect_success 'goto hunk' ' test_cmp expect actual.trimmed ' -test_expect_success 'navigate to hunk via regex' ' +test_expect_success 'goto hunk 1 with "g1"' ' + test_when_finished "git reset" && + tr _ " " >expect <<-EOF && + _10 + +15 + _20 + (1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]?_ + EOF + test_write_lines s y g1 | git add -p >actual && + tail -n 4 <actual >actual.trimmed && + test_cmp expect actual.trimmed +' + +test_expect_success 'navigate to hunk via regex /pattern' ' test_when_finished "git reset" && tr _ " " >expect <<-EOF && (2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,p,?]? @@ -1,2 +1,3 @@ @@ -542,6 +562,19 @@ test_expect_success 'navigate to hunk via regex' ' test_cmp expect actual.trimmed ' +test_expect_success 'navigate to hunk via regex / pattern' ' + test_when_finished "git reset" && + tr _ " " >expect <<-EOF && + _10 + +15 + _20 + (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 4 <actual >actual.trimmed && + test_cmp expect actual.trimmed +' + test_expect_success 'split hunk "add -p (edit)"' ' # Split, say Edit and do nothing. Then: # diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh index f27d09cfd9..db7b403bc1 100755 --- a/t/t3900-i18n-commit.sh +++ b/t/t3900-i18n-commit.sh @@ -5,6 +5,7 @@ test_description='commit and log output encodings' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh compare_with () { diff --git a/t/t3901-i18n-patch.sh b/t/t3901-i18n-patch.sh index 4b37f78829..5f0b9afc3f 100755 --- a/t/t3901-i18n-patch.sh +++ b/t/t3901-i18n-patch.sh @@ -8,6 +8,7 @@ test_description='i18n settings and format-patch | am pipe' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh check_encoding () { diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index 00db82fb24..a7f71f8126 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -393,6 +393,15 @@ test_expect_success 'stash --staged' ' test bar,bar4 = $(cat file),$(cat file2) ' +test_expect_success 'stash --staged with binary file' ' + printf "\0" >file && + git add file && + git stash --staged && + git stash pop && + printf "\0" >expect && + test_cmp expect file +' + test_expect_success 'dont assume push with non-option args' ' test_must_fail git stash -q drop 2>err && test_grep -e "subcommand wasn'\''t specified; '\''push'\'' can'\''t be assumed due to unexpected token '\''drop'\''" err diff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh index 0f7348ec21..0f61f01ef4 100755 --- a/t/t3906-stash-submodule.sh +++ b/t/t3906-stash-submodule.sh @@ -2,6 +2,7 @@ test_description='stash can handle submodules' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-submodule-update.sh diff --git a/t/t3907-stash-show-config.sh b/t/t3907-stash-show-config.sh index 10914bba7b..7a2eb98b86 100755 --- a/t/t3907-stash-show-config.sh +++ b/t/t3907-stash-show-config.sh @@ -2,6 +2,7 @@ test_description='Test git stash show configuration.' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t3910-mac-os-precompose.sh b/t/t3910-mac-os-precompose.sh index 898267a6bd..6d5918c8fe 100755 --- a/t/t3910-mac-os-precompose.sh +++ b/t/t3910-mac-os-precompose.sh @@ -37,6 +37,27 @@ Alongc=$Alongc$Alongc$Alongc$Alongc$Alongc #50 Byte Alongc=$Alongc$Alongc$Alongc$Alongc$Alongc #250 Byte Alongc=$Alongc$AEligatu$AEligatu #254 Byte + +ls_files_nfc_nfd () { + test_when_finished "git config --global --unset core.precomposeunicode" && + prglbl=$1 + prlocl=$2 + aumlcreat=$3 + aumllist=$4 + git config --global core.precomposeunicode $prglbl && + ( + rm -rf .git && + mkdir -p "somewhere/$prglbl/$prlocl/$aumlcreat" && + mypwd=$PWD && + cd "somewhere/$prglbl/$prlocl/$aumlcreat" && + git init && + git config core.precomposeunicode $prlocl && + git --literal-pathspecs ls-files "$mypwd/somewhere/$prglbl/$prlocl/$aumllist" 2>err && + >expected && + test_cmp expected err + ) +} + test_expect_success "detect if nfd needed" ' precomposeunicode=$(git config core.precomposeunicode) && test "$precomposeunicode" = true && @@ -211,8 +232,8 @@ test_expect_success "unicode decomposed: git restore -p . " ' ' # Test if the global core.precomposeunicode stops autosensing -# Must be the last test case test_expect_success "respect git config --global core.precomposeunicode" ' + test_when_finished "git config --global --unset core.precomposeunicode" && git config --global core.precomposeunicode true && rm -rf .git && git init && @@ -220,4 +241,20 @@ test_expect_success "respect git config --global core.precomposeunicode" ' test "$precomposeunicode" = "true" ' +test_expect_success "ls-files false false nfd nfd" ' + ls_files_nfc_nfd false false $Adiarnfd $Adiarnfd +' + +test_expect_success "ls-files false true nfd nfd" ' + ls_files_nfc_nfd false true $Adiarnfd $Adiarnfd +' + +test_expect_success "ls-files true false nfd nfd" ' + ls_files_nfc_nfd true false $Adiarnfd $Adiarnfd +' + +test_expect_success "ls-files true true nfd nfd" ' + ls_files_nfc_nfd true true $Adiarnfd $Adiarnfd +' + test_done diff --git a/t/t4001-diff-rename.sh b/t/t4001-diff-rename.sh index 49c042a38a..cd1931dd55 100755 --- a/t/t4001-diff-rename.sh +++ b/t/t4001-diff-rename.sh @@ -3,9 +3,9 @@ # Copyright (c) 2005 Junio C Hamano # -test_description='Test rename detection in diff engine. +test_description='Test rename detection in diff engine.' -' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-diff.sh diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index e37a1411ee..884f83fb8a 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -820,8 +820,8 @@ test_expect_success 'format-patch --notes --signoff' ' ' test_expect_success 'format-patch notes output control' ' + test_when_finished "git notes remove HEAD || :" && git notes add -m "notes config message" HEAD && - test_when_finished git notes remove HEAD && git format-patch -1 --stdout >out && ! grep "notes config message" out && @@ -848,10 +848,10 @@ test_expect_success 'format-patch notes output control' ' ' test_expect_success 'format-patch with multiple notes refs' ' + test_when_finished "git notes --ref note1 remove HEAD; + git notes --ref note2 remove HEAD || :" && git notes --ref note1 add -m "this is note 1" HEAD && - test_when_finished git notes --ref note1 remove HEAD && git notes --ref note2 add -m "this is note 2" HEAD && - test_when_finished git notes --ref note2 remove HEAD && git format-patch -1 --stdout >out && ! grep "this is note 1" out && @@ -892,10 +892,10 @@ test_expect_success 'format-patch with multiple notes refs' ' test_expect_success 'format-patch with multiple notes refs in config' ' test_when_finished "test_unconfig format.notes" && + test_when_finished "git notes --ref note1 remove HEAD; + git notes --ref note2 remove HEAD || :" && git notes --ref note1 add -m "this is note 1" HEAD && - test_when_finished git notes --ref note1 remove HEAD && git notes --ref note2 add -m "this is note 2" HEAD && - test_when_finished git notes --ref note2 remove HEAD && git config format.notes note1 && git format-patch -1 --stdout >out && @@ -1368,12 +1368,38 @@ test_expect_success 'empty subject prefix does not have extra space' ' test_cmp expect actual ' -test_expect_success '--rfc' ' +test_expect_success '--rfc and --no-rfc' ' cat >expect <<-\EOF && Subject: [RFC PATCH 1/1] header with . in it EOF git format-patch -n -1 --stdout --rfc >patch && grep "^Subject:" patch >actual && + test_cmp expect actual && + git format-patch -n -1 --stdout --rfc --no-rfc >patch && + sed -e "s/RFC //" expect >expect-raw && + grep "^Subject:" patch >actual && + test_cmp expect-raw actual +' + +test_expect_success '--rfc=WIP and --rfc=' ' + cat >expect <<-\EOF && + Subject: [WIP PATCH 1/1] header with . in it + EOF + git format-patch -n -1 --stdout --rfc=WIP >patch && + grep "^Subject:" patch >actual && + test_cmp expect actual && + git format-patch -n -1 --stdout --rfc --rfc= >patch && + sed -e "s/WIP //" expect >expect-raw && + grep "^Subject:" patch >actual && + test_cmp expect-raw actual +' + +test_expect_success '--rfc=-(WIP) appends' ' + cat >expect <<-\EOF && + Subject: [PATCH (WIP) 1/1] header with . in it + EOF + git format-patch -n -1 --stdout --rfc="-(WIP)" >patch && + grep "^Subject:" patch >actual && test_cmp expect actual ' @@ -1397,6 +1423,27 @@ test_expect_success '--rfc is argument order independent' ' test_cmp expect actual ' +test_expect_success '--subject-prefix="<non-empty>" and -k cannot be used together' ' + echo "fatal: options '\''--subject-prefix/--rfc'\'' and '\''-k'\'' cannot be used together" >expect.err && + test_must_fail git format-patch -1 --stdout --subject-prefix="MYPREFIX" -k >actual.out 2>actual.err && + test_must_be_empty actual.out && + test_cmp expect.err actual.err +' + +test_expect_success '--subject-prefix="" and -k cannot be used together' ' + echo "fatal: options '\''--subject-prefix/--rfc'\'' and '\''-k'\'' cannot be used together" >expect.err && + test_must_fail git format-patch -1 --stdout --subject-prefix="" -k >actual.out 2>actual.err && + test_must_be_empty actual.out && + test_cmp expect.err actual.err +' + +test_expect_success '--rfc and -k cannot be used together' ' + echo "fatal: options '\''--subject-prefix/--rfc'\'' and '\''-k'\'' cannot be used together" >expect.err && + test_must_fail git format-patch -1 --stdout --rfc -k >actual.out 2>actual.err && + test_must_be_empty actual.out && + test_cmp expect.err actual.err +' + test_expect_success '--from=ident notices bogus ident' ' test_must_fail git format-patch -1 --stdout --from=foo >patch ' @@ -2435,16 +2482,55 @@ test_expect_success 'interdiff: reroll-count with a integer' ' ' test_expect_success 'interdiff: solo-patch' ' - cat >expect <<-\EOF && - +fleep - - EOF git format-patch --interdiff=boop~2 -1 boop && - test_grep "^Interdiff:$" 0001-fleep.patch && - sed "1,/^ @@ /d; /^$/q" 0001-fleep.patch >actual && + + # remove up to the last "patch" output line, + # and remove everything below the signature mark. + sed -e "1,/^+fleep\$/d" -e "/^-- /,\$d" 0001-fleep.patch >actual && + + # fabricate Interdiff output. + git diff boop~2 boop >inter && + { + echo && + echo "Interdiff:" && + sed -e "s/^/ /" inter + } >expect && test_cmp expect actual ' +test_expect_success 'range-diff: solo-patch' ' + git format-patch --creation-factor=999 \ + --range-diff=boop~2..boop~1 -1 boop && + + # remove up to the last "patch" output line, + # and remove everything below the signature mark. + sed -e "1,/^+fleep\$/d" -e "/^-- /,\$d" 0001-fleep.patch >actual && + + # fabricate range-diff output. + { + echo && + echo "Range-diff:" && + git range-diff --creation-factor=999 \ + boop~2..boop~1 boop~1..boop + } >expect && + test_cmp expect actual +' + +test_expect_success 'interdiff: multi-patch, implicit --cover-letter' ' + test_when_finished "rm -f v23-0*.patch" && + git format-patch --interdiff=boop~2 -2 -v23 && + test_grep "^Interdiff against v22:$" v23-0000-cover-letter.patch && + test_cmp expect actual +' + +test_expect_success 'interdiff: explicit --no-cover-letter defeats implied --cover-letter' ' + test_when_finished "rm -f v23-0*.patch" && + test_must_fail git format-patch --no-cover-letter \ + --interdiff=boop~2 -2 -v23 && + test_must_fail git -c format.coverLetter=no format-patch \ + --interdiff=boop~2 -2 -v23 +' + test_expect_success 'format-patch does not respect diff.noprefix' ' git -c diff.noprefix format-patch -1 --stdout >actual && grep "^--- a/blorp" actual diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index b443626afd..851cfe4f32 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -1184,6 +1184,15 @@ test_expect_success 'detect moved code, complete file' ' test_cmp expected actual ' +test_expect_success '--color-moved with --no-ext-diff' ' + test_config color.diff.oldMoved "yellow" && + test_config color.diff.newMoved "blue" && + args="--color --color-moved=zebra --no-renames HEAD" && + git diff $args >expect && + git -c diff.external=echo diff --no-ext-diff $args >actual && + test_cmp expect actual +' + test_expect_success 'detect malicious moved code, inside file' ' test_config color.diff.oldMoved "normal red" && test_config color.diff.newMoved "normal green" && diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh index fdd865f7c3..3baa52a9bf 100755 --- a/t/t4020-diff-external.sh +++ b/t/t4020-diff-external.sh @@ -172,6 +172,72 @@ test_expect_success 'no diff with -diff' ' grep Binary out ' +check_external_diff () { + expect_code=$1 + expect_out=$2 + expect_err=$3 + command_code=$4 + trust_exit_code=$5 + shift 5 + options="$@" + + command="echo output; exit $command_code;" + desc="external diff '$command' with trustExitCode=$trust_exit_code" + with_options="${options:+ with }$options" + + test_expect_success "$desc via attribute$with_options" " + test_config diff.foo.command \"$command\" && + test_config diff.foo.trustExitCode $trust_exit_code && + echo \"file diff=foo\" >.gitattributes && + test_expect_code $expect_code git diff $options >out 2>err && + test_cmp $expect_out out && + test_cmp $expect_err err + " + + test_expect_success "$desc via diff.external$with_options" " + test_config diff.external \"$command\" && + test_config diff.trustExitCode $trust_exit_code && + >.gitattributes && + test_expect_code $expect_code git diff $options >out 2>err && + test_cmp $expect_out out && + test_cmp $expect_err err + " + + test_expect_success "$desc via GIT_EXTERNAL_DIFF$with_options" " + >.gitattributes && + test_expect_code $expect_code env \ + GIT_EXTERNAL_DIFF=\"$command\" \ + GIT_EXTERNAL_DIFF_TRUST_EXIT_CODE=$trust_exit_code \ + git diff $options >out 2>err && + test_cmp $expect_out out && + test_cmp $expect_err err + " +} + +test_expect_success 'setup output files' ' + : >empty && + echo output >output && + echo "fatal: external diff died, stopping at file" >error +' + +check_external_diff 0 output empty 0 off +check_external_diff 128 output error 1 off +check_external_diff 0 output empty 0 on +check_external_diff 0 output empty 1 on +check_external_diff 128 output error 2 on + +check_external_diff 1 output empty 0 off --exit-code +check_external_diff 128 output error 1 off --exit-code +check_external_diff 0 output empty 0 on --exit-code +check_external_diff 1 output empty 1 on --exit-code +check_external_diff 128 output error 2 on --exit-code + +check_external_diff 1 empty empty 0 off --quiet +check_external_diff 1 empty empty 1 off --quiet # we don't even call the program +check_external_diff 0 empty empty 0 on --quiet +check_external_diff 1 empty empty 1 on --quiet +check_external_diff 128 empty error 2 on --quiet + echo NULZbetweenZwords | perl -pe 'y/Z/\000/' > file test_expect_success 'force diff with "diff"' ' diff --git a/t/t4026-color.sh b/t/t4026-color.sh index cc3f60d468..b05f2a9b60 100755 --- a/t/t4026-color.sh +++ b/t/t4026-color.sh @@ -96,8 +96,8 @@ test_expect_success '256 colors' ' color "254 bold 255" "[1;38;5;254;48;5;255m" ' -test_expect_success '24-bit colors' ' - color "#ff00ff black" "[38;2;255;0;255;40m" +test_expect_success 'RGB colors' ' + color "#ff00ff #0f0" "[38;2;255;0;255;48;2;0;255;0m" ' test_expect_success '"default" foreground' ' @@ -112,7 +112,7 @@ test_expect_success '"default" can be combined with attributes' ' color "default default no-reverse bold" "[1;27;39;49m" ' -test_expect_success '"normal" yields no color at all"' ' +test_expect_success '"normal" yields no color at all' ' color "normal black" "[40m" ' @@ -140,6 +140,26 @@ test_expect_success 'extra character after attribute' ' invalid_color "dimX" ' +test_expect_success 'non-hex character in RGB color' ' + invalid_color "#x23456" && + invalid_color "#1x3456" && + invalid_color "#12x456" && + invalid_color "#123x56" && + invalid_color "#1234x6" && + invalid_color "#12345x" && + invalid_color "#x23" && + invalid_color "#1x3" && + invalid_color "#12x" +' + +test_expect_success 'wrong number of letters in RGB color' ' + invalid_color "#1" && + invalid_color "#23" && + invalid_color "#789a" && + invalid_color "#bcdef" && + invalid_color "#1234567" +' + test_expect_success 'unknown color slots are ignored (diff)' ' git config color.diff.nosuchslotwilleverbedefined white && git diff --color diff --git a/t/t4041-diff-submodule-option.sh b/t/t4041-diff-submodule-option.sh index 0c1502d4b0..8fc40e75eb 100755 --- a/t/t4041-diff-submodule-option.sh +++ b/t/t4041-diff-submodule-option.sh @@ -12,6 +12,7 @@ This test tries to verify the sanity of the --submodule option of git diff. GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Tested non-UTF-8 encoding diff --git a/t/t4043-diff-rename-binary.sh b/t/t4043-diff-rename-binary.sh index 2a2cf91352..e486493908 100755 --- a/t/t4043-diff-rename-binary.sh +++ b/t/t4043-diff-rename-binary.sh @@ -5,6 +5,7 @@ test_description='Move a binary file' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh diff --git a/t/t4046-diff-unmerged.sh b/t/t4046-diff-unmerged.sh index ffaf69335f..afda629c98 100755 --- a/t/t4046-diff-unmerged.sh +++ b/t/t4046-diff-unmerged.sh @@ -20,13 +20,15 @@ test_expect_success setup ' for t in o x do path="$b$o$t" && - case "$path" in ooo) continue ;; esac && - paths="$paths$path " && - p=" $path" && - case "$b" in x) echo "$m1$p" ;; esac && - case "$o" in x) echo "$m2$p" ;; esac && - case "$t" in x) echo "$m3$p" ;; esac || - return 1 + if test "$path" != ooo + then + paths="$paths$path " && + p=" $path" && + case "$b" in x) echo "$m1$p" ;; esac && + case "$o" in x) echo "$m2$p" ;; esac && + case "$t" in x) echo "$m3$p" ;; esac || + return 1 + fi done done done >ls-files-s.expect && @@ -96,4 +98,12 @@ test_expect_success 'diff --stat' ' test_cmp diff-stat.expect diff-stat.actual ' +test_expect_success 'diff --quiet' ' + test_expect_code 1 git diff --cached --quiet +' + +test_expect_success 'diff --quiet --ignore-all-space' ' + test_expect_code 1 git diff --cached --quiet --ignore-all-space +' + test_done diff --git a/t/t4059-diff-submodule-not-initialized.sh b/t/t4059-diff-submodule-not-initialized.sh index d489230df8..668f526303 100755 --- a/t/t4059-diff-submodule-not-initialized.sh +++ b/t/t4059-diff-submodule-not-initialized.sh @@ -9,6 +9,7 @@ This test tries to verify that add_submodule_odb works when the submodule was initialized previously but the checkout has since been removed. ' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Tested non-UTF-8 encoding diff --git a/t/t4060-diff-submodule-option-diff-format.sh b/t/t4060-diff-submodule-option-diff-format.sh index 97c6424cd5..8ce67442d9 100755 --- a/t/t4060-diff-submodule-option-diff-format.sh +++ b/t/t4060-diff-submodule-option-diff-format.sh @@ -10,6 +10,7 @@ test_description='Support for diff format verbose submodule difference in git di This test tries to verify the sanity of --submodule=diff option of git diff. ' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Tested non-UTF-8 encoding diff --git a/t/t4061-diff-indent.sh b/t/t4061-diff-indent.sh index 7750b87ca1..2942e5d9b9 100755 --- a/t/t4061-diff-indent.sh +++ b/t/t4061-diff-indent.sh @@ -6,6 +6,7 @@ test_description='Test diff indent heuristic. GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-diff.sh diff --git a/t/t4120-apply-popt.sh b/t/t4120-apply-popt.sh index 697e86c0ff..f788428540 100755 --- a/t/t4120-apply-popt.sh +++ b/t/t4120-apply-popt.sh @@ -5,6 +5,7 @@ test_description='git apply -p handling.' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t4131-apply-fake-ancestor.sh b/t/t4131-apply-fake-ancestor.sh index b1361ce546..40c92115a6 100755 --- a/t/t4131-apply-fake-ancestor.sh +++ b/t/t4131-apply-fake-ancestor.sh @@ -5,6 +5,7 @@ test_description='git apply --build-fake-ancestor handling.' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t4137-apply-submodule.sh b/t/t4137-apply-submodule.sh index 07d5262537..ebd0d4ad17 100755 --- a/t/t4137-apply-submodule.sh +++ b/t/t4137-apply-submodule.sh @@ -2,6 +2,7 @@ test_description='git apply handling submodules' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-submodule-update.sh diff --git a/t/t4151-am-abort.sh b/t/t4151-am-abort.sh index edb38da701..1825a89d6a 100755 --- a/t/t4151-am-abort.sh +++ b/t/t4151-am-abort.sh @@ -2,6 +2,7 @@ test_description='am --abort' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t4153-am-resume-override-opts.sh b/t/t4153-am-resume-override-opts.sh index 4add7c7757..a4d0c03ca6 100755 --- a/t/t4153-am-resume-override-opts.sh +++ b/t/t4153-am-resume-override-opts.sh @@ -2,8 +2,8 @@ test_description='git-am command-line options override saved options' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh -. "$TEST_DIRECTORY"/lib-terminal.sh format_patch () { git format-patch --stdout -1 "$1" >"$1".eml @@ -27,7 +27,12 @@ test_expect_success 'setup' ' format_patch side2 ' -test_expect_success TTY '--3way overrides --no-3way' ' +test_expect_success '--retry fails without in-progress operation' ' + test_must_fail git am --retry 2>err && + test_grep "operation not in progress" err +' + +test_expect_success '--3way overrides --no-3way' ' rm -fr .git/rebase-apply && git reset --hard && git checkout renamed-file && @@ -40,7 +45,7 @@ test_expect_success TTY '--3way overrides --no-3way' ' # Applying side1 with am --3way will succeed due to the threeway-merge. # Applying side2 will fail as --3way does not apply to it. - test_must_fail test_terminal git am --3way </dev/zero && + test_must_fail git am --retry --3way && test_path_is_dir .git/rebase-apply && test side1 = "$(cat file2)" ' @@ -84,7 +89,7 @@ test_expect_success '--signoff overrides --no-signoff' ' test $(git cat-file commit HEAD | grep -c "Signed-off-by:") -eq 0 ' -test_expect_success TTY '--reject overrides --no-reject' ' +test_expect_success '--reject overrides --no-reject' ' rm -fr .git/rebase-apply && git reset --hard && git checkout first && @@ -94,7 +99,7 @@ test_expect_success TTY '--reject overrides --no-reject' ' test_path_is_dir .git/rebase-apply && test_path_is_missing file.rej && - test_must_fail test_terminal git am --reject </dev/zero && + test_must_fail git am --retry --reject </dev/zero && test_path_is_dir .git/rebase-apply && test_path_is_file file.rej ' diff --git a/t/t4202-log.sh b/t/t4202-log.sh index 60fe60d761..51f7beb59f 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -1237,6 +1237,30 @@ test_expect_success 'log.abbrevCommit configuration' ' test_cmp expect.whatchanged.full actual ' +test_expect_success '--abbrev-commit with core.abbrev=false' ' + git log --no-abbrev >expect && + git -c core.abbrev=false log --abbrev-commit >actual && + test_cmp expect actual +' + +test_expect_success '--abbrev-commit with --no-abbrev' ' + git log --no-abbrev >expect && + git log --abbrev-commit --no-abbrev >actual && + test_cmp expect actual +' + +test_expect_success '--abbrev-commit with core.abbrev=9000' ' + git log --no-abbrev >expect && + git -c core.abbrev=9000 log --abbrev-commit >actual && + test_cmp expect actual +' + +test_expect_success '--abbrev-commit with --abbrev=9000' ' + git log --no-abbrev >expect && + git log --abbrev-commit --abbrev=9000 >actual && + test_cmp expect actual +' + test_expect_success 'show added path under "--follow -M"' ' # This tests for a regression introduced in v1.7.2-rc0~103^2~2 test_create_repo regression && @@ -2022,7 +2046,7 @@ test_expect_success GPGSM 'log --graph --show-signature x509' ' test_expect_success GPGSSH 'log --graph --show-signature ssh' ' test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && git log --graph --show-signature -n1 signed-ssh >actual && - grep "${GOOD_SIGNATURE_TRUSTED}" actual + grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual ' test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'log shows failure on expired signature key' ' diff --git a/t/t4204-patch-id.sh b/t/t4204-patch-id.sh index a7fa94ce0a..605faea0c7 100755 --- a/t/t4204-patch-id.sh +++ b/t/t4204-patch-id.sh @@ -310,4 +310,38 @@ test_expect_success 'patch-id handles diffs with one line of before/after' ' test_config patchid.stable true && calc_patch_id diffu1stable <diffu1 ' + +test_expect_failure 'patch-id computes same ID with different object hashes' ' + test_when_finished "rm -rf repo-sha1 repo-sha256" && + + cat >diff <<-\EOF && + diff --git a/bar b/bar + index bdaf90f..31051f6 100644 + --- a/bar + +++ b/bar + @@ -2 +2,2 @@ + b + +c + EOF + + git init --object-format=sha1 repo-sha1 && + git -C repo-sha1 patch-id <diff >patch-id-sha1 && + git init --object-format=sha256 repo-sha256 && + git -C repo-sha256 patch-id <diff >patch-id-sha256 && + test_cmp patch-id-sha1 patch-id-sha256 +' + +test_expect_success 'patch-id without repository' ' + cat >diff <<-\EOF && + diff --git a/bar b/bar + index bdaf90f..31051f6 100644 + --- a/bar + +++ b/bar + @@ -2 +2,2 @@ + b + +c + EOF + nongit git patch-id <diff +' + test_done diff --git a/t/t4208-log-magic-pathspec.sh b/t/t4208-log-magic-pathspec.sh index 806b2809d4..2a46eb6bed 100755 --- a/t/t4208-log-magic-pathspec.sh +++ b/t/t4208-log-magic-pathspec.sh @@ -5,6 +5,7 @@ test_description='magic pathspec tests using git-log' 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/t4210-log-i18n.sh b/t/t4210-log-i18n.sh index 75216f19ce..7120030b5c 100755 --- a/t/t4210-log-i18n.sh +++ b/t/t4210-log-i18n.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test log with i18n features' + +TEST_PASSES_SANITIZE_LEAK=true . ./lib-gettext.sh # two forms of é diff --git a/t/t4216-log-bloom.sh b/t/t4216-log-bloom.sh index 2ba0324a69..3f163dc396 100755 --- a/t/t4216-log-bloom.sh +++ b/t/t4216-log-bloom.sh @@ -82,7 +82,23 @@ test_bloom_filters_used () { test_bloom_filters_not_used () { log_args=$1 setup "$log_args" && - ! grep -q "statistics:{\"filter_not_present\":" "$TRASH_DIRECTORY/trace.perf" && + + if grep -q "statistics:{\"filter_not_present\":" "$TRASH_DIRECTORY/trace.perf" + then + # if the Bloom filter system is initialized, ensure that no + # filters were used + data="statistics:{" + # unusable filters (e.g., those computed with a + # different value of commitGraph.changedPathsVersion) + # are counted in the filter_not_present bucket, so any + # value is OK there. + data="$data\"filter_not_present\":[0-9][0-9]*," + data="$data\"maybe\":0," + data="$data\"definitely_not\":0," + data="$data\"false_positive\":0}" + + grep -q "$data" "$TRASH_DIRECTORY/trace.perf" + fi && test_cmp log_wo_bloom log_w_bloom } @@ -163,7 +179,7 @@ test_expect_success 'setup - add commit-graph to the chain with Bloom filters' ' test_bloom_filters_used_when_some_filters_are_missing () { log_args=$1 - bloom_trace_prefix="statistics:{\"filter_not_present\":3,\"maybe\":6,\"definitely_not\":9" + bloom_trace_prefix="statistics:{\"filter_not_present\":3,\"maybe\":6,\"definitely_not\":10" setup "$log_args" && grep -q "$bloom_trace_prefix" "$TRASH_DIRECTORY/trace.perf" && test_cmp log_wo_bloom log_w_bloom @@ -206,6 +222,10 @@ test_filter_trunc_large () { grep "\"key\":\"filter-trunc-large\",\"value\":\"$1\"" $2 } +test_filter_upgraded () { + grep "\"key\":\"filter-upgraded\",\"value\":\"$1\"" $2 +} + test_expect_success 'correctly report changes over limit' ' git init limits && ( @@ -405,8 +425,307 @@ test_expect_success 'Bloom generation backfills empty commits' ' ) ' +graph=.git/objects/info/commit-graph +graphdir=.git/objects/info/commit-graphs +chain=$graphdir/commit-graph-chain + +test_expect_success 'setup for mixed Bloom setting tests' ' + repo=mixed-bloom-settings && + + git init $repo && + for i in one two three + do + test_commit -C $repo $i file || return 1 + done +' + +test_expect_success 'ensure Bloom filters with incompatible settings are ignored' ' + # Compute Bloom filters with "unusual" settings. + git -C $repo rev-parse one >in && + GIT_TEST_BLOOM_SETTINGS_NUM_HASHES=3 git -C $repo commit-graph write \ + --stdin-commits --changed-paths --split <in && + layer=$(head -n 1 $repo/$chain) && + + # A commit-graph layer without Bloom filters "hides" the layers + # below ... + git -C $repo rev-parse two >in && + git -C $repo commit-graph write --stdin-commits --no-changed-paths \ + --split=no-merge <in && + + # Another commit-graph layer that has Bloom filters, but with + # standard settings, and is thus incompatible with the base + # layer written above. + git -C $repo rev-parse HEAD >in && + git -C $repo commit-graph write --stdin-commits --changed-paths \ + --split=no-merge <in && + + test_line_count = 3 $repo/$chain && + + # Ensure that incompatible Bloom filters are ignored. + git -C $repo -c core.commitGraph=false log --oneline --no-decorate -- file \ + >expect 2>err && + git -C $repo log --oneline --no-decorate -- file >actual 2>err && + test_cmp expect actual && + grep "disabling Bloom filters for commit-graph layer .$layer." err +' + +test_expect_success 'merge graph layers with incompatible Bloom settings' ' + # Ensure that incompatible Bloom filters are ignored when + # merging existing layers. + >trace2.txt && + GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ + git -C $repo commit-graph write --reachable --changed-paths 2>err && + grep "disabling Bloom filters for commit-graph layer .$layer." err && + grep "{\"hash_version\":1,\"num_hashes\":7,\"bits_per_entry\":10,\"max_changed_paths\":512" trace2.txt && + + test_path_is_file $repo/$graph && + test_dir_is_empty $repo/$graphdir && + + git -C $repo -c core.commitGraph=false log --oneline --no-decorate -- \ + file >expect && + trace_out="$(pwd)/trace.perf" && + GIT_TRACE2_PERF="$trace_out" \ + git -C $repo log --oneline --no-decorate -- file >actual 2>err && + + test_cmp expect actual && + grep "statistics:{\"filter_not_present\":0," trace.perf && + test_must_be_empty err +' + +# chosen to be the same under all Unicode normalization forms +CENT=$(printf "\302\242") + +test_expect_success 'ensure Bloom filter with incompatible versions are ignored' ' + rm "$repo/$graph" && + + git -C $repo log --oneline --no-decorate -- $CENT >expect && + + # Compute v1 Bloom filters for commits at the bottom. + git -C $repo rev-parse HEAD^ >in && + git -C $repo commit-graph write --stdin-commits --changed-paths \ + --split <in && + + # Compute v2 Bloomfilters for the rest of the commits at the top. + git -C $repo rev-parse HEAD >in && + git -C $repo -c commitGraph.changedPathsVersion=2 commit-graph write \ + --stdin-commits --changed-paths --split=no-merge <in && + + test_line_count = 2 $repo/$chain && + + git -C $repo log --oneline --no-decorate -- $CENT >actual 2>err && + test_cmp expect actual && + + layer="$(head -n 1 $repo/$chain)" && + cat >expect.err <<-EOF && + warning: disabling Bloom filters for commit-graph layer $SQ$layer$SQ due to incompatible settings + EOF + test_cmp expect.err err && + + # Merge the two layers with incompatible bloom filter versions, + # ensuring that the v2 filters are used. + >trace2.txt && + GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ + git -C $repo -c commitGraph.changedPathsVersion=2 commit-graph write --reachable --changed-paths 2>err && + grep "disabling Bloom filters for commit-graph layer .$layer." err && + grep "{\"hash_version\":2,\"num_hashes\":7,\"bits_per_entry\":10,\"max_changed_paths\":512" trace2.txt +' + +get_first_changed_path_filter () { + test-tool read-graph bloom-filters >filters.dat && + head -n 1 filters.dat +} + +test_expect_success 'set up repo with high bit path, version 1 changed-path' ' + git init highbit1 && + test_commit -C highbit1 c1 "$CENT" && + git -C highbit1 commit-graph write --reachable --changed-paths +' + +test_expect_success 'setup check value of version 1 changed-path' ' + ( + cd highbit1 && + echo "52a9" >expect && + get_first_changed_path_filter >actual + ) +' + +# expect will not match actual if char is unsigned by default. Write the test +# in this way, so that a user running this test script can still see if the two +# files match. (It will appear as an ordinary success if they match, and a skip +# if not.) +if test_cmp highbit1/expect highbit1/actual +then + test_set_prereq SIGNED_CHAR_BY_DEFAULT +fi +test_expect_success SIGNED_CHAR_BY_DEFAULT 'check value of version 1 changed-path' ' + # Only the prereq matters for this test. + true +' + +test_expect_success 'setup make another commit' ' + # "git log" does not use Bloom filters for root commits - see how, in + # revision.c, rev_compare_tree() (the only code path that eventually calls + # get_bloom_filter()) is only called by try_to_simplify_commit() when the commit + # has one parent. Therefore, make another commit so that we perform the tests on + # a non-root commit. + test_commit -C highbit1 anotherc1 "another$CENT" +' + +test_expect_success 'version 1 changed-path used when version 1 requested' ' + ( + cd highbit1 && + test_bloom_filters_used "-- another$CENT" + ) +' + +test_expect_success 'version 1 changed-path not used when version 2 requested' ' + ( + cd highbit1 && + git config --add commitGraph.changedPathsVersion 2 && + test_bloom_filters_not_used "-- another$CENT" + ) +' + +test_expect_success 'version 1 changed-path used when autodetect requested' ' + ( + cd highbit1 && + git config --add commitGraph.changedPathsVersion -1 && + test_bloom_filters_used "-- another$CENT" + ) +' + +test_expect_success 'when writing another commit graph, preserve existing version 1 of changed-path' ' + test_commit -C highbit1 c1double "$CENT$CENT" && + git -C highbit1 commit-graph write --reachable --changed-paths && + ( + cd highbit1 && + git config --add commitGraph.changedPathsVersion -1 && + echo "options: bloom(1,10,7) read_generation_data" >expect && + test-tool read-graph >full && + grep options full >actual && + test_cmp expect actual + ) +' + +test_expect_success 'set up repo with high bit path, version 2 changed-path' ' + git init highbit2 && + git -C highbit2 config --add commitGraph.changedPathsVersion 2 && + test_commit -C highbit2 c2 "$CENT" && + git -C highbit2 commit-graph write --reachable --changed-paths +' + +test_expect_success 'check value of version 2 changed-path' ' + ( + cd highbit2 && + echo "c01f" >expect && + get_first_changed_path_filter >actual && + test_cmp expect actual + ) +' + +test_expect_success 'setup make another commit' ' + # "git log" does not use Bloom filters for root commits - see how, in + # revision.c, rev_compare_tree() (the only code path that eventually calls + # get_bloom_filter()) is only called by try_to_simplify_commit() when the commit + # has one parent. Therefore, make another commit so that we perform the tests on + # a non-root commit. + test_commit -C highbit2 anotherc2 "another$CENT" +' + +test_expect_success 'version 2 changed-path used when version 2 requested' ' + ( + cd highbit2 && + test_bloom_filters_used "-- another$CENT" + ) +' + +test_expect_success 'version 2 changed-path not used when version 1 requested' ' + ( + cd highbit2 && + git config --add commitGraph.changedPathsVersion 1 && + test_bloom_filters_not_used "-- another$CENT" + ) +' + +test_expect_success 'version 2 changed-path used when autodetect requested' ' + ( + cd highbit2 && + git config --add commitGraph.changedPathsVersion -1 && + test_bloom_filters_used "-- another$CENT" + ) +' + +test_expect_success 'when writing another commit graph, preserve existing version 2 of changed-path' ' + test_commit -C highbit2 c2double "$CENT$CENT" && + git -C highbit2 commit-graph write --reachable --changed-paths && + ( + cd highbit2 && + git config --add commitGraph.changedPathsVersion -1 && + echo "options: bloom(2,10,7) read_generation_data" >expect && + test-tool read-graph >full && + grep options full >actual && + test_cmp expect actual + ) +' + +test_expect_success 'when writing commit graph, do not reuse changed-path of another version' ' + git init doublewrite && + test_commit -C doublewrite c "$CENT" && + + git -C doublewrite config --add commitGraph.changedPathsVersion 1 && + >trace2.txt && + GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ + git -C doublewrite commit-graph write --reachable --changed-paths && + test_filter_computed 1 trace2.txt && + test_filter_upgraded 0 trace2.txt && + + git -C doublewrite commit-graph write --reachable --changed-paths && + for v in -2 3 + do + git -C doublewrite config --add commitGraph.changedPathsVersion $v && + git -C doublewrite commit-graph write --reachable --changed-paths 2>err && + cat >expect <<-EOF && + warning: attempting to write a commit-graph, but ${SQ}commitGraph.changedPathsVersion${SQ} ($v) is not supported + EOF + test_cmp expect err || return 1 + done && + + git -C doublewrite config --add commitGraph.changedPathsVersion 2 && + >trace2.txt && + GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ + git -C doublewrite commit-graph write --reachable --changed-paths && + test_filter_computed 1 trace2.txt && + test_filter_upgraded 0 trace2.txt && + + ( + cd doublewrite && + echo "c01f" >expect && + get_first_changed_path_filter >actual && + test_cmp expect actual + ) +' + +test_expect_success 'when writing commit graph, reuse changed-path of another version where possible' ' + git init upgrade && + + test_commit -C upgrade base no-high-bits && + + git -C upgrade config --add commitGraph.changedPathsVersion 1 && + >trace2.txt && + GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ + git -C upgrade commit-graph write --reachable --changed-paths && + test_filter_computed 1 trace2.txt && + test_filter_upgraded 0 trace2.txt && + + git -C upgrade config --add commitGraph.changedPathsVersion 2 && + >trace2.txt && + GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ + git -C upgrade commit-graph write --reachable --changed-paths && + test_filter_computed 0 trace2.txt && + test_filter_upgraded 1 trace2.txt +' + corrupt_graph () { - graph=.git/objects/info/commit-graph && test_when_finished "rm -rf $graph" && git commit-graph write --reachable --changed-paths && corrupt_chunk_file $graph "$@" diff --git a/t/t4253-am-keep-cr-dos.sh b/t/t4253-am-keep-cr-dos.sh index 0ee69d2a0c..2bcdd9f34f 100755 --- a/t/t4253-am-keep-cr-dos.sh +++ b/t/t4253-am-keep-cr-dos.sh @@ -9,6 +9,7 @@ test_description='git-am mbox with dos line ending. GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Three patches which will be added as files with dos line ending. diff --git a/t/t4255-am-submodule.sh b/t/t4255-am-submodule.sh index a7ba08f728..04f3ccfc41 100755 --- a/t/t4255-am-submodule.sh +++ b/t/t4255-am-submodule.sh @@ -2,6 +2,7 @@ test_description='git am handling submodules' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-submodule-update.sh diff --git a/t/t5001-archive-attr.sh b/t/t5001-archive-attr.sh index eaf959d8f6..7310774af5 100755 --- a/t/t5001-archive-attr.sh +++ b/t/t5001-archive-attr.sh @@ -133,7 +133,8 @@ test_expect_success 'git archive vs. bare' ' ' test_expect_success 'git archive with worktree attributes, bare' ' - (cd bare && git archive --worktree-attributes HEAD) >bare-worktree.tar && + (cd bare && + git -c attr.tree=HEAD archive --worktree-attributes HEAD) >bare-worktree.tar && (mkdir bare-worktree && cd bare-worktree && "$TAR" xf -) <bare-worktree.tar ' diff --git a/t/t5150-request-pull.sh b/t/t5150-request-pull.sh index cb67bac1c4..86bee33160 100755 --- a/t/t5150-request-pull.sh +++ b/t/t5150-request-pull.sh @@ -5,6 +5,7 @@ test_description='Test workflows involving pull request.' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh if ! test_have_prereq PERL diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index 61e2be2903..4ad023c846 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -3,9 +3,9 @@ # Copyright (c) 2005 Junio C Hamano # -test_description='git pack-object +test_description='git pack-object' -' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t5305-include-tag.sh b/t/t5305-include-tag.sh index 44bd9ef45f..dc8fe55c82 100755 --- a/t/t5305-include-tag.sh +++ b/t/t5305-include-tag.sh @@ -4,6 +4,7 @@ test_description='git pack-object --include-tag' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh TRASH=$(pwd) diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh index dd09134db0..10d2a6bf92 100755 --- a/t/t5319-multi-pack-index.sh +++ b/t/t5319-multi-pack-index.sh @@ -350,6 +350,29 @@ test_expect_success 'preferred packs must be non-empty' ' ) ' +test_expect_success 'preferred pack from existing MIDX without bitmaps' ' + git init preferred-without-bitmaps && + ( + cd preferred-without-bitmaps && + + test_commit one && + pack="$(git pack-objects --all $objdir/pack/pack </dev/null)" && + + git multi-pack-index write && + + # make another pack so that the subsequent MIDX write + # has something to do + test_commit two && + git repack -d && + + # write a new MIDX without bitmaps reusing the singular + # pack from the existing MIDX as the preferred pack in + # the new MIDX + git multi-pack-index write --preferred-pack=pack-$pack.pack + ) + +' + test_expect_success 'verify multi-pack-index success' ' git multi-pack-index verify --object-dir=$objdir ' diff --git a/t/t5324-split-commit-graph.sh b/t/t5324-split-commit-graph.sh index 281266f788..77e91547ea 100755 --- a/t/t5324-split-commit-graph.sh +++ b/t/t5324-split-commit-graph.sh @@ -13,7 +13,8 @@ test_expect_success 'setup repo' ' git init && git config core.commitGraph true && git config gc.writeCommitGraph false && - infodir=".git/objects/info" && + objdir=".git/objects" && + infodir="$objdir/info" && graphdir="$infodir/commit-graphs" && test_oid_cache <<-EOM shallow sha1:2132 @@ -718,4 +719,27 @@ test_expect_success 'write generation data chunk when commit-graph chain is repl ) ' +test_expect_success 'temporary graph layer is discarded upon failure' ' + git init layer-discard && + ( + cd layer-discard && + + test_commit A && + test_commit B && + + # Intentionally remove commit "A" from the object store + # so that the commit-graph machinery fails to parse the + # parents of "B". + # + # This takes place after the commit-graph machinery has + # initialized a new temporary file to store the contents + # of the new graph layer, so will allow us to ensure + # that the temporary file is discarded upon failure. + rm $objdir/$(test_oid_to_path $(git rev-parse HEAD^)) && + + test_must_fail git commit-graph write --reachable --split && + test_dir_is_empty $graphdir + ) +' + test_done diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh index 5d7d321840..916da389b6 100755 --- a/t/t5326-multi-pack-bitmaps.sh +++ b/t/t5326-multi-pack-bitmaps.sh @@ -434,6 +434,27 @@ test_expect_success 'tagged commits are selected for bitmapping' ' ) ' +test_expect_success 'do not follow replace objects for MIDX bitmap' ' + rm -fr repo && + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + + test_commit A && + test_commit B && + git checkout --orphan=orphan A && + test_commit orphan && + + git replace A HEAD && + git repack -ad --write-midx --write-bitmap-index && + + # generating reachability bitmaps with replace refs + # enabled will result in broken clones + git clone --no-local --bare . clone.git + ) +' + corrupt_file () { chmod a+w "$1" && printf "bogus" | dd of="$1" bs=1 seek="12" conv=notrunc @@ -530,4 +551,34 @@ do ' done +test_expect_success 'remove one packfile between MIDX bitmap writes' ' + git init remove-pack-between-writes && + ( + cd remove-pack-between-writes && + + test_commit A && + test_commit B && + test_commit C && + + # Create packs with the prefix "pack-A", "pack-B", + # "pack-C" to impose a lexicographic order on these + # packs so the pack being removed is always from the + # middle. + packdir=.git/objects/pack && + A="$(echo A | git pack-objects $packdir/pack-A --revs)" && + B="$(echo B | git pack-objects $packdir/pack-B --revs)" && + C="$(echo C | git pack-objects $packdir/pack-C --revs)" && + + git multi-pack-index write --bitmap && + + cat >in <<-EOF && + pack-A-$A.idx + pack-C-$C.idx + EOF + git multi-pack-index write --bitmap --stdin-packs <in && + + git rev-list --test-bitmap HEAD + ) +' + test_done diff --git a/t/t5332-multi-pack-reuse.sh b/t/t5332-multi-pack-reuse.sh index 3c20738bce..ed823f37bc 100755 --- a/t/t5332-multi-pack-reuse.sh +++ b/t/t5332-multi-pack-reuse.sh @@ -204,4 +204,30 @@ test_expect_success 'omit delta from uninteresting base (cross pack)' ' test_pack_objects_reused_all $(($objects_nr - 1)) $packs_nr ' +test_expect_success 'non-omitted delta in MIDX preferred pack' ' + test_config pack.allowPackReuse single && + + cat >p1.objects <<-EOF && + $(git rev-parse $base) + ^$(git rev-parse $delta^) + EOF + cat >p2.objects <<-EOF && + $(git rev-parse F) + EOF + + p1="$(git pack-objects --revs $packdir/pack <p1.objects)" && + p2="$(git pack-objects --revs $packdir/pack <p2.objects)" && + + cat >in <<-EOF && + pack-$p1.idx + pack-$p2.idx + EOF + git multi-pack-index write --bitmap --stdin-packs \ + --preferred-pack=pack-$p1.pack <in && + + git show-index <$packdir/pack-$p1.idx >expect && + + test_pack_objects_reused_all $(wc -l <expect) 1 +' + test_done diff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh new file mode 100755 index 0000000000..f052f395a7 --- /dev/null +++ b/t/t5333-pseudo-merge-bitmaps.sh @@ -0,0 +1,393 @@ +#!/bin/sh + +test_description='pseudo-merge bitmaps' + +GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 + +. ./test-lib.sh + +test_pseudo_merges () { + test-tool bitmap dump-pseudo-merges +} + +test_pseudo_merge_commits () { + test-tool bitmap dump-pseudo-merge-commits "$1" +} + +test_pseudo_merges_satisfied () { + test_trace2_data bitmap pseudo_merges_satisfied "$1" +} + +test_pseudo_merges_cascades () { + test_trace2_data bitmap pseudo_merges_cascades "$1" +} + +test_pseudo_merges_reused () { + test_trace2_data pack-bitmap-write building_bitmaps_pseudo_merge_reused "$1" +} + +tag_everything () { + git rev-list --all --no-object-names >in && + perl -lne ' + print "create refs/tags/" . $. . " " . $1 if /([0-9a-f]+)/ + ' <in | git update-ref --stdin +} + +test_expect_success 'setup' ' + test_commit_bulk 512 && + tag_everything +' + +test_expect_success 'bitmap traversal without pseudo-merges' ' + git repack -adb && + + git rev-list --count --all --objects >expect && + + : >trace2.txt && + GIT_TRACE2_EVENT=$PWD/trace2.txt \ + git rev-list --count --all --objects --use-bitmap-index >actual && + + test_pseudo_merges_satisfied 0 <trace2.txt && + test_pseudo_merges_cascades 0 <trace2.txt && + test_pseudo_merges >merges && + test_must_be_empty merges && + test_cmp expect actual +' + +test_expect_success 'pseudo-merges accurately represent their objects' ' + test_config bitmapPseudoMerge.test.pattern "refs/tags/" && + test_config bitmapPseudoMerge.test.maxMerges 8 && + test_config bitmapPseudoMerge.test.stableThreshold never && + + git repack -adb && + + test_pseudo_merges >merges && + test_line_count = 8 merges && + + for i in $(test_seq 0 $(($(wc -l <merges)-1))) + do + test-tool bitmap dump-pseudo-merge-commits $i >commits && + + git rev-list --objects --no-object-names --stdin <commits >expect.raw && + test-tool bitmap dump-pseudo-merge-objects $i >actual.raw && + + sort -u <expect.raw >expect && + sort -u <actual.raw >actual && + + test_cmp expect actual || return 1 + done +' + +test_expect_success 'bitmap traversal with pseudo-merges' ' + : >trace2.txt && + GIT_TRACE2_EVENT=$PWD/trace2.txt \ + git rev-list --count --all --objects --use-bitmap-index >actual && + git rev-list --count --all --objects >expect && + + test_pseudo_merges_satisfied 8 <trace2.txt && + test_pseudo_merges_cascades 1 <trace2.txt && + test_cmp expect actual +' + +test_expect_success 'stale bitmap traversal with pseudo-merges' ' + test_commit other && + + : >trace2.txt && + GIT_TRACE2_EVENT=$PWD/trace2.txt \ + git rev-list --count --all --objects --use-bitmap-index >actual && + git rev-list --count --all --objects >expect && + + test_pseudo_merges_satisfied 8 <trace2.txt && + test_pseudo_merges_cascades 1 <trace2.txt && + test_cmp expect actual +' + +test_expect_success 'bitmapPseudoMerge.sampleRate adjusts commit selection rate' ' + test_config bitmapPseudoMerge.test.pattern "refs/tags/" && + test_config bitmapPseudoMerge.test.maxMerges 1 && + test_config bitmapPseudoMerge.test.stableThreshold never && + + commits_nr=$(git rev-list --all --count) && + + for rate in 1.0 0.5 0.25 + do + git -c bitmapPseudoMerge.test.sampleRate=$rate repack -adb && + + test_pseudo_merges >merges && + test_line_count = 1 merges && + test_pseudo_merge_commits 0 >commits && + + test-tool bitmap list-commits >bitmaps && + bitmaps_nr="$(wc -l <bitmaps)" && + + perl -MPOSIX -e "print ceil(\$ARGV[0]*(\$ARGV[1]-\$ARGV[2]))" \ + "$rate" "$commits_nr" "$bitmaps_nr" >expect && + + test $(cat expect) -eq $(wc -l <commits) || return 1 + done +' + +test_expect_success 'bitmapPseudoMerge.threshold excludes newer commits' ' + git init pseudo-merge-threshold && + ( + cd pseudo-merge-threshold && + + new="1672549200" && # 2023-01-01 + old="1641013200" && # 2022-01-01 + + GIT_COMMITTER_DATE="$new +0000" && + export GIT_COMMITTER_DATE && + test_commit_bulk --message="new" --notick 128 && + + GIT_COMMITTER_DATE="$old +0000" && + export GIT_COMMITTER_DATE && + test_commit_bulk --message="old" --notick 128 && + + tag_everything && + + git \ + -c bitmapPseudoMerge.test.pattern="refs/tags/" \ + -c bitmapPseudoMerge.test.maxMerges=1 \ + -c bitmapPseudoMerge.test.threshold=$(($new - 1)) \ + -c bitmapPseudoMerge.test.stableThreshold=never \ + repack -adb && + + test_pseudo_merges >merges && + test_line_count = 1 merges && + + test_pseudo_merge_commits 0 >oids && + git cat-file --batch <oids >commits && + + test $(wc -l <oids) = $(grep -c "^committer.*$old +0000$" commits) + ) +' + +test_expect_success 'bitmapPseudoMerge.stableThreshold creates stable groups' ' + ( + cd pseudo-merge-threshold && + + new="1672549200" && # 2023-01-01 + mid="1654059600" && # 2022-06-01 + old="1641013200" && # 2022-01-01 + + GIT_COMMITTER_DATE="$mid +0000" && + export GIT_COMMITTER_DATE && + test_commit_bulk --message="mid" --notick 128 && + + git for-each-ref --format="delete %(refname)" refs/tags >in && + git update-ref --stdin <in && + + tag_everything && + + git \ + -c bitmapPseudoMerge.test.pattern="refs/tags/" \ + -c bitmapPseudoMerge.test.maxMerges=1 \ + -c bitmapPseudoMerge.test.threshold=$(($new - 1)) \ + -c bitmapPseudoMerge.test.stableThreshold=$(($mid - 1)) \ + -c bitmapPseudoMerge.test.stableSize=10 \ + repack -adb && + + test_pseudo_merges >merges && + merges_nr="$(wc -l <merges)" && + + for i in $(test_seq $(($merges_nr - 1))) + do + test_pseudo_merge_commits 0 >oids && + git cat-file --batch <oids >commits && + + expect="$(grep -c "^committer.*$old +0000$" commits)" && + actual="$(wc -l <oids)" && + + test $expect = $actual || return 1 + done && + + test_pseudo_merge_commits $(($merges_nr - 1)) >oids && + git cat-file --batch <oids >commits && + test $(wc -l <oids) = $(grep -c "^committer.*$mid +0000$" commits) + ) +' + +test_expect_success 'out of order thresholds are rejected' ' + test_must_fail git \ + -c bitmapPseudoMerge.test.pattern="refs/*" \ + -c bitmapPseudoMerge.test.threshold=1.month.ago \ + -c bitmapPseudoMerge.test.stableThreshold=1.week.ago \ + repack -adb 2>err && + + cat >expect <<-EOF && + fatal: pseudo-merge group ${SQ}test${SQ} has unstable threshold before stable one + EOF + + test_cmp expect err +' + +test_expect_success 'pseudo-merge pattern with capture groups' ' + git init pseudo-merge-captures && + ( + cd pseudo-merge-captures && + + test_commit_bulk 128 && + tag_everything && + + for r in $(test_seq 8) + do + test_commit_bulk 16 && + + git rev-list HEAD~16.. >in && + + perl -lne "print \"create refs/remotes/$r/tags/\$. \$_\"" <in | + git update-ref --stdin || return 1 + done && + + git \ + -c bitmapPseudoMerge.tags.pattern="refs/remotes/([0-9]+)/tags/" \ + -c bitmapPseudoMerge.tags.maxMerges=1 \ + repack -adb && + + git for-each-ref --format="%(objectname) %(refname)" >refs && + + test_pseudo_merges >merges && + for m in $(test_seq 0 $(($(wc -l <merges) - 1))) + do + test_pseudo_merge_commits $m >oids && + grep -f oids refs | + perl -lne "print \$1 if /refs\/remotes\/([0-9]+)/" | + sort -u || return 1 + done >remotes && + + test $(wc -l <remotes) -eq $(sort -u <remotes | wc -l) + ) +' + +test_expect_success 'pseudo-merge overlap setup' ' + git init pseudo-merge-overlap && + ( + cd pseudo-merge-overlap && + + test_commit_bulk 256 && + tag_everything && + + git \ + -c bitmapPseudoMerge.all.pattern="refs/" \ + -c bitmapPseudoMerge.all.maxMerges=1 \ + -c bitmapPseudoMerge.all.stableThreshold=never \ + -c bitmapPseudoMerge.tags.pattern="refs/tags/" \ + -c bitmapPseudoMerge.tags.maxMerges=1 \ + -c bitmapPseudoMerge.tags.stableThreshold=never \ + repack -adb + ) +' + +test_expect_success 'pseudo-merge overlap generates overlapping groups' ' + ( + cd pseudo-merge-overlap && + + test_pseudo_merges >merges && + test_line_count = 2 merges && + + test_pseudo_merge_commits 0 >commits-0.raw && + test_pseudo_merge_commits 1 >commits-1.raw && + + sort commits-0.raw >commits-0 && + sort commits-1.raw >commits-1 && + + comm -12 commits-0 commits-1 >overlap && + + test_line_count -gt 0 overlap + ) +' + +test_expect_success 'pseudo-merge overlap traversal' ' + ( + cd pseudo-merge-overlap && + + : >trace2.txt && + GIT_TRACE2_EVENT=$PWD/trace2.txt \ + git rev-list --count --all --objects --use-bitmap-index >actual && + git rev-list --count --all --objects >expect && + + test_pseudo_merges_satisfied 2 <trace2.txt && + test_pseudo_merges_cascades 1 <trace2.txt && + test_cmp expect actual + ) +' + +test_expect_success 'pseudo-merge overlap stale traversal' ' + ( + cd pseudo-merge-overlap && + + test_commit other && + + : >trace2.txt && + GIT_TRACE2_EVENT=$PWD/trace2.txt \ + git rev-list --count --all --objects --use-bitmap-index >actual && + git rev-list --count --all --objects >expect && + + test_pseudo_merges_satisfied 2 <trace2.txt && + test_pseudo_merges_cascades 1 <trace2.txt && + test_cmp expect actual + ) +' + +test_expect_success 'pseudo-merge reuse' ' + git init pseudo-merge-reuse && + ( + cd pseudo-merge-reuse && + + stable="1641013200" && # 2022-01-01 + unstable="1672549200" && # 2023-01-01 + + GIT_COMMITTER_DATE="$stable +0000" && + export GIT_COMMITTER_DATE && + test_commit_bulk --notick 128 && + GIT_COMMITTER_DATE="$unstable +0000" && + export GIT_COMMITTER_DATE && + test_commit_bulk --notick 128 && + + tag_everything && + + git \ + -c bitmapPseudoMerge.test.pattern="refs/tags/" \ + -c bitmapPseudoMerge.test.maxMerges=1 \ + -c bitmapPseudoMerge.test.threshold=now \ + -c bitmapPseudoMerge.test.stableThreshold=$(($unstable - 1)) \ + -c bitmapPseudoMerge.test.stableSize=512 \ + repack -adb && + + test_pseudo_merges >merges && + test_line_count = 2 merges && + + test_pseudo_merge_commits 0 >stable-oids.before && + test_pseudo_merge_commits 1 >unstable-oids.before && + + : >trace2.txt && + GIT_TRACE2_EVENT=$PWD/trace2.txt git \ + -c bitmapPseudoMerge.test.pattern="refs/tags/" \ + -c bitmapPseudoMerge.test.maxMerges=2 \ + -c bitmapPseudoMerge.test.threshold=now \ + -c bitmapPseudoMerge.test.stableThreshold=$(($unstable - 1)) \ + -c bitmapPseudoMerge.test.stableSize=512 \ + repack -adb && + + test_pseudo_merges_reused 1 <trace2.txt && + + test_pseudo_merges >merges && + test_line_count = 3 merges && + + test_pseudo_merge_commits 0 >stable-oids.after && + for i in 1 2 + do + test_pseudo_merge_commits $i || return 1 + done >unstable-oids.after && + + sort -u <stable-oids.before >expect && + sort -u <stable-oids.after >actual && + test_cmp expect actual && + + sort -u <unstable-oids.before >expect && + sort -u <unstable-oids.after >actual && + test_cmp expect actual + ) +' + +test_done diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh index ad7f8c6f00..e99e728236 100755 --- a/t/t5407-post-rewrite-hook.sh +++ b/t/t5407-post-rewrite-hook.sh @@ -7,6 +7,7 @@ test_description='Test the post-rewrite hook.' 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/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh index 1bc15a3f08..585ea0ee16 100755 --- a/t/t5500-fetch-pack.sh +++ b/t/t5500-fetch-pack.sh @@ -993,6 +993,16 @@ test_expect_success 'ensure bogus fetch.negotiationAlgorithm yields error' ' fetch origin server_has both_have_2 ' +test_expect_success 'fetch-pack with fsckObjects and keep-file does not segfault' ' + rm -rf server client && + test_create_repo server && + test_commit -C server one && + + test_create_repo client && + git -c fetch.fsckObjects=true \ + -C client fetch-pack -k -k ../server HEAD +' + test_expect_success 'filtering by size' ' rm -rf server client && test_create_repo server && @@ -1046,7 +1056,7 @@ fetch_filter_blob_limit_zero () { # Ensure that commit is fetched, but blob is not commit=$(git -C "$SERVER" rev-parse two) && - blob=$(git hash-object server/two.t) && + blob=$(git hash-object "$SERVER/two.t") && git -C client rev-list --objects --missing=allow-any "$commit" >oids && grep "$commit" oids && ! grep "$blob" oids diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 7789ff12c4..08424e878e 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -1492,4 +1492,40 @@ test_expect_success 'refs/remotes/* <src> refspec and unqualified <dst> DWIM and ) ' +test_expect_success 'empty config clears remote.*.url list' ' + test_when_finished "git config --remove-section remote.multi" && + git config --add remote.multi.url wrong-one && + git config --add remote.multi.url wrong-two && + git -c remote.multi.url= \ + -c remote.multi.url=right-one \ + -c remote.multi.url=right-two \ + remote show -n multi >actual.raw && + grep URL actual.raw >actual && + cat >expect <<-\EOF && + Fetch URL: right-one + Push URL: right-one + Push URL: right-two + EOF + test_cmp expect actual +' + +test_expect_success 'empty config clears remote.*.pushurl list' ' + test_when_finished "git config --remove-section remote.multi" && + git config --add remote.multi.url right && + git config --add remote.multi.url will-be-ignored && + git config --add remote.multi.pushurl wrong-push-one && + git config --add remote.multi.pushurl wrong-push-two && + git -c remote.multi.pushurl= \ + -c remote.multi.pushurl=right-push-one \ + -c remote.multi.pushurl=right-push-two \ + remote show -n multi >actual.raw && + grep URL actual.raw >actual && + cat >expect <<-\EOF && + Fetch URL: right + Push URL: right-push-one + Push URL: right-push-two + EOF + test_cmp expect actual +' + test_done diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 4eb569f4df..3b3991ab86 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -1091,6 +1091,22 @@ test_expect_success 'branchname D/F conflict resolved by --prune' ' test_cmp expect actual ' +test_expect_success 'branchname D/F conflict rejected with targeted error message' ' + git clone . df-conflict-error && + git branch dir_conflict && + ( + cd df-conflict-error && + git update-ref refs/remotes/origin/dir_conflict/file HEAD && + test_must_fail git fetch 2>err && + test_grep "error: some local refs could not be updated; try running" err && + test_grep " ${SQ}git remote prune origin${SQ} to remove any old, conflicting branches" err && + git pack-refs --all && + test_must_fail git fetch 2>err-packed && + test_grep "error: some local refs could not be updated; try running" err-packed && + test_grep " ${SQ}git remote prune origin${SQ} to remove any old, conflicting branches" err-packed + ) +' + test_expect_success 'fetching a one-level ref works' ' test_commit extra && git reset --hard HEAD^ && @@ -1252,6 +1268,30 @@ EOF test_cmp fatal-expect fatal-actual ' +test_expect_success SYMLINKS 'clone does not get confused by a D/F conflict' ' + git init df-conflict && + ( + cd df-conflict && + ln -s .git a && + git add a && + test_tick && + git commit -m symlink && + test_commit a- && + rm a && + mkdir -p a/hooks && + write_script a/hooks/post-checkout <<-EOF && + echo WHOOPSIE >&2 + echo whoopsie >"$TRASH_DIRECTORY"/whoops + EOF + git add a/hooks/post-checkout && + test_tick && + git commit -m post-checkout + ) && + git clone df-conflict clone 2>err && + test_grep ! WHOOPS err && + test_path_is_missing whoops +' + . "$TEST_DIRECTORY"/lib-httpd.sh start_httpd diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh index 5dbe107ce8..42e77eb5a9 100755 --- a/t/t5512-ls-remote.sh +++ b/t/t5512-ls-remote.sh @@ -47,6 +47,7 @@ test_expect_success setup ' git show-ref -d >refs && sed -e "s/ / /" refs >>expected.all && + grep refs/heads/ expected.all >expected.branches && git remote add self "$(pwd)/.git" && git remote add self2 "." ' @@ -71,6 +72,27 @@ test_expect_success 'ls-remote self' ' test_cmp expected.all actual ' +test_expect_success 'ls-remote --branches self' ' + git ls-remote --branches self >actual && + test_cmp expected.branches actual && + git ls-remote -b self >actual && + test_cmp expected.branches actual +' + +test_expect_success 'ls-remote -h is deprecated w/o warning' ' + git ls-remote -h self >actual 2>warning && + test_cmp expected.branches actual && + test_grep ! deprecated warning +' + +test_expect_success 'ls-remote --heads is deprecated and hidden w/o warning' ' + test_expect_code 129 git ls-remote -h >short-help && + test_grep ! -e --head short-help && + git ls-remote --heads self >actual 2>warning && + test_cmp expected.branches actual && + test_grep ! deprecated warning +' + test_expect_success 'ls-remote --sort="version:refname" --tags self' ' generate_references \ refs/tags/mark \ @@ -275,7 +297,7 @@ test_expect_success 'ls-remote with filtered symref (refname)' ' test_cmp expect actual ' -test_expect_success 'ls-remote with filtered symref (--heads)' ' +test_expect_success 'ls-remote with filtered symref (--branches)' ' git symbolic-ref refs/heads/foo refs/tags/mark && cat >expect.v2 <<-EOF && ref: refs/tags/mark refs/heads/foo @@ -283,9 +305,9 @@ test_expect_success 'ls-remote with filtered symref (--heads)' ' $rev refs/heads/main EOF grep -v "^ref: refs/tags/" <expect.v2 >expect.v0 && - git -c protocol.version=0 ls-remote --symref --heads . >actual.v0 && + git -c protocol.version=0 ls-remote --symref --branches . >actual.v0 && test_cmp expect.v0 actual.v0 && - git -c protocol.version=2 ls-remote --symref --heads . >actual.v2 && + git -c protocol.version=2 ls-remote --symref --branches . >actual.v2 && test_cmp expect.v2 actual.v2 ' @@ -335,9 +357,9 @@ test_expect_success 'ls-remote patterns work with all protocol versions' ' test_expect_success 'ls-remote prefixes work with all protocol versions' ' git for-each-ref --format="%(objectname) %(refname)" \ refs/heads/ refs/tags/ >expect && - git -c protocol.version=0 ls-remote --heads --tags . >actual.v0 && + git -c protocol.version=0 ls-remote --branches --tags . >actual.v0 && test_cmp expect actual.v0 && - git -c protocol.version=2 ls-remote --heads --tags . >actual.v2 && + git -c protocol.version=2 ls-remote --branches --tags . >actual.v2 && test_cmp expect actual.v2 ' diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 2e7c0e1648..9d693eb57f 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -230,6 +230,16 @@ test_expect_success 'push with negotiation proceeds anyway even if negotiation f test_grep "push negotiation failed" err ' +test_expect_success 'push deletion with negotiation' ' + mk_empty testrepo && + git push testrepo $the_first_commit:refs/heads/master && + git -c push.negotiate=1 push testrepo \ + :master $the_first_commit:refs/heads/next 2>errors-2 && + test_grep ! "negotiate-only needs one or " errors-2 && + git -c push.negotiate=1 push testrepo :next 2>errors-1 && + test_grep ! "negotiate-only needs one or " errors-1 +' + test_expect_success 'push with negotiation does not attempt to fetch submodules' ' mk_empty submodule_upstream && test_commit -C submodule_upstream submodule_commit && diff --git a/t/t5529-push-errors.sh b/t/t5529-push-errors.sh index 0247137cb3..17d7257892 100755 --- a/t/t5529-push-errors.sh +++ b/t/t5529-push-errors.sh @@ -2,6 +2,9 @@ test_description='detect some push errors early (before contacting remote)' +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh @@ -38,6 +41,20 @@ test_expect_success 'detect missing sha1 expressions early' ' test_cmp expect rp-ran ' +# We use an existing local_ref, since it follows a different flow in +# 'builtin/push.c:set_refspecs()' and we want to test that regression. +test_expect_success 'detect empty remote with existing local ref' ' + test_must_fail git push "" main 2> stderr && + grep "fatal: bad repository ${SQ}${SQ}" stderr +' + +# While similar to the previous test, here we want to ensure that +# even targeted refspecs are handled. +test_expect_success 'detect empty remote with targeted refspec' ' + test_must_fail git push "" HEAD:refs/heads/main 2> stderr && + grep "fatal: bad repository ${SQ}${SQ}" stderr +' + test_expect_success 'detect ambiguous refs early' ' git branch foo && git tag foo && diff --git a/t/t5550-http-fetch-dumb.sh b/t/t5550-http-fetch-dumb.sh index 4c3b32785d..ea8e48f627 100755 --- a/t/t5550-http-fetch-dumb.sh +++ b/t/t5550-http-fetch-dumb.sh @@ -25,6 +25,12 @@ test_expect_success 'setup repository' ' git commit -m two ' +test_expect_success 'packfile without repository does not crash' ' + echo "fatal: not a git repository" >expect && + test_must_fail nongit git http-fetch --packfile=abc 2>err && + test_cmp expect err +' + setup_post_update_server_info_hook () { test_hook --setup -C "$1" post-update <<-\EOF && exec git update-server-info @@ -55,6 +61,21 @@ test_expect_success 'list refs from outside any repository' ' test_cmp expect actual ' + +test_expect_success 'list detached HEAD from outside any repository' ' + git clone --mirror "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \ + "$HTTPD_DOCUMENT_ROOT_PATH/repo-detached.git" && + git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo-detached.git" \ + update-ref --no-deref HEAD refs/heads/main && + git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo-detached.git" update-server-info && + cat >expect <<-EOF && + $(git rev-parse main) HEAD + $(git rev-parse main) refs/heads/main + EOF + nongit git ls-remote "$HTTPD_URL/dumb/repo-detached.git" >actual && + test_cmp expect actual +' + test_expect_success 'create password-protected repository' ' mkdir -p "$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/" && cp -Rf "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \ diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh index a623a1058c..7b5ab0eae1 100755 --- a/t/t5551-http-fetch-smart.sh +++ b/t/t5551-http-fetch-smart.sh @@ -643,7 +643,6 @@ test_expect_success 'clone empty SHA-256 repository with protocol v0' ' test_expect_success 'passing hostname resolution information works' ' BOGUS_HOST=gitbogusexamplehost.invalid && BOGUS_HTTPD_URL=$HTTPD_PROTO://$BOGUS_HOST:$LIB_HTTPD_PORT && - test_must_fail git ls-remote "$BOGUS_HTTPD_URL/smart/repo.git" >/dev/null && git -c "http.curloptResolve=$BOGUS_HOST:$LIB_HTTPD_PORT:127.0.0.1" ls-remote "$BOGUS_HTTPD_URL/smart/repo.git" >/dev/null ' diff --git a/t/t5553-set-upstream.sh b/t/t5553-set-upstream.sh index 48050162c2..70e3376d31 100755 --- a/t/t5553-set-upstream.sh +++ b/t/t5553-set-upstream.sh @@ -73,10 +73,10 @@ test_expect_success 'fetch --set-upstream main:other does not set the branch oth check_config_missing other2 ' -test_expect_success 'fetch --set-upstream http://nosuchdomain.example.com fails with invalid url' ' +test_expect_success 'fetch --set-upstream ./does-not-exist fails with invalid url' ' # main explicitly not cleared, we check that it is not touched from previous value clear_config other other2 && - test_must_fail git fetch --set-upstream http://nosuchdomain.example.com && + test_must_fail git fetch --set-upstream ./does-not-exist && check_config main upstream refs/heads/other && check_config_missing other && check_config_missing other2 @@ -143,10 +143,10 @@ test_expect_success 'pull --set-upstream upstream tag does not set the tag' ' check_config_missing three ' -test_expect_success 'pull --set-upstream http://nosuchdomain.example.com fails with invalid url' ' +test_expect_success 'pull --set-upstream ./does-not-exist fails with invalid url' ' # main explicitly not cleared, we check that it is not touched from previous value clear_config other other2 three && - test_must_fail git pull --set-upstream http://nosuchdomain.example.com && + test_must_fail git pull --set-upstream ./does-not-exist && check_config main upstream refs/heads/other && check_config_missing other && check_config_missing other2 && diff --git a/t/t5558-clone-bundle-uri.sh b/t/t5558-clone-bundle-uri.sh index 1ca5f745e7..cd05321e17 100755 --- a/t/t5558-clone-bundle-uri.sh +++ b/t/t5558-clone-bundle-uri.sh @@ -3,6 +3,7 @@ test_description='test fetching bundles with --bundle-uri' . ./test-lib.sh +. "$TEST_DIRECTORY"/lib-bundle.sh test_expect_success 'fail to clone from non-existent file' ' test_when_finished rm -rf test && @@ -19,10 +20,39 @@ test_expect_success 'fail to clone from non-bundle file' ' test_expect_success 'create bundle' ' git init clone-from && - git -C clone-from checkout -b topic && - test_commit -C clone-from A && - test_commit -C clone-from B && - git -C clone-from bundle create B.bundle topic + ( + cd clone-from && + git checkout -b topic && + + test_commit A && + git bundle create A.bundle topic && + + test_commit B && + git bundle create B.bundle topic && + + # Create a bundle with reference pointing to non-existent object. + commit_a=$(git rev-parse A) && + commit_b=$(git rev-parse B) && + sed -e "/^$/q" -e "s/$commit_a /$commit_b /" \ + <A.bundle >bad-header.bundle && + convert_bundle_to_pack \ + <A.bundle >>bad-header.bundle && + + tree_b=$(git rev-parse B^{tree}) && + cat >data <<-EOF && + tree $tree_b + parent $commit_b + author A U Thor + committer A U Thor + + commit: this is a commit with bad emails + + EOF + bad_commit=$(git hash-object --literally -t commit -w --stdin <data) && + git branch bad $bad_commit && + git bundle create bad-object.bundle bad && + git update-ref -d refs/heads/bad + ) ' test_expect_success 'clone with path bundle' ' @@ -33,6 +63,33 @@ test_expect_success 'clone with path bundle' ' test_cmp expect actual ' +test_expect_success 'clone with bundle that has bad header' ' + # Write bundle ref fails, but clone can still proceed. + git clone --bundle-uri="clone-from/bad-header.bundle" \ + clone-from clone-bad-header 2>err && + commit_b=$(git -C clone-from rev-parse B) && + test_grep "trying to write ref '\''refs/bundles/topic'\'' with nonexistent object $commit_b" err && + git -C clone-bad-header for-each-ref --format="%(refname)" >refs && + test_grep ! "refs/bundles/" refs +' + +test_expect_success 'clone with bundle that has bad object' ' + # Unbundle succeeds if no fsckObjects configured. + git clone --bundle-uri="clone-from/bad-object.bundle" \ + clone-from clone-bad-object-no-fsck && + git -C clone-bad-object-no-fsck for-each-ref --format="%(refname)" >refs && + grep "refs/bundles/" refs >actual && + test_write_lines refs/bundles/bad >expect && + test_cmp expect actual && + + # Unbundle fails with fsckObjects set true, but clone can still proceed. + git -c fetch.fsckObjects=true clone --bundle-uri="clone-from/bad-object.bundle" \ + clone-from clone-bad-object-fsck 2>err && + test_grep "missingEmail" err && + git -C clone-bad-object-fsck for-each-ref --format="%(refname)" >refs && + test_grep ! "refs/bundles/" refs +' + test_expect_success 'clone with path bundle and non-default hash' ' test_when_finished "rm -rf clone-path-non-default-hash" && GIT_DEFAULT_HASH=sha256 git clone --bundle-uri="clone-from/B.bundle" \ @@ -259,6 +316,128 @@ test_expect_success 'clone bundle list (file, any mode, all failures)' ' ! grep "refs/bundles/" refs ' +test_expect_success 'negotiation: bundle with part of wanted commits' ' + test_when_finished "rm -f trace*.txt" && + GIT_TRACE_PACKET="$(pwd)/trace-packet.txt" \ + git clone --no-local --bundle-uri="clone-from/A.bundle" \ + clone-from nego-bundle-part && + git -C nego-bundle-part for-each-ref --format="%(refname)" >refs && + grep "refs/bundles/" refs >actual && + test_write_lines refs/bundles/topic >expect && + test_cmp expect actual && + # Ensure that refs/bundles/topic are sent as "have". + tip=$(git -C clone-from rev-parse A) && + test_grep "clone> have $tip" trace-packet.txt +' + +test_expect_success 'negotiation: bundle with all wanted commits' ' + test_when_finished "rm -f trace*.txt" && + GIT_TRACE_PACKET="$(pwd)/trace-packet.txt" \ + git clone --no-local --single-branch --branch=topic --no-tags \ + --bundle-uri="clone-from/B.bundle" \ + clone-from nego-bundle-all && + git -C nego-bundle-all for-each-ref --format="%(refname)" >refs && + grep "refs/bundles/" refs >actual && + test_write_lines refs/bundles/topic >expect && + test_cmp expect actual && + # We already have all needed commits so no "want" needed. + test_grep ! "clone> want " trace-packet.txt +' + +test_expect_success 'negotiation: bundle list (no heuristic)' ' + test_when_finished "rm -f trace*.txt" && + cat >bundle-list <<-EOF && + [bundle] + version = 1 + mode = all + + [bundle "bundle-1"] + uri = file://$(pwd)/clone-from/bundle-1.bundle + + [bundle "bundle-2"] + uri = file://$(pwd)/clone-from/bundle-2.bundle + EOF + + GIT_TRACE_PACKET="$(pwd)/trace-packet.txt" \ + git clone --no-local --bundle-uri="file://$(pwd)/bundle-list" \ + clone-from nego-bundle-list-no-heuristic && + + git -C nego-bundle-list-no-heuristic for-each-ref --format="%(refname)" >refs && + grep "refs/bundles/" refs >actual && + cat >expect <<-\EOF && + refs/bundles/base + refs/bundles/left + EOF + test_cmp expect actual && + tip=$(git -C nego-bundle-list-no-heuristic rev-parse refs/bundles/left) && + test_grep "clone> have $tip" trace-packet.txt +' + +test_expect_success 'negotiation: bundle list (creationToken)' ' + test_when_finished "rm -f trace*.txt" && + cat >bundle-list <<-EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "bundle-1"] + uri = file://$(pwd)/clone-from/bundle-1.bundle + creationToken = 1 + + [bundle "bundle-2"] + uri = file://$(pwd)/clone-from/bundle-2.bundle + creationToken = 2 + EOF + + GIT_TRACE_PACKET="$(pwd)/trace-packet.txt" \ + git clone --no-local --bundle-uri="file://$(pwd)/bundle-list" \ + clone-from nego-bundle-list-heuristic && + + git -C nego-bundle-list-heuristic for-each-ref --format="%(refname)" >refs && + grep "refs/bundles/" refs >actual && + cat >expect <<-\EOF && + refs/bundles/base + refs/bundles/left + EOF + test_cmp expect actual && + tip=$(git -C nego-bundle-list-heuristic rev-parse refs/bundles/left) && + test_grep "clone> have $tip" trace-packet.txt +' + +test_expect_success 'negotiation: bundle list with all wanted commits' ' + test_when_finished "rm -f trace*.txt" && + cat >bundle-list <<-EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "bundle-1"] + uri = file://$(pwd)/clone-from/bundle-1.bundle + creationToken = 1 + + [bundle "bundle-2"] + uri = file://$(pwd)/clone-from/bundle-2.bundle + creationToken = 2 + EOF + + GIT_TRACE_PACKET="$(pwd)/trace-packet.txt" \ + git clone --no-local --single-branch --branch=left --no-tags \ + --bundle-uri="file://$(pwd)/bundle-list" \ + clone-from nego-bundle-list-all && + + git -C nego-bundle-list-all for-each-ref --format="%(refname)" >refs && + grep "refs/bundles/" refs >actual && + cat >expect <<-\EOF && + refs/bundles/base + refs/bundles/left + EOF + test_cmp expect actual && + # We already have all needed commits so no "want" needed. + test_grep ! "clone> want " trace-packet.txt +' + ######################################################################### # HTTP tests begin here diff --git a/t/t5563-simple-http-auth.sh b/t/t5563-simple-http-auth.sh index ab8a721ccc..ba03f6a09f 100755 --- a/t/t5563-simple-http-auth.sh +++ b/t/t5563-simple-http-auth.sh @@ -2,6 +2,7 @@ test_description='test http auth header and credential helper interop' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-httpd.sh @@ -21,9 +22,17 @@ test_expect_success 'setup_credential_helper' ' CREDENTIAL_HELPER="$TRASH_DIRECTORY/bin/git-credential-test-helper" && write_script "$CREDENTIAL_HELPER" <<-\EOF cmd=$1 - teefile=$cmd-query.cred + teefile=$cmd-query-temp.cred catfile=$cmd-reply.cred sed -n -e "/^$/q" -e "p" >>$teefile + state=$(sed -ne "s/^state\[\]=helper://p" "$teefile") + if test -z "$state" + then + mv "$teefile" "$cmd-query.cred" + else + mv "$teefile" "$cmd-query-$state.cred" + catfile="$cmd-reply-$state.cred" + fi if test "$cmd" = "get" then cat $catfile @@ -32,13 +41,15 @@ test_expect_success 'setup_credential_helper' ' ' set_credential_reply () { - cat >"$TRASH_DIRECTORY/$1-reply.cred" + local suffix="$(test -n "$2" && echo "-$2")" + cat >"$TRASH_DIRECTORY/$1-reply$suffix.cred" } expect_credential_query () { - cat >"$TRASH_DIRECTORY/$1-expect.cred" && - test_cmp "$TRASH_DIRECTORY/$1-expect.cred" \ - "$TRASH_DIRECTORY/$1-query.cred" + local suffix="$(test -n "$2" && echo "-$2")" + cat >"$TRASH_DIRECTORY/$1-expect$suffix.cred" && + test_cmp "$TRASH_DIRECTORY/$1-expect$suffix.cred" \ + "$TRASH_DIRECTORY/$1-query$suffix.cred" } per_test_cleanup () { @@ -63,17 +74,20 @@ test_expect_success 'access using basic auth' ' # Basic base64(alice:secret-passwd) cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && - Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== + id=1 creds=Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== EOF cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && - WWW-Authenticate: Basic realm="example.com" + id=1 status=200 + id=default response=WWW-Authenticate: Basic realm="example.com" EOF test_config_global credential.helper test-helper && git ls-remote "$HTTPD_URL/custom_auth/repo.git" && expect_credential_query get <<-EOF && + capability[]=authtype + capability[]=state protocol=http host=$HTTPD_DEST wwwauth[]=Basic realm="example.com" @@ -87,6 +101,45 @@ test_expect_success 'access using basic auth' ' EOF ' +test_expect_success 'access using basic auth via authtype' ' + test_when_finished "per_test_cleanup" && + + set_credential_reply get <<-EOF && + capability[]=authtype + authtype=Basic + credential=YWxpY2U6c2VjcmV0LXBhc3N3ZA== + EOF + + # Basic base64(alice:secret-passwd) + cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && + id=1 creds=Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== + EOF + + cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && + id=1 status=200 + id=default response=WWW-Authenticate: Basic realm="example.com" + EOF + + test_config_global credential.helper test-helper && + GIT_CURL_VERBOSE=1 git ls-remote "$HTTPD_URL/custom_auth/repo.git" && + + expect_credential_query get <<-EOF && + capability[]=authtype + capability[]=state + protocol=http + host=$HTTPD_DEST + wwwauth[]=Basic realm="example.com" + EOF + + expect_credential_query store <<-EOF + capability[]=authtype + authtype=Basic + credential=YWxpY2U6c2VjcmV0LXBhc3N3ZA== + protocol=http + host=$HTTPD_DEST + EOF +' + test_expect_success 'access using basic auth invalid credentials' ' test_when_finished "per_test_cleanup" && @@ -97,17 +150,20 @@ test_expect_success 'access using basic auth invalid credentials' ' # Basic base64(alice:secret-passwd) cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && - Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== + id=1 creds=Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== EOF cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && - WWW-Authenticate: Basic realm="example.com" + id=1 status=200 + id=default response=WWW-Authenticate: Basic realm="example.com" EOF test_config_global credential.helper test-helper && test_must_fail git ls-remote "$HTTPD_URL/custom_auth/repo.git" && expect_credential_query get <<-EOF && + capability[]=authtype + capability[]=state protocol=http host=$HTTPD_DEST wwwauth[]=Basic realm="example.com" @@ -122,6 +178,122 @@ test_expect_success 'access using basic auth invalid credentials' ' EOF ' +test_expect_success 'access using basic proactive auth' ' + test_when_finished "per_test_cleanup" && + + set_credential_reply get <<-EOF && + username=alice + password=secret-passwd + EOF + + # Basic base64(alice:secret-passwd) + cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && + id=1 creds=Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== + EOF + + cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && + id=1 status=200 + id=default status=403 + EOF + + test_config_global credential.helper test-helper && + test_config_global http.proactiveAuth basic && + git ls-remote "$HTTPD_URL/custom_auth/repo.git" && + + expect_credential_query get <<-EOF && + capability[]=authtype + capability[]=state + protocol=http + host=$HTTPD_DEST + wwwauth[]=Basic + EOF + + expect_credential_query store <<-EOF + protocol=http + host=$HTTPD_DEST + username=alice + password=secret-passwd + EOF +' + +test_expect_success 'access using auto proactive auth with basic default' ' + test_when_finished "per_test_cleanup" && + + set_credential_reply get <<-EOF && + username=alice + password=secret-passwd + EOF + + # Basic base64(alice:secret-passwd) + cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && + id=1 creds=Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== + EOF + + cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && + id=1 status=200 + id=default status=403 + EOF + + test_config_global credential.helper test-helper && + test_config_global http.proactiveAuth auto && + git ls-remote "$HTTPD_URL/custom_auth/repo.git" && + + expect_credential_query get <<-EOF && + capability[]=authtype + capability[]=state + protocol=http + host=$HTTPD_DEST + EOF + + expect_credential_query store <<-EOF + protocol=http + host=$HTTPD_DEST + username=alice + password=secret-passwd + EOF +' + +test_expect_success 'access using auto proactive auth with authtype from credential helper' ' + test_when_finished "per_test_cleanup" && + + set_credential_reply get <<-EOF && + capability[]=authtype + authtype=Bearer + credential=YS1naXQtdG9rZW4= + EOF + + # Basic base64(a-git-token) + cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && + id=1 creds=Bearer YS1naXQtdG9rZW4= + EOF + + CHALLENGE="$HTTPD_ROOT_PATH/custom-auth.challenge" && + + cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && + id=1 status=200 + id=default status=403 + EOF + + test_config_global credential.helper test-helper && + test_config_global http.proactiveAuth auto && + git ls-remote "$HTTPD_URL/custom_auth/repo.git" && + + expect_credential_query get <<-EOF && + capability[]=authtype + capability[]=state + protocol=http + host=$HTTPD_DEST + EOF + + expect_credential_query store <<-EOF + capability[]=authtype + authtype=Bearer + credential=YS1naXQtdG9rZW4= + protocol=http + host=$HTTPD_DEST + EOF +' + test_expect_success 'access using basic auth with extra challenges' ' test_when_finished "per_test_cleanup" && @@ -132,19 +304,22 @@ test_expect_success 'access using basic auth with extra challenges' ' # Basic base64(alice:secret-passwd) cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && - Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== + id=1 creds=Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== EOF cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && - WWW-Authenticate: FooBar param1="value1" param2="value2" - WWW-Authenticate: Bearer authorize_uri="id.example.com" p=1 q=0 - WWW-Authenticate: Basic realm="example.com" + id=1 status=200 + id=default response=WWW-Authenticate: FooBar param1="value1" param2="value2" + id=default response=WWW-Authenticate: Bearer authorize_uri="id.example.com" p=1 q=0 + id=default response=WWW-Authenticate: Basic realm="example.com" EOF test_config_global credential.helper test-helper && git ls-remote "$HTTPD_URL/custom_auth/repo.git" && expect_credential_query get <<-EOF && + capability[]=authtype + capability[]=state protocol=http host=$HTTPD_DEST wwwauth[]=FooBar param1="value1" param2="value2" @@ -170,19 +345,22 @@ test_expect_success 'access using basic auth mixed-case wwwauth header name' ' # Basic base64(alice:secret-passwd) cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && - Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== + id=1 creds=Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== EOF cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && - www-authenticate: foobar param1="value1" param2="value2" - WWW-AUTHENTICATE: BEARER authorize_uri="id.example.com" p=1 q=0 - WwW-aUtHeNtIcAtE: baSiC realm="example.com" + id=1 status=200 + id=default response=www-authenticate: foobar param1="value1" param2="value2" + id=default response=WWW-AUTHENTICATE: BEARER authorize_uri="id.example.com" p=1 q=0 + id=default response=WwW-aUtHeNtIcAtE: baSiC realm="example.com" EOF test_config_global credential.helper test-helper && git ls-remote "$HTTPD_URL/custom_auth/repo.git" && expect_credential_query get <<-EOF && + capability[]=authtype + capability[]=state protocol=http host=$HTTPD_DEST wwwauth[]=foobar param1="value1" param2="value2" @@ -208,24 +386,27 @@ test_expect_success 'access using basic auth with wwwauth header continuations' # Basic base64(alice:secret-passwd) cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && - Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== + id=1 creds=Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== EOF # Note that leading and trailing whitespace is important to correctly # simulate a continuation/folded header. cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && - WWW-Authenticate: FooBar param1="value1" - param2="value2" - WWW-Authenticate: Bearer authorize_uri="id.example.com" - p=1 - q=0 - WWW-Authenticate: Basic realm="example.com" + id=1 status=200 + id=default response=WWW-Authenticate: FooBar param1="value1" + id=default response= param2="value2" + id=default response=WWW-Authenticate: Bearer authorize_uri="id.example.com" + id=default response= p=1 + id=default response= q=0 + id=default response=WWW-Authenticate: Basic realm="example.com" EOF test_config_global credential.helper test-helper && git ls-remote "$HTTPD_URL/custom_auth/repo.git" && expect_credential_query get <<-EOF && + capability[]=authtype + capability[]=state protocol=http host=$HTTPD_DEST wwwauth[]=FooBar param1="value1" param2="value2" @@ -251,26 +432,29 @@ test_expect_success 'access using basic auth with wwwauth header empty continuat # Basic base64(alice:secret-passwd) cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && - Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== + id=1 creds=Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== EOF CHALLENGE="$HTTPD_ROOT_PATH/custom-auth.challenge" && # Note that leading and trailing whitespace is important to correctly # simulate a continuation/folded header. - printf "WWW-Authenticate: FooBar param1=\"value1\"\r\n" >"$CHALLENGE" && - printf " \r\n" >>"$CHALLENGE" && - printf " param2=\"value2\"\r\n" >>"$CHALLENGE" && - printf "WWW-Authenticate: Bearer authorize_uri=\"id.example.com\"\r\n" >>"$CHALLENGE" && - printf " p=1\r\n" >>"$CHALLENGE" && - printf " \r\n" >>"$CHALLENGE" && - printf " q=0\r\n" >>"$CHALLENGE" && - printf "WWW-Authenticate: Basic realm=\"example.com\"\r\n" >>"$CHALLENGE" && + printf "id=1 status=200\n" >"$CHALLENGE" && + printf "id=default response=WWW-Authenticate: FooBar param1=\"value1\"\r\n" >>"$CHALLENGE" && + printf "id=default response= \r\n" >>"$CHALLENGE" && + printf "id=default response= param2=\"value2\"\r\n" >>"$CHALLENGE" && + printf "id=default response=WWW-Authenticate: Bearer authorize_uri=\"id.example.com\"\r\n" >>"$CHALLENGE" && + printf "id=default response= p=1\r\n" >>"$CHALLENGE" && + printf "id=default response= \r\n" >>"$CHALLENGE" && + printf "id=default response= q=0\r\n" >>"$CHALLENGE" && + printf "id=default response=WWW-Authenticate: Basic realm=\"example.com\"\r\n" >>"$CHALLENGE" && test_config_global credential.helper test-helper && git ls-remote "$HTTPD_URL/custom_auth/repo.git" && expect_credential_query get <<-EOF && + capability[]=authtype + capability[]=state protocol=http host=$HTTPD_DEST wwwauth[]=FooBar param1="value1" param2="value2" @@ -296,22 +480,25 @@ test_expect_success 'access using basic auth with wwwauth header mixed line-endi # Basic base64(alice:secret-passwd) cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && - Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== + id=1 creds=Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== EOF CHALLENGE="$HTTPD_ROOT_PATH/custom-auth.challenge" && # Note that leading and trailing whitespace is important to correctly # simulate a continuation/folded header. - printf "WWW-Authenticate: FooBar param1=\"value1\"\r\n" >"$CHALLENGE" && - printf " \r\n" >>"$CHALLENGE" && - printf "\tparam2=\"value2\"\r\n" >>"$CHALLENGE" && - printf "WWW-Authenticate: Basic realm=\"example.com\"" >>"$CHALLENGE" && + printf "id=1 status=200\n" >"$CHALLENGE" && + printf "id=default response=WWW-Authenticate: FooBar param1=\"value1\"\r\n" >>"$CHALLENGE" && + printf "id=default response= \r\n" >>"$CHALLENGE" && + printf "id=default response=\tparam2=\"value2\"\r\n" >>"$CHALLENGE" && + printf "id=default response=WWW-Authenticate: Basic realm=\"example.com\"" >>"$CHALLENGE" && test_config_global credential.helper test-helper && git ls-remote "$HTTPD_URL/custom_auth/repo.git" && expect_credential_query get <<-EOF && + capability[]=authtype + capability[]=state protocol=http host=$HTTPD_DEST wwwauth[]=FooBar param1="value1" param2="value2" @@ -326,4 +513,166 @@ test_expect_success 'access using basic auth with wwwauth header mixed line-endi EOF ' +test_expect_success 'access using bearer auth' ' + test_when_finished "per_test_cleanup" && + + set_credential_reply get <<-EOF && + capability[]=authtype + authtype=Bearer + credential=YS1naXQtdG9rZW4= + EOF + + # Basic base64(a-git-token) + cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && + id=1 creds=Bearer YS1naXQtdG9rZW4= + EOF + + CHALLENGE="$HTTPD_ROOT_PATH/custom-auth.challenge" && + + cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && + id=1 status=200 + id=default response=WWW-Authenticate: FooBar param1="value1" param2="value2" + id=default response=WWW-Authenticate: Bearer authorize_uri="id.example.com" p=1 q=0 + id=default response=WWW-Authenticate: Basic realm="example.com" + EOF + + test_config_global credential.helper test-helper && + git ls-remote "$HTTPD_URL/custom_auth/repo.git" && + + expect_credential_query get <<-EOF && + capability[]=authtype + capability[]=state + protocol=http + host=$HTTPD_DEST + wwwauth[]=FooBar param1="value1" param2="value2" + wwwauth[]=Bearer authorize_uri="id.example.com" p=1 q=0 + wwwauth[]=Basic realm="example.com" + EOF + + expect_credential_query store <<-EOF + capability[]=authtype + authtype=Bearer + credential=YS1naXQtdG9rZW4= + protocol=http + host=$HTTPD_DEST + EOF +' + +test_expect_success 'access using bearer auth with invalid credentials' ' + test_when_finished "per_test_cleanup" && + + set_credential_reply get <<-EOF && + capability[]=authtype + authtype=Bearer + credential=incorrect-token + EOF + + # Basic base64(a-git-token) + cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && + id=1 creds=Bearer YS1naXQtdG9rZW4= + EOF + + CHALLENGE="$HTTPD_ROOT_PATH/custom-auth.challenge" && + + cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && + id=1 status=200 + id=default response=WWW-Authenticate: FooBar param1="value1" param2="value2" + id=default response=WWW-Authenticate: Bearer authorize_uri="id.example.com" p=1 q=0 + id=default response=WWW-Authenticate: Basic realm="example.com" + EOF + + test_config_global credential.helper test-helper && + test_must_fail git ls-remote "$HTTPD_URL/custom_auth/repo.git" && + + expect_credential_query get <<-EOF && + capability[]=authtype + capability[]=state + protocol=http + host=$HTTPD_DEST + wwwauth[]=FooBar param1="value1" param2="value2" + wwwauth[]=Bearer authorize_uri="id.example.com" p=1 q=0 + wwwauth[]=Basic realm="example.com" + EOF + + expect_credential_query erase <<-EOF + capability[]=authtype + authtype=Bearer + credential=incorrect-token + protocol=http + host=$HTTPD_DEST + wwwauth[]=FooBar param1="value1" param2="value2" + wwwauth[]=Bearer authorize_uri="id.example.com" p=1 q=0 + wwwauth[]=Basic realm="example.com" + EOF +' + +test_expect_success 'access using three-legged auth' ' + test_when_finished "per_test_cleanup" && + + set_credential_reply get <<-EOF && + capability[]=authtype + capability[]=state + authtype=Multistage + credential=YS1naXQtdG9rZW4= + state[]=helper:foobar + continue=1 + EOF + + set_credential_reply get foobar <<-EOF && + capability[]=authtype + capability[]=state + authtype=Multistage + credential=YW5vdGhlci10b2tlbg== + state[]=helper:bazquux + EOF + + cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && + id=1 creds=Multistage YS1naXQtdG9rZW4= + id=2 creds=Multistage YW5vdGhlci10b2tlbg== + EOF + + CHALLENGE="$HTTPD_ROOT_PATH/custom-auth.challenge" && + + cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && + id=1 status=401 response=WWW-Authenticate: Multistage challenge="456" + id=1 status=401 response=WWW-Authenticate: Bearer authorize_uri="id.example.com" p=1 q=0 + id=2 status=200 + id=default response=WWW-Authenticate: Multistage challenge="123" + id=default response=WWW-Authenticate: Bearer authorize_uri="id.example.com" p=1 q=0 + EOF + + test_config_global credential.helper test-helper && + git ls-remote "$HTTPD_URL/custom_auth/repo.git" && + + expect_credential_query get <<-EOF && + capability[]=authtype + capability[]=state + protocol=http + host=$HTTPD_DEST + wwwauth[]=Multistage challenge="123" + wwwauth[]=Bearer authorize_uri="id.example.com" p=1 q=0 + EOF + + expect_credential_query get foobar <<-EOF && + capability[]=authtype + capability[]=state + authtype=Multistage + protocol=http + host=$HTTPD_DEST + wwwauth[]=Multistage challenge="456" + wwwauth[]=Bearer authorize_uri="id.example.com" p=1 q=0 + state[]=helper:foobar + EOF + + expect_credential_query store bazquux <<-EOF + capability[]=authtype + capability[]=state + authtype=Multistage + credential=YW5vdGhlci10b2tlbg== + protocol=http + host=$HTTPD_DEST + state[]=helper:bazquux + EOF +' + test_done diff --git a/t/t5564-http-proxy.sh b/t/t5564-http-proxy.sh index 9da5134614..bb35b87071 100755 --- a/t/t5564-http-proxy.sh +++ b/t/t5564-http-proxy.sh @@ -2,6 +2,7 @@ test_description="test fetching through http proxy" +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-httpd.sh diff --git a/t/t5581-http-curl-verbose.sh b/t/t5581-http-curl-verbose.sh index cded79c16b..724f610054 100755 --- a/t/t5581-http-curl-verbose.sh +++ b/t/t5581-http-curl-verbose.sh @@ -4,6 +4,7 @@ test_description='test GIT_CURL_VERBOSE' 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-httpd.sh start_httpd diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh index ca43185681..5d7ea147f1 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -46,6 +46,13 @@ test_expect_success 'output from clone' ' test $(grep Clon output | wc -l) = 1 ' +test_expect_success 'output from clone with core.abbrev does not crash' ' + rm -fr dst && + echo "Cloning into ${SQ}dst${SQ}..." >expect && + git -c core.abbrev=12 clone -n "file://$(pwd)/src" dst >actual 2>&1 && + test_cmp expect actual +' + test_expect_success 'clone does not keep pack' ' rm -fr dst && @@ -650,6 +657,21 @@ test_expect_success CASE_INSENSITIVE_FS 'colliding file detection' ' test_grep "the following paths have collided" icasefs/warning ' +test_expect_success CASE_INSENSITIVE_FS,SYMLINKS \ + 'colliding symlink/directory keeps directory' ' + git init icasefs-colliding-symlink && + ( + cd icasefs-colliding-symlink && + a=$(printf a | git hash-object -w --stdin) && + printf "100644 %s 0\tA/dir/b\n120000 %s 0\ta\n" $a $a >idx && + git update-index --index-info <idx && + test_tick && + git commit -m initial + ) && + git clone icasefs-colliding-symlink icasefs-colliding-symlink-clone && + test_file_not_empty icasefs-colliding-symlink-clone/A/dir/b +' + test_expect_success 'clone with GIT_DEFAULT_HASH' ' ( sane_unset GIT_DEFAULT_HASH && diff --git a/t/t5605-clone-local.sh b/t/t5605-clone-local.sh index a3055869bc..d9a320abd2 100755 --- a/t/t5605-clone-local.sh +++ b/t/t5605-clone-local.sh @@ -4,6 +4,7 @@ test_description='test local clone' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh repo_is_hardlinked() { @@ -163,7 +164,7 @@ test_expect_success REFFILES 'local clone from repo with corrupt refs fails grac echo a >corrupt/.git/refs/heads/topic && test_must_fail git clone corrupt working 2>err && - grep "has a null OID" err + grep "has neither a valid OID nor a target" err ' test_done diff --git a/t/t5607-clone-bundle.sh b/t/t5607-clone-bundle.sh index 0d1e92d996..7ceaa8194d 100755 --- a/t/t5607-clone-bundle.sh +++ b/t/t5607-clone-bundle.sh @@ -4,6 +4,7 @@ test_description='some bundle related tests' 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' ' @@ -138,6 +139,41 @@ test_expect_success 'fetch SHA-1 from bundle' ' git fetch --no-tags foo/tip.bundle "$(cat hash)" ' +test_expect_success 'clone bundle with different fsckObjects configurations' ' + test_create_repo bundle-fsck && + ( + cd bundle-fsck && + test_commit A && + commit_a=$(git rev-parse A) && + tree_a=$(git rev-parse A^{tree}) && + cat >data <<-EOF && + tree $tree_a + parent $commit_a + author A U Thor + committer A U Thor + + commit: this is a commit with bad emails + + EOF + bad_commit=$(git hash-object --literally -t commit -w --stdin <data) && + git branch bad $bad_commit && + git bundle create bad.bundle bad + ) && + + git clone bundle-fsck/bad.bundle bundle-no-fsck && + + git -c fetch.fsckObjects=false -c transfer.fsckObjects=true \ + clone bundle-fsck/bad.bundle bundle-fetch-no-fsck && + + test_must_fail git -c fetch.fsckObjects=true \ + clone bundle-fsck/bad.bundle bundle-fetch-fsck 2>err && + test_grep "missingEmail" err && + + test_must_fail git -c transfer.fsckObjects=true \ + clone bundle-fsck/bad.bundle bundle-transfer-fsck 2>err && + test_grep "missingEmail" err +' + test_expect_success 'git bundle uses expected default format' ' git bundle create bundle HEAD^.. && cat >expect <<-EOF && diff --git a/t/t5612-clone-refspec.sh b/t/t5612-clone-refspec.sh index 3126cfd7e9..72762de977 100755 --- a/t/t5612-clone-refspec.sh +++ b/t/t5612-clone-refspec.sh @@ -4,6 +4,7 @@ test_description='test refspec written by clone-command' 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/t5801-remote-helpers.sh b/t/t5801-remote-helpers.sh index 4e0a77f985..20f43f7b7d 100755 --- a/t/t5801-remote-helpers.sh +++ b/t/t5801-remote-helpers.sh @@ -38,6 +38,29 @@ test_expect_success 'cloning from local repo' ' test_cmp server/file local/file ' +test_expect_success 'clone with remote.*.vcs config' ' + GIT_TRACE=$PWD/vcs-clone.trace \ + git clone --no-local -c remote.origin.vcs=testgit "$PWD/server" vcs-clone && + test_grep remote-testgit vcs-clone.trace +' + +test_expect_success 'fetch with configured remote.*.vcs' ' + git init vcs-fetch && + git -C vcs-fetch config remote.origin.vcs testgit && + git -C vcs-fetch config remote.origin.url "$PWD/server" && + GIT_TRACE=$PWD/vcs-fetch.trace \ + git -C vcs-fetch fetch origin && + test_grep remote-testgit vcs-fetch.trace +' + +test_expect_success 'vcs remote with no url' ' + NOURL_UPSTREAM=$PWD/server && + export NOURL_UPSTREAM && + git init vcs-nourl && + git -C vcs-nourl config remote.origin.vcs nourl && + git -C vcs-nourl fetch origin +' + test_expect_success 'create new commit on remote' ' (cd server && echo content >>file && diff --git a/t/t5801/git-remote-nourl b/t/t5801/git-remote-nourl new file mode 100755 index 0000000000..09be6013c5 --- /dev/null +++ b/t/t5801/git-remote-nourl @@ -0,0 +1,3 @@ +#!/bin/sh + +exec git-remote-testgit "$1" "$NOURL_UPSTREAM" diff --git a/t/t5801/git-remote-testgit b/t/t5801/git-remote-testgit index c5b10f5775..f8b476499f 100755 --- a/t/t5801/git-remote-testgit +++ b/t/t5801/git-remote-testgit @@ -26,7 +26,8 @@ then t_refspec="" fi -GIT_DIR="$url/.git" +unset $(git rev-parse --local-env-vars) +GIT_DIR=$(git -C "$url" rev-parse --absolute-git-dir) export GIT_DIR force= diff --git a/t/t6000-rev-list-misc.sh b/t/t6000-rev-list-misc.sh index 6289a2e8b0..f6d17ee902 100755 --- a/t/t6000-rev-list-misc.sh +++ b/t/t6000-rev-list-misc.sh @@ -5,6 +5,7 @@ test_description='miscellaneous rev-list tests' 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/t6001-rev-list-graft.sh b/t/t6001-rev-list-graft.sh index 73a2465aa0..3553bbbfe7 100755 --- a/t/t6001-rev-list-graft.sh +++ b/t/t6001-rev-list-graft.sh @@ -5,6 +5,7 @@ test_description='Revision traversal vs grafts and path limiter' 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/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh index 573eb97a0f..f1623b1c06 100755 --- a/t/t6006-rev-list-format.sh +++ b/t/t6006-rev-list-format.sh @@ -8,6 +8,7 @@ test_description='git rev-list --pretty=format test' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-terminal.sh diff --git a/t/t6013-rev-list-reverse-parents.sh b/t/t6013-rev-list-reverse-parents.sh index 39793cbbd6..4128269c1d 100755 --- a/t/t6013-rev-list-reverse-parents.sh +++ b/t/t6013-rev-list-reverse-parents.sh @@ -5,6 +5,7 @@ test_description='--reverse combines with --parents' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh diff --git a/t/t6017-rev-list-stdin.sh b/t/t6017-rev-list-stdin.sh index 4821b90e74..a0a40fe55c 100755 --- a/t/t6017-rev-list-stdin.sh +++ b/t/t6017-rev-list-stdin.sh @@ -8,6 +8,7 @@ test_description='log family learns --stdin' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh check () { diff --git a/t/t6020-bundle-misc.sh b/t/t6020-bundle-misc.sh index 3e6bcbf30c..fe75a06572 100755 --- a/t/t6020-bundle-misc.sh +++ b/t/t6020-bundle-misc.sh @@ -8,6 +8,7 @@ test_description='Test git-bundle' 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-bundle.sh . "$TEST_DIRECTORY"/lib-terminal.sh diff --git a/t/t6041-bisect-submodule.sh b/t/t6041-bisect-submodule.sh index 82013fc903..3946e18089 100755 --- a/t/t6041-bisect-submodule.sh +++ b/t/t6041-bisect-submodule.sh @@ -2,6 +2,7 @@ test_description='bisect can handle submodules' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-submodule-update.sh diff --git a/t/t6112-rev-list-filters-objects.sh b/t/t6112-rev-list-filters-objects.sh index 43e1afd44c..0387f35a32 100755 --- a/t/t6112-rev-list-filters-objects.sh +++ b/t/t6112-rev-list-filters-objects.sh @@ -701,4 +701,16 @@ test_expect_success 'expand blob limit in protocol' ' grep "blob:limit=1024" trace ' +test_expect_success EXPENSIVE 'large sparse filter file ignored' ' + blob=$(dd if=/dev/zero bs=101M count=1 | + git hash-object -w --stdin) && + test_must_fail \ + git rev-list --all --objects --filter=sparse:oid=$blob 2>err && + cat >expect <<-EOF && + warning: ignoring excessively large pattern blob: $blob + fatal: unable to parse sparse filter data in $blob + EOF + test_cmp expect err +' + test_done diff --git a/t/t6115-rev-list-du.sh b/t/t6115-rev-list-du.sh index c0cfda62fa..21c4a211b1 100755 --- a/t/t6115-rev-list-du.sh +++ b/t/t6115-rev-list-du.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='basic tests of rev-list --disk-usage' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # we want a mix of reachable and unreachable, as well as diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh index e78315d23d..79e0f19deb 100755 --- a/t/t6120-describe.sh +++ b/t/t6120-describe.sh @@ -671,4 +671,40 @@ test_expect_success 'setup misleading taggerdates' ' check_describe newer-tag-older-commit~1 --contains unique-file~2 +test_expect_success 'describe --dirty with a file with changed stat' ' + test_when_finished "rm -fr stat-dirty" && + git init stat-dirty && + ( + cd stat-dirty && + + echo A >file && + git add file && + git commit -m A && + git tag A -a -m A && + echo "A" >expect && + + test-tool chmtime -10 file && + git describe --dirty >actual && + test_cmp expect actual + ) +' + +test_expect_success 'describe --broken --dirty with a file with changed stat' ' + test_when_finished "rm -fr stat-dirty" && + git init stat-dirty && + ( + cd stat-dirty && + + echo A >file && + git add file && + git commit -m A && + git tag A -a -m A && + echo "A" >expect && + + test-tool chmtime -10 file && + git describe --dirty --broken >actual && + test_cmp expect actual + ) +' + test_done diff --git a/t/t6130-pathspec-noglob.sh b/t/t6130-pathspec-noglob.sh index ba7902c9cd..82de25d549 100755 --- a/t/t6130-pathspec-noglob.sh +++ b/t/t6130-pathspec-noglob.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test globbing (and noglob) of pathspec limiting' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'create commits with glob characters' ' diff --git a/t/t6400-merge-df.sh b/t/t6400-merge-df.sh index 3de4ef6bd9..27d6efdc9a 100755 --- a/t/t6400-merge-df.sh +++ b/t/t6400-merge-df.sh @@ -7,6 +7,7 @@ test_description='Test merge with directory/file conflicts' 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 'prepare repository' ' diff --git a/t/t6402-merge-rename.sh b/t/t6402-merge-rename.sh index 2738b50c2a..729aac9842 100755 --- a/t/t6402-merge-rename.sh +++ b/t/t6402-merge-rename.sh @@ -4,6 +4,7 @@ test_description='Merge-recursive merging renames' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh modify () { diff --git a/t/t6406-merge-attr.sh b/t/t6406-merge-attr.sh index 156a1efacf..9bf9524934 100755 --- a/t/t6406-merge-attr.sh +++ b/t/t6406-merge-attr.sh @@ -185,7 +185,7 @@ test_expect_success !WINDOWS 'custom merge driver that is killed with a signal' >./please-abort && echo "* merge=custom" >.gitattributes && - test_must_fail git merge main 2>err && + test_expect_code 2 git merge main 2>err && grep "^error: failed to execute internal merge" err && git ls-files -u >output && git diff --name-only HEAD >>output && @@ -261,4 +261,44 @@ test_expect_success 'binary files with union attribute' ' grep -i "warning.*cannot merge.*HEAD vs. bin-main" output ' +test_expect_success !WINDOWS 'custom merge driver that is killed with a signal on recursive merge' ' + test_when_finished "rm -f output please-abort" && + test_when_finished "git checkout side" && + + git reset --hard anchor && + + git checkout -b base-a main^ && + echo base-a >text && + git commit -m base-a text && + + git checkout -b base-b main^ && + echo base-b >text && + git commit -m base-b text && + + git checkout -b recursive-a base-a && + test_must_fail git merge base-b && + echo recursive-a >text && + git add text && + git commit -m recursive-a && + + git checkout -b recursive-b base-b && + test_must_fail git merge base-a && + echo recursive-b >text && + git add text && + git commit -m recursive-b && + + git config --replace-all \ + merge.custom.driver "./custom-merge %O %A %B 0 %P %S %X %Y" && + git config --replace-all \ + merge.custom.name "custom merge driver for testing" && + + >./please-abort && + echo "* merge=custom" >.gitattributes && + test_expect_code 2 git merge recursive-a 2>err && + grep "error: failed to execute internal merge" err && + git ls-files -u >output && + git diff --name-only HEAD >>output && + test_must_be_empty output +' + test_done diff --git a/t/t6412-merge-large-rename.sh b/t/t6412-merge-large-rename.sh index ca018d11f5..d0863a8fb5 100755 --- a/t/t6412-merge-large-rename.sh +++ b/t/t6412-merge-large-rename.sh @@ -4,6 +4,7 @@ test_description='merging with large rename matrix' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh count() { diff --git a/t/t6426-merge-skip-unneeded-updates.sh b/t/t6426-merge-skip-unneeded-updates.sh index b059475ed0..62f0180325 100755 --- a/t/t6426-merge-skip-unneeded-updates.sh +++ b/t/t6426-merge-skip-unneeded-updates.sh @@ -22,6 +22,7 @@ test_description="merge cases" # underscore notation is to differentiate different # files that might be renamed into each other's paths.) +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-merge.sh diff --git a/t/t6427-diff3-conflict-markers.sh b/t/t6427-diff3-conflict-markers.sh index dd5fe6a402..a13271b349 100755 --- a/t/t6427-diff3-conflict-markers.sh +++ b/t/t6427-diff3-conflict-markers.sh @@ -5,6 +5,7 @@ test_description='recursive merge diff3 style conflict markers' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Setup: diff --git a/t/t6429-merge-sequence-rename-caching.sh b/t/t6429-merge-sequence-rename-caching.sh index 0f39ed0d08..cb1c4ceef7 100755 --- a/t/t6429-merge-sequence-rename-caching.sh +++ b/t/t6429-merge-sequence-rename-caching.sh @@ -2,6 +2,7 @@ test_description="remember regular & dir renames in sequence of merges" +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # diff --git a/t/t6430-merge-recursive.sh b/t/t6430-merge-recursive.sh index ca15e6dd6d..555f00f78a 100755 --- a/t/t6430-merge-recursive.sh +++ b/t/t6430-merge-recursive.sh @@ -5,6 +5,7 @@ test_description='merge-recursive backend test' 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-merge.sh diff --git a/t/t6432-merge-recursive-space-options.sh b/t/t6432-merge-recursive-space-options.sh index db4b77e63d..c93538b0c3 100755 --- a/t/t6432-merge-recursive-space-options.sh +++ b/t/t6432-merge-recursive-space-options.sh @@ -14,6 +14,7 @@ test_description='merge-recursive space options 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/t6434-merge-recursive-rename-options.sh b/t/t6434-merge-recursive-rename-options.sh index a11707835b..df1d0c156c 100755 --- a/t/t6434-merge-recursive-rename-options.sh +++ b/t/t6434-merge-recursive-rename-options.sh @@ -29,6 +29,7 @@ mentions this in a different context). GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh get_expected_stages () { diff --git a/t/t6436-merge-overwrite.sh b/t/t6436-merge-overwrite.sh index 4f4376421e..ccc620477d 100755 --- a/t/t6436-merge-overwrite.sh +++ b/t/t6436-merge-overwrite.sh @@ -7,6 +7,7 @@ Do not overwrite changes.' 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/t6438-submodule-directory-file-conflicts.sh b/t/t6438-submodule-directory-file-conflicts.sh index 8df67a0ef9..3594190af8 100755 --- a/t/t6438-submodule-directory-file-conflicts.sh +++ b/t/t6438-submodule-directory-file-conflicts.sh @@ -2,6 +2,7 @@ test_description='merge can handle submodules' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-submodule-update.sh diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh index 43d40175f8..1b5909d1b7 100755 --- a/t/t6500-gc.sh +++ b/t/t6500-gc.sh @@ -158,7 +158,7 @@ test_expect_success TTY 'with TTY: gc --no-quiet' ' git -c gc.writeCommitGraph=true gc --no-quiet >stdout 2>stderr && test_must_be_empty stdout && test_grep "Enumerating objects" stderr && - test_grep "Computing commit graph generation numbers" stderr + test_grep "Computing commit graph generation numbers: 100% (4/4), done." stderr ' test_expect_success 'gc --quiet' ' diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh index 879a6dce60..86258f9f43 100755 --- a/t/t7001-mv.sh +++ b/t/t7001-mv.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='git mv in subdirs' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-diff-data.sh diff --git a/t/t7002-mv-sparse-checkout.sh b/t/t7002-mv-sparse-checkout.sh index 26582ae4e5..57969ce805 100755 --- a/t/t7002-mv-sparse-checkout.sh +++ b/t/t7002-mv-sparse-checkout.sh @@ -2,6 +2,7 @@ test_description='git mv in sparse working trees' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh setup_sparse_checkout () { diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 696866d779..fa6336edf9 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -668,6 +668,115 @@ test_expect_success \ test_cmp expect actual ' +# trailers + +test_expect_success 'create tag with -m and --trailer' ' + get_tag_header tag-with-inline-message-and-trailers $commit commit $time >expect && + cat >>expect <<-\EOF && + create tag with trailers + + my-trailer: here + alt-trailer: there + EOF + git tag -m "create tag with trailers" \ + --trailer my-trailer=here \ + --trailer alt-trailer=there \ + tag-with-inline-message-and-trailers && + get_tag_msg tag-with-inline-message-and-trailers >actual && + test_cmp expect actual +' + +test_expect_success 'list tag extracting trailers' ' + cat >expect <<-\EOF && + my-trailer: here + alt-trailer: there + + EOF + git tag --list --format="%(trailers)" tag-with-inline-message-and-trailers >actual && + test_cmp expect actual +' + +test_expect_success 'create tag with -F and --trailer' ' + echo "create tag from message file using --trailer" >messagefilewithnotrailers && + get_tag_header tag-with-file-message-and-trailers $commit commit $time >expect && + cat >>expect <<-\EOF && + create tag from message file using --trailer + + my-trailer: here + alt-trailer: there + EOF + git tag -F messagefilewithnotrailers \ + --trailer my-trailer=here \ + --trailer alt-trailer=there \ + tag-with-file-message-and-trailers && + get_tag_msg tag-with-file-message-and-trailers >actual && + test_cmp expect actual +' + +test_expect_success 'create tag with -m and --trailer and --edit' ' + write_script fakeeditor <<-\EOF && + sed -e "1s/^/EDITED: /g" <"$1" >"$1-" + mv "$1-" "$1" + EOF + get_tag_header tag-with-edited-inline-message-and-trailers $commit commit $time >expect && + cat >>expect <<-\EOF && + EDITED: create tag with trailers + + my-trailer: here + alt-trailer: there + EOF + GIT_EDITOR=./fakeeditor git tag --edit \ + -m "create tag with trailers" \ + --trailer my-trailer=here \ + --trailer alt-trailer=there \ + tag-with-edited-inline-message-and-trailers && + get_tag_msg tag-with-edited-inline-message-and-trailers >actual && + test_cmp expect actual +' + +test_expect_success 'create tag with -F and --trailer and --edit' ' + echo "create tag from message file using --trailer" >messagefilewithnotrailers && + get_tag_header tag-with-edited-file-message-and-trailers $commit commit $time >expect && + cat >>expect <<-\EOF && + EDITED: create tag from message file using --trailer + + my-trailer: here + alt-trailer: there + EOF + GIT_EDITOR=./fakeeditor git tag --edit \ + -F messagefilewithnotrailers \ + --trailer my-trailer=here \ + --trailer alt-trailer=there \ + tag-with-edited-file-message-and-trailers && + get_tag_msg tag-with-edited-file-message-and-trailers >actual && + test_cmp expect actual +' + +test_expect_success 'create annotated tag and force editor when only --trailer is given' ' + write_script fakeeditor <<-\EOF && + echo "add a line" >"$1-" + cat <"$1" >>"$1-" + mv "$1-" "$1" + EOF + get_tag_header tag-with-trailers-and-no-message $commit commit $time >expect && + cat >>expect <<-\EOF && + add a line + + my-trailer: here + alt-trailer: there + EOF + GIT_EDITOR=./fakeeditor git tag \ + --trailer my-trailer=here \ + --trailer alt-trailer=there \ + tag-with-trailers-and-no-message && + get_tag_msg tag-with-trailers-and-no-message >actual && + test_cmp expect actual +' + +test_expect_success 'bad editor causes panic when only --trailer is given' ' + test_must_fail env GIT_EDITOR=false git tag --trailer my-trailer=here tag-will-not-exist +' + # listing messages for annotated non-signed tags: test_expect_success \ @@ -810,6 +919,11 @@ test_expect_success 'git tag --format with ahead-behind' ' refs/tags/tag-lines 0 1 ! refs/tags/tag-one-line 0 1 ! refs/tags/tag-right 0 0 ! + refs/tags/tag-with-edited-file-message-and-trailers 0 1 ! + refs/tags/tag-with-edited-inline-message-and-trailers 0 1 ! + refs/tags/tag-with-file-message-and-trailers 0 1 ! + refs/tags/tag-with-inline-message-and-trailers 0 1 ! + refs/tags/tag-with-trailers-and-no-message 0 1 ! refs/tags/tag-zero-lines 0 1 ! EOF git tag -l --format="%(refname) %(ahead-behind:HEAD) !" >actual 2>err && diff --git a/t/t7005-editor.sh b/t/t7005-editor.sh index 5fcf281dfb..b9822294fe 100755 --- a/t/t7005-editor.sh +++ b/t/t7005-editor.sh @@ -2,6 +2,7 @@ test_description='GIT_EDITOR, core.editor, and stuff' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh unset EDITOR VISUAL GIT_EDITOR diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh index e56ca5b0fa..a0296d6ca4 100755 --- a/t/t7006-pager.sh +++ b/t/t7006-pager.sh @@ -2,6 +2,7 @@ test_description='Test automatic use of a pager.' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-pager.sh . "$TEST_DIRECTORY"/lib-terminal.sh @@ -725,18 +726,11 @@ test_expect_success TTY 'git discards pager non-zero exit without SIGPIPE' ' test_path_is_file pager-used ' -test_expect_success TTY 'git skips paging nonexisting command' ' - test_when_finished "rm trace.normal" && +test_expect_success TTY 'git errors when asked to execute nonexisting pager' ' + test_when_finished "rm -f err" && test_config core.pager "does-not-exist" && - GIT_TRACE2="$(pwd)/trace.normal" && - export GIT_TRACE2 && - test_when_finished "unset GIT_TRACE2" && - - test_terminal git log && - - grep child_exit trace.normal >child-exits && - test_line_count = 1 child-exits && - grep " code:-1 " child-exits + test_must_fail test_terminal git log 2>err && + test_grep "unable to execute pager" err ' test_expect_success TTY 'git returns SIGPIPE on propagated signals from pager' ' @@ -762,7 +756,7 @@ test_expect_success TTY 'git returns SIGPIPE on propagated signals from pager' ' test_expect_success TTY 'non-existent pager doesnt cause crash' ' test_config pager.show invalid-pager && - test_terminal git show + test_must_fail test_terminal git show ' test_done diff --git a/t/t7010-setup.sh b/t/t7010-setup.sh index 520f96d09f..d9add2162e 100755 --- a/t/t7010-setup.sh +++ b/t/t7010-setup.sh @@ -2,6 +2,7 @@ test_description='setup taking and sanitizing funny paths' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t7012-skip-worktree-writing.sh b/t/t7012-skip-worktree-writing.sh index cd5c20fe51..d984200c17 100755 --- a/t/t7012-skip-worktree-writing.sh +++ b/t/t7012-skip-worktree-writing.sh @@ -5,6 +5,7 @@ test_description='test worktree writing operations when skip-worktree is used' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t7102-reset.sh b/t/t7102-reset.sh index 62d9f846ce..2add26d768 100755 --- a/t/t7102-reset.sh +++ b/t/t7102-reset.sh @@ -10,6 +10,7 @@ Documented tests for git reset' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh commit_msg () { diff --git a/t/t7112-reset-submodule.sh b/t/t7112-reset-submodule.sh index a3e2413bc3..b0d3d93b0b 100755 --- a/t/t7112-reset-submodule.sh +++ b/t/t7112-reset-submodule.sh @@ -2,6 +2,7 @@ test_description='reset can handle submodules' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-submodule-update.sh diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 42352dc0db..189d8e341b 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -23,6 +23,7 @@ Test switching across them. GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_tick diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index 5c4a89df5c..981488885f 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -1451,4 +1451,35 @@ test_expect_success 'recursive clone respects -q' ' test_must_be_empty actual ' +test_expect_success '`submodule init` and `init.templateDir`' ' + mkdir -p tmpl/hooks && + write_script tmpl/hooks/post-checkout <<-EOF && + echo HOOK-RUN >&2 + echo I was here >hook.run + exit 1 + EOF + + test_config init.templateDir "$(pwd)/tmpl" && + test_when_finished \ + "git config --global --unset init.templateDir || true" && + ( + sane_unset GIT_TEMPLATE_DIR && + NO_SET_GIT_TEMPLATE_DIR=t && + export NO_SET_GIT_TEMPLATE_DIR && + + git config --global init.templateDir "$(pwd)/tmpl" && + test_must_fail git submodule \ + add "$submodurl" sub-global 2>err && + git config --global --unset init.templateDir && + test_grep HOOK-RUN err && + test_path_is_file sub-global/hook.run && + + git config init.templateDir "$(pwd)/tmpl" && + git submodule add "$submodurl" sub-local 2>err && + git config --unset init.templateDir && + test_grep ! HOOK-RUN err && + test_path_is_missing sub-local/hook.run + ) +' + test_done diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh index 8491b8c58b..297c6c3b5c 100755 --- a/t/t7406-submodule-update.sh +++ b/t/t7406-submodule-update.sh @@ -1202,4 +1202,52 @@ test_expect_success 'commit with staged submodule change with ignoreSubmodules a add_submodule_commit_and_validate ' +test_expect_success CASE_INSENSITIVE_FS,SYMLINKS \ + 'submodule paths must not follow symlinks' ' + + # This is only needed because we want to run this in a self-contained + # test without having to spin up an HTTP server; However, it would not + # be needed in a real-world scenario where the submodule is simply + # hosted on a public site. + test_config_global protocol.file.allow always && + + # Make sure that Git tries to use symlinks on Windows + test_config_global core.symlinks true && + + tell_tale_path="$PWD/tell.tale" && + git init hook && + ( + cd hook && + mkdir -p y/hooks && + write_script y/hooks/post-checkout <<-EOF && + echo HOOK-RUN >&2 + echo hook-run >"$tell_tale_path" + EOF + git add y/hooks/post-checkout && + test_tick && + git commit -m post-checkout + ) && + + hook_repo_path="$(pwd)/hook" && + git init captain && + ( + cd captain && + git submodule add --name x/y "$hook_repo_path" A/modules/x && + test_tick && + git commit -m add-submodule && + + printf .git >dotgit.txt && + git hash-object -w --stdin <dotgit.txt >dot-git.hash && + printf "120000 %s 0\ta\n" "$(cat dot-git.hash)" >index.info && + git update-index --index-info <index.info && + test_tick && + git commit -m add-symlink + ) && + + test_path_is_missing "$tell_tale_path" && + git clone --recursive captain hooked 2>err && + test_grep ! HOOK-RUN err && + test_path_is_missing "$tell_tale_path" +' + test_done diff --git a/t/t7417-submodule-path-url.sh b/t/t7417-submodule-path-url.sh index 5e3051da8b..dbbb3853dc 100755 --- a/t/t7417-submodule-path-url.sh +++ b/t/t7417-submodule-path-url.sh @@ -4,6 +4,7 @@ test_description='check handling of .gitmodule path with dash' 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/t7421-submodule-summary-add.sh b/t/t7421-submodule-summary-add.sh index ce64d8b137..479c8fdde1 100755 --- a/t/t7421-submodule-summary-add.sh +++ b/t/t7421-submodule-summary-add.sh @@ -10,6 +10,7 @@ while making sure to add submodules using `git submodule add` instead of `git add` as done in t7401. ' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t7423-submodule-symlinks.sh b/t/t7423-submodule-symlinks.sh new file mode 100755 index 0000000000..f45d806201 --- /dev/null +++ b/t/t7423-submodule-symlinks.sh @@ -0,0 +1,68 @@ +#!/bin/sh + +test_description='check that submodule operations do not follow symlinks' + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +test_expect_success 'prepare' ' + git config --global protocol.file.allow always && + test_commit initial && + git init upstream && + test_commit -C upstream upstream submodule_file && + git submodule add ./upstream a/sm && + test_tick && + git commit -m submodule +' + +test_expect_success SYMLINKS 'git submodule update must not create submodule behind symlink' ' + rm -rf a b && + mkdir b && + ln -s b a && + test_path_is_missing b/sm && + test_must_fail git submodule update && + test_path_is_missing b/sm +' + +test_expect_success SYMLINKS,CASE_INSENSITIVE_FS 'git submodule update must not create submodule behind symlink on case insensitive fs' ' + rm -rf a b && + mkdir b && + ln -s b A && + test_must_fail git submodule update && + test_path_is_missing b/sm +' + +prepare_symlink_to_repo() { + rm -rf a && + mkdir a && + git init a/target && + git -C a/target fetch ../../upstream && + ln -s target a/sm +} + +test_expect_success SYMLINKS 'git restore --recurse-submodules must not be confused by a symlink' ' + prepare_symlink_to_repo && + test_must_fail git restore --recurse-submodules a/sm && + test_path_is_missing a/sm/submodule_file && + test_path_is_dir a/target/.git && + test_path_is_missing a/target/submodule_file +' + +test_expect_success SYMLINKS 'git restore --recurse-submodules must not migrate git dir of symlinked repo' ' + prepare_symlink_to_repo && + rm -rf .git/modules && + test_must_fail git restore --recurse-submodules a/sm && + test_path_is_dir a/target/.git && + test_path_is_missing .git/modules/a/sm && + test_path_is_missing a/target/submodule_file +' + +test_expect_success SYMLINKS 'git checkout -f --recurse-submodules must not migrate git dir of symlinked repo when removing submodule' ' + prepare_symlink_to_repo && + rm -rf .git/modules && + test_must_fail git checkout -f --recurse-submodules initial && + test_path_is_dir a/target/.git && + test_path_is_missing .git/modules/a/sm +' + +test_done diff --git a/t/t7450-bad-git-dotfiles.sh b/t/t7450-bad-git-dotfiles.sh index 46d4fb0354..4a9c22c9e2 100755 --- a/t/t7450-bad-git-dotfiles.sh +++ b/t/t7450-bad-git-dotfiles.sh @@ -320,7 +320,7 @@ test_expect_success WINDOWS 'prevent git~1 squatting on Windows' ' fi ' -test_expect_success 'git dirs of sibling submodules must not be nested' ' +test_expect_success 'setup submodules with nested git dirs' ' git init nested && test_commit -C nested nested && ( @@ -338,9 +338,39 @@ test_expect_success 'git dirs of sibling submodules must not be nested' ' git add .gitmodules thing1 thing2 && test_tick && git commit -m nested - ) && + ) +' + +test_expect_success 'git dirs of sibling submodules must not be nested' ' test_must_fail git clone --recurse-submodules nested clone 2>err && test_grep "is inside git dir" err ' +test_expect_success 'submodule git dir nesting detection must work with parallel cloning' ' + test_must_fail git clone --recurse-submodules --jobs=2 nested clone_parallel 2>err && + cat err && + grep -E "(already exists|is inside git dir|not a git repository)" err && + { + test_path_is_missing .git/modules/hippo/HEAD || + test_path_is_missing .git/modules/hippo/hooks/HEAD + } +' + +test_expect_success 'checkout -f --recurse-submodules must not use a nested gitdir' ' + git clone nested nested_checkout && + ( + cd nested_checkout && + git submodule init && + git submodule update thing1 && + mkdir -p .git/modules/hippo/hooks/refs && + mkdir -p .git/modules/hippo/hooks/objects/info && + echo "../../../../objects" >.git/modules/hippo/hooks/objects/info/alternates && + echo "ref: refs/heads/master" >.git/modules/hippo/hooks/HEAD + ) && + test_must_fail git -C nested_checkout checkout -f --recurse-submodules HEAD 2>err && + cat err && + grep "is inside git dir" err && + test_path_is_missing nested_checkout/thing2/.git +' + test_done diff --git a/t/t7501-commit-basic-functionality.sh b/t/t7501-commit-basic-functionality.sh index cc12f99f11..52f5e28154 100755 --- a/t/t7501-commit-basic-functionality.sh +++ b/t/t7501-commit-basic-functionality.sh @@ -9,6 +9,7 @@ test_description='git commit' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY/lib-diff.sh" diff --git a/t/t7505-prepare-commit-msg-hook.sh b/t/t7505-prepare-commit-msg-hook.sh index 2128142a61..b88383df9e 100755 --- a/t/t7505-prepare-commit-msg-hook.sh +++ b/t/t7505-prepare-commit-msg-hook.sh @@ -5,6 +5,7 @@ test_description='prepare-commit-msg hook' 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 'set up commits for rebasing' ' diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh index 802f8f704c..cdd5f2c697 100755 --- a/t/t7512-status-help.sh +++ b/t/t7512-status-help.sh @@ -10,6 +10,7 @@ test_description='git status advice' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-rebase.sh diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh index e5ff073099..65fd3d8552 100755 --- a/t/t7600-merge.sh +++ b/t/t7600-merge.sh @@ -29,6 +29,7 @@ Testing basic merge operations/option parsing. GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-gpg.sh @@ -236,6 +237,16 @@ test_expect_success 'merge c1 with c2' ' verify_parents $c1 $c2 ' +test_expect_success 'merge c1 with c2 when index.lock exists' ' + test_when_finished rm .git/index.lock && + git reset --hard c1 && + >.git/index.lock && + test_must_fail git merge c2 && + test_path_is_missing .git/MERGE_HEAD && + test_path_is_missing .git/MERGE_MODE && + test_path_is_missing .git/MERGE_MSG +' + test_expect_success 'merge --squash c3 with c7' ' git reset --hard c3 && test_must_fail git merge --squash c7 && diff --git a/t/t7606-merge-custom.sh b/t/t7606-merge-custom.sh index 81fb7c474c..135cb23085 100755 --- a/t/t7606-merge-custom.sh +++ b/t/t7606-merge-custom.sh @@ -14,6 +14,7 @@ Testing a custom strategy. * (tag: c0) c0 " +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'set up custom strategy' ' diff --git a/t/t7611-merge-abort.sh b/t/t7611-merge-abort.sh index d6975ca48d..992a8f9874 100755 --- a/t/t7611-merge-abort.sh +++ b/t/t7611-merge-abort.sh @@ -25,6 +25,7 @@ Next, test git merge --abort with the following variables: 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/t7900-maintenance.sh b/t/t7900-maintenance.sh index 0943dfa18a..8595489ceb 100755 --- a/t/t7900-maintenance.sh +++ b/t/t7900-maintenance.sh @@ -639,9 +639,9 @@ test_expect_success 'start from empty cron table' ' # start registers the repo git config --get --global --fixed-value maintenance.repo "$(pwd)" && - grep "for-each-repo --config=maintenance.repo maintenance run --schedule=daily" cron.txt && - grep "for-each-repo --config=maintenance.repo maintenance run --schedule=hourly" cron.txt && - grep "for-each-repo --config=maintenance.repo maintenance run --schedule=weekly" cron.txt + grep "for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=daily" cron.txt && + grep "for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=hourly" cron.txt && + grep "for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=weekly" cron.txt ' test_expect_success 'stop from existing schedule' ' diff --git a/t/t8002-blame.sh b/t/t8002-blame.sh index 0147de304b..3596634039 100755 --- a/t/t8002-blame.sh +++ b/t/t8002-blame.sh @@ -5,6 +5,7 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME TEST_CREATE_REPO_NO_TEMPLATE=1 +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh PROG='git blame -c' diff --git a/t/t8003-blame-corner-cases.sh b/t/t8003-blame-corner-cases.sh index 731265541a..6288352f57 100755 --- a/t/t8003-blame-corner-cases.sh +++ b/t/t8003-blame-corner-cases.sh @@ -4,6 +4,7 @@ test_description='git blame corner cases' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh pick_fc='s/^[0-9a-f^]* *\([^ ]*\) *(\([^ ]*\) .*/\1-\2/' diff --git a/t/t8004-blame-with-conflicts.sh b/t/t8004-blame-with-conflicts.sh index 35414a5336..2c2a0b33f9 100755 --- a/t/t8004-blame-with-conflicts.sh +++ b/t/t8004-blame-with-conflicts.sh @@ -6,6 +6,7 @@ test_description='git blame on conflicted files' 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 first case' ' diff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh index 7683515155..42f8be25a3 100755 --- a/t/t8006-blame-textconv.sh +++ b/t/t8006-blame-textconv.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='git blame textconv support' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh find_blame() { diff --git a/t/t8008-blame-formats.sh b/t/t8008-blame-formats.sh index ae4b579d24..fb5d225a67 100755 --- a/t/t8008-blame-formats.sh +++ b/t/t8008-blame-formats.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='blame output in various formats on a simple case' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t8009-blame-vs-topicbranches.sh b/t/t8009-blame-vs-topicbranches.sh index 72596e38b2..30331713b9 100755 --- a/t/t8009-blame-vs-topicbranches.sh +++ b/t/t8009-blame-vs-topicbranches.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='blaming trough history with topic branches' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Creates the history shown below. '*'s mark the first parent in the merges. diff --git a/t/t8011-blame-split-file.sh b/t/t8011-blame-split-file.sh index bdda0c03fe..da1801f4d2 100755 --- a/t/t8011-blame-split-file.sh +++ b/t/t8011-blame-split-file.sh @@ -10,6 +10,8 @@ Note that we need to use "blame -C" to find the commit for all lines. We will not bother testing that the non-C case fails to find it. That is how blame behaves now, but it is not a property we want to make sure is retained. ' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # help avoid typing and reading long strings of similar lines diff --git a/t/t8012-blame-colors.sh b/t/t8012-blame-colors.sh index c3a5f6d01f..9a79c109f2 100755 --- a/t/t8012-blame-colors.sh +++ b/t/t8012-blame-colors.sh @@ -5,6 +5,7 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME TEST_CREATE_REPO_NO_TEMPLATE=1 +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh PROG='git blame -c' diff --git a/t/t8013-blame-ignore-revs.sh b/t/t8013-blame-ignore-revs.sh index dbfbd86e83..d33788d867 100755 --- a/t/t8013-blame-ignore-revs.sh +++ b/t/t8013-blame-ignore-revs.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='ignore revisions when blaming' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Creates: diff --git a/t/t8014-blame-ignore-fuzzy.sh b/t/t8014-blame-ignore-fuzzy.sh index 0bd0341301..933222cea1 100755 --- a/t/t8014-blame-ignore-fuzzy.sh +++ b/t/t8014-blame-ignore-fuzzy.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='git blame ignore fuzzy heuristic' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh pick_author='s/^[0-9a-f^]* *(\([^ ]*\) .*/\1/' diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 5a771000c9..64a4ab3736 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -1299,6 +1299,49 @@ test_expect_success $PREREQ 'utf8 sender is not duplicated' ' test_line_count = 1 msgfrom ' +test_expect_success $PREREQ 'setup expect for cc list' " +cat >expected-cc <<\EOF +!recipient@example.com! +!author@example.com! +!one@example.com! +!os@example.com! +!odd_?=mail@example.com! +!doug@example.com! +!codev@example.com! +!thor.au@example.com! +EOF +" + +test_expect_success $PREREQ 'cc list is sanitized' ' + clean_fake_sendmail && + test_commit weird_cc_body && + test_when_finished "git reset --hard HEAD^" && + git commit --amend -F - <<-EOF && + Test Cc: sanitization. + + Cc: Person, One <one@example.com> + Cc: Ronnie O${SQ}Sullivan <os@example.com> + Reviewed-by: Füñný Nâmé <odd_?=mail@example.com> + Reported-by: bugger on Jira + Reported-by: Douglas Reporter <doug@example.com> [from Jira profile] + BugID: 12345 + Co-developed-by: "C. O. Developer" <codev@example.com> + Signed-off-by: A. U. Thor <thor.au@example.com> + EOF + git send-email -1 --to=recipient@example.com \ + --smtp-server="$(pwd)/fake.sendmail" >actual-show-all-headers && + test_cmp expected-cc commandline1 && + test_grep "^(body) Adding cc: \"Person, One\" <one@example.com>" actual-show-all-headers && + test_grep "^(body) Adding cc: Ronnie O${SQ}Sullivan <os@example.com>" actual-show-all-headers && + test_grep "^(body) Adding cc: =?UTF-8?q?F=C3=BC=C3=B1n=C3=BD=20N=C3=A2m=C3=A9?="\ +" <odd_?=mail@example.com>" actual-show-all-headers && + test_grep "^(body) Ignoring Reported-by .* bugger on Jira" actual-show-all-headers && + test_grep "^(body) Adding cc: Douglas Reporter <doug@example.com>" actual-show-all-headers && + test_grep ! "12345" actual-show-all-headers && + test_grep "^(body) Adding cc: \"C. O. Developer\" <codev@example.com>" actual-show-all-headers && + test_grep "^(body) Adding cc: \"A. U. Thor\" <thor.au@example.com>" actual-show-all-headers +' + test_expect_success $PREREQ 'sendemail.composeencoding works' ' clean_fake_sendmail && git config sendemail.composeencoding iso-8859-1 && @@ -2526,7 +2569,7 @@ test_expect_success $PREREQ 'test forbidSendmailVariables behavior override' ' test_expect_success $PREREQ '--compose handles lowercase headers' ' write_script fake-editor <<-\EOF && - sed "s/^From:.*/from: edited-from@example.com/i" "$1" >"$1.tmp" && + sed "s/^[Ff][Rr][Oo][Mm]:.*/from: edited-from@example.com/" "$1" >"$1.tmp" && mv "$1.tmp" "$1" EOF clean_fake_sendmail && diff --git a/t/t9004-example.sh b/t/t9004-example.sh deleted file mode 100755 index 590aab0304..0000000000 --- a/t/t9004-example.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -test_description='check that example code compiles and runs' - -TEST_PASSES_SANITIZE_LEAK=true -. ./test-lib.sh - -test_expect_success 'decorate' ' - test-tool example-decorate -' - -test_done diff --git a/t/t9118-git-svn-funky-branch-names.sh b/t/t9118-git-svn-funky-branch-names.sh index d3261e35b8..a34fd46ecc 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" | sed -ne '/not-a/ { s/\///; s/@/%40/; p }') +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/t9129-git-svn-i18n-commitencoding.sh b/t/t9129-git-svn-i18n-commitencoding.sh index 185248a4cd..01e1e8a8f7 100755 --- a/t/t9129-git-svn-i18n-commitencoding.sh +++ b/t/t9129-git-svn-i18n-commitencoding.sh @@ -4,7 +4,6 @@ test_description='git svn honors i18n.commitEncoding in config' -TEST_FAILS_SANITIZE_LEAK=true . ./lib-git-svn.sh compare_git_head_with () { diff --git a/t/t9139-git-svn-non-utf8-commitencoding.sh b/t/t9139-git-svn-non-utf8-commitencoding.sh index b7f756b2b7..22d80b0be2 100755 --- a/t/t9139-git-svn-non-utf8-commitencoding.sh +++ b/t/t9139-git-svn-non-utf8-commitencoding.sh @@ -4,7 +4,6 @@ test_description='git svn refuses to dcommit non-UTF8 messages' -TEST_FAILS_SANITIZE_LEAK=true . ./lib-git-svn.sh # ISO-2022-JP can pass for valid UTF-8, so skipping that in this test diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh index a44eabf0d8..3d4842164c 100755 --- a/t/t9200-git-cvsexportcommit.sh +++ b/t/t9200-git-cvsexportcommit.sh @@ -4,6 +4,7 @@ # test_description='Test export of commits to CVS' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh if ! test_have_prereq PERL; then diff --git a/t/t9210-scalar.sh b/t/t9210-scalar.sh index 428339e342..a41b4fcc08 100755 --- a/t/t9210-scalar.sh +++ b/t/t9210-scalar.sh @@ -180,6 +180,44 @@ test_expect_success 'scalar reconfigure' ' test true = "$(git -C one/src config core.preloadIndex)" ' +test_expect_success 'scalar reconfigure --all with includeIf.onbranch' ' + repos="two three four" && + for num in $repos + do + git init $num/src && + scalar register $num/src && + git -C $num/src config includeif."onbranch:foo".path something && + git -C $num/src config core.preloadIndex false || return 1 + done && + + scalar reconfigure --all && + + for num in $repos + do + test true = "$(git -C $num/src config core.preloadIndex)" || return 1 + done +' + + test_expect_success 'scalar reconfigure --all with detached HEADs' ' + repos="two three four" && + for num in $repos + do + rm -rf $num/src && + git init $num/src && + scalar register $num/src && + git -C $num/src config core.preloadIndex false && + test_commit -C $num/src initial && + git -C $num/src switch --detach HEAD || return 1 + done && + + scalar reconfigure --all && + + for num in $repos + do + test true = "$(git -C $num/src config core.preloadIndex)" || return 1 + done +' + test_expect_success '`reconfigure -a` removes stale config entries' ' git init stale/src && scalar register stale && diff --git a/t/t9401-git-cvsserver-crlf.sh b/t/t9401-git-cvsserver-crlf.sh index a34805acdc..a67e6abd49 100755 --- a/t/t9401-git-cvsserver-crlf.sh +++ b/t/t9401-git-cvsserver-crlf.sh @@ -12,6 +12,7 @@ repository using cvs CLI client via git-cvsserver server' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh marked_as () { diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh index 7679780fb8..ccfa415384 100755 --- a/t/t9500-gitweb-standalone-no-errors.sh +++ b/t/t9500-gitweb-standalone-no-errors.sh @@ -13,6 +13,7 @@ or warnings to log.' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./lib-gitweb.sh # ---------------------------------------------------------------------- diff --git a/t/t9502-gitweb-standalone-parse-output.sh b/t/t9502-gitweb-standalone-parse-output.sh index 81d5625557..b41ea19331 100755 --- a/t/t9502-gitweb-standalone-parse-output.sh +++ b/t/t9502-gitweb-standalone-parse-output.sh @@ -13,6 +13,7 @@ in the HTTP header or the actual script output.' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./lib-gitweb.sh # ---------------------------------------------------------------------- diff --git a/t/t9600-cvsimport.sh b/t/t9600-cvsimport.sh index 5680849218..41fcf3606b 100755 --- a/t/t9600-cvsimport.sh +++ b/t/t9600-cvsimport.sh @@ -4,6 +4,7 @@ test_description='git cvsimport basic tests' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./lib-cvs.sh if ! test_have_prereq NOT_ROOT; then diff --git a/t/t9601-cvsimport-vendor-branch.sh b/t/t9601-cvsimport-vendor-branch.sh index 116cddba3a..e007669495 100755 --- a/t/t9601-cvsimport-vendor-branch.sh +++ b/t/t9601-cvsimport-vendor-branch.sh @@ -35,6 +35,7 @@ test_description='git cvsimport handling of vendor branches' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./lib-cvs.sh setup_cvs_test_repository t9601 diff --git a/t/t9602-cvsimport-branches-tags.sh b/t/t9602-cvsimport-branches-tags.sh index e5266c9a87..3768e3bd8c 100755 --- a/t/t9602-cvsimport-branches-tags.sh +++ b/t/t9602-cvsimport-branches-tags.sh @@ -7,6 +7,7 @@ test_description='git cvsimport handling of branches and tags' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./lib-cvs.sh setup_cvs_test_repository t9602 diff --git a/t/t9603-cvsimport-patchsets.sh b/t/t9603-cvsimport-patchsets.sh index 19f38f78f2..2a387fdbaa 100755 --- a/t/t9603-cvsimport-patchsets.sh +++ b/t/t9603-cvsimport-patchsets.sh @@ -12,6 +12,8 @@ # bug. test_description='git cvsimport testing for correct patchset estimation' + +TEST_PASSES_SANITIZE_LEAK=true . ./lib-cvs.sh setup_cvs_test_repository t9603 diff --git a/t/t9604-cvsimport-timestamps.sh b/t/t9604-cvsimport-timestamps.sh index 2d03259729..9cf0685d56 100755 --- a/t/t9604-cvsimport-timestamps.sh +++ b/t/t9604-cvsimport-timestamps.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='git cvsimport timestamps' + +TEST_PASSES_SANITIZE_LEAK=true . ./lib-cvs.sh test_lazy_prereq POSIX_TIMEZONE ' diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 569cf23104..932d5ad759 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -73,7 +73,7 @@ _get_comp_words_by_ref () print_comp () { local IFS=$'\n' - echo "${COMPREPLY[*]}" > out + printf '%s\n' "${COMPREPLY[*]}" > out } run_completion () @@ -2518,6 +2518,29 @@ test_expect_success 'complete tree filename with metacharacters' ' EOF ' +test_expect_success 'symbolic-ref completes builtin options' ' + test_completion "git symbolic-ref --d" <<-\EOF + --delete Z + EOF +' + +test_expect_success 'symbolic-ref completes short ref names' ' + test_completion "git symbolic-ref foo m" <<-\EOF + main Z + mybranch Z + mytag Z + EOF +' + +test_expect_success 'symbolic-ref completes full ref names' ' + test_completion "git symbolic-ref foo refs/" <<-\EOF + refs/heads/main Z + refs/heads/mybranch Z + refs/tags/mytag Z + refs/tags/A Z + EOF +' + test_expect_success PERL 'send-email' ' test_completion "git send-email --cov" <<-\EOF && --cover-from-description=Z @@ -2719,30 +2742,58 @@ do ' done -test_expect_success 'git config - section' ' - test_completion "git config br" <<-\EOF +test_expect_success 'git config subcommand' ' + test_completion "git config " <<-\EOF + edit Z + get Z + list Z + remove-section Z + rename-section Z + set Z + unset Z + EOF +' + +test_expect_success 'git config subcommand options' ' + test_completion "git config get --show-" <<-\EOF + --show-names Z + --show-origin Z + --show-scope Z + EOF +' + +test_expect_success 'git config get' ' + test_when_finished "rm -f cfgfile" && + git config set --file cfgfile foo.bar baz && + test_completion "git config get --file cfgfile foo." <<-\EOF + foo.bar Z + EOF +' + +test_expect_success 'git config set - section' ' + test_completion "git config set br" <<-\EOF branch.Z browser.Z EOF ' -test_expect_success 'git config - section include, includeIf' ' - test_completion "git config inclu" <<-\EOF +test_expect_success 'git config set - section include, includeIf' ' + test_completion "git config set inclu" <<-\EOF include.Z includeIf.Z EOF ' -test_expect_success 'git config - variable name' ' - test_completion "git config log.d" <<-\EOF +test_expect_success 'git config set - variable name' ' + test_completion "git config set log.d" <<-\EOF log.date Z log.decorate Z log.diffMerges Z EOF ' -test_expect_success 'git config - variable name include' ' - test_completion "git config include.p" <<-\EOF +test_expect_success 'git config set - variable name include' ' + test_completion "git config set include.p" <<-\EOF include.path Z EOF ' @@ -2753,8 +2804,8 @@ test_expect_success 'setup for git config submodule tests' ' git submodule add ./sub ' -test_expect_success 'git config - variable name - submodule and __git_compute_first_level_config_vars_for_section' ' - test_completion "git config submodule." <<-\EOF +test_expect_success 'git config set - variable name - submodule and __git_compute_first_level_config_vars_for_section' ' + test_completion "git config set submodule." <<-\EOF submodule.active Z submodule.alternateErrorStrategy Z submodule.alternateLocation Z @@ -2765,8 +2816,8 @@ test_expect_success 'git config - variable name - submodule and __git_compute_fi EOF ' -test_expect_success 'git config - variable name - __git_compute_second_level_config_vars_for_section' ' - test_completion "git config submodule.sub." <<-\EOF +test_expect_success 'git config set - variable name - __git_compute_second_level_config_vars_for_section' ' + test_completion "git config set submodule.sub." <<-\EOF submodule.sub.url Z submodule.sub.update Z submodule.sub.branch Z @@ -2776,8 +2827,8 @@ test_expect_success 'git config - variable name - __git_compute_second_level_con EOF ' -test_expect_success 'git config - value' ' - test_completion "git config color.pager " <<-\EOF +test_expect_success 'git config set - value' ' + test_completion "git config set color.pager " <<-\EOF false Z true Z EOF diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index 862d80c974..fde9bf54fc 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -458,6 +458,7 @@ test_commit_bulk () { indir=. ref=HEAD n=1 + notick= message='commit %s' filename='%s.t' contents='content %s' @@ -488,6 +489,9 @@ test_commit_bulk () { filename="${1#--*=}-%s.t" contents="${1#--*=} %s" ;; + --notick) + notick=yes + ;; -*) BUG "invalid test_commit_bulk option: $1" ;; @@ -507,7 +511,10 @@ test_commit_bulk () { while test "$total" -gt 0 do - test_tick && + if test -z "$notick" + then + test_tick + fi && echo "commit $ref" printf 'author %s <%s> %s\n' \ "$GIT_AUTHOR_NAME" \ @@ -865,6 +872,24 @@ test_verify_prereq () { BUG "'$test_prereq' does not look like a prereq" } +# assign the variable named by "$1" with the contents of "$2"; +# if "$2" is "-", then read stdin into "$1" instead +test_body_or_stdin () { + if test "$2" != "-" + then + eval "$1=\$2" + return + fi + + # start with a newline, to match hanging newline from open-quote style + eval "$1=\$LF" + local test_line + while IFS= read -r test_line + do + eval "$1=\${$1}\${test_line}\${LF}" + done +} + test_expect_failure () { test_start_ "$@" test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= @@ -874,9 +899,11 @@ test_expect_failure () { export test_prereq if ! test_skip "$@" then + local test_body + test_body_or_stdin test_body "$2" test -n "$test_skip_test_preamble" || - say >&3 "checking known breakage of $TEST_NUMBER.$test_count '$1': $2" - if test_run_ "$2" expecting_failure + say >&3 "checking known breakage of $TEST_NUMBER.$test_count '$1': $test_body" + if test_run_ "$test_body" expecting_failure then test_known_broken_ok_ "$1" else @@ -895,13 +922,15 @@ test_expect_success () { export test_prereq if ! test_skip "$@" then + local test_body + test_body_or_stdin test_body "$2" test -n "$test_skip_test_preamble" || - say >&3 "expecting success of $TEST_NUMBER.$test_count '$1': $2" - if test_run_ "$2" + say >&3 "expecting success of $TEST_NUMBER.$test_count '$1': $test_body" + if test_run_ "$test_body" then test_ok_ "$1" else - test_failure_ "$@" + test_failure_ "$1" "$test_body" fi fi test_finish_ @@ -1096,6 +1125,11 @@ test_must_fail_acceptable () { done fi + if test "$1" = "nongit" + then + shift + fi + case "$1" in git|__git*|scalar|test-tool|test_terminal) return 0 diff --git a/t/test-lib.sh b/t/test-lib.sh index 79d3e0e7d9..54247604cb 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -1269,9 +1269,12 @@ check_test_results_san_file_ () { then say "As TEST_PASSES_SANITIZE_LEAK=true isn't set the above leak is 'ok' with GIT_TEST_PASSING_SANITIZE_LEAK=check" && invert_exit_code=t - else - say "With GIT_TEST_SANITIZE_LEAK_LOG=true our logs revealed a memory leak, exit non-zero!" && + elif test "$test_failure" = 0 + then + say "Our logs revealed a memory leak, exit non-zero!" && invert_exit_code=t + else + say "Our logs revealed a memory leak..." fi } @@ -1575,33 +1578,28 @@ then test_done fi - if test_bool_env GIT_TEST_SANITIZE_LEAK_LOG false + if ! mkdir -p "$TEST_RESULTS_SAN_DIR" then - if ! mkdir -p "$TEST_RESULTS_SAN_DIR" - then - BAIL_OUT "cannot create $TEST_RESULTS_SAN_DIR" - fi && - TEST_RESULTS_SAN_FILE="$TEST_RESULTS_SAN_DIR/$TEST_RESULTS_SAN_FILE_PFX" + BAIL_OUT "cannot create $TEST_RESULTS_SAN_DIR" + fi && + TEST_RESULTS_SAN_FILE="$TEST_RESULTS_SAN_DIR/$TEST_RESULTS_SAN_FILE_PFX" - # In case "test-results" is left over from a previous - # run: Only report if new leaks show up. - TEST_RESULTS_SAN_DIR_NR_LEAKS_STARTUP=$(nr_san_dir_leaks_) + # In case "test-results" is left over from a previous + # run: Only report if new leaks show up. + TEST_RESULTS_SAN_DIR_NR_LEAKS_STARTUP=$(nr_san_dir_leaks_) - # Don't litter *.leak dirs if there was nothing to report - test_atexit "rmdir \"$TEST_RESULTS_SAN_DIR\" 2>/dev/null || :" + # Don't litter *.leak dirs if there was nothing to report + test_atexit "rmdir \"$TEST_RESULTS_SAN_DIR\" 2>/dev/null || :" + + prepend_var LSAN_OPTIONS : dedup_token_length=9999 + prepend_var LSAN_OPTIONS : log_exe_name=1 + prepend_var LSAN_OPTIONS : log_path=\"$TEST_RESULTS_SAN_FILE\" + export LSAN_OPTIONS - prepend_var LSAN_OPTIONS : dedup_token_length=9999 - prepend_var LSAN_OPTIONS : log_exe_name=1 - prepend_var LSAN_OPTIONS : log_path=\"$TEST_RESULTS_SAN_FILE\" - export LSAN_OPTIONS - fi elif test "$GIT_TEST_PASSING_SANITIZE_LEAK" = "check" || test_bool_env GIT_TEST_PASSING_SANITIZE_LEAK false then BAIL_OUT_ENV_NEEDS_SANITIZE_LEAK "GIT_TEST_PASSING_SANITIZE_LEAK=true" -elif test_bool_env GIT_TEST_SANITIZE_LEAK_LOG false -then - BAIL_OUT_ENV_NEEDS_SANITIZE_LEAK "GIT_TEST_SANITIZE_LEAK_LOG=true" fi if test "${GIT_TEST_CHAIN_LINT:-1}" != 0 && diff --git a/t/test-terminal.perl b/t/test-terminal.perl index 3810e9bb43..b8fd6a4f13 100755 --- a/t/test-terminal.perl +++ b/t/test-terminal.perl @@ -5,17 +5,15 @@ use warnings; use IO::Pty; use File::Copy; -# Run @$argv in the background with stdio redirected to $in, $out and $err. +# Run @$argv in the background with stdio redirected to $out and $err. sub start_child { - my ($argv, $in, $out, $err) = @_; + my ($argv, $out, $err) = @_; my $pid = fork; if (not defined $pid) { die "fork failed: $!" } elsif ($pid == 0) { - open STDIN, "<&", $in; open STDOUT, ">&", $out; open STDERR, ">&", $err; - close $in; close $out; exec(@$argv) or die "cannot exec '$argv->[0]': $!" } @@ -51,17 +49,6 @@ sub xsendfile { copy($in, $out, 4096) or $!{EIO} or die "cannot copy from child: $!"; } -sub copy_stdin { - my ($in) = @_; - my $pid = fork; - if (!$pid) { - xsendfile($in, \*STDIN); - exit 0; - } - close($in); - return $pid; -} - sub copy_stdio { my ($out, $err) = @_; my $pid = fork; @@ -81,25 +68,15 @@ if ($#ARGV < 1) { die "usage: test-terminal program args"; } $ENV{TERM} = 'vt100'; -my $parent_in = new IO::Pty; my $parent_out = new IO::Pty; my $parent_err = new IO::Pty; -$parent_in->set_raw(); $parent_out->set_raw(); $parent_err->set_raw(); -$parent_in->slave->set_raw(); $parent_out->slave->set_raw(); $parent_err->slave->set_raw(); -my $pid = start_child(\@ARGV, $parent_in->slave, $parent_out->slave, $parent_err->slave); -close $parent_in->slave; +my $pid = start_child(\@ARGV, $parent_out->slave, $parent_err->slave); close $parent_out->slave; close $parent_err->slave; -my $in_pid = copy_stdin($parent_in); copy_stdio($parent_out, $parent_err); my $ret = finish_child($pid); -# If the child process terminates before our copy_stdin() process is able to -# write all of its data to $parent_in, the copy_stdin() process could stall. -# Send SIGTERM to it to ensure it terminates. -kill 'TERM', $in_pid; -finish_child($in_pid); exit($ret); diff --git a/t/unit-tests/lib-oid.c b/t/unit-tests/lib-oid.c new file mode 100644 index 0000000000..37105f0a8f --- /dev/null +++ b/t/unit-tests/lib-oid.c @@ -0,0 +1,52 @@ +#include "test-lib.h" +#include "lib-oid.h" +#include "strbuf.h" +#include "hex.h" + +static int init_hash_algo(void) +{ + static int algo = -1; + + if (algo < 0) { + const char *algo_name = getenv("GIT_TEST_DEFAULT_HASH"); + algo = algo_name ? hash_algo_by_name(algo_name) : GIT_HASH_SHA1; + + if (!check(algo != GIT_HASH_UNKNOWN)) + test_msg("BUG: invalid GIT_TEST_DEFAULT_HASH value ('%s')", + algo_name); + } + return algo; +} + +static int get_oid_arbitrary_hex_algop(const char *hex, struct object_id *oid, + const struct git_hash_algo *algop) +{ + int ret; + size_t sz = strlen(hex); + struct strbuf buf = STRBUF_INIT; + + if (!check(sz <= algop->hexsz)) { + test_msg("BUG: hex string (%s) bigger than maximum allowed (%lu)", + hex, (unsigned long)algop->hexsz); + return -1; + } + + strbuf_add(&buf, hex, sz); + strbuf_addchars(&buf, '0', algop->hexsz - sz); + + ret = get_oid_hex_algop(buf.buf, oid, algop); + if (!check_int(ret, ==, 0)) + test_msg("BUG: invalid hex input (%s) provided", hex); + + strbuf_release(&buf); + return ret; +} + +int get_oid_arbitrary_hex(const char *hex, struct object_id *oid) +{ + int hash_algo = init_hash_algo(); + + if (!check_int(hash_algo, !=, GIT_HASH_UNKNOWN)) + return -1; + return get_oid_arbitrary_hex_algop(hex, oid, &hash_algos[hash_algo]); +} diff --git a/t/unit-tests/lib-oid.h b/t/unit-tests/lib-oid.h new file mode 100644 index 0000000000..8d2acca768 --- /dev/null +++ b/t/unit-tests/lib-oid.h @@ -0,0 +1,17 @@ +#ifndef LIB_OID_H +#define LIB_OID_H + +#include "hash.h" + +/* + * Convert arbitrary hex string to object_id. + * For example, passing "abc12" will generate + * "abc1200000000000000000000000000000000000" hex of length 40 for SHA-1 and + * create object_id with that. + * WARNING: passing a string of length more than the hexsz of respective hash + * algo is not allowed. The hash algo is decided based on GIT_TEST_DEFAULT_HASH + * environment variable. + */ +int get_oid_arbitrary_hex(const char *s, struct object_id *oid); + +#endif /* LIB_OID_H */ diff --git a/t/unit-tests/t-example-decorate.c b/t/unit-tests/t-example-decorate.c new file mode 100644 index 0000000000..a4a75db735 --- /dev/null +++ b/t/unit-tests/t-example-decorate.c @@ -0,0 +1,82 @@ +#define USE_THE_REPOSITORY_VARIABLE + +#include "test-lib.h" +#include "object.h" +#include "decorate.h" +#include "repository.h" + +struct test_vars { + struct object *one, *two, *three; + struct decoration n; + int decoration_a, decoration_b; +}; + +static void t_add(struct test_vars *vars) +{ + void *ret = add_decoration(&vars->n, vars->one, &vars->decoration_a); + + if (!check(ret == NULL)) + test_msg("when adding a brand-new object, NULL should be returned"); + ret = add_decoration(&vars->n, vars->two, NULL); + if (!check(ret == NULL)) + test_msg("when adding a brand-new object, NULL should be returned"); +} + +static void t_readd(struct test_vars *vars) +{ + void *ret = add_decoration(&vars->n, vars->one, NULL); + + if (!check(ret == &vars->decoration_a)) + test_msg("when readding an already existing object, existing decoration should be returned"); + ret = add_decoration(&vars->n, vars->two, &vars->decoration_b); + if (!check(ret == NULL)) + test_msg("when readding an already existing object, existing decoration should be returned"); +} + +static void t_lookup(struct test_vars *vars) +{ + void *ret = lookup_decoration(&vars->n, vars->one); + + if (!check(ret == NULL)) + test_msg("lookup should return added declaration"); + ret = lookup_decoration(&vars->n, vars->two); + if (!check(ret == &vars->decoration_b)) + test_msg("lookup should return added declaration"); + ret = lookup_decoration(&vars->n, vars->three); + if (!check(ret == NULL)) + test_msg("lookup for unknown object should return NULL"); +} + +static void t_loop(struct test_vars *vars) +{ + int i, objects_noticed = 0; + + for (i = 0; i < vars->n.size; i++) { + if (vars->n.entries[i].base) + objects_noticed++; + } + if (!check_int(objects_noticed, ==, 2)) + test_msg("should have 2 objects"); +} + +int cmd_main(int argc UNUSED, const char **argv UNUSED) +{ + struct object_id one_oid = { { 1 } }, two_oid = { { 2 } }, three_oid = { { 3 } }; + struct test_vars vars = { 0 }; + + vars.one = lookup_unknown_object(the_repository, &one_oid); + vars.two = lookup_unknown_object(the_repository, &two_oid); + vars.three = lookup_unknown_object(the_repository, &three_oid); + + TEST(t_add(&vars), + "Add 2 objects, one with a non-NULL decoration and one with a NULL decoration."); + TEST(t_readd(&vars), + "When re-adding an already existing object, the old decoration is returned."); + TEST(t_lookup(&vars), + "Lookup returns the added declarations, or NULL if the object was never added."); + TEST(t_loop(&vars), "The user can also loop through all entries."); + + clear_decoration(&vars.n, NULL); + + return test_done(); +} diff --git a/t/unit-tests/t-hash.c b/t/unit-tests/t-hash.c new file mode 100644 index 0000000000..e9a78bf2c0 --- /dev/null +++ b/t/unit-tests/t-hash.c @@ -0,0 +1,84 @@ +#include "test-lib.h" +#include "hex.h" +#include "strbuf.h" + +static void check_hash_data(const void *data, size_t data_length, + const char *expected_hashes[]) +{ + if (!check(data != NULL)) { + test_msg("BUG: NULL data pointer provided"); + return; + } + + for (size_t i = 1; i < ARRAY_SIZE(hash_algos); i++) { + git_hash_ctx ctx; + unsigned char hash[GIT_MAX_HEXSZ]; + const struct git_hash_algo *algop = &hash_algos[i]; + + algop->init_fn(&ctx); + algop->update_fn(&ctx, data, data_length); + algop->final_fn(hash, &ctx); + + if (!check_str(hash_to_hex_algop(hash, algop), expected_hashes[i - 1])) + test_msg("result does not match with the expected for %s\n", hash_algos[i].name); + } +} + +/* Works with a NUL terminated string. Doesn't work if it should contain a NUL character. */ +#define TEST_HASH_STR(data, expected_sha1, expected_sha256) do { \ + const char *expected_hashes[] = { expected_sha1, expected_sha256 }; \ + TEST(check_hash_data(data, strlen(data), expected_hashes), \ + "SHA1 and SHA256 (%s) works", #data); \ + } while (0) + +/* Only works with a literal string, useful when it contains a NUL character. */ +#define TEST_HASH_LITERAL(literal, expected_sha1, expected_sha256) do { \ + const char *expected_hashes[] = { expected_sha1, expected_sha256 }; \ + TEST(check_hash_data(literal, (sizeof(literal) - 1), expected_hashes), \ + "SHA1 and SHA256 (%s) works", #literal); \ + } while (0) + +int cmd_main(int argc, const char **argv) +{ + struct strbuf aaaaaaaaaa_100000 = STRBUF_INIT; + struct strbuf alphabet_100000 = STRBUF_INIT; + + strbuf_addstrings(&aaaaaaaaaa_100000, "aaaaaaaaaa", 100000); + strbuf_addstrings(&alphabet_100000, "abcdefghijklmnopqrstuvwxyz", 100000); + + TEST_HASH_STR("", + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + TEST_HASH_STR("a", + "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", + "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"); + TEST_HASH_STR("abc", + "a9993e364706816aba3e25717850c26c9cd0d89d", + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"); + TEST_HASH_STR("message digest", + "c12252ceda8be8994d5fa0290a47231c1d16aae3", + "f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650"); + TEST_HASH_STR("abcdefghijklmnopqrstuvwxyz", + "32d10c7b8cf96570ca04ce37f2a19d84240d3a89", + "71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73"); + TEST_HASH_STR(aaaaaaaaaa_100000.buf, + "34aa973cd4c4daa4f61eeb2bdbad27316534016f", + "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"); + TEST_HASH_STR(alphabet_100000.buf, + "e7da7c55b3484fdf52aebec9cbe7b85a98f02fd4", + "e406ba321ca712ad35a698bf0af8d61fc4dc40eca6bdcea4697962724ccbde35"); + TEST_HASH_LITERAL("blob 0\0", + "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813"); + TEST_HASH_LITERAL("blob 3\0abc", + "f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f", + "c1cf6e465077930e88dc5136641d402f72a229ddd996f627d60e9639eaba35a6"); + TEST_HASH_LITERAL("tree 0\0", + "4b825dc642cb6eb9a060e54bf8d69288fbee4904", + "6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321"); + + strbuf_release(&aaaaaaaaaa_100000); + strbuf_release(&alphabet_100000); + + return test_done(); +} diff --git a/t/unit-tests/t-oidmap.c b/t/unit-tests/t-oidmap.c new file mode 100644 index 0000000000..b22e52d08b --- /dev/null +++ b/t/unit-tests/t-oidmap.c @@ -0,0 +1,181 @@ +#include "test-lib.h" +#include "lib-oid.h" +#include "oidmap.h" +#include "hash.h" +#include "hex.h" + +/* + * Elements we will put in oidmap structs are made of a key: the entry.oid + * field, which is of type struct object_id, and a value: the name field (could + * be a refname for example). + */ +struct test_entry { + struct oidmap_entry entry; + char name[FLEX_ARRAY]; +}; + +static const char *const key_val[][2] = { { "11", "one" }, + { "22", "two" }, + { "33", "three" } }; + +static void setup(void (*f)(struct oidmap *map)) +{ + struct oidmap map = OIDMAP_INIT; + int ret = 0; + + for (size_t i = 0; i < ARRAY_SIZE(key_val); i++){ + struct test_entry *entry; + + FLEX_ALLOC_STR(entry, name, key_val[i][1]); + if ((ret = get_oid_arbitrary_hex(key_val[i][0], &entry->entry.oid))) { + free(entry); + break; + } + entry = oidmap_put(&map, entry); + if (!check(entry == NULL)) + free(entry); + } + + if (!ret) + f(&map); + oidmap_free(&map, 1); +} + +static void t_replace(struct oidmap *map) +{ + struct test_entry *entry, *prev; + + FLEX_ALLOC_STR(entry, name, "un"); + if (get_oid_arbitrary_hex("11", &entry->entry.oid)) + return; + prev = oidmap_put(map, entry); + if (!check(prev != NULL)) + return; + check_str(prev->name, "one"); + free(prev); + + FLEX_ALLOC_STR(entry, name, "deux"); + if (get_oid_arbitrary_hex("22", &entry->entry.oid)) + return; + prev = oidmap_put(map, entry); + if (!check(prev != NULL)) + return; + check_str(prev->name, "two"); + free(prev); +} + +static void t_get(struct oidmap *map) +{ + struct test_entry *entry; + struct object_id oid; + + if (get_oid_arbitrary_hex("22", &oid)) + return; + entry = oidmap_get(map, &oid); + if (!check(entry != NULL)) + return; + check_str(entry->name, "two"); + + if (get_oid_arbitrary_hex("44", &oid)) + return; + check(oidmap_get(map, &oid) == NULL); + + if (get_oid_arbitrary_hex("11", &oid)) + return; + entry = oidmap_get(map, &oid); + if (!check(entry != NULL)) + return; + check_str(entry->name, "one"); +} + +static void t_remove(struct oidmap *map) +{ + struct test_entry *entry; + struct object_id oid; + + if (get_oid_arbitrary_hex("11", &oid)) + return; + entry = oidmap_remove(map, &oid); + if (!check(entry != NULL)) + return; + check_str(entry->name, "one"); + check(oidmap_get(map, &oid) == NULL); + free(entry); + + if (get_oid_arbitrary_hex("22", &oid)) + return; + entry = oidmap_remove(map, &oid); + if (!check(entry != NULL)) + return; + check_str(entry->name, "two"); + check(oidmap_get(map, &oid) == NULL); + free(entry); + + if (get_oid_arbitrary_hex("44", &oid)) + return; + check(oidmap_remove(map, &oid) == NULL); +} + +static int key_val_contains(struct test_entry *entry, char seen[]) +{ + for (size_t i = 0; i < ARRAY_SIZE(key_val); i++) { + struct object_id oid; + + if (get_oid_arbitrary_hex(key_val[i][0], &oid)) + return -1; + + if (oideq(&entry->entry.oid, &oid)) { + if (seen[i]) + return 2; + seen[i] = 1; + return 0; + } + } + return 1; +} + +static void t_iterate(struct oidmap *map) +{ + struct oidmap_iter iter; + struct test_entry *entry; + char seen[ARRAY_SIZE(key_val)] = { 0 }; + int count = 0; + + oidmap_iter_init(map, &iter); + while ((entry = oidmap_iter_next(&iter))) { + int ret; + if (!check_int((ret = key_val_contains(entry, seen)), ==, 0)) { + switch (ret) { + case -1: + break; /* error message handled by get_oid_arbitrary_hex() */ + case 1: + test_msg("obtained entry was not given in the input\n" + " name: %s\n oid: %s\n", + entry->name, oid_to_hex(&entry->entry.oid)); + break; + case 2: + test_msg("duplicate entry detected\n" + " name: %s\n oid: %s\n", + entry->name, oid_to_hex(&entry->entry.oid)); + break; + default: + test_msg("BUG: invalid return value (%d) from key_val_contains()", + ret); + break; + } + } else { + count++; + } + } + check_int(count, ==, ARRAY_SIZE(key_val)); + check_int(hashmap_get_size(&map->map), ==, ARRAY_SIZE(key_val)); +} + +int cmd_main(int argc UNUSED, const char **argv UNUSED) +{ + TEST(setup(t_replace), "replace works"); + TEST(setup(t_get), "get works"); + TEST(setup(t_remove), "remove works"); + TEST(setup(t_iterate), "iterate works"); + return test_done(); +} diff --git a/t/unit-tests/t-oidtree.c b/t/unit-tests/t-oidtree.c new file mode 100644 index 0000000000..a38754b066 --- /dev/null +++ b/t/unit-tests/t-oidtree.c @@ -0,0 +1,122 @@ +#include "test-lib.h" +#include "lib-oid.h" +#include "oidtree.h" +#include "hash.h" +#include "hex.h" +#include "strvec.h" + +#define FILL_TREE(tree, ...) \ + do { \ + const char *hexes[] = { __VA_ARGS__ }; \ + if (fill_tree_loc(tree, hexes, ARRAY_SIZE(hexes))) \ + return; \ + } while (0) + +static int fill_tree_loc(struct oidtree *ot, const char *hexes[], size_t n) +{ + for (size_t i = 0; i < n; i++) { + struct object_id oid; + if (!check_int(get_oid_arbitrary_hex(hexes[i], &oid), ==, 0)) + return -1; + oidtree_insert(ot, &oid); + } + return 0; +} + +static void check_contains(struct oidtree *ot, const char *hex, int expected) +{ + struct object_id oid; + + if (!check_int(get_oid_arbitrary_hex(hex, &oid), ==, 0)) + return; + if (!check_int(oidtree_contains(ot, &oid), ==, expected)) + test_msg("oid: %s", oid_to_hex(&oid)); +} + +struct expected_hex_iter { + size_t i; + struct strvec expected_hexes; + const char *query; +}; + +static enum cb_next check_each_cb(const struct object_id *oid, void *data) +{ + struct expected_hex_iter *hex_iter = data; + struct object_id expected; + + if (!check_int(hex_iter->i, <, hex_iter->expected_hexes.nr)) { + test_msg("error: extraneous callback for query: ('%s'), object_id: ('%s')", + hex_iter->query, oid_to_hex(oid)); + return CB_BREAK; + } + + if (!check_int(get_oid_arbitrary_hex(hex_iter->expected_hexes.v[hex_iter->i], + &expected), ==, 0)) + ; /* the data is bogus and cannot be used */ + else if (!check(oideq(oid, &expected))) + test_msg("expected: %s\n got: %s\n query: %s", + oid_to_hex(&expected), oid_to_hex(oid), hex_iter->query); + + hex_iter->i += 1; + return CB_CONTINUE; +} + +LAST_ARG_MUST_BE_NULL +static void check_each(struct oidtree *ot, const char *query, ...) +{ + struct object_id oid; + struct expected_hex_iter hex_iter = { .expected_hexes = STRVEC_INIT, + .query = query }; + const char *arg; + va_list hex_args; + + va_start(hex_args, query); + while ((arg = va_arg(hex_args, const char *))) + strvec_push(&hex_iter.expected_hexes, arg); + va_end(hex_args); + + if (!check_int(get_oid_arbitrary_hex(query, &oid), ==, 0)) + return; + oidtree_each(ot, &oid, strlen(query), check_each_cb, &hex_iter); + + if (!check_int(hex_iter.i, ==, hex_iter.expected_hexes.nr)) + test_msg("error: could not find some 'object_id's for query ('%s')", query); + strvec_clear(&hex_iter.expected_hexes); +} + +static void setup(void (*f)(struct oidtree *ot)) +{ + struct oidtree ot; + + oidtree_init(&ot); + f(&ot); + oidtree_clear(&ot); +} + +static void t_contains(struct oidtree *ot) +{ + FILL_TREE(ot, "444", "1", "2", "3", "4", "5", "a", "b", "c", "d", "e"); + check_contains(ot, "44", 0); + check_contains(ot, "441", 0); + check_contains(ot, "440", 0); + check_contains(ot, "444", 1); + check_contains(ot, "4440", 1); + check_contains(ot, "4444", 0); +} + +static void t_each(struct oidtree *ot) +{ + FILL_TREE(ot, "f", "9", "8", "123", "321", "320", "a", "b", "c", "d", "e"); + check_each(ot, "12300", "123", NULL); + check_each(ot, "3211", NULL); /* should not reach callback */ + check_each(ot, "3210", "321", NULL); + check_each(ot, "32100", "321", NULL); + check_each(ot, "32", "320", "321", NULL); +} + +int cmd_main(int argc UNUSED, const char **argv UNUSED) +{ + TEST(setup(t_contains), "oidtree insert and contains works"); + TEST(setup(t_each), "oidtree each works"); + return test_done(); +} diff --git a/t/unit-tests/t-reftable-basics.c b/t/unit-tests/t-reftable-basics.c new file mode 100644 index 0000000000..4e80bdf16d --- /dev/null +++ b/t/unit-tests/t-reftable-basics.c @@ -0,0 +1,160 @@ +/* +Copyright 2020 Google LLC + +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file or at +https://developers.google.com/open-source/licenses/bsd +*/ + +#include "test-lib.h" +#include "reftable/basics.h" + +struct integer_needle_lesseq_args { + int needle; + int *haystack; +}; + +static int integer_needle_lesseq(size_t i, void *_args) +{ + struct integer_needle_lesseq_args *args = _args; + return args->needle <= args->haystack[i]; +} + +static void test_binsearch(void) +{ + int haystack[] = { 2, 4, 6, 8, 10 }; + struct { + int needle; + size_t expected_idx; + } testcases[] = { + {-9000, 0}, + {-1, 0}, + {0, 0}, + {2, 0}, + {3, 1}, + {4, 1}, + {7, 3}, + {9, 4}, + {10, 4}, + {11, 5}, + {9000, 5}, + }; + + for (size_t i = 0; i < ARRAY_SIZE(testcases); i++) { + struct integer_needle_lesseq_args args = { + .haystack = haystack, + .needle = testcases[i].needle, + }; + size_t idx; + + idx = binsearch(ARRAY_SIZE(haystack), &integer_needle_lesseq, &args); + check_int(idx, ==, testcases[i].expected_idx); + } +} + +static void test_names_length(void) +{ + const char *a[] = { "a", "b", NULL }; + check_int(names_length(a), ==, 2); +} + +static void test_names_equal(void) +{ + const char *a[] = { "a", "b", "c", NULL }; + const char *b[] = { "a", "b", "d", NULL }; + const char *c[] = { "a", "b", NULL }; + + check(names_equal(a, a)); + check(!names_equal(a, b)); + check(!names_equal(a, c)); +} + +static void test_parse_names_normal(void) +{ + char in1[] = "line\n"; + char in2[] = "a\nb\nc"; + char **out = NULL; + parse_names(in1, strlen(in1), &out); + check_str(out[0], "line"); + check(!out[1]); + free_names(out); + + parse_names(in2, strlen(in2), &out); + check_str(out[0], "a"); + check_str(out[1], "b"); + check_str(out[2], "c"); + check(!out[3]); + free_names(out); +} + +static void test_parse_names_drop_empty(void) +{ + char in[] = "a\n\nb\n"; + char **out = NULL; + parse_names(in, strlen(in), &out); + check_str(out[0], "a"); + /* simply '\n' should be dropped as empty string */ + check_str(out[1], "b"); + check(!out[2]); + free_names(out); +} + +static void test_common_prefix(void) +{ + struct strbuf a = STRBUF_INIT; + struct strbuf b = STRBUF_INIT; + struct { + const char *a, *b; + int want; + } cases[] = { + {"abcdef", "abc", 3}, + { "abc", "ab", 2 }, + { "", "abc", 0 }, + { "abc", "abd", 2 }, + { "abc", "pqr", 0 }, + }; + + for (size_t i = 0; i < ARRAY_SIZE(cases); i++) { + strbuf_addstr(&a, cases[i].a); + strbuf_addstr(&b, cases[i].b); + check_int(common_prefix_size(&a, &b), ==, cases[i].want); + strbuf_reset(&a); + strbuf_reset(&b); + } + strbuf_release(&a); + strbuf_release(&b); +} + +static void test_u24_roundtrip(void) +{ + uint32_t in = 0x112233; + uint8_t dest[3]; + uint32_t out; + put_be24(dest, in); + out = get_be24(dest); + check_int(in, ==, out); +} + +static void test_u16_roundtrip(void) +{ + uint32_t in = 0xfef1; + uint8_t dest[3]; + uint32_t out; + put_be16(dest, in); + out = get_be16(dest); + check_int(in, ==, out); +} + +int cmd_main(int argc, const char *argv[]) +{ + TEST(test_common_prefix(), "common_prefix_size works"); + TEST(test_parse_names_normal(), "parse_names works for basic input"); + TEST(test_parse_names_drop_empty(), "parse_names drops empty string"); + TEST(test_binsearch(), "binary search with binsearch works"); + TEST(test_names_length(), "names_length retuns size of a NULL-terminated string array"); + TEST(test_names_equal(), "names_equal compares NULL-terminated string arrays"); + TEST(test_u24_roundtrip(), "put_be24 and get_be24 work"); + TEST(test_u16_roundtrip(), "put_be16 and get_be16 work"); + + return test_done(); +} diff --git a/t/unit-tests/t-reftable-record.c b/t/unit-tests/t-reftable-record.c new file mode 100644 index 0000000000..cb649ee419 --- /dev/null +++ b/t/unit-tests/t-reftable-record.c @@ -0,0 +1,551 @@ +/* + Copyright 2020 Google LLC + + Use of this source code is governed by a BSD-style + license that can be found in the LICENSE file or at + https://developers.google.com/open-source/licenses/bsd +*/ + +#include "test-lib.h" +#include "reftable/constants.h" +#include "reftable/record.h" + +static void t_copy(struct reftable_record *rec) +{ + struct reftable_record copy; + uint8_t typ; + + typ = reftable_record_type(rec); + reftable_record_init(©, typ); + reftable_record_copy_from(©, rec, GIT_SHA1_RAWSZ); + /* do it twice to catch memory leaks */ + reftable_record_copy_from(©, rec, GIT_SHA1_RAWSZ); + check(reftable_record_equal(rec, ©, GIT_SHA1_RAWSZ)); + + reftable_record_release(©); +} + +static void t_varint_roundtrip(void) +{ + uint64_t inputs[] = { 0, + 1, + 27, + 127, + 128, + 257, + 4096, + ((uint64_t)1 << 63), + ((uint64_t)1 << 63) + ((uint64_t)1 << 63) - 1 }; + + for (size_t i = 0; i < ARRAY_SIZE(inputs); i++) { + uint8_t dest[10]; + + struct string_view out = { + .buf = dest, + .len = sizeof(dest), + }; + uint64_t in = inputs[i]; + int n = put_var_int(&out, in); + uint64_t got = 0; + + check_int(n, >, 0); + out.len = n; + n = get_var_int(&got, &out); + check_int(n, >, 0); + + check_int(got, ==, in); + } +} + +static void set_hash(uint8_t *h, int j) +{ + for (int i = 0; i < hash_size(GIT_SHA1_FORMAT_ID); i++) + h[i] = (j >> i) & 0xff; +} + +static void t_reftable_ref_record_comparison(void) +{ + struct reftable_record in[3] = { + { + .type = BLOCK_TYPE_REF, + .u.ref.refname = (char *) "refs/heads/master", + .u.ref.value_type = REFTABLE_REF_VAL1, + }, + { + .type = BLOCK_TYPE_REF, + .u.ref.refname = (char *) "refs/heads/master", + .u.ref.value_type = REFTABLE_REF_DELETION, + }, + { + .type = BLOCK_TYPE_REF, + .u.ref.refname = (char *) "HEAD", + .u.ref.value_type = REFTABLE_REF_SYMREF, + .u.ref.value.symref = (char *) "refs/heads/master", + }, + }; + + check(!reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); + check(!reftable_record_cmp(&in[0], &in[1])); + + check(!reftable_record_equal(&in[1], &in[2], GIT_SHA1_RAWSZ)); + check_int(reftable_record_cmp(&in[1], &in[2]), >, 0); + + in[1].u.ref.value_type = in[0].u.ref.value_type; + check(reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); + check(!reftable_record_cmp(&in[0], &in[1])); +} + +static void t_reftable_ref_record_compare_name(void) +{ + struct reftable_ref_record recs[3] = { + { + .refname = (char *) "refs/heads/a" + }, + { + .refname = (char *) "refs/heads/b" + }, + { + .refname = (char *) "refs/heads/a" + }, + }; + + check_int(reftable_ref_record_compare_name(&recs[0], &recs[1]), <, 0); + check_int(reftable_ref_record_compare_name(&recs[1], &recs[0]), >, 0); + check_int(reftable_ref_record_compare_name(&recs[0], &recs[2]), ==, 0); +} + +static void t_reftable_ref_record_roundtrip(void) +{ + struct strbuf scratch = STRBUF_INIT; + + for (int i = REFTABLE_REF_DELETION; i < REFTABLE_NR_REF_VALUETYPES; i++) { + struct reftable_record in = { + .type = BLOCK_TYPE_REF, + .u.ref.value_type = i, + }; + struct reftable_record out = { .type = BLOCK_TYPE_REF }; + struct strbuf key = STRBUF_INIT; + uint8_t buffer[1024] = { 0 }; + struct string_view dest = { + .buf = buffer, + .len = sizeof(buffer), + }; + int n, m; + + in.u.ref.value_type = i; + switch (i) { + case REFTABLE_REF_DELETION: + break; + case REFTABLE_REF_VAL1: + set_hash(in.u.ref.value.val1, 1); + break; + case REFTABLE_REF_VAL2: + set_hash(in.u.ref.value.val2.value, 1); + set_hash(in.u.ref.value.val2.target_value, 2); + break; + case REFTABLE_REF_SYMREF: + in.u.ref.value.symref = xstrdup("target"); + break; + } + in.u.ref.refname = xstrdup("refs/heads/master"); + + t_copy(&in); + + check_int(reftable_record_val_type(&in), ==, i); + check_int(reftable_record_is_deletion(&in), ==, i == REFTABLE_REF_DELETION); + + reftable_record_key(&in, &key); + n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ); + check_int(n, >, 0); + + /* decode into a non-zero reftable_record to test for leaks. */ + m = reftable_record_decode(&out, key, i, dest, GIT_SHA1_RAWSZ, &scratch); + check_int(n, ==, m); + + check(reftable_ref_record_equal(&in.u.ref, &out.u.ref, + GIT_SHA1_RAWSZ)); + reftable_record_release(&in); + + strbuf_release(&key); + reftable_record_release(&out); + } + + strbuf_release(&scratch); +} + +static void t_reftable_log_record_comparison(void) +{ + struct reftable_record in[3] = { + { + .type = BLOCK_TYPE_LOG, + .u.log.refname = (char *) "refs/heads/master", + .u.log.update_index = 42, + }, + { + .type = BLOCK_TYPE_LOG, + .u.log.refname = (char *) "refs/heads/master", + .u.log.update_index = 22, + }, + { + .type = BLOCK_TYPE_LOG, + .u.log.refname = (char *) "refs/heads/main", + .u.log.update_index = 22, + }, + }; + + check(!reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); + check(!reftable_record_equal(&in[1], &in[2], GIT_SHA1_RAWSZ)); + check_int(reftable_record_cmp(&in[1], &in[2]), >, 0); + /* comparison should be reversed for equal keys, because + * comparison is now performed on the basis of update indices */ + check_int(reftable_record_cmp(&in[0], &in[1]), <, 0); + + in[1].u.log.update_index = in[0].u.log.update_index; + check(reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); + check(!reftable_record_cmp(&in[0], &in[1])); +} + +static void t_reftable_log_record_compare_key(void) +{ + struct reftable_log_record logs[3] = { + { + .refname = (char *) "refs/heads/a", + .update_index = 1, + }, + { + .refname = (char *) "refs/heads/b", + .update_index = 2, + }, + { + .refname = (char *) "refs/heads/a", + .update_index = 3, + }, + }; + + check_int(reftable_log_record_compare_key(&logs[0], &logs[1]), <, 0); + check_int(reftable_log_record_compare_key(&logs[1], &logs[0]), >, 0); + + logs[1].update_index = logs[0].update_index; + check_int(reftable_log_record_compare_key(&logs[0], &logs[1]), <, 0); + + check_int(reftable_log_record_compare_key(&logs[0], &logs[2]), >, 0); + check_int(reftable_log_record_compare_key(&logs[2], &logs[0]), <, 0); + logs[2].update_index = logs[0].update_index; + check_int(reftable_log_record_compare_key(&logs[0], &logs[2]), ==, 0); +} + +static void t_reftable_log_record_roundtrip(void) +{ + struct reftable_log_record in[] = { + { + .refname = xstrdup("refs/heads/master"), + .update_index = 42, + .value_type = REFTABLE_LOG_UPDATE, + .value = { + .update = { + .name = xstrdup("han-wen"), + .email = xstrdup("hanwen@google.com"), + .message = xstrdup("test"), + .time = 1577123507, + .tz_offset = 100, + }, + } + }, + { + .refname = xstrdup("refs/heads/master"), + .update_index = 22, + .value_type = REFTABLE_LOG_DELETION, + }, + { + .refname = xstrdup("branch"), + .update_index = 33, + .value_type = REFTABLE_LOG_UPDATE, + } + }; + struct strbuf scratch = STRBUF_INIT; + set_hash(in[0].value.update.new_hash, 1); + set_hash(in[0].value.update.old_hash, 2); + set_hash(in[2].value.update.new_hash, 3); + set_hash(in[2].value.update.old_hash, 4); + + check(!reftable_log_record_is_deletion(&in[0])); + check(reftable_log_record_is_deletion(&in[1])); + check(!reftable_log_record_is_deletion(&in[2])); + + for (size_t i = 0; i < ARRAY_SIZE(in); i++) { + struct reftable_record rec = { .type = BLOCK_TYPE_LOG }; + struct strbuf key = STRBUF_INIT; + uint8_t buffer[1024] = { 0 }; + struct string_view dest = { + .buf = buffer, + .len = sizeof(buffer), + }; + /* populate out, to check for leaks. */ + struct reftable_record out = { + .type = BLOCK_TYPE_LOG, + .u.log = { + .refname = xstrdup("old name"), + .value_type = REFTABLE_LOG_UPDATE, + .value = { + .update = { + .name = xstrdup("old name"), + .email = xstrdup("old@email"), + .message = xstrdup("old message"), + }, + }, + }, + }; + int n, m, valtype; + + rec.u.log = in[i]; + + t_copy(&rec); + + reftable_record_key(&rec, &key); + + n = reftable_record_encode(&rec, dest, GIT_SHA1_RAWSZ); + check_int(n, >=, 0); + valtype = reftable_record_val_type(&rec); + m = reftable_record_decode(&out, key, valtype, dest, + GIT_SHA1_RAWSZ, &scratch); + check_int(n, ==, m); + + check(reftable_log_record_equal(&in[i], &out.u.log, + GIT_SHA1_RAWSZ)); + reftable_log_record_release(&in[i]); + strbuf_release(&key); + reftable_record_release(&out); + } + + strbuf_release(&scratch); +} + +static void t_key_roundtrip(void) +{ + uint8_t buffer[1024] = { 0 }; + struct string_view dest = { + .buf = buffer, + .len = sizeof(buffer), + }; + struct strbuf last_key = STRBUF_INIT; + struct strbuf key = STRBUF_INIT; + struct strbuf roundtrip = STRBUF_INIT; + int restart; + uint8_t extra; + int n, m; + uint8_t rt_extra; + + strbuf_addstr(&last_key, "refs/heads/master"); + strbuf_addstr(&key, "refs/tags/bla"); + extra = 6; + n = reftable_encode_key(&restart, dest, last_key, key, extra); + check(!restart); + check_int(n, >, 0); + + strbuf_addstr(&roundtrip, "refs/heads/master"); + m = reftable_decode_key(&roundtrip, &rt_extra, dest); + check_int(n, ==, m); + check(!strbuf_cmp(&key, &roundtrip)); + check_int(rt_extra, ==, extra); + + strbuf_release(&last_key); + strbuf_release(&key); + strbuf_release(&roundtrip); +} + +static void t_reftable_obj_record_comparison(void) +{ + + uint8_t id_bytes[] = { 0, 1, 2, 3, 4, 5, 6 }; + uint64_t offsets[] = { 0, 16, 32, 48, 64, 80, 96, 112}; + struct reftable_record in[3] = { + { + .type = BLOCK_TYPE_OBJ, + .u.obj.hash_prefix = id_bytes, + .u.obj.hash_prefix_len = 7, + .u.obj.offsets = offsets, + .u.obj.offset_len = 8, + }, + { + .type = BLOCK_TYPE_OBJ, + .u.obj.hash_prefix = id_bytes, + .u.obj.hash_prefix_len = 7, + .u.obj.offsets = offsets, + .u.obj.offset_len = 5, + }, + { + .type = BLOCK_TYPE_OBJ, + .u.obj.hash_prefix = id_bytes, + .u.obj.hash_prefix_len = 5, + }, + }; + + check(!reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); + check(!reftable_record_cmp(&in[0], &in[1])); + + check(!reftable_record_equal(&in[1], &in[2], GIT_SHA1_RAWSZ)); + check_int(reftable_record_cmp(&in[1], &in[2]), >, 0); + + in[1].u.obj.offset_len = in[0].u.obj.offset_len; + check(reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); + check(!reftable_record_cmp(&in[0], &in[1])); +} + +static void t_reftable_obj_record_roundtrip(void) +{ + uint8_t testHash1[GIT_SHA1_RAWSZ] = { 1, 2, 3, 4, 0 }; + uint64_t till9[] = { 1, 2, 3, 4, 500, 600, 700, 800, 9000 }; + struct reftable_obj_record recs[3] = { + { + .hash_prefix = testHash1, + .hash_prefix_len = 5, + .offsets = till9, + .offset_len = 3, + }, + { + .hash_prefix = testHash1, + .hash_prefix_len = 5, + .offsets = till9, + .offset_len = 9, + }, + { + .hash_prefix = testHash1, + .hash_prefix_len = 5, + }, + }; + struct strbuf scratch = STRBUF_INIT; + + for (size_t i = 0; i < ARRAY_SIZE(recs); i++) { + uint8_t buffer[1024] = { 0 }; + struct string_view dest = { + .buf = buffer, + .len = sizeof(buffer), + }; + struct reftable_record in = { + .type = BLOCK_TYPE_OBJ, + .u = { + .obj = recs[i], + }, + }; + struct strbuf key = STRBUF_INIT; + struct reftable_record out = { .type = BLOCK_TYPE_OBJ }; + int n, m; + uint8_t extra; + + check(!reftable_record_is_deletion(&in)); + t_copy(&in); + reftable_record_key(&in, &key); + n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ); + check_int(n, >, 0); + extra = reftable_record_val_type(&in); + m = reftable_record_decode(&out, key, extra, dest, + GIT_SHA1_RAWSZ, &scratch); + check_int(n, ==, m); + + check(reftable_record_equal(&in, &out, GIT_SHA1_RAWSZ)); + strbuf_release(&key); + reftable_record_release(&out); + } + + strbuf_release(&scratch); +} + +static void t_reftable_index_record_comparison(void) +{ + struct reftable_record in[3] = { + { + .type = BLOCK_TYPE_INDEX, + .u.idx.offset = 22, + .u.idx.last_key = STRBUF_INIT, + }, + { + .type = BLOCK_TYPE_INDEX, + .u.idx.offset = 32, + .u.idx.last_key = STRBUF_INIT, + }, + { + .type = BLOCK_TYPE_INDEX, + .u.idx.offset = 32, + .u.idx.last_key = STRBUF_INIT, + }, + }; + strbuf_addstr(&in[0].u.idx.last_key, "refs/heads/master"); + strbuf_addstr(&in[1].u.idx.last_key, "refs/heads/master"); + strbuf_addstr(&in[2].u.idx.last_key, "refs/heads/branch"); + + check(!reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); + check(!reftable_record_cmp(&in[0], &in[1])); + + check(!reftable_record_equal(&in[1], &in[2], GIT_SHA1_RAWSZ)); + check_int(reftable_record_cmp(&in[1], &in[2]), >, 0); + + in[1].u.idx.offset = in[0].u.idx.offset; + check(reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); + check(!reftable_record_cmp(&in[0], &in[1])); + + for (size_t i = 0; i < ARRAY_SIZE(in); i++) + reftable_record_release(&in[i]); +} + +static void t_reftable_index_record_roundtrip(void) +{ + struct reftable_record in = { + .type = BLOCK_TYPE_INDEX, + .u.idx = { + .offset = 42, + .last_key = STRBUF_INIT, + }, + }; + uint8_t buffer[1024] = { 0 }; + struct string_view dest = { + .buf = buffer, + .len = sizeof(buffer), + }; + struct strbuf scratch = STRBUF_INIT; + struct strbuf key = STRBUF_INIT; + struct reftable_record out = { + .type = BLOCK_TYPE_INDEX, + .u.idx = { .last_key = STRBUF_INIT }, + }; + int n, m; + uint8_t extra; + + strbuf_addstr(&in.u.idx.last_key, "refs/heads/master"); + reftable_record_key(&in, &key); + t_copy(&in); + + check(!reftable_record_is_deletion(&in)); + check(!strbuf_cmp(&key, &in.u.idx.last_key)); + n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ); + check_int(n, >, 0); + + extra = reftable_record_val_type(&in); + m = reftable_record_decode(&out, key, extra, dest, GIT_SHA1_RAWSZ, + &scratch); + check_int(m, ==, n); + + check(reftable_record_equal(&in, &out, GIT_SHA1_RAWSZ)); + + reftable_record_release(&out); + strbuf_release(&key); + strbuf_release(&scratch); + strbuf_release(&in.u.idx.last_key); +} + +int cmd_main(int argc, const char *argv[]) +{ + TEST(t_reftable_ref_record_comparison(), "comparison operations work on ref record"); + TEST(t_reftable_log_record_comparison(), "comparison operations work on log record"); + TEST(t_reftable_index_record_comparison(), "comparison operations work on index record"); + TEST(t_reftable_obj_record_comparison(), "comparison operations work on obj record"); + TEST(t_reftable_ref_record_compare_name(), "reftable_ref_record_compare_name works"); + TEST(t_reftable_log_record_compare_key(), "reftable_log_record_compare_key works"); + TEST(t_reftable_log_record_roundtrip(), "record operations work on log record"); + TEST(t_reftable_ref_record_roundtrip(), "record operations work on ref record"); + TEST(t_varint_roundtrip(), "put_var_int and get_var_int work"); + TEST(t_key_roundtrip(), "reftable_encode_key and reftable_decode_key work"); + TEST(t_reftable_obj_record_roundtrip(), "record operations work on obj record"); + TEST(t_reftable_index_record_roundtrip(), "record operations work on index record"); + + return test_done(); +} diff --git a/t/unit-tests/t-strbuf.c b/t/unit-tests/t-strbuf.c index de434a4441..6027dafef7 100644 --- a/t/unit-tests/t-strbuf.c +++ b/t/unit-tests/t-strbuf.c @@ -2,7 +2,8 @@ #include "strbuf.h" /* wrapper that supplies tests with an empty, initialized strbuf */ -static void setup(void (*f)(struct strbuf*, void*), void *data) +static void setup(void (*f)(struct strbuf*, const void*), + const void *data) { struct strbuf buf = STRBUF_INIT; @@ -13,7 +14,8 @@ static void setup(void (*f)(struct strbuf*, void*), void *data) } /* wrapper that supplies tests with a populated, initialized strbuf */ -static void setup_populated(void (*f)(struct strbuf*, void*), char *init_str, void *data) +static void setup_populated(void (*f)(struct strbuf*, const void*), + const char *init_str, const void *data) { struct strbuf buf = STRBUF_INIT; @@ -64,7 +66,7 @@ static void t_dynamic_init(void) strbuf_release(&buf); } -static void t_addch(struct strbuf *buf, void *data) +static void t_addch(struct strbuf *buf, const void *data) { const char *p_ch = data; const char ch = *p_ch; @@ -83,7 +85,7 @@ static void t_addch(struct strbuf *buf, void *data) check_char(buf->buf[buf->len], ==, '\0'); } -static void t_addstr(struct strbuf *buf, void *data) +static void t_addstr(struct strbuf *buf, const void *data) { const char *text = data; size_t len = strlen(text); diff --git a/t/unit-tests/t-strcmp-offset.c b/t/unit-tests/t-strcmp-offset.c new file mode 100644 index 0000000000..fe4c2706b1 --- /dev/null +++ b/t/unit-tests/t-strcmp-offset.c @@ -0,0 +1,35 @@ +#include "test-lib.h" +#include "read-cache-ll.h" + +static void check_strcmp_offset(const char *string1, const char *string2, + int expect_result, uintmax_t expect_offset) +{ + size_t offset; + int result = strcmp_offset(string1, string2, &offset); + + /* + * Because different CRTs behave differently, only rely on signs of the + * result values. + */ + result = (result < 0 ? -1 : + result > 0 ? 1 : + 0); + + check_int(result, ==, expect_result); + check_uint((uintmax_t)offset, ==, expect_offset); +} + +#define TEST_STRCMP_OFFSET(string1, string2, expect_result, expect_offset) \ + TEST(check_strcmp_offset(string1, string2, expect_result, \ + expect_offset), \ + "strcmp_offset(%s, %s) works", #string1, #string2) + +int cmd_main(int argc, const char **argv) +{ + TEST_STRCMP_OFFSET("abc", "abc", 0, 3); + TEST_STRCMP_OFFSET("abc", "def", -1, 0); + TEST_STRCMP_OFFSET("abc", "abz", -1, 2); + TEST_STRCMP_OFFSET("abc", "abcdef", -1, 3); + + return test_done(); +} diff --git a/t/unit-tests/t-strvec.c b/t/unit-tests/t-strvec.c new file mode 100644 index 0000000000..d4615ab06d --- /dev/null +++ b/t/unit-tests/t-strvec.c @@ -0,0 +1,272 @@ +#include "test-lib.h" +#include "strbuf.h" +#include "strvec.h" + +#define check_strvec(vec, ...) \ + check_strvec_loc(TEST_LOCATION(), vec, __VA_ARGS__) +LAST_ARG_MUST_BE_NULL +static void check_strvec_loc(const char *loc, struct strvec *vec, ...) +{ + va_list ap; + size_t nr = 0; + + va_start(ap, vec); + while (1) { + const char *str = va_arg(ap, const char *); + if (!str) + break; + + if (!check_uint(vec->nr, >, nr) || + !check_uint(vec->alloc, >, nr) || + !check_str(vec->v[nr], str)) { + struct strbuf msg = STRBUF_INIT; + strbuf_addf(&msg, "strvec index %"PRIuMAX, (uintmax_t) nr); + test_assert(loc, msg.buf, 0); + strbuf_release(&msg); + va_end(ap); + return; + } + + nr++; + } + va_end(ap); + + check_uint(vec->nr, ==, nr); + check_uint(vec->alloc, >=, nr); + check_pointer_eq(vec->v[nr], NULL); +} + +static void t_static_init(void) +{ + struct strvec vec = STRVEC_INIT; + check_pointer_eq(vec.v, empty_strvec); + check_uint(vec.nr, ==, 0); + check_uint(vec.alloc, ==, 0); +} + +static void t_dynamic_init(void) +{ + struct strvec vec; + strvec_init(&vec); + check_pointer_eq(vec.v, empty_strvec); + check_uint(vec.nr, ==, 0); + check_uint(vec.alloc, ==, 0); +} + +static void t_clear(void) +{ + struct strvec vec = STRVEC_INIT; + strvec_push(&vec, "foo"); + strvec_clear(&vec); + check_pointer_eq(vec.v, empty_strvec); + check_uint(vec.nr, ==, 0); + check_uint(vec.alloc, ==, 0); +} + +static void t_push(void) +{ + struct strvec vec = STRVEC_INIT; + + strvec_push(&vec, "foo"); + check_strvec(&vec, "foo", NULL); + + strvec_push(&vec, "bar"); + check_strvec(&vec, "foo", "bar", NULL); + + strvec_clear(&vec); +} + +static void t_pushf(void) +{ + struct strvec vec = STRVEC_INIT; + strvec_pushf(&vec, "foo: %d", 1); + check_strvec(&vec, "foo: 1", NULL); + strvec_clear(&vec); +} + +static void t_pushl(void) +{ + struct strvec vec = STRVEC_INIT; + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + check_strvec(&vec, "foo", "bar", "baz", NULL); + strvec_clear(&vec); +} + +static void t_pushv(void) +{ + const char *strings[] = { + "foo", "bar", "baz", NULL, + }; + struct strvec vec = STRVEC_INIT; + + strvec_pushv(&vec, strings); + check_strvec(&vec, "foo", "bar", "baz", NULL); + + strvec_clear(&vec); +} + +static void t_replace_at_head(void) +{ + struct strvec vec = STRVEC_INIT; + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_replace(&vec, 0, "replaced"); + check_strvec(&vec, "replaced", "bar", "baz", NULL); + strvec_clear(&vec); +} + +static void t_replace_at_tail(void) +{ + struct strvec vec = STRVEC_INIT; + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_replace(&vec, 2, "replaced"); + check_strvec(&vec, "foo", "bar", "replaced", NULL); + strvec_clear(&vec); +} + +static void t_replace_in_between(void) +{ + struct strvec vec = STRVEC_INIT; + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_replace(&vec, 1, "replaced"); + check_strvec(&vec, "foo", "replaced", "baz", NULL); + strvec_clear(&vec); +} + +static void t_replace_with_substring(void) +{ + struct strvec vec = STRVEC_INIT; + strvec_pushl(&vec, "foo", NULL); + strvec_replace(&vec, 0, vec.v[0] + 1); + check_strvec(&vec, "oo", NULL); + strvec_clear(&vec); +} + +static void t_remove_at_head(void) +{ + struct strvec vec = STRVEC_INIT; + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_remove(&vec, 0); + check_strvec(&vec, "bar", "baz", NULL); + strvec_clear(&vec); +} + +static void t_remove_at_tail(void) +{ + struct strvec vec = STRVEC_INIT; + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_remove(&vec, 2); + check_strvec(&vec, "foo", "bar", NULL); + strvec_clear(&vec); +} + +static void t_remove_in_between(void) +{ + struct strvec vec = STRVEC_INIT; + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_remove(&vec, 1); + check_strvec(&vec, "foo", "baz", NULL); + strvec_clear(&vec); +} + +static void t_pop_empty_array(void) +{ + struct strvec vec = STRVEC_INIT; + strvec_pop(&vec); + check_strvec(&vec, NULL); + strvec_clear(&vec); +} + +static void t_pop_non_empty_array(void) +{ + struct strvec vec = STRVEC_INIT; + strvec_pushl(&vec, "foo", "bar", "baz", NULL); + strvec_pop(&vec); + check_strvec(&vec, "foo", "bar", NULL); + strvec_clear(&vec); +} + +static void t_split_empty_string(void) +{ + struct strvec vec = STRVEC_INIT; + strvec_split(&vec, ""); + check_strvec(&vec, NULL); + strvec_clear(&vec); +} + +static void t_split_single_item(void) +{ + struct strvec vec = STRVEC_INIT; + strvec_split(&vec, "foo"); + check_strvec(&vec, "foo", NULL); + strvec_clear(&vec); +} + +static void t_split_multiple_items(void) +{ + struct strvec vec = STRVEC_INIT; + strvec_split(&vec, "foo bar baz"); + check_strvec(&vec, "foo", "bar", "baz", NULL); + strvec_clear(&vec); +} + +static void t_split_whitespace_only(void) +{ + struct strvec vec = STRVEC_INIT; + strvec_split(&vec, " \t\n"); + check_strvec(&vec, NULL); + strvec_clear(&vec); +} + +static void t_split_multiple_consecutive_whitespaces(void) +{ + struct strvec vec = STRVEC_INIT; + strvec_split(&vec, "foo\n\t bar"); + check_strvec(&vec, "foo", "bar", NULL); + strvec_clear(&vec); +} + +static void t_detach(void) +{ + struct strvec vec = STRVEC_INIT; + const char **detached; + + strvec_push(&vec, "foo"); + + detached = strvec_detach(&vec); + check_str(detached[0], "foo"); + check_pointer_eq(detached[1], NULL); + + check_pointer_eq(vec.v, empty_strvec); + check_uint(vec.nr, ==, 0); + check_uint(vec.alloc, ==, 0); + + free((char *) detached[0]); + free(detached); +} + +int cmd_main(int argc, const char **argv) +{ + TEST(t_static_init(), "static initialization"); + TEST(t_dynamic_init(), "dynamic initialization"); + TEST(t_clear(), "clear"); + TEST(t_push(), "push"); + TEST(t_pushf(), "pushf"); + TEST(t_pushl(), "pushl"); + TEST(t_pushv(), "pushv"); + TEST(t_replace_at_head(), "replace at head"); + TEST(t_replace_in_between(), "replace in between"); + TEST(t_replace_at_tail(), "replace at tail"); + TEST(t_replace_with_substring(), "replace with substring"); + TEST(t_remove_at_head(), "remove at head"); + TEST(t_remove_in_between(), "remove in between"); + TEST(t_remove_at_tail(), "remove at tail"); + TEST(t_pop_empty_array(), "pop with empty array"); + TEST(t_pop_non_empty_array(), "pop with non-empty array"); + TEST(t_split_empty_string(), "split empty string"); + TEST(t_split_single_item(), "split single item"); + TEST(t_split_multiple_items(), "split multiple items"); + TEST(t_split_whitespace_only(), "split whitespace only"); + TEST(t_split_multiple_consecutive_whitespaces(), "split multiple consecutive whitespaces"); + TEST(t_detach(), "detach"); + return test_done(); +} diff --git a/t/unit-tests/t-trailer.c b/t/unit-tests/t-trailer.c new file mode 100644 index 0000000000..2ecca359d9 --- /dev/null +++ b/t/unit-tests/t-trailer.c @@ -0,0 +1,315 @@ +#include "test-lib.h" +#include "trailer.h" + +struct contents { + const char *raw; + const char *key; + const char *val; +}; + +static void t_trailer_iterator(const char *msg, size_t num_expected, + struct contents *contents) +{ + struct trailer_iterator iter; + size_t i = 0; + + trailer_iterator_init(&iter, msg); + while (trailer_iterator_advance(&iter)) { + if (num_expected) { + check_str(iter.raw, contents[i].raw); + check_str(iter.key.buf, contents[i].key); + check_str(iter.val.buf, contents[i].val); + } + i++; + } + trailer_iterator_release(&iter); + + check_uint(i, ==, num_expected); +} + +static void run_t_trailer_iterator(void) +{ + + static struct test_cases { + const char *name; + const char *msg; + size_t num_expected; + struct contents contents[10]; + } tc[] = { + { + "empty input", + "", + 0, + {{0}}, + }, + { + "no newline at beginning", + "Fixes: x\n" + "Acked-by: x\n" + "Reviewed-by: x\n", + 0, + {{0}}, + }, + { + "newline at beginning", + "\n" + "Fixes: x\n" + "Acked-by: x\n" + "Reviewed-by: x\n", + 3, + { + { + .raw = "Fixes: x\n", + .key = "Fixes", + .val = "x", + }, + { + .raw = "Acked-by: x\n", + .key = "Acked-by", + .val = "x", + }, + { + .raw = "Reviewed-by: x\n", + .key = "Reviewed-by", + .val = "x", + }, + { + 0 + }, + }, + }, + { + "without body text", + "subject: foo bar\n" + "\n" + "Fixes: x\n" + "Acked-by: x\n" + "Reviewed-by: x\n", + 3, + { + { + .raw = "Fixes: x\n", + .key = "Fixes", + .val = "x", + }, + { + .raw = "Acked-by: x\n", + .key = "Acked-by", + .val = "x", + }, + { + .raw = "Reviewed-by: x\n", + .key = "Reviewed-by", + .val = "x", + }, + { + 0 + }, + }, + }, + { + "with body text, without divider", + "my subject\n" + "\n" + "my body which is long\n" + "and contains some special\n" + "chars like : = ? !\n" + "hello\n" + "\n" + "Fixes: x\n" + "Acked-by: x\n" + "Reviewed-by: x\n" + "Signed-off-by: x\n", + 4, + { + { + .raw = "Fixes: x\n", + .key = "Fixes", + .val = "x", + }, + { + .raw = "Acked-by: x\n", + .key = "Acked-by", + .val = "x", + }, + { + .raw = "Reviewed-by: x\n", + .key = "Reviewed-by", + .val = "x", + }, + { + .raw = "Signed-off-by: x\n", + .key = "Signed-off-by", + .val = "x", + }, + { + 0 + }, + }, + }, + { + "with body text, without divider (second trailer block)", + "my subject\n" + "\n" + "my body which is long\n" + "and contains some special\n" + "chars like : = ? !\n" + "hello\n" + "\n" + "Fixes: x\n" + "Acked-by: x\n" + "Reviewed-by: x\n" + "Signed-off-by: x\n" + "\n" + /* + * Because this is the last trailer block, it takes + * precedence over the first one encountered above. + */ + "Helped-by: x\n" + "Signed-off-by: x\n", + 2, + { + { + .raw = "Helped-by: x\n", + .key = "Helped-by", + .val = "x", + }, + { + .raw = "Signed-off-by: x\n", + .key = "Signed-off-by", + .val = "x", + }, + { + 0 + }, + }, + }, + { + "with body text, with divider", + "my subject\n" + "\n" + "my body which is long\n" + "and contains some special\n" + "chars like : = ? !\n" + "hello\n" + "\n" + "---\n" + "\n" + /* + * This trailer still counts because the iterator + * always ignores the divider. + */ + "Signed-off-by: x\n", + 1, + { + { + .raw = "Signed-off-by: x\n", + .key = "Signed-off-by", + .val = "x", + }, + { + 0 + }, + }, + }, + { + "with non-trailer lines in trailer block", + "subject: foo bar\n" + "\n" + /* + * Even though this trailer block has a non-trailer line + * in it, it's still a valid trailer block because it's + * at least 25% trailers and is Git-generated (see + * git_generated_prefixes[] in trailer.c). + */ + "not a trailer line\n" + "not a trailer line\n" + "not a trailer line\n" + "Signed-off-by: x\n", + /* + * Even though there is only really 1 real "trailer" + * (Signed-off-by), we still have 4 trailer objects + * because we still want to iterate through the entire + * block. + */ + 4, + { + { + .raw = "not a trailer line\n", + .key = "not a trailer line", + .val = "", + }, + { + .raw = "not a trailer line\n", + .key = "not a trailer line", + .val = "", + }, + { + .raw = "not a trailer line\n", + .key = "not a trailer line", + .val = "", + }, + { + .raw = "Signed-off-by: x\n", + .key = "Signed-off-by", + .val = "x", + }, + { + 0 + }, + }, + }, + { + "with non-trailer lines (one too many) in trailer block", + "subject: foo bar\n" + "\n" + /* + * This block has only 20% trailers, so it's below the + * 25% threshold. + */ + "not a trailer line\n" + "not a trailer line\n" + "not a trailer line\n" + "not a trailer line\n" + "Signed-off-by: x\n", + 0, + {{0}}, + }, + { + "with non-trailer lines (only 1) in trailer block, but no Git-generated trailers", + "subject: foo bar\n" + "\n" + /* + * This block has only 1 non-trailer out of 10 (IOW, 90% + * trailers) but is not considered a trailer block + * because the 25% threshold only applies to cases where + * there was a Git-generated trailer. + */ + "Reviewed-by: x\n" + "Reviewed-by: x\n" + "Reviewed-by: x\n" + "Helped-by: x\n" + "Helped-by: x\n" + "Helped-by: x\n" + "Acked-by: x\n" + "Acked-by: x\n" + "Acked-by: x\n" + "not a trailer line\n", + 0, + {{0}}, + }, + }; + + for (int i = 0; i < sizeof(tc) / sizeof(tc[0]); i++) { + TEST(t_trailer_iterator(tc[i].msg, + tc[i].num_expected, + tc[i].contents), + "%s", tc[i].name); + } +} + +int cmd_main(int argc, const char **argv) +{ + run_t_trailer_iterator(); + return test_done(); +} diff --git a/t/unit-tests/test-lib.c b/t/unit-tests/test-lib.c index 66d6980ffb..3c513ce59a 100644 --- a/t/unit-tests/test-lib.c +++ b/t/unit-tests/test-lib.c @@ -318,6 +318,19 @@ int check_bool_loc(const char *loc, const char *check, int ok) union test__tmp test__tmp[2]; +int check_pointer_eq_loc(const char *loc, const char *check, int ok, + const void *a, const void *b) +{ + int ret = test_assert(loc, check, ok); + + if (!ret) { + test_msg(" left: %p", a); + test_msg(" right: %p", b); + } + + return ret; +} + int check_int_loc(const char *loc, const char *check, int ok, intmax_t a, intmax_t b) { diff --git a/t/unit-tests/test-lib.h b/t/unit-tests/test-lib.h index a8f07ae0b7..2de6d715d5 100644 --- a/t/unit-tests/test-lib.h +++ b/t/unit-tests/test-lib.h @@ -79,6 +79,18 @@ int check_bool_loc(const char *loc, const char *check, int ok); * Compare two integers. Prints a message with the two values if the * comparison fails. NB this is not thread safe. */ +#define check_pointer_eq(a, b) \ + (test__tmp[0].p = (a), test__tmp[1].p = (b), \ + check_pointer_eq_loc(TEST_LOCATION(), #a" == "#b, \ + test__tmp[0].p == test__tmp[1].p, \ + test__tmp[0].p, test__tmp[1].p)) +int check_pointer_eq_loc(const char *loc, const char *check, int ok, + const void *a, const void *b); + +/* + * Compare two integers. Prints a message with the two values if the + * comparison fails. NB this is not thread safe. + */ #define check_int(a, op, b) \ (test__tmp[0].i = (a), test__tmp[1].i = (b), \ check_int_loc(TEST_LOCATION(), #a" "#op" "#b, \ @@ -136,6 +148,7 @@ union test__tmp { intmax_t i; uintmax_t u; char c; + const void *p; }; extern union test__tmp test__tmp[2]; |
