diff options
Diffstat (limited to 't')
389 files changed, 8087 insertions, 1162 deletions
diff --git a/t/Makefile b/t/Makefile index 882782a519..2c2b252240 100644 --- a/t/Makefile +++ b/t/Makefile @@ -94,7 +94,7 @@ check-chainlint: done \ } >'$(CHAINLINTTMP_SQ)'/expect && \ $(CHAINLINT) --emit-all '$(CHAINLINTTMP_SQ)'/tests | \ - grep -v '^[ ]*$$' >'$(CHAINLINTTMP_SQ)'/actual && \ + sed -e 's/^[1-9][0-9]* //;/^[ ]*$$/d' >'$(CHAINLINTTMP_SQ)'/actual && \ if test -f ../GIT-BUILD-OPTIONS; then \ . ../GIT-BUILD-OPTIONS; \ fi && \ @@ -449,10 +449,6 @@ the --sparse command-line argument. GIT_TEST_PRELOAD_INDEX=<boolean> exercises the preload-index code path by overriding the minimum number of cache entries required per thread. -GIT_TEST_ADD_I_USE_BUILTIN=<boolean>, when false, disables the -built-in version of git add -i. See 'add.interactive.useBuiltin' in -git-config(1). - GIT_TEST_INDEX_THREADS=<n> enables exercising the multi-threaded loading of the index for the whole test suite by bypassing the default number of cache entries and thread minimums. Setting this to 1 will make the diff --git a/t/chainlint.pl b/t/chainlint.pl index 976db4b8a0..e966412999 100755 --- a/t/chainlint.pl +++ b/t/chainlint.pl @@ -67,6 +67,7 @@ sub new { bless { parser => $parser, buff => $s, + lineno => 1, heretags => [] } => $class; } @@ -75,7 +76,9 @@ sub scan_heredoc_tag { my $self = shift @_; ${$self->{buff}} =~ /\G(-?)/gc; my $indented = $1; - my $tag = $self->scan_token(); + my $token = $self->scan_token(); + return "<<$indented" unless $token; + my $tag = $token->[0]; $tag =~ s/['"\\]//g; push(@{$self->{heretags}}, $indented ? "\t$tag" : "$tag"); return "<<$indented$tag"; @@ -95,7 +98,9 @@ sub scan_op { sub scan_sqstring { my $self = shift @_; ${$self->{buff}} =~ /\G([^']*'|.*\z)/sgc; - return "'" . $1; + my $s = $1; + $self->{lineno} += () = $s =~ /\n/sg; + return "'" . $s; } sub scan_dqstring { @@ -113,7 +118,7 @@ sub scan_dqstring { if ($c eq '\\') { $s .= '\\', last unless $$b =~ /\G(.)/sgc; $c = $1; - next if $c eq "\n"; # line splice + $self->{lineno}++, next if $c eq "\n"; # line splice # backslash escapes only $, `, ", \ in dq-string $s .= '\\' unless $c =~ /^[\$`"\\]$/; $s .= $c; @@ -121,6 +126,7 @@ sub scan_dqstring { } die("internal error scanning dq-string '$c'\n"); } + $self->{lineno} += () = $s =~ /\n/sg; return $s; } @@ -135,6 +141,7 @@ sub scan_balanced { $depth--; last if $depth == 0; } + $self->{lineno} += () = $s =~ /\n/sg; return $s; } @@ -149,7 +156,7 @@ sub scan_dollar { my $self = shift @_; my $b = $self->{buff}; return $self->scan_balanced('(', ')') if $$b =~ /\G\((?=\()/gc; # $((...)) - return '(' . join(' ', $self->scan_subst()) . ')' if $$b =~ /\G\(/gc; # $(...) + return '(' . join(' ', map {$_->[0]} $self->scan_subst()) . ')' if $$b =~ /\G\(/gc; # $(...) return $self->scan_balanced('{', '}') if $$b =~ /\G\{/gc; # ${...} return $1 if $$b =~ /\G(\w+)/gc; # $var return $1 if $$b =~ /\G([@*#?$!0-9-])/gc; # $*, $1, $$, etc. @@ -161,8 +168,11 @@ sub swallow_heredocs { my $b = $self->{buff}; my $tags = $self->{heretags}; while (my $tag = shift @$tags) { + my $start = pos($$b); my $indent = $tag =~ s/^\t// ? '\\s*' : ''; $$b =~ /(?:\G|\n)$indent\Q$tag\E(?:\n|\z)/gc; + my $body = substr($$b, $start, pos($$b) - $start); + $self->{lineno} += () = $body =~ /\n/sg; } } @@ -170,34 +180,37 @@ sub scan_token { my $self = shift @_; my $b = $self->{buff}; my $token = ''; + my ($start, $startln); RESTART: + $startln = $self->{lineno}; $$b =~ /\G[ \t]+/gc; # skip whitespace (but not newline) - return "\n" if $$b =~ /\G#[^\n]*(?:\n|\z)/gc; # comment + $start = pos($$b) || 0; + $self->{lineno}++, return ["\n", $start, pos($$b), $startln, $startln] if $$b =~ /\G#[^\n]*(?:\n|\z)/gc; # comment while (1) { # slurp up non-special characters $token .= $1 if $$b =~ /\G([^\\;&|<>(){}'"\$\s]+)/gc; # handle special characters last unless $$b =~ /\G(.)/sgc; my $c = $1; - last if $c =~ /^[ \t]$/; # whitespace ends token + pos($$b)--, last if $c =~ /^[ \t]$/; # whitespace ends token pos($$b)--, last if length($token) && $c =~ /^[;&|<>(){}\n]$/; $token .= $self->scan_sqstring(), next if $c eq "'"; $token .= $self->scan_dqstring(), next if $c eq '"'; $token .= $c . $self->scan_dollar(), next if $c eq '$'; - $self->swallow_heredocs(), $token = $c, last if $c eq "\n"; + $self->{lineno}++, $self->swallow_heredocs(), $token = $c, last if $c eq "\n"; $token = $self->scan_op($c), last if $c =~ /^[;&|<>]$/; $token = $c, last if $c =~ /^[(){}]$/; if ($c eq '\\') { $token .= '\\', last unless $$b =~ /\G(.)/sgc; $c = $1; - next if $c eq "\n" && length($token); # line splice - goto RESTART if $c eq "\n"; # line splice + $self->{lineno}++, next if $c eq "\n" && length($token); # line splice + $self->{lineno}++, goto RESTART if $c eq "\n"; # line splice $token .= '\\' . $c; next; } die("internal error scanning character '$c'\n"); } - return length($token) ? $token : undef; + return length($token) ? [$token, $start, pos($$b), $startln, $self->{lineno}] : undef; } # ShellParser parses POSIX shell scripts (with minor extensions for Bash). It @@ -239,14 +252,14 @@ sub stop_at { my ($self, $token) = @_; return 1 unless defined($token); my $stop = ${$self->{stop}}[-1] if @{$self->{stop}}; - return defined($stop) && $token =~ $stop; + return defined($stop) && $token->[0] =~ $stop; } sub expect { my ($self, $expect) = @_; my $token = $self->next_token(); - return $token if defined($token) && $token eq $expect; - push(@{$self->{output}}, "?!ERR?! expected '$expect' but found '" . (defined($token) ? $token : "<end-of-input>") . "'\n"); + return $token if defined($token) && $token->[0] eq $expect; + push(@{$self->{output}}, "?!ERR?! expected '$expect' but found '" . (defined($token) ? $token->[0] : "<end-of-input>") . "'\n"); $self->untoken($token) if defined($token); return (); } @@ -255,7 +268,7 @@ sub optional_newlines { my $self = shift @_; my @tokens; while (my $token = $self->peek()) { - last unless $token eq "\n"; + last unless $token->[0] eq "\n"; push(@tokens, $self->next_token()); } return @tokens; @@ -278,7 +291,7 @@ sub parse_case_pattern { my @tokens; while (defined(my $token = $self->next_token())) { push(@tokens, $token); - last if $token eq ')'; + last if $token->[0] eq ')'; } return @tokens; } @@ -293,13 +306,13 @@ sub parse_case { $self->optional_newlines()); while (1) { my $token = $self->peek(); - last unless defined($token) && $token ne 'esac'; + last unless defined($token) && $token->[0] ne 'esac'; push(@tokens, $self->parse_case_pattern(), $self->optional_newlines(), $self->parse(qr/^(?:;;|esac)$/)); # item body $token = $self->peek(); - last unless defined($token) && $token ne 'esac'; + last unless defined($token) && $token->[0] ne 'esac'; push(@tokens, $self->expect(';;'), $self->optional_newlines()); @@ -315,7 +328,7 @@ sub parse_for { $self->next_token(), # variable $self->optional_newlines()); my $token = $self->peek(); - if (defined($token) && $token eq 'in') { + if (defined($token) && $token->[0] eq 'in') { push(@tokens, $self->expect('in'), $self->optional_newlines()); @@ -339,11 +352,11 @@ sub parse_if { $self->optional_newlines(), $self->parse(qr/^(?:elif|else|fi)$/)); # if/elif body my $token = $self->peek(); - last unless defined($token) && $token eq 'elif'; + last unless defined($token) && $token->[0] eq 'elif'; push(@tokens, $self->expect('elif')); } my $token = $self->peek(); - if (defined($token) && $token eq 'else') { + if (defined($token) && $token->[0] eq 'else') { push(@tokens, $self->expect('else'), $self->optional_newlines(), @@ -380,7 +393,7 @@ sub parse_bash_array_assignment { my @tokens = $self->expect('('); while (defined(my $token = $self->next_token())) { push(@tokens, $token); - last if $token eq ')'; + last if $token->[0] eq ')'; } return @tokens; } @@ -398,29 +411,31 @@ sub parse_cmd { my $self = shift @_; my $cmd = $self->next_token(); return () unless defined($cmd); - return $cmd if $cmd eq "\n"; + return $cmd if $cmd->[0] eq "\n"; my $token; my @tokens = $cmd; - if ($cmd eq '!') { + if ($cmd->[0] eq '!') { push(@tokens, $self->parse_cmd()); return @tokens; - } elsif (my $f = $compound{$cmd}) { + } elsif (my $f = $compound{$cmd->[0]}) { push(@tokens, $self->$f()); - } elsif (defined($token = $self->peek()) && $token eq '(') { - if ($cmd !~ /\w=$/) { + } elsif (defined($token = $self->peek()) && $token->[0] eq '(') { + if ($cmd->[0] !~ /\w=$/) { push(@tokens, $self->parse_func()); return @tokens; } - $tokens[-1] .= join(' ', $self->parse_bash_array_assignment()); + my @array = $self->parse_bash_array_assignment(); + $tokens[-1]->[0] .= join(' ', map {$_->[0]} @array); + $tokens[-1]->[2] = $array[$#array][2] if @array; } while (defined(my $token = $self->next_token())) { $self->untoken($token), last if $self->stop_at($token); push(@tokens, $token); - last if $token =~ /^(?:[;&\n|]|&&|\|\|)$/; + last if $token->[0] =~ /^(?:[;&\n|]|&&|\|\|)$/; } - push(@tokens, $self->next_token()) if $tokens[-1] ne "\n" && defined($token = $self->peek()) && $token eq "\n"; + push(@tokens, $self->next_token()) if $tokens[-1]->[0] ne "\n" && defined($token = $self->peek()) && $token->[0] eq "\n"; return @tokens; } @@ -453,11 +468,18 @@ package TestParser; use base 'ShellParser'; +sub new { + my $class = shift @_; + my $self = $class->SUPER::new(@_); + $self->{problems} = []; + return $self; +} + sub find_non_nl { my $tokens = shift @_; my $n = shift @_; $n = $#$tokens if !defined($n); - $n-- while $n >= 0 && $$tokens[$n] eq "\n"; + $n-- while $n >= 0 && $$tokens[$n]->[0] eq "\n"; return $n; } @@ -467,7 +489,7 @@ sub ends_with { for my $needle (reverse(@$needles)) { return undef if $n < 0; $n = find_non_nl($tokens, $n), next if $needle eq "\n"; - return undef if $$tokens[$n] !~ $needle; + return undef if $$tokens[$n]->[0] !~ $needle; $n--; } return 1; @@ -486,13 +508,13 @@ sub parse_loop_body { my $self = shift @_; my @tokens = $self->SUPER::parse_loop_body(@_); # did loop signal failure via "|| return" or "|| exit"? - return @tokens if !@tokens || grep(/^(?:return|exit|\$\?)$/, @tokens); + return @tokens if !@tokens || grep {$_->[0] =~ /^(?:return|exit|\$\?)$/} @tokens; # did loop upstream of a pipe signal failure via "|| echo 'impossible # text'" as the final command in the loop body? return @tokens if ends_with(\@tokens, [qr/^\|\|$/, "\n", qr/^echo$/, qr/^.+$/]); # flag missing "return/exit" handling explicit failure in loop body my $n = find_non_nl(\@tokens); - splice(@tokens, $n + 1, 0, '?!LOOP?!'); + push(@{$self->{problems}}, ['LOOP', $tokens[$n]]); return @tokens; } @@ -505,8 +527,13 @@ my @safe_endings = ( sub accumulate { my ($self, $tokens, $cmd) = @_; + my $problems = $self->{problems}; + + # no previous command to check for missing "&&" goto DONE unless @$tokens; - goto DONE if @$cmd == 1 && $$cmd[0] eq "\n"; + + # new command is empty line; can't yet check if previous is missing "&&" + goto DONE if @$cmd == 1 && $$cmd[0]->[0] eq "\n"; # did previous command end with "&&", "|", "|| return" or similar? goto DONE if match_ending($tokens, \@safe_endings); @@ -514,20 +541,20 @@ sub accumulate { # if this command handles "$?" specially, then okay for previous # command to be missing "&&" for my $token (@$cmd) { - goto DONE if $token =~ /\$\?/; + goto DONE if $token->[0] =~ /\$\?/; } # if this command is "false", "return 1", or "exit 1" (which signal # failure explicitly), then okay for all preceding commands to be # missing "&&" - if ($$cmd[0] =~ /^(?:false|return|exit)$/) { - @$tokens = grep(!/^\?!AMP\?!$/, @$tokens); + if ($$cmd[0]->[0] =~ /^(?:false|return|exit)$/) { + @$problems = grep {$_->[0] ne 'AMP'} @$problems; goto DONE; } # flag missing "&&" at end of previous command my $n = find_non_nl($tokens); - splice(@$tokens, $n + 1, 0, '?!AMP?!') unless $n < 0; + push(@$problems, ['AMP', $tokens->[$n]]) unless $n < 0; DONE: $self->SUPER::accumulate($tokens, $cmd); @@ -553,7 +580,7 @@ sub new { # composition of multiple strings and non-string character runs; for instance, # `"test body"` unwraps to `test body`; `word"a b"42'c d'` to `worda b42c d` sub unwrap { - my $token = @_ ? shift @_ : $_; + my $token = (@_ ? shift @_ : $_)->[0]; # simple case: 'sqstring' or "dqstring" return $token if $token =~ s/^'([^']*)'$/$1/; return $token if $token =~ s/^"([^"]*)"$/$1/; @@ -584,13 +611,25 @@ sub check_test { $self->{ntests}++; my $parser = TestParser->new(\$body); my @tokens = $parser->parse(); - return unless $emit_all || grep(/\?![^?]+\?!/, @tokens); + my $problems = $parser->{problems}; + return unless $emit_all || @$problems; my $c = main::fd_colors(1); - my $checked = join(' ', @tokens); - $checked =~ s/^\n//; - $checked =~ s/^ //mg; - $checked =~ s/ $//mg; + my $lineno = $_[1]->[3]; + my $start = 0; + my $checked = ''; + for (sort {$a->[1]->[2] <=> $b->[1]->[2]} @$problems) { + my ($label, $token) = @$_; + my $pos = $token->[2]; + $checked .= substr($body, $start, $pos - $start) . " ?!$label?! "; + $start = $pos; + } + $checked .= substr($body, $start); + $checked =~ s/^/$lineno++ . ' '/mge; + $checked =~ s/^\d+ \n//; + $checked =~ s/(\s) \?!/$1?!/mg; + $checked =~ s/\?! (\s)/?!$1/mg; $checked =~ s/(\?![^?]+\?!)/$c->{rev}$c->{red}$1$c->{reset}/mg; + $checked =~ s/^\d+/$c->{dim}$&$c->{reset}/mg; $checked .= "\n" unless $checked =~ /\n$/; push(@{$self->{output}}, "$c->{blue}# chainlint: $title$c->{reset}\n$checked"); } @@ -598,9 +637,9 @@ sub check_test { sub parse_cmd { my $self = shift @_; my @tokens = $self->SUPER::parse_cmd(); - return @tokens unless @tokens && $tokens[0] =~ /^test_expect_(?:success|failure)$/; + return @tokens unless @tokens && $tokens[0]->[0] =~ /^test_expect_(?:success|failure)$/; my $n = $#tokens; - $n-- while $n >= 0 && $tokens[$n] =~ /^(?:[;&\n|]|&&|\|\|)$/; + $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 return @tokens; @@ -622,25 +661,39 @@ if (eval {require Time::HiRes; Time::HiRes->import(); 1;}) { # thread and ignore %ENV changes in subthreads. $ENV{TERM} = $ENV{USER_TERM} if $ENV{USER_TERM}; -my @NOCOLORS = (bold => '', rev => '', reset => '', blue => '', green => '', red => ''); +my @NOCOLORS = (bold => '', rev => '', dim => '', reset => '', blue => '', green => '', red => ''); my %COLORS = (); sub get_colors { return \%COLORS if %COLORS; - if (exists($ENV{NO_COLOR}) || - system("tput sgr0 >/dev/null 2>&1") != 0 || - system("tput bold >/dev/null 2>&1") != 0 || - system("tput rev >/dev/null 2>&1") != 0 || - system("tput setaf 1 >/dev/null 2>&1") != 0) { + if (exists($ENV{NO_COLOR})) { %COLORS = @NOCOLORS; return \%COLORS; } - %COLORS = (bold => `tput bold`, - rev => `tput rev`, - reset => `tput sgr0`, - blue => `tput setaf 4`, - green => `tput setaf 2`, - red => `tput setaf 1`); - chomp(%COLORS); + if ($ENV{TERM} =~ /xterm|xterm-\d+color|xterm-new|xterm-direct|nsterm|nsterm-\d+color|nsterm-direct/) { + %COLORS = (bold => "\e[1m", + rev => "\e[7m", + dim => "\e[2m", + reset => "\e[0m", + blue => "\e[34m", + green => "\e[32m", + red => "\e[31m"); + return \%COLORS; + } + if (system("tput sgr0 >/dev/null 2>&1") == 0 && + system("tput bold >/dev/null 2>&1") == 0 && + system("tput rev >/dev/null 2>&1") == 0 && + system("tput dim >/dev/null 2>&1") == 0 && + system("tput setaf 1 >/dev/null 2>&1") == 0) { + %COLORS = (bold => `tput bold`, + rev => `tput rev`, + dim => `tput dim`, + reset => `tput sgr0`, + blue => `tput setaf 4`, + green => `tput setaf 2`, + red => `tput setaf 1`); + return \%COLORS; + } + %COLORS = @NOCOLORS; return \%COLORS; } @@ -656,7 +709,7 @@ sub ncores { # Windows return $ENV{NUMBER_OF_PROCESSORS} if exists($ENV{NUMBER_OF_PROCESSORS}); # Linux / MSYS2 / Cygwin / WSL - do { local @ARGV='/proc/cpuinfo'; return scalar(grep(/^processor\s*:/, <>)); } if -r '/proc/cpuinfo'; + do { local @ARGV='/proc/cpuinfo'; return scalar(grep(/^processor[\s\d]*:/, <>)); } if -r '/proc/cpuinfo'; # macOS & BSD return qx/sysctl -n hw.ncpu/ if $^O =~ /(?:^darwin$|bsd)/; return 1; diff --git a/t/chainlint/block-comment.expect b/t/chainlint/block-comment.expect index d10b2eeaf2..df2beea888 100644 --- a/t/chainlint/block-comment.expect +++ b/t/chainlint/block-comment.expect @@ -1,6 +1,8 @@ ( { + # show a echo a && + # show b echo b } ) diff --git a/t/chainlint/case-comment.expect b/t/chainlint/case-comment.expect index 1e4b054bda..641c157b98 100644 --- a/t/chainlint/case-comment.expect +++ b/t/chainlint/case-comment.expect @@ -1,7 +1,10 @@ ( case "$x" in + # found foo x) foo ;; + # found other *) + # treat it as bar bar ;; esac diff --git a/t/chainlint/close-subshell.expect b/t/chainlint/close-subshell.expect index 0f87db9ae6..2192a2870a 100644 --- a/t/chainlint/close-subshell.expect +++ b/t/chainlint/close-subshell.expect @@ -15,7 +15,8 @@ ) | wuzzle && ( bop -) | fazz fozz && +) | fazz \ + fozz && ( bup ) | diff --git a/t/chainlint/comment.expect b/t/chainlint/comment.expect index f76fde1ffb..a68f1f9d7c 100644 --- a/t/chainlint/comment.expect +++ b/t/chainlint/comment.expect @@ -1,4 +1,8 @@ ( + # comment 1 nothing && + # comment 2 something + # comment 3 + # comment 4 ) diff --git a/t/chainlint/double-here-doc.expect b/t/chainlint/double-here-doc.expect index 75477bb1ad..cd584a4357 100644 --- a/t/chainlint/double-here-doc.expect +++ b/t/chainlint/double-here-doc.expect @@ -1,2 +1,12 @@ -run_sub_test_lib_test_err run-inv-range-start "--run invalid range start" --run="a-5" <<-EOF && -check_sub_test_lib_test_err run-inv-range-start <<-EOF_OUT 3 <<-EOF_ERR +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 diff --git a/t/chainlint/empty-here-doc.expect b/t/chainlint/empty-here-doc.expect index f42f2d41ba..e8733c97c6 100644 --- a/t/chainlint/empty-here-doc.expect +++ b/t/chainlint/empty-here-doc.expect @@ -1,3 +1,4 @@ git ls-tree $tree path > current && -cat > expected <<EOF && +cat > expected <<\EOF && +EOF test_output diff --git a/t/chainlint/for-loop.expect b/t/chainlint/for-loop.expect index a5810c9bdd..d65c82129a 100644 --- a/t/chainlint/for-loop.expect +++ b/t/chainlint/for-loop.expect @@ -2,7 +2,9 @@ for i in a b c do echo $i ?!AMP?! - cat <<-EOF ?!LOOP?! + cat <<-\EOF ?!LOOP?! + bar + EOF done ?!AMP?! for i in a b c; do echo $i && diff --git a/t/chainlint/here-doc-close-subshell.expect b/t/chainlint/here-doc-close-subshell.expect index 2af9ced71c..7d9c2b5607 100644 --- a/t/chainlint/here-doc-close-subshell.expect +++ b/t/chainlint/here-doc-close-subshell.expect @@ -1,2 +1,4 @@ ( - cat <<-INPUT) + cat <<-\INPUT) + fizz + INPUT diff --git a/t/chainlint/here-doc-indent-operator.expect b/t/chainlint/here-doc-indent-operator.expect index fb6cf7285d..f92a7ce999 100644 --- a/t/chainlint/here-doc-indent-operator.expect +++ b/t/chainlint/here-doc-indent-operator.expect @@ -1,5 +1,11 @@ -cat > expect <<-EOF && +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?! +cat >expect << -EOF ?!AMP?! +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 f8b3aa73c4..b7364c82c8 100644 --- a/t/chainlint/here-doc-multi-line-command-subst.expect +++ b/t/chainlint/here-doc-multi-line-command-subst.expect @@ -1,5 +1,8 @@ ( - x=$(bobble <<-END && + x=$(bobble <<-\END && + fossil + vegetable + END wiffle) ?!AMP?! echo $x ) diff --git a/t/chainlint/here-doc-multi-line-string.expect b/t/chainlint/here-doc-multi-line-string.expect index be64b26869..6c13bdcbfb 100644 --- a/t/chainlint/here-doc-multi-line-string.expect +++ b/t/chainlint/here-doc-multi-line-string.expect @@ -1,5 +1,7 @@ ( - cat <<-TXT && echo "multi-line + cat <<-\TXT && echo "multi-line string" ?!AMP?! + fizzle + TXT bap ) diff --git a/t/chainlint/here-doc.expect b/t/chainlint/here-doc.expect index 110059ba58..1df3f78282 100644 --- a/t/chainlint/here-doc.expect +++ b/t/chainlint/here-doc.expect @@ -1,7 +1,25 @@ -boodle wobba gorgo snoot wafta snurb <<EOF && +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 && +cat <<"zump" >boo && +snoz +boz +woz +zump -horticulture <<EOF +horticulture <<\EOF +gomez +morticia +wednesday +pugsly +EOF diff --git a/t/chainlint/if-then-else.expect b/t/chainlint/if-then-else.expect index 44d86c3597..cbaaf857d4 100644 --- a/t/chainlint/if-then-else.expect +++ b/t/chainlint/if-then-else.expect @@ -8,7 +8,9 @@ echo foo else echo foo && - cat <<-EOF + cat <<-\EOF + bar + EOF fi ?!AMP?! echo poodle ) && diff --git a/t/chainlint/incomplete-line.expect b/t/chainlint/incomplete-line.expect index ffac8f9018..134d3a14f5 100644 --- a/t/chainlint/incomplete-line.expect +++ b/t/chainlint/incomplete-line.expect @@ -1,4 +1,10 @@ -line 1 line 2 line 3 line 4 && +line 1 \ +line 2 \ +line 3 \ +line 4 && ( - line 5 line 6 line 7 line 8 + line 5 \ + line 6 \ + line 7 \ + line 8 ) diff --git a/t/chainlint/inline-comment.expect b/t/chainlint/inline-comment.expect index dd0dace077..6bad218530 100644 --- a/t/chainlint/inline-comment.expect +++ b/t/chainlint/inline-comment.expect @@ -1,6 +1,6 @@ ( - foobar && - barfoo ?!AMP?! + foobar && # comment 1 + barfoo ?!AMP?! # wrong position for && flibble "not a # comment" ) && diff --git a/t/chainlint/loop-detect-status.expect b/t/chainlint/loop-detect-status.expect index 0ad23bb35e..24da9e86d5 100644 --- a/t/chainlint/loop-detect-status.expect +++ b/t/chainlint/loop-detect-status.expect @@ -2,7 +2,7 @@ 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)) || diff --git a/t/chainlint/nested-here-doc.expect b/t/chainlint/nested-here-doc.expect index e3bef63f75..29b3832a98 100644 --- a/t/chainlint/nested-here-doc.expect +++ b/t/chainlint/nested-here-doc.expect @@ -1,7 +1,30 @@ cat <<ARBITRARY >foop && +naddle +fub <<EOF + nozzle + noodle +EOF +formp +ARBITRARY ( - cat <<-INPUT_END && - cat <<-EOT ?!AMP?! + 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 ) diff --git a/t/chainlint/nested-subshell-comment.expect b/t/chainlint/nested-subshell-comment.expect index be4b27a305..9138cf386d 100644 --- a/t/chainlint/nested-subshell-comment.expect +++ b/t/chainlint/nested-subshell-comment.expect @@ -2,6 +2,8 @@ foo && ( bar && + # bottles wobble while fiddles gobble + # minor numbers of cows (or do they?) baz && snaff ) ?!AMP?! diff --git a/t/chainlint/subshell-here-doc.expect b/t/chainlint/subshell-here-doc.expect index 029d129299..52789278d1 100644 --- a/t/chainlint/subshell-here-doc.expect +++ b/t/chainlint/subshell-here-doc.expect @@ -1,10 +1,30 @@ ( - echo wobba gorgo snoot wafta snurb <<-EOF && + echo wobba \ + gorgo snoot \ + wafta snurb <<-EOF && + quoth the raven, + nevermore... + EOF + cat <<EOF >bip ?!AMP?! - echo <<-EOF >bop + fish fly high +EOF + + echo <<-\EOF >bop + gomez + morticia + wednesday + pugsly + EOF ) && ( - cat <<-ARBITRARY >bup && - cat <<-ARBITRARY3 >bup3 && + cat <<-\ARBITRARY >bup && + glink + FIZZ + ARBITRARY + cat <<-"ARBITRARY3" >bup3 && + glink + FIZZ + ARBITRARY3 meep ) diff --git a/t/chainlint/t7900-subtree.expect b/t/chainlint/t7900-subtree.expect index 69167da2f2..71b3b3bc20 100644 --- a/t/chainlint/t7900-subtree.expect +++ b/t/chainlint/t7900-subtree.expect @@ -4,12 +4,16 @@ 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 diff --git a/t/chainlint/while-loop.expect b/t/chainlint/while-loop.expect index f272aa21fe..1f5eaea0fd 100644 --- a/t/chainlint/while-loop.expect +++ b/t/chainlint/while-loop.expect @@ -2,7 +2,9 @@ while true do echo foo ?!AMP?! - cat <<-EOF ?!LOOP?! + cat <<-\EOF ?!LOOP?! + bar + EOF done ?!AMP?! while true; do echo foo && diff --git a/t/check-non-portable-shell.pl b/t/check-non-portable-shell.pl index fd3303552b..dd8107cd7d 100755 --- a/t/check-non-portable-shell.pl +++ b/t/check-non-portable-shell.pl @@ -45,6 +45,7 @@ while (<>) { /\bhead\s+-c\b/ and err 'head -c is not portable (use test_copy_bytes BYTES <file >out)'; /(?:\$\(seq|^\s*seq\b)/ and err 'seq is not portable (use test_seq)'; /\bgrep\b.*--file\b/ and err 'grep --file FILE is not portable (use grep -f FILE)'; + /\b[ef]grep\b/ and err 'egrep/fgrep obsolescent (use grep -E/-F)'; /\bexport\s+[A-Za-z0-9_]*=/ and err '"export FOO=bar" is not portable (use FOO=bar && export FOO)'; /^\s*([A-Z0-9_]+=(\w*|(["']).*?\3)\s+)+(\w+)/ and exists($func{$4}) and err '"FOO=bar shell_func" assignment extends beyond "shell_func"'; diff --git a/t/helper/test-bloom.c b/t/helper/test-bloom.c index 6c900ca668..127f134a2a 100644 --- a/t/helper/test-bloom.c +++ b/t/helper/test-bloom.c @@ -1,5 +1,6 @@ -#include "git-compat-util.h" +#include "cache.h" #include "bloom.h" +#include "hex.h" #include "test-tool.h" #include "commit.h" diff --git a/t/helper/test-bundle-uri.c b/t/helper/test-bundle-uri.c new file mode 100644 index 0000000000..b18e760310 --- /dev/null +++ b/t/helper/test-bundle-uri.c @@ -0,0 +1,136 @@ +#include "test-tool.h" +#include "parse-options.h" +#include "bundle-uri.h" +#include "strbuf.h" +#include "string-list.h" +#include "transport.h" +#include "ref-filter.h" +#include "remote.h" +#include "refs.h" + +enum input_mode { + KEY_VALUE_PAIRS, + CONFIG_FILE, +}; + +static int cmd__bundle_uri_parse(int argc, const char **argv, enum input_mode mode) +{ + const char *key_value_usage[] = { + "test-tool bundle-uri parse-key-values <input>", + NULL + }; + const char *config_usage[] = { + "test-tool bundle-uri parse-config <input>", + NULL + }; + const char **usage = key_value_usage; + struct option options[] = { + OPT_END(), + }; + struct strbuf sb = STRBUF_INIT; + struct bundle_list list; + int err = 0; + FILE *fp; + + if (mode == CONFIG_FILE) + usage = config_usage; + + argc = parse_options(argc, argv, NULL, options, usage, + PARSE_OPT_STOP_AT_NON_OPTION); + + init_bundle_list(&list); + + list.baseURI = xstrdup("<uri>"); + + switch (mode) { + case KEY_VALUE_PAIRS: + if (argc != 1) + goto usage; + fp = fopen(argv[0], "r"); + if (!fp) + die("failed to open '%s'", argv[0]); + while (strbuf_getline(&sb, fp) != EOF) { + if (bundle_uri_parse_line(&list, sb.buf)) + err = error("bad line: '%s'", sb.buf); + } + fclose(fp); + break; + + case CONFIG_FILE: + if (argc != 1) + goto usage; + err = bundle_uri_parse_config_format("<uri>", argv[0], &list); + break; + } + strbuf_release(&sb); + + print_bundle_list(stdout, &list); + + clear_bundle_list(&list); + + return !!err; + +usage: + usage_with_options(usage, options); +} + +static int cmd_ls_remote(int argc, const char **argv) +{ + const char *dest; + struct remote *remote; + struct transport *transport; + int status = 0; + + dest = argc > 1 ? argv[1] : NULL; + + remote = remote_get(dest); + if (!remote) { + if (dest) + 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) { + error(_("could not get the bundle-uri list")); + status = 1; + goto cleanup; + } + + print_bundle_list(stdout, transport->bundles); + +cleanup: + if (transport_disconnect(transport)) + return 1; + return status; +} + +int cmd__bundle_uri(int argc, const char **argv) +{ + const char *usage[] = { + "test-tool bundle-uri <subcommand> [<options>]", + NULL + }; + struct option options[] = { + OPT_END(), + }; + + argc = parse_options(argc, argv, NULL, options, usage, + PARSE_OPT_STOP_AT_NON_OPTION | + PARSE_OPT_KEEP_ARGV0); + if (argc == 1) + goto usage; + + if (!strcmp(argv[1], "parse-key-values")) + return cmd__bundle_uri_parse(argc - 1, argv + 1, KEY_VALUE_PAIRS); + if (!strcmp(argv[1], "parse-config")) + return cmd__bundle_uri_parse(argc - 1, argv + 1, CONFIG_FILE); + if (!strcmp(argv[1], "ls-remote")) + return cmd_ls_remote(argc - 1, argv + 1); + error("there is no test-tool bundle-uri tool '%s'", argv[1]); + +usage: + usage_with_options(usage, options); +} diff --git a/t/helper/test-cache-tree.c b/t/helper/test-cache-tree.c new file mode 100644 index 0000000000..615e648e55 --- /dev/null +++ b/t/helper/test-cache-tree.c @@ -0,0 +1,66 @@ +#define USE_THE_INDEX_VARIABLE +#include "test-tool.h" +#include "cache.h" +#include "hex.h" +#include "tree.h" +#include "cache-tree.h" +#include "parse-options.h" + +static char const * const test_cache_tree_usage[] = { + N_("test-tool cache-tree <options> (control|prime|update)"), + NULL +}; + +int cmd__cache_tree(int argc, const char **argv) +{ + struct object_id oid; + struct tree *tree; + int empty = 0; + int invalidate_qty = 0; + int i; + + struct option options[] = { + OPT_BOOL(0, "empty", &empty, + N_("clear the cache tree before each iteration")), + OPT_INTEGER_F(0, "invalidate", &invalidate_qty, + N_("number of entries in the cache tree to invalidate (default 0)"), + PARSE_OPT_NONEG), + OPT_END() + }; + + setup_git_directory(); + + argc = parse_options(argc, argv, NULL, options, test_cache_tree_usage, 0); + + if (repo_read_index(the_repository) < 0) + die(_("unable to read index file")); + + oidcpy(&oid, &the_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(); + } else if (invalidate_qty) { + /* invalidate the specified number of unique paths */ + float f_interval = (float)the_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); + } + + 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); + else if (!strcmp(argv[0], "update")) + cache_tree_update(&the_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]); + + return 0; +} diff --git a/t/helper/test-crontab.c b/t/helper/test-crontab.c index e6c1b1e22b..597027a96e 100644 --- a/t/helper/test-crontab.c +++ b/t/helper/test-crontab.c @@ -1,5 +1,4 @@ #include "test-tool.h" -#include "cache.h" /* * Usage: test-tool crontab <file> -l|<input> diff --git a/t/helper/test-ctype.c b/t/helper/test-ctype.c index 92c4c2313e..534ca66441 100644 --- a/t/helper/test-ctype.c +++ b/t/helper/test-ctype.c @@ -1,5 +1,4 @@ #include "test-tool.h" -#include "cache.h" static int rc; @@ -11,9 +10,14 @@ static void report_error(const char *class, int ch) static int is_in(const char *s, int ch) { - /* We can't find NUL using strchr. It's classless anyway. */ + /* + * We can't find NUL using strchr. Accept it as the first + * character in the spec -- there are no empty classes. + */ if (ch == '\0') - return 0; + return ch == *s; + if (*s == '\0') + s++; return !!strchr(s, ch); } @@ -28,6 +32,20 @@ static int is_in(const char *s, int ch) #define DIGIT "0123456789" #define LOWER "abcdefghijklmnopqrstuvwxyz" #define UPPER "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define PUNCT "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" +#define ASCII \ + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \ + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \ + "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" \ + "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" \ + "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" \ + "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" \ + "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" \ + "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" +#define CNTRL \ + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \ + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \ + "\x7f" int cmd__ctype(int argc, const char **argv) { @@ -38,6 +56,13 @@ int cmd__ctype(int argc, const char **argv) TEST_CLASS(is_glob_special, "*?[\\"); TEST_CLASS(is_regex_special, "$()*+.?[\\^{|"); TEST_CLASS(is_pathspec_magic, "!\"#%&',-/:;<=>@_`~"); + TEST_CLASS(isascii, ASCII); + TEST_CLASS(islower, LOWER); + TEST_CLASS(isupper, UPPER); + TEST_CLASS(iscntrl, CNTRL); + TEST_CLASS(ispunct, PUNCT); + TEST_CLASS(isxdigit, DIGIT "abcdefABCDEF"); + TEST_CLASS(isprint, LOWER UPPER DIGIT PUNCT " "); return rc; } diff --git a/t/helper/test-dir-iterator.c b/t/helper/test-dir-iterator.c index 659b6bfa81..6b297bd753 100644 --- a/t/helper/test-dir-iterator.c +++ b/t/helper/test-dir-iterator.c @@ -15,7 +15,7 @@ static const char *error_name(int error_number) /* * usage: - * tool-test dir-iterator [--follow-symlinks] [--pedantic] directory_path + * tool-test dir-iterator [--pedantic] directory_path */ int cmd__dir_iterator(int argc, const char **argv) { @@ -24,9 +24,7 @@ int cmd__dir_iterator(int argc, const char **argv) int iter_status; for (++argv, --argc; *argv && starts_with(*argv, "--"); ++argv, --argc) { - if (strcmp(*argv, "--follow-symlinks") == 0) - flags |= DIR_ITERATOR_FOLLOW_SYMLINKS; - else if (strcmp(*argv, "--pedantic") == 0) + if (strcmp(*argv, "--pedantic") == 0) flags |= DIR_ITERATOR_PEDANTIC; else die("invalid option '%s'", *argv); diff --git a/t/helper/test-dump-cache-tree.c b/t/helper/test-dump-cache-tree.c index 0d6d7f1ecb..92dfc1aa8c 100644 --- a/t/helper/test-dump-cache-tree.c +++ b/t/helper/test-dump-cache-tree.c @@ -1,5 +1,7 @@ +#define USE_THE_INDEX_VARIABLE #include "test-tool.h" #include "cache.h" +#include "hex.h" #include "tree.h" #include "cache-tree.h" @@ -62,12 +64,12 @@ int cmd__dump_cache_tree(int ac, const char **av) int ret; setup_git_directory(); - if (read_cache() < 0) + if (repo_read_index(the_repository) < 0) die("unable to read index file"); istate = the_index; istate.cache_tree = another; cache_tree_update(&istate, WRITE_TREE_DRY_RUN); - ret = dump_cache_tree(active_cache_tree, another, ""); + ret = dump_cache_tree(the_index.cache_tree, another, ""); cache_tree_free(&another); return ret; diff --git a/t/helper/test-dump-split-index.c b/t/helper/test-dump-split-index.c index a209880eb3..813d0a38fa 100644 --- a/t/helper/test-dump-split-index.c +++ b/t/helper/test-dump-split-index.c @@ -1,5 +1,7 @@ +#define USE_THE_INDEX_VARIABLE #include "test-tool.h" #include "cache.h" +#include "hex.h" #include "split-index.h" #include "ewah/ewok.h" diff --git a/t/helper/test-dump-untracked-cache.c b/t/helper/test-dump-untracked-cache.c index 99010614f6..af953fabe8 100644 --- a/t/helper/test-dump-untracked-cache.c +++ b/t/helper/test-dump-untracked-cache.c @@ -1,7 +1,8 @@ -#define USE_THE_INDEX_COMPATIBILITY_MACROS +#define USE_THE_INDEX_VARIABLE #include "test-tool.h" #include "cache.h" #include "dir.h" +#include "hex.h" static int compare_untracked(const void *a_, const void *b_) { @@ -51,7 +52,7 @@ int cmd__dump_untracked_cache(int ac, const char **av) xsetenv("GIT_CONFIG_VALUE_0", "keep", 1); setup_git_directory(); - if (read_cache() < 0) + if (repo_read_index(the_repository) < 0) die("unable to read index file"); uc = the_index.untracked; if (!uc) { diff --git a/t/helper/test-env-helper.c b/t/helper/test-env-helper.c new file mode 100644 index 0000000000..66c88b8ff3 --- /dev/null +++ b/t/helper/test-env-helper.c @@ -0,0 +1,100 @@ +#include "test-tool.h" +#include "config.h" +#include "parse-options.h" + +static char const * const env__helper_usage[] = { + "test-tool env-helper --type=[bool|ulong] <options> <env-var>", + NULL +}; + +enum cmdmode { + ENV_HELPER_TYPE_BOOL = 1, + ENV_HELPER_TYPE_ULONG +}; + +static int option_parse_type(const struct option *opt, const char *arg, + int unset) +{ + enum cmdmode *cmdmode = opt->value; + + BUG_ON_OPT_NEG(unset); + + if (!strcmp(arg, "bool")) + *cmdmode = ENV_HELPER_TYPE_BOOL; + else if (!strcmp(arg, "ulong")) + *cmdmode = ENV_HELPER_TYPE_ULONG; + else + die("unrecognized --type argument, %s", arg); + + return 0; +} + +int cmd__env_helper(int argc, const char **argv) +{ + int exit_code = 0; + const char *env_variable = NULL; + const char *env_default = NULL; + int ret; + int ret_int, default_int; + unsigned long ret_ulong, default_ulong; + enum cmdmode cmdmode = 0; + struct option opts[] = { + OPT_CALLBACK_F(0, "type", &cmdmode, "type", + "value is given this type", PARSE_OPT_NONEG, + option_parse_type), + OPT_STRING(0, "default", &env_default, "value", + "default for git_env_*(...) to fall back on"), + OPT_BOOL(0, "exit-code", &exit_code, + "be quiet only use git_env_*() value as exit code"), + OPT_END(), + }; + + argc = parse_options(argc, argv, NULL, opts, env__helper_usage, + PARSE_OPT_KEEP_UNKNOWN_OPT); + if (env_default && !*env_default) + usage_with_options(env__helper_usage, opts); + if (!cmdmode) + usage_with_options(env__helper_usage, opts); + if (argc != 1) + usage_with_options(env__helper_usage, opts); + env_variable = argv[0]; + + switch (cmdmode) { + case ENV_HELPER_TYPE_BOOL: + if (env_default) { + default_int = git_parse_maybe_bool(env_default); + if (default_int == -1) { + error("option `--default' expects a boolean value with `--type=bool`, not `%s`", + env_default); + usage_with_options(env__helper_usage, opts); + } + } else { + default_int = 0; + } + ret_int = git_env_bool(env_variable, default_int); + if (!exit_code) + puts(ret_int ? "true" : "false"); + ret = ret_int; + break; + case ENV_HELPER_TYPE_ULONG: + if (env_default) { + if (!git_parse_ulong(env_default, &default_ulong)) { + error("option `--default' expects an unsigned long value with `--type=ulong`, not `%s`", + env_default); + usage_with_options(env__helper_usage, opts); + } + } else { + default_ulong = 0; + } + ret_ulong = git_env_ulong(env_variable, default_ulong); + if (!exit_code) + printf("%lu\n", ret_ulong); + ret = ret_ulong; + break; + default: + BUG("unknown <type> value"); + break; + } + + return !ret; +} diff --git a/t/helper/test-example-decorate.c b/t/helper/test-example-decorate.c index b9d1200eb9..7c7fc8efc1 100644 --- a/t/helper/test-example-decorate.c +++ b/t/helper/test-example-decorate.c @@ -1,5 +1,5 @@ #include "test-tool.h" -#include "cache.h" +#include "git-compat-util.h" #include "object.h" #include "decorate.h" diff --git a/t/helper/test-fake-ssh.c b/t/helper/test-fake-ssh.c index 12beee99ad..27323cb367 100644 --- a/t/helper/test-fake-ssh.c +++ b/t/helper/test-fake-ssh.c @@ -8,7 +8,7 @@ int cmd_main(int argc, const char **argv) struct strbuf buf = STRBUF_INIT; FILE *f; int i; - const char *child_argv[] = { NULL, NULL }; + struct child_process cmd = CHILD_PROCESS_INIT; /* First, print all parameters into $TRASH_DIRECTORY/ssh-output */ if (!trash_directory) @@ -17,6 +17,7 @@ int cmd_main(int argc, const char **argv) f = fopen(buf.buf, "w"); if (!f) die("Could not write to %s", buf.buf); + strbuf_release(&buf); for (i = 0; i < argc; i++) fprintf(f, "%s%s", i > 0 ? " " : "", i > 0 ? argv[i] : "ssh:"); fprintf(f, "\n"); @@ -25,6 +26,7 @@ int cmd_main(int argc, const char **argv) /* Now, evaluate the *last* parameter */ if (argc < 2) return 0; - child_argv[0] = argv[argc - 1]; - return run_command_v_opt(child_argv, RUN_USING_SHELL); + cmd.use_shell = 1; + strvec_push(&cmd.args, argv[argc - 1]); + return run_command(&cmd); } diff --git a/t/helper/test-fast-rebase.c b/t/helper/test-fast-rebase.c index 45665ec19a..b1edb92a03 100644 --- a/t/helper/test-fast-rebase.c +++ b/t/helper/test-fast-rebase.c @@ -10,11 +10,12 @@ * refactoring is the better route). */ -#define USE_THE_INDEX_COMPATIBILITY_MACROS +#define USE_THE_INDEX_VARIABLE #include "test-tool.h" #include "cache-tree.h" #include "commit.h" +#include "hex.h" #include "lockfile.h" #include "merge-ort.h" #include "refs.h" @@ -123,7 +124,7 @@ int cmd__fast_rebase(int argc, const char **argv) die(_("Cannot read HEAD")); assert(oideq(&onto->object.oid, &head)); - hold_locked_index(&lock, LOCK_DIE_ON_ERROR); + repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR); if (repo_read_index(the_repository) < 0) BUG("Could not read index"); diff --git a/t/helper/test-genzeros.c b/t/helper/test-genzeros.c index 8ca988d621..47af843b68 100644 --- a/t/helper/test-genzeros.c +++ b/t/helper/test-genzeros.c @@ -17,15 +17,16 @@ int cmd__genzeros(int argc, const char **argv) /* Writing out individual NUL bytes is slow... */ while (count < 0) - if (write(1, zeros, ARRAY_SIZE(zeros)) < 0) - return -1; + if (xwrite(1, zeros, ARRAY_SIZE(zeros)) < 0) + die_errno("write error"); while (count > 0) { - n = write(1, zeros, count < ARRAY_SIZE(zeros) ? - count : ARRAY_SIZE(zeros)); + n = xwrite(1, zeros, + count < ARRAY_SIZE(zeros) + ? count : ARRAY_SIZE(zeros)); if (n < 0) - return -1; + die_errno("write error"); count -= n; } diff --git a/t/helper/test-hash.c b/t/helper/test-hash.c index 5860dab0ff..016248106a 100644 --- a/t/helper/test-hash.c +++ b/t/helper/test-hash.c @@ -1,5 +1,6 @@ #include "test-tool.h" #include "cache.h" +#include "hex.h" int cmd_hash_impl(int ac, const char **av, int algo) { diff --git a/t/helper/test-json-writer.c b/t/helper/test-json-writer.c index 8c3edacc00..86887f5320 100644 --- a/t/helper/test-json-writer.c +++ b/t/helper/test-json-writer.c @@ -1,5 +1,4 @@ #include "test-tool.h" -#include "cache.h" #include "json-writer.h" static const char *expect_obj1 = "{\"a\":\"abc\",\"b\":42,\"c\":true}"; diff --git a/t/helper/test-lazy-init-name-hash.c b/t/helper/test-lazy-init-name-hash.c index cd1b4c9736..ab86c14c8b 100644 --- a/t/helper/test-lazy-init-name-hash.c +++ b/t/helper/test-lazy-init-name-hash.c @@ -1,3 +1,4 @@ +#define USE_THE_INDEX_VARIABLE #include "test-tool.h" #include "cache.h" #include "parse-options.h" @@ -32,7 +33,7 @@ static void dump_run(void) struct dir_entry *dir; struct cache_entry *ce; - read_cache(); + repo_read_index(the_repository); if (single) { test_lazy_init_name_hash(&the_index, 0); } else { @@ -49,7 +50,7 @@ static void dump_run(void) ent /* member name */) printf("name %08x %s\n", ce->ent.hash, ce->name); - discard_cache(); + discard_index(&the_index); } /* @@ -66,7 +67,7 @@ static uint64_t time_runs(int try_threaded) for (i = 0; i < count; i++) { t0 = getnanotime(); - read_cache(); + repo_read_index(the_repository); t1 = getnanotime(); nr_threads_used = test_lazy_init_name_hash(&the_index, try_threaded); t2 = getnanotime(); @@ -89,7 +90,7 @@ static uint64_t time_runs(int try_threaded) the_index.cache_nr); fflush(stdout); - discard_cache(); + discard_index(&the_index); } avg = sum / count; @@ -113,9 +114,9 @@ static void analyze_run(void) int i; int nr; - read_cache(); + repo_read_index(the_repository); cache_nr_limit = the_index.cache_nr; - discard_cache(); + discard_index(&the_index); nr = analyze; while (1) { @@ -128,23 +129,23 @@ static void analyze_run(void) nr = cache_nr_limit; for (i = 0; i < count; i++) { - read_cache(); + repo_read_index(the_repository); the_index.cache_nr = nr; /* cheap truncate of index */ t1s = getnanotime(); test_lazy_init_name_hash(&the_index, 0); t2s = getnanotime(); sum_single += (t2s - t1s); the_index.cache_nr = cache_nr_limit; - discard_cache(); + discard_index(&the_index); - read_cache(); + repo_read_index(the_repository); the_index.cache_nr = nr; /* cheap truncate of index */ t1m = getnanotime(); nr_threads_used = test_lazy_init_name_hash(&the_index, 1); t2m = getnanotime(); sum_multi += (t2m - t1m); the_index.cache_nr = cache_nr_limit; - discard_cache(); + discard_index(&the_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 4079fdee06..04bc2563f3 100644 --- a/t/helper/test-match-trees.c +++ b/t/helper/test-match-trees.c @@ -1,5 +1,6 @@ #include "test-tool.h" #include "cache.h" +#include "hex.h" #include "tree.h" int cmd__match_trees(int ac, const char **av) diff --git a/t/helper/test-oid-array.c b/t/helper/test-oid-array.c index d1324d086a..0906993ad5 100644 --- a/t/helper/test-oid-array.c +++ b/t/helper/test-oid-array.c @@ -1,5 +1,6 @@ #include "test-tool.h" #include "cache.h" +#include "hex.h" #include "oid-array.h" static int print_oid(const struct object_id *oid, void *data) diff --git a/t/helper/test-oidmap.c b/t/helper/test-oidmap.c index 0acf99931e..883d40efd4 100644 --- a/t/helper/test-oidmap.c +++ b/t/helper/test-oidmap.c @@ -1,5 +1,6 @@ #include "test-tool.h" #include "cache.h" +#include "hex.h" #include "oidmap.h" #include "strbuf.h" diff --git a/t/helper/test-oidtree.c b/t/helper/test-oidtree.c index d48a409f4e..0b82431a70 100644 --- a/t/helper/test-oidtree.c +++ b/t/helper/test-oidtree.c @@ -1,5 +1,6 @@ #include "test-tool.h" #include "cache.h" +#include "hex.h" #include "oidtree.h" static enum cb_next print_oid(const struct object_id *oid, void *data) diff --git a/t/helper/test-pack-mtimes.c b/t/helper/test-pack-mtimes.c index f7b79daf4c..f68b3761b6 100644 --- a/t/helper/test-pack-mtimes.c +++ b/t/helper/test-pack-mtimes.c @@ -1,5 +1,6 @@ #include "git-compat-util.h" #include "test-tool.h" +#include "hex.h" #include "strbuf.h" #include "object-store.h" #include "packfile.h" diff --git a/t/helper/test-partial-clone.c b/t/helper/test-partial-clone.c index 3f102cfddd..da17fd37eb 100644 --- a/t/helper/test-partial-clone.c +++ b/t/helper/test-partial-clone.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "hex.h" #include "test-tool.h" #include "repository.h" #include "object-store.h" diff --git a/t/helper/test-path-utils.c b/t/helper/test-path-utils.c index d20e1b7a18..f69709d674 100644 --- a/t/helper/test-path-utils.c +++ b/t/helper/test-path-utils.c @@ -8,7 +8,8 @@ * GIT_CEILING_DIRECTORIES. If the path is unusable for some reason, * die with an explanation. */ -static int normalize_ceiling_entry(struct string_list_item *item, void *unused) +static int normalize_ceiling_entry(struct string_list_item *item, + void *data UNUSED) { char *ceil = item->string; diff --git a/t/helper/test-pcre2-config.c b/t/helper/test-pcre2-config.c index 5258fdddba..5d0b2a2e10 100644 --- a/t/helper/test-pcre2-config.c +++ b/t/helper/test-pcre2-config.c @@ -1,5 +1,4 @@ #include "test-tool.h" -#include "cache.h" #include "grep.h" int cmd__pcre2_config(int argc, const char **argv) diff --git a/t/helper/test-prio-queue.c b/t/helper/test-prio-queue.c index 133b5e6f4a..4915412e07 100644 --- a/t/helper/test-prio-queue.c +++ b/t/helper/test-prio-queue.c @@ -1,8 +1,7 @@ #include "test-tool.h" -#include "cache.h" #include "prio-queue.h" -static int intcmp(const void *va, const void *vb, void *data) +static int intcmp(const void *va, const void *vb, void *data UNUSED) { const int *a = va, *b = vb; return *a - *b; diff --git a/t/helper/test-proc-receive.c b/t/helper/test-proc-receive.c index cc08506cf0..7e12d4f9aa 100644 --- a/t/helper/test-proc-receive.c +++ b/t/helper/test-proc-receive.c @@ -1,12 +1,13 @@ #include "cache.h" #include "connect.h" +#include "hex.h" #include "parse-options.h" #include "pkt-line.h" #include "sigchain.h" #include "test-tool.h" static const char *proc_receive_usage[] = { - "test-tool proc-receive [<options>...]", + "test-tool proc-receive [<options>]", NULL }; diff --git a/t/helper/test-reach.c b/t/helper/test-reach.c index 2f65c7f6a5..de8f26639d 100644 --- a/t/helper/test-reach.c +++ b/t/helper/test-reach.c @@ -1,8 +1,9 @@ #include "test-tool.h" -#include "cache.h" +#include "alloc.h" #include "commit.h" #include "commit-reach.h" #include "config.h" +#include "hex.h" #include "parse-options.h" #include "ref-filter.h" #include "string-list.h" diff --git a/t/helper/test-read-cache.c b/t/helper/test-read-cache.c index b736ef1642..23e9e27109 100644 --- a/t/helper/test-read-cache.c +++ b/t/helper/test-read-cache.c @@ -1,3 +1,4 @@ +#define USE_THE_INDEX_VARIABLE #include "test-tool.h" #include "cache.h" #include "config.h" @@ -20,7 +21,7 @@ int cmd__read_cache(int argc, const char **argv) git_config(git_default_config, NULL); for (i = 0; i < cnt; i++) { - read_cache(); + repo_read_index(the_repository); if (name) { int pos; @@ -33,7 +34,7 @@ int cmd__read_cache(int argc, const char **argv) ce_uptodate(the_index.cache[pos]) ? "" : " not"); write_file(name, "%d\n", i); } - discard_cache(); + discard_index(&the_index); } return 0; } diff --git a/t/helper/test-read-midx.c b/t/helper/test-read-midx.c index 27072ba94d..0a883cdf26 100644 --- a/t/helper/test-read-midx.c +++ b/t/helper/test-read-midx.c @@ -1,5 +1,6 @@ #include "test-tool.h" #include "cache.h" +#include "hex.h" #include "midx.h" #include "repository.h" #include "object-store.h" diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c index ae8a5648da..1745b088b7 100644 --- a/t/helper/test-ref-store.c +++ b/t/helper/test-ref-store.c @@ -1,5 +1,6 @@ #include "test-tool.h" #include "cache.h" +#include "hex.h" #include "refs.h" #include "worktree.h" #include "object-store.h" diff --git a/t/helper/test-repository.c b/t/helper/test-repository.c index 56f0e3c1be..10a6dfc216 100644 --- a/t/helper/test-repository.c +++ b/t/helper/test-repository.c @@ -3,6 +3,7 @@ #include "commit-graph.h" #include "commit.h" #include "config.h" +#include "hex.h" #include "object-store.h" #include "object.h" #include "repository.h" diff --git a/t/helper/test-run-command.c b/t/helper/test-run-command.c index c9283b47af..b0d041ec5f 100644 --- a/t/helper/test-run-command.c +++ b/t/helper/test-run-command.c @@ -9,8 +9,6 @@ */ #include "test-tool.h" -#include "git-compat-util.h" -#include "cache.h" #include "run-command.h" #include "strvec.h" #include "strbuf.h" @@ -24,7 +22,7 @@ static int number_callbacks; static int parallel_next(struct child_process *cp, struct strbuf *err, void *cb, - void **task_cb) + void **task_cb UNUSED) { struct child_process *d = cb; if (number_callbacks >= 4) @@ -40,10 +38,10 @@ static int parallel_next(struct child_process *cp, return 1; } -static int no_job(struct child_process *cp, +static int no_job(struct child_process *cp UNUSED, struct strbuf *err, - void *cb, - void **task_cb) + void *cb UNUSED, + void **task_cb UNUSED) { if (err) strbuf_addstr(err, "no further jobs available\n"); @@ -52,10 +50,10 @@ static int no_job(struct child_process *cp, return 0; } -static int task_finished(int result, +static int task_finished(int result UNUSED, struct strbuf *err, - void *pp_cb, - void *pp_task_cb) + void *pp_cb UNUSED, + void *pp_task_cb UNUSED) { if (err) strbuf_addstr(err, "asking for a quick stop\n"); @@ -136,7 +134,7 @@ static const char * const testsuite_usage[] = { static int testsuite(int argc, const char **argv) { struct testsuite suite = TESTSUITE_INIT; - int max_jobs = 1, i, ret; + int max_jobs = 1, i, ret = 0; DIR *dir; struct dirent *d; struct option options[] = { @@ -152,6 +150,12 @@ static int testsuite(int argc, const char **argv) "write JUnit-style XML files"), OPT_END() }; + struct run_process_parallel_opts opts = { + .get_next_task = next_test, + .start_failure = test_failed, + .task_finished = test_finished, + .data = &suite, + }; argc = parse_options(argc, argv, NULL, options, testsuite_usage, PARSE_OPT_STOP_AT_NON_OPTION); @@ -192,8 +196,8 @@ static int testsuite(int argc, const char **argv) fprintf(stderr, "Running %"PRIuMAX" tests (%d at a time)\n", (uintmax_t)suite.tests.nr, max_jobs); - ret = run_processes_parallel(max_jobs, next_test, test_failed, - test_finished, &suite); + opts.processes = max_jobs; + run_processes_parallel(&opts); if (suite.failed.nr > 0) { ret = 1; @@ -206,7 +210,7 @@ static int testsuite(int argc, const char **argv) string_list_clear(&suite.tests, 0); string_list_clear(&suite.failed, 0); - return !!ret; + return ret; } static uint64_t my_random_next = 1234; @@ -381,13 +385,17 @@ int cmd__run_command(int argc, const char **argv) { struct child_process proc = CHILD_PROCESS_INIT; int jobs; + int ret; + struct run_process_parallel_opts opts = { + .data = &proc, + }; if (argc > 1 && !strcmp(argv[1], "testsuite")) - exit(testsuite(argc - 1, argv + 1)); + return testsuite(argc - 1, argv + 1); if (!strcmp(argv[1], "inherited-handle")) - exit(inherit_handle(argv[0])); + return inherit_handle(argv[0]); if (!strcmp(argv[1], "inherited-handle-child")) - exit(inherit_handle_child()); + return inherit_handle_child(); if (argc >= 2 && !strcmp(argv[1], "quote-stress-test")) return !!quote_stress_test(argc - 1, argv + 1); @@ -404,41 +412,52 @@ int cmd__run_command(int argc, const char **argv) argv += 2; argc -= 2; } - if (argc < 3) - return 1; + if (argc < 3) { + ret = 1; + goto cleanup; + } strvec_pushv(&proc.args, (const char **)argv + 2); if (!strcmp(argv[1], "start-command-ENOENT")) { - if (start_command(&proc) < 0 && errno == ENOENT) - return 0; + if (start_command(&proc) < 0 && errno == ENOENT) { + ret = 0; + goto cleanup; + } fprintf(stderr, "FAIL %s\n", argv[1]); return 1; } - if (!strcmp(argv[1], "run-command")) - exit(run_command(&proc)); + if (!strcmp(argv[1], "run-command")) { + ret = run_command(&proc); + goto cleanup; + } if (!strcmp(argv[1], "--ungroup")) { argv += 1; argc -= 1; - run_processes_parallel_ungroup = 1; + opts.ungroup = 1; } jobs = atoi(argv[2]); strvec_clear(&proc.args); strvec_pushv(&proc.args, (const char **)argv + 3); - if (!strcmp(argv[1], "run-command-parallel")) - exit(run_processes_parallel(jobs, parallel_next, - NULL, NULL, &proc)); - - if (!strcmp(argv[1], "run-command-abort")) - exit(run_processes_parallel(jobs, parallel_next, - NULL, task_finished, &proc)); - - if (!strcmp(argv[1], "run-command-no-jobs")) - exit(run_processes_parallel(jobs, no_job, - NULL, task_finished, &proc)); - - fprintf(stderr, "check usage\n"); - return 1; + if (!strcmp(argv[1], "run-command-parallel")) { + opts.get_next_task = parallel_next; + } else if (!strcmp(argv[1], "run-command-abort")) { + opts.get_next_task = parallel_next; + opts.task_finished = task_finished; + } else if (!strcmp(argv[1], "run-command-no-jobs")) { + opts.get_next_task = no_job; + opts.task_finished = task_finished; + } else { + ret = 1; + fprintf(stderr, "check usage\n"); + goto cleanup; + } + opts.processes = jobs; + run_processes_parallel(&opts); + ret = 0; +cleanup: + child_process_clear(&proc); + return ret; } diff --git a/t/helper/test-scrap-cache-tree.c b/t/helper/test-scrap-cache-tree.c index 026c802479..a26107ed70 100644 --- a/t/helper/test-scrap-cache-tree.c +++ b/t/helper/test-scrap-cache-tree.c @@ -1,3 +1,4 @@ +#define USE_THE_INDEX_VARIABLE #include "test-tool.h" #include "cache.h" #include "lockfile.h" @@ -9,11 +10,11 @@ int cmd__scrap_cache_tree(int ac, const char **av) struct lock_file index_lock = LOCK_INIT; setup_git_directory(); - hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR); - if (read_cache() < 0) + 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(&active_cache_tree); - active_cache_tree = NULL; + cache_tree_free(&the_index.cache_tree); + the_index.cache_tree = NULL; if (write_locked_index(&the_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 d860c387c3..71fe5c6145 100644 --- a/t/helper/test-sha1.c +++ b/t/helper/test-sha1.c @@ -5,3 +5,11 @@ int cmd__sha1(int ac, const char **av) { return cmd_hash_impl(ac, av, GIT_HASH_SHA1); } + +int cmd__sha1_is_sha1dc(int argc UNUSED, const char **argv UNUSED) +{ +#ifdef platform_SHA_IS_SHA1DC + return 0; +#endif + return 1; +} diff --git a/t/helper/test-sigchain.c b/t/helper/test-sigchain.c index d013bccdda..d1cf7377b7 100644 --- a/t/helper/test-sigchain.c +++ b/t/helper/test-sigchain.c @@ -1,5 +1,4 @@ #include "test-tool.h" -#include "cache.h" #include "sigchain.h" #define X(f) \ diff --git a/t/helper/test-simple-ipc.c b/t/helper/test-simple-ipc.c index 28365ff85b..3d1436da59 100644 --- a/t/helper/test-simple-ipc.c +++ b/t/helper/test-simple-ipc.c @@ -3,13 +3,14 @@ */ #include "test-tool.h" -#include "cache.h" +#include "gettext.h" #include "strbuf.h" #include "simple-ipc.h" #include "parse-options.h" #include "thread-utils.h" #include "strvec.h" #include "run-command.h" +#include "trace2.h" #ifndef SUPPORTS_SIMPLE_IPC int cmd__simple_ipc(int argc, const char **argv) diff --git a/t/helper/test-submodule-nested-repo-config.c b/t/helper/test-submodule-nested-repo-config.c index dc1c14bde3..a3848a8b66 100644 --- a/t/helper/test-submodule-nested-repo-config.c +++ b/t/helper/test-submodule-nested-repo-config.c @@ -1,4 +1,5 @@ #include "test-tool.h" +#include "cache.h" #include "submodule-config.h" static void die_usage(const char **argv, const char *msg) diff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c index b7d117cd55..e060cc6226 100644 --- a/t/helper/test-submodule.c +++ b/t/helper/test-submodule.c @@ -111,10 +111,94 @@ static int cmd__submodule_resolve_relative_url(int argc, const char **argv) return 0; } +static int cmd__submodule_config_list(int argc, const char **argv) +{ + struct option options[] = { + OPT_END() + }; + const char *const usage[] = { + "test-tool submodule config-list <key>", + NULL + }; + argc = parse_options(argc, argv, "test-tools", options, usage, + PARSE_OPT_KEEP_ARGV0); + + setup_git_directory(); + + if (argc == 2) + return print_config_from_gitmodules(the_repository, argv[1]); + usage_with_options(usage, options); +} + +static int cmd__submodule_config_set(int argc, const char **argv) +{ + struct option options[] = { + OPT_END() + }; + const char *const usage[] = { + "test-tool submodule config-set <key> <value>", + NULL + }; + argc = parse_options(argc, argv, "test-tools", options, usage, + PARSE_OPT_KEEP_ARGV0); + + setup_git_directory(); + + /* Equivalent to ACTION_SET in builtin/config.c */ + if (argc == 3) { + if (!is_writing_gitmodules_ok()) + die("please make sure that the .gitmodules file is in the working tree"); + + return config_set_in_gitmodules_file_gently(argv[1], argv[2]); + } + usage_with_options(usage, options); +} + +static int cmd__submodule_config_unset(int argc, const char **argv) +{ + struct option options[] = { + OPT_END() + }; + const char *const usage[] = { + "test-tool submodule config-unset <key>", + NULL + }; + + setup_git_directory(); + + if (argc == 2) { + if (!is_writing_gitmodules_ok()) + die("please make sure that the .gitmodules file is in the working tree"); + return config_set_in_gitmodules_file_gently(argv[1], NULL); + } + usage_with_options(usage, options); +} + +static int cmd__submodule_config_writeable(int argc, const char **argv) +{ + struct option options[] = { + OPT_END() + }; + const char *const usage[] = { + "test-tool submodule config-writeable", + NULL + }; + setup_git_directory(); + + if (argc == 1) + return is_writing_gitmodules_ok() ? 0 : -1; + + usage_with_options(usage, options); +} + static struct test_cmd cmds[] = { { "check-name", cmd__submodule_check_name }, { "is-active", cmd__submodule_is_active }, { "resolve-relative-url", cmd__submodule_resolve_relative_url}, + { "config-list", cmd__submodule_config_list }, + { "config-set", cmd__submodule_config_set }, + { "config-unset", cmd__submodule_config_unset }, + { "config-writeable", cmd__submodule_config_writeable }, }; int cmd__submodule(int argc, const char **argv) diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c index d1d013bcd9..abe8a785eb 100644 --- a/t/helper/test-tool.c +++ b/t/helper/test-tool.c @@ -13,6 +13,8 @@ static struct test_cmd cmds[] = { { "advise", cmd__advise_if_enabled }, { "bitmap", cmd__bitmap }, { "bloom", cmd__bloom }, + { "bundle-uri", cmd__bundle_uri }, + { "cache-tree", cmd__cache_tree }, { "chmtime", cmd__chmtime }, { "config", cmd__config }, { "crontab", cmd__crontab }, @@ -26,6 +28,7 @@ static struct test_cmd cmds[] = { { "dump-fsmonitor", cmd__dump_fsmonitor }, { "dump-split-index", cmd__dump_split_index }, { "dump-untracked-cache", cmd__dump_untracked_cache }, + { "env-helper", cmd__env_helper }, { "example-decorate", cmd__example_decorate }, { "fast-rebase", cmd__fast_rebase }, { "fsmonitor-client", cmd__fsmonitor_client }, @@ -72,6 +75,7 @@ static struct test_cmd cmds[] = { { "scrap-cache-tree", cmd__scrap_cache_tree }, { "serve-v2", cmd__serve_v2 }, { "sha1", cmd__sha1 }, + { "sha1-is-sha1dc", cmd__sha1_is_sha1dc }, { "sha256", cmd__sha256 }, { "sigchain", cmd__sigchain }, { "simple-ipc", cmd__simple_ipc }, diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h index 6b46b6444b..ea2672436c 100644 --- a/t/helper/test-tool.h +++ b/t/helper/test-tool.h @@ -1,12 +1,13 @@ #ifndef TEST_TOOL_H #define TEST_TOOL_H -#define USE_THE_INDEX_COMPATIBILITY_MACROS #include "git-compat-util.h" int cmd__advise_if_enabled(int argc, const char **argv); int cmd__bitmap(int argc, const char **argv); int cmd__bloom(int argc, const char **argv); +int cmd__bundle_uri(int argc, const char **argv); +int cmd__cache_tree(int argc, const char **argv); int cmd__chmtime(int argc, const char **argv); int cmd__config(int argc, const char **argv); int cmd__crontab(int argc, const char **argv); @@ -21,6 +22,7 @@ int cmd__dump_fsmonitor(int argc, const char **argv); int cmd__dump_split_index(int argc, const char **argv); int cmd__dump_untracked_cache(int argc, const char **argv); int cmd__dump_reftable(int argc, const char **argv); +int cmd__env_helper(int argc, const char **argv); int cmd__example_decorate(int argc, const char **argv); int cmd__fast_rebase(int argc, const char **argv); int cmd__fsmonitor_client(int argc, const char **argv); @@ -65,6 +67,7 @@ int cmd__run_command(int argc, const char **argv); int cmd__scrap_cache_tree(int argc, const char **argv); int cmd__serve_v2(int argc, const char **argv); int cmd__sha1(int argc, const char **argv); +int cmd__sha1_is_sha1dc(int argc, const char **argv); int cmd__oid_array(int argc, const char **argv); int cmd__sha256(int argc, const char **argv); int cmd__sigchain(int argc, const char **argv); diff --git a/t/helper/test-trace2.c b/t/helper/test-trace2.c index a714130ece..f374c21ec3 100644 --- a/t/helper/test-trace2.c +++ b/t/helper/test-trace2.c @@ -132,6 +132,7 @@ static int ut_003error(int argc, const char **argv) */ static int ut_004child(int argc, const char **argv) { + struct child_process cmd = CHILD_PROCESS_INIT; int result; /* @@ -141,7 +142,8 @@ static int ut_004child(int argc, const char **argv) if (!argc) return 0; - result = run_command_v_opt(argv, 0); + strvec_pushv(&cmd.args, argv); + result = run_command(&cmd); exit(result); } @@ -229,6 +231,187 @@ static int ut_010bug_BUG(int argc, const char **argv) } /* + * Single-threaded timer test. Create several intervals using the + * TEST1 timer. The test script can verify that an aggregate Trace2 + * "timer" event is emitted indicating that we started+stopped the + * timer the requested number of times. + */ +static int ut_100timer(int argc, const char **argv) +{ + const char *usage_error = + "expect <count> <ms_delay>"; + + int count = 0; + int delay = 0; + int k; + + if (argc != 2) + die("%s", usage_error); + if (get_i(&count, argv[0])) + die("%s", usage_error); + if (get_i(&delay, argv[1])) + die("%s", usage_error); + + for (k = 0; k < count; k++) { + trace2_timer_start(TRACE2_TIMER_ID_TEST1); + sleep_millisec(delay); + trace2_timer_stop(TRACE2_TIMER_ID_TEST1); + } + + return 0; +} + +struct ut_101_data { + int count; + int delay; +}; + +static void *ut_101timer_thread_proc(void *_ut_101_data) +{ + struct ut_101_data *data = _ut_101_data; + int k; + + trace2_thread_start("ut_101"); + + for (k = 0; k < data->count; k++) { + trace2_timer_start(TRACE2_TIMER_ID_TEST2); + sleep_millisec(data->delay); + trace2_timer_stop(TRACE2_TIMER_ID_TEST2); + } + + trace2_thread_exit(); + return NULL; +} + +/* + * Multi-threaded timer test. Create several threads that each create + * several intervals using the TEST2 timer. The test script can verify + * that an individual Trace2 "th_timer" events for each thread and an + * aggregate "timer" event are generated. + */ +static int ut_101timer(int argc, const char **argv) +{ + const char *usage_error = + "expect <count> <ms_delay> <threads>"; + + struct ut_101_data data = { 0, 0 }; + int nr_threads = 0; + int k; + pthread_t *pids = NULL; + + if (argc != 3) + die("%s", usage_error); + if (get_i(&data.count, argv[0])) + die("%s", usage_error); + if (get_i(&data.delay, argv[1])) + die("%s", usage_error); + if (get_i(&nr_threads, argv[2])) + die("%s", usage_error); + + CALLOC_ARRAY(pids, nr_threads); + + for (k = 0; k < nr_threads; k++) { + if (pthread_create(&pids[k], NULL, ut_101timer_thread_proc, &data)) + die("failed to create thread[%d]", k); + } + + for (k = 0; k < nr_threads; k++) { + if (pthread_join(pids[k], NULL)) + die("failed to join thread[%d]", k); + } + + free(pids); + + return 0; +} + +/* + * Single-threaded counter test. Add several values to the TEST1 counter. + * The test script can verify that the final sum is reported in the "counter" + * event. + */ +static int ut_200counter(int argc, const char **argv) +{ + const char *usage_error = + "expect <v1> [<v2> [...]]"; + int value; + int k; + + if (argc < 1) + die("%s", usage_error); + + for (k = 0; k < argc; k++) { + if (get_i(&value, argv[k])) + die("invalid value[%s] -- %s", + argv[k], usage_error); + trace2_counter_add(TRACE2_COUNTER_ID_TEST1, value); + } + + return 0; +} + +/* + * Multi-threaded counter test. Create seveal threads that each increment + * the TEST2 global counter. The test script can verify that an individual + * "th_counter" event is generated with a partial sum for each thread and + * that a final aggregate "counter" event is generated. + */ + +struct ut_201_data { + int v1; + int v2; +}; + +static void *ut_201counter_thread_proc(void *_ut_201_data) +{ + struct ut_201_data *data = _ut_201_data; + + trace2_thread_start("ut_201"); + + trace2_counter_add(TRACE2_COUNTER_ID_TEST2, data->v1); + trace2_counter_add(TRACE2_COUNTER_ID_TEST2, data->v2); + + trace2_thread_exit(); + return NULL; +} + +static int ut_201counter(int argc, const char **argv) +{ + const char *usage_error = + "expect <v1> <v2> <threads>"; + + struct ut_201_data data = { 0, 0 }; + int nr_threads = 0; + int k; + pthread_t *pids = NULL; + + if (argc != 3) + die("%s", usage_error); + if (get_i(&data.v1, argv[0])) + die("%s", usage_error); + if (get_i(&data.v2, argv[1])) + die("%s", usage_error); + if (get_i(&nr_threads, argv[2])) + die("%s", usage_error); + + CALLOC_ARRAY(pids, nr_threads); + + for (k = 0; k < nr_threads; k++) { + if (pthread_create(&pids[k], NULL, ut_201counter_thread_proc, &data)) + die("failed to create thread[%d]", k); + } + + for (k = 0; k < nr_threads; k++) { + if (pthread_join(pids[k], NULL)) + die("failed to join thread[%d]", k); + } + + free(pids); + + return 0; +} + +/* * Usage: * test-tool trace2 <ut_name_1> <ut_usage_1> * test-tool trace2 <ut_name_2> <ut_usage_2> @@ -248,6 +431,12 @@ static struct unit_test ut_table[] = { { ut_008bug, "008bug", "" }, { ut_009bug_BUG, "009bug_BUG","" }, { ut_010bug_BUG, "010bug_BUG","" }, + + { ut_100timer, "100timer", "<count> <ms_delay>" }, + { ut_101timer, "101timer", "<count> <ms_delay> <threads>" }, + + { ut_200counter, "200counter", "<v1> [<v2> [<v3> [...]]]" }, + { ut_201counter, "201counter", "<v1> <v2> <threads>" }, }; /* clang-format on */ diff --git a/t/helper/test-wildmatch.c b/t/helper/test-wildmatch.c index 2c103d1824..a95bb4da9b 100644 --- a/t/helper/test-wildmatch.c +++ b/t/helper/test-wildmatch.c @@ -1,5 +1,4 @@ #include "test-tool.h" -#include "cache.h" int cmd__wildmatch(int argc, const char **argv) { diff --git a/t/helper/test-write-cache.c b/t/helper/test-write-cache.c index 8837717d36..7d45cd61e8 100644 --- a/t/helper/test-write-cache.c +++ b/t/helper/test-write-cache.c @@ -1,3 +1,4 @@ +#define USE_THE_INDEX_VARIABLE #include "test-tool.h" #include "cache.h" #include "lockfile.h" @@ -9,9 +10,10 @@ int cmd__write_cache(int argc, const char **argv) if (argc == 2) cnt = strtol(argv[1], NULL, 0); setup_git_directory(); - read_cache(); + repo_read_index(the_repository); for (i = 0; i < cnt; i++) { - hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR); + repo_hold_locked_index(the_repository, &index_lock, + LOCK_DIE_ON_ERROR); if (write_locked_index(&the_index, &index_lock, COMMIT_LOCK)) die("unable to write index file"); } diff --git a/t/interop/interop-lib.sh b/t/interop/interop-lib.sh index 3e0a2911d4..62f4481b6e 100644 --- a/t/interop/interop-lib.sh +++ b/t/interop/interop-lib.sh @@ -68,7 +68,7 @@ generate_wrappers () { wrap_git .bin/git.a "$DIR_A" && wrap_git .bin/git.b "$DIR_B" && write_script .bin/git <<-\EOF && - echo >&2 fatal: test tried to run generic git + echo >&2 fatal: test tried to run generic git: $* exit 1 EOF PATH=$(pwd)/.bin:$PATH diff --git a/t/lib-bundle-uri-protocol.sh b/t/lib-bundle-uri-protocol.sh new file mode 100644 index 0000000000..a4a1af8d02 --- /dev/null +++ b/t/lib-bundle-uri-protocol.sh @@ -0,0 +1,216 @@ +# Set up and run tests of the 'bundle-uri' command in protocol v2 +# +# The test that includes this script should set BUNDLE_URI_PROTOCOL +# to one of "file", "git", or "http". + +BUNDLE_URI_TEST_PARENT= +BUNDLE_URI_TEST_URI= +BUNDLE_URI_TEST_BUNDLE_URI= +case "$BUNDLE_URI_PROTOCOL" in +file) + BUNDLE_URI_PARENT=file_parent + BUNDLE_URI_REPO_URI="file://$PWD/file_parent" + BUNDLE_URI_BUNDLE_URI="$BUNDLE_URI_REPO_URI/fake.bdl" + test_set_prereq BUNDLE_URI_FILE + ;; +git) + . "$TEST_DIRECTORY"/lib-git-daemon.sh + 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" + test_set_prereq BUNDLE_URI_GIT + ;; +http) + . "$TEST_DIRECTORY"/lib-httpd.sh + 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" + test_set_prereq BUNDLE_URI_HTTP + ;; +*) + BUG "Need to pass valid BUNDLE_URI_PROTOCOL (was \"$BUNDLE_URI_PROTOCOL\")" + ;; +esac + +test_expect_success "setup protocol v2 $BUNDLE_URI_PROTOCOL:// tests" ' + git init "$BUNDLE_URI_PARENT" && + test_commit -C "$BUNDLE_URI_PARENT" one && + git -C "$BUNDLE_URI_PARENT" config uploadpack.advertiseBundleURIs true +' + +case "$BUNDLE_URI_PROTOCOL" in +http) + test_expect_success "setup config for $BUNDLE_URI_PROTOCOL:// tests" ' + git -C "$BUNDLE_URI_PARENT" config http.receivepack true + ' + ;; +*) + ;; +esac +BUNDLE_URI_BUNDLE_URI_ESCAPED=$(echo "$BUNDLE_URI_BUNDLE_URI" | test_uri_escape) + +test_expect_success "connect with $BUNDLE_URI_PROTOCOL:// using protocol v2: no bundle-uri" ' + test_when_finished "rm -f log" && + test_when_finished "git -C \"$BUNDLE_URI_PARENT\" config uploadpack.advertiseBundleURIs true" && + git -C "$BUNDLE_URI_PARENT" config uploadpack.advertiseBundleURIs false && + + GIT_TRACE_PACKET="$PWD/log" \ + git \ + -c protocol.version=2 \ + ls-remote --symref "$BUNDLE_URI_REPO_URI" \ + >actual 2>err && + + # Server responded using protocol v2 + grep "< version 2" log && + + ! grep bundle-uri log +' + +test_expect_success "connect with $BUNDLE_URI_PROTOCOL:// using protocol v2: have bundle-uri" ' + test_when_finished "rm -f log" && + + GIT_TRACE_PACKET="$PWD/log" \ + git \ + -c protocol.version=2 \ + ls-remote --symref "$BUNDLE_URI_REPO_URI" \ + >actual 2>err && + + # Server responded using protocol v2 + grep "< version 2" log && + + # Server advertised bundle-uri capability + grep "< bundle-uri" log +' + +test_expect_success "clone with $BUNDLE_URI_PROTOCOL:// using protocol v2: request bundle-uris" ' + test_when_finished "rm -rf log* cloned*" && + + GIT_TRACE_PACKET="$PWD/log" \ + git \ + -c transfer.bundleURI=false \ + -c protocol.version=2 \ + clone "$BUNDLE_URI_REPO_URI" cloned \ + >actual 2>err && + + # Server responded using protocol v2 + grep "< version 2" log && + + # Server advertised bundle-uri capability + grep "< bundle-uri" log && + + # Client did not issue bundle-uri command + ! grep "> command=bundle-uri" log && + + GIT_TRACE_PACKET="$PWD/log" \ + git \ + -c transfer.bundleURI=true \ + -c protocol.version=2 \ + clone "$BUNDLE_URI_REPO_URI" cloned2 \ + >actual 2>err && + + # Server responded using protocol v2 + grep "< version 2" log && + + # Server advertised bundle-uri capability + grep "< bundle-uri" log && + + # Client issued bundle-uri command + grep "> command=bundle-uri" log && + + GIT_TRACE_PACKET="$PWD/log3" \ + git \ + -c transfer.bundleURI=true \ + -c protocol.version=2 \ + clone --bundle-uri="$BUNDLE_URI_BUNDLE_URI" \ + "$BUNDLE_URI_REPO_URI" cloned3 \ + >actual 2>err && + + # Server responded using protocol v2 + grep "< version 2" log3 && + + # Server advertised bundle-uri capability + grep "< bundle-uri" log3 && + + # Client did not issue bundle-uri command (--bundle-uri override) + ! grep "> command=bundle-uri" log3 +' + +# The remaining tests will all assume transfer.bundleURI=true +# +# This test can be removed when transfer.bundleURI is enabled by default. +test_expect_success 'enable transfer.bundleURI for remaining tests' ' + git config --global transfer.bundleURI true +' + +test_expect_success "test bundle-uri with $BUNDLE_URI_PROTOCOL:// using protocol v2" ' + test_config -C "$BUNDLE_URI_PARENT" \ + bundle.only.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED" && + + # All data about bundle URIs + cat >expect <<-EOF && + [bundle] + version = 1 + mode = all + [bundle "only"] + uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED + EOF + + test-tool bundle-uri \ + ls-remote \ + "$BUNDLE_URI_REPO_URI" \ + >actual && + test_cmp_config_output expect actual +' + +test_expect_success "test bundle-uri with $BUNDLE_URI_PROTOCOL:// using protocol v2 and extra data" ' + test_config -C "$BUNDLE_URI_PARENT" \ + bundle.only.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED" && + + # Extra data should be ignored + test_config -C "$BUNDLE_URI_PARENT" bundle.only.extra bogus && + + # All data about bundle URIs + cat >expect <<-EOF && + [bundle] + version = 1 + mode = all + [bundle "only"] + uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED + EOF + + test-tool bundle-uri \ + ls-remote \ + "$BUNDLE_URI_REPO_URI" \ + >actual && + test_cmp_config_output expect actual +' + +test_expect_success "test bundle-uri with $BUNDLE_URI_PROTOCOL:// using protocol v2 with list" ' + test_config -C "$BUNDLE_URI_PARENT" \ + bundle.bundle1.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED-1.bdl" && + test_config -C "$BUNDLE_URI_PARENT" \ + bundle.bundle2.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED-2.bdl" && + test_config -C "$BUNDLE_URI_PARENT" \ + bundle.bundle3.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED-3.bdl" && + + # All data about bundle URIs + cat >expect <<-EOF && + [bundle] + version = 1 + mode = all + [bundle "bundle1"] + uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED-1.bdl + [bundle "bundle2"] + uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED-2.bdl + [bundle "bundle3"] + uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED-3.bdl + EOF + + test-tool bundle-uri \ + ls-remote \ + "$BUNDLE_URI_REPO_URI" \ + >actual && + test_cmp_config_output expect actual +' diff --git a/t/lib-diff-alternative.sh b/t/lib-diff-alternative.sh index 8d1e408bb5..a8f5d3274a 100644 --- a/t/lib-diff-alternative.sh +++ b/t/lib-diff-alternative.sh @@ -105,10 +105,46 @@ index $file1..$file2 100644 } EOF + cat >expect_diffstat <<EOF + file1 => file2 | 21 ++++++++++----------- + 1 file changed, 10 insertions(+), 11 deletions(-) +EOF + STRATEGY=$1 + test_expect_success "$STRATEGY diff from attributes" ' + echo "file* diff=driver" >.gitattributes && + git config diff.driver.algorithm "$STRATEGY" && + test_must_fail git diff --no-index file1 file2 > output && + cat expect && + cat output && + test_cmp expect output + ' + + test_expect_success "$STRATEGY diff from attributes has valid diffstat" ' + echo "file* diff=driver" >.gitattributes && + git config diff.driver.algorithm "$STRATEGY" && + test_must_fail git diff --stat --no-index file1 file2 > output && + test_cmp expect_diffstat output + ' + test_expect_success "$STRATEGY diff" ' - test_must_fail git diff --no-index "--$STRATEGY" file1 file2 > output && + test_must_fail git diff --no-index "--diff-algorithm=$STRATEGY" file1 file2 > output && + test_cmp expect output + ' + + test_expect_success "$STRATEGY diff command line precedence before attributes" ' + echo "file* diff=driver" >.gitattributes && + git config diff.driver.algorithm myers && + test_must_fail git diff --no-index "--diff-algorithm=$STRATEGY" file1 file2 > output && + test_cmp expect output + ' + + test_expect_success "$STRATEGY diff attributes precedence before config" ' + git config diff.algorithm default && + echo "file* diff=driver" >.gitattributes && + git config diff.driver.algorithm "$STRATEGY" && + test_must_fail git diff --no-index file1 file2 > output && test_cmp expect output ' diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh index 1f6b9b08d1..6805229dcb 100644 --- a/t/lib-httpd.sh +++ b/t/lib-httpd.sh @@ -25,6 +25,7 @@ # LIB_HTTPD_DAV enable DAV # LIB_HTTPD_SVN enable SVN at given location (e.g. "svn") # LIB_HTTPD_SSL enable SSL +# LIB_HTTPD_PROXY enable proxy # # Copyright (c) 2008 Clemens Buchacher <drizzd@aon.at> # @@ -65,7 +66,8 @@ done for DEFAULT_HTTPD_MODULE_PATH in '/usr/libexec/apache2' \ '/usr/lib/apache2/modules' \ '/usr/lib64/httpd/modules' \ - '/usr/lib/httpd/modules' + '/usr/lib/httpd/modules' \ + '/usr/libexec/httpd' do if test -d "$DEFAULT_HTTPD_MODULE_PATH" then @@ -98,16 +100,19 @@ then fi HTTPD_VERSION=$($LIB_HTTPD_PATH -v | \ - sed -n 's/^Server version: Apache\/\([0-9]*\)\..*$/\1/p; q') + sed -n 's/^Server version: Apache\/\([0-9.]*\).*$/\1/p; q') +HTTPD_VERSION_MAJOR=$(echo $HTTPD_VERSION | cut -d. -f1) +HTTPD_VERSION_MINOR=$(echo $HTTPD_VERSION | cut -d. -f2) -if test -n "$HTTPD_VERSION" +if test -n "$HTTPD_VERSION_MAJOR" then if test -z "$LIB_HTTPD_MODULE_PATH" then - if ! test $HTTPD_VERSION -ge 2 + if ! test "$HTTPD_VERSION_MAJOR" -eq 2 || + ! test "$HTTPD_VERSION_MINOR" -ge 4 then test_skip_or_die GIT_TEST_HTTPD \ - "at least Apache version 2 is required" + "at least Apache version 2.4 is required" fi if ! test -d "$DEFAULT_HTTPD_MODULE_PATH" then @@ -129,6 +134,7 @@ install_script () { prepare_httpd() { mkdir -p "$HTTPD_DOCUMENT_ROOT_PATH" cp "$TEST_PATH"/passwd "$HTTPD_ROOT_PATH" + cp "$TEST_PATH"/proxy-passwd "$HTTPD_ROOT_PATH" install_script incomplete-length-upload-pack-v2-http.sh install_script incomplete-body-upload-pack-v2-http.sh install_script error-no-report.sh @@ -136,6 +142,7 @@ prepare_httpd() { install_script error-smart-http.sh install_script error.sh install_script apply-one-time-perl.sh + install_script nph-custom-auth.sh ln -s "$LIB_HTTPD_MODULE_PATH" "$HTTPD_ROOT_PATH/modules" @@ -172,6 +179,16 @@ prepare_httpd() { export LIB_HTTPD_SVN LIB_HTTPD_SVNPATH fi fi + + if test -n "$LIB_HTTPD_PROXY" + then + HTTPD_PARA="$HTTPD_PARA -DPROXY" + fi +} + +enable_http2 () { + HTTPD_PARA="$HTTPD_PARA -DHTTP2" + test_set_prereq HTTP2 } start_httpd() { @@ -211,8 +228,12 @@ test_http_push_nonff () { git commit -a -m path2 --amend && test_must_fail git push -v origin >output 2>&1 && - (cd "$REMOTE_REPO" && - test $HEAD = $(git rev-parse --verify HEAD)) + ( + cd "$REMOTE_REPO" && + echo "$HEAD" >expect && + git rev-parse --verify HEAD >actual && + test_cmp expect actual + ) ' test_expect_success 'non-fast-forward push show ref status' ' @@ -274,11 +295,11 @@ expect_askpass() { none) ;; pass) - echo "askpass: Password for 'http://$2@$dest': " + echo "askpass: Password for '$HTTPD_PROTO://$2@$dest': " ;; both) - echo "askpass: Username for 'http://$dest': " - echo "askpass: Password for 'http://$2@$dest': " + echo "askpass: Username for '$HTTPD_PROTO://$dest': " + echo "askpass: Password for '$HTTPD_PROTO://$2@$dest': " ;; *) false diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf index 706799391b..f43a25c1f1 100644 --- a/t/lib-httpd/apache.conf +++ b/t/lib-httpd/apache.conf @@ -29,17 +29,11 @@ ErrorLog error.log LoadModule setenvif_module modules/mod_setenvif.so </IfModule> -<IfVersion < 2.4> -LockFile accept.lock -</IfVersion> - -<IfVersion < 2.1> -<IfModule !mod_auth.c> - LoadModule auth_module modules/mod_auth.so -</IfModule> -</IfVersion> +<IfDefine HTTP2> +LoadModule http2_module modules/mod_http2.so +Protocols h2 h2c +</IfDefine> -<IfVersion >= 2.1> <IfModule !mod_auth_basic.c> LoadModule auth_basic_module modules/mod_auth_basic.so </IfModule> @@ -52,9 +46,23 @@ LockFile accept.lock <IfModule !mod_authz_host.c> LoadModule authz_host_module modules/mod_authz_host.so </IfModule> -</IfVersion> -<IfVersion >= 2.4> +<IfDefine PROXY> +<IfModule !mod_proxy.c> + LoadModule proxy_module modules/mod_proxy.so +</IfModule> +<IfModule !mod_proxy_http.c> + LoadModule proxy_http_module modules/mod_proxy_http.so +</IfModule> +ProxyRequests On +<Proxy "*"> + AuthType Basic + AuthName "proxy-auth" + AuthUserFile proxy-passwd + Require valid-user +</Proxy> +</IfDefine> + <IfModule !mod_authn_core.c> LoadModule authn_core_module modules/mod_authn_core.so </IfModule> @@ -64,13 +72,20 @@ LockFile accept.lock <IfModule !mod_access_compat.c> LoadModule access_compat_module modules/mod_access_compat.so </IfModule> -<IfModule !mod_mpm_prefork.c> - LoadModule mpm_prefork_module modules/mod_mpm_prefork.so -</IfModule> <IfModule !mod_unixd.c> LoadModule unixd_module modules/mod_unixd.so </IfModule> -</IfVersion> + +<IfDefine HTTP2> +<IfModule !mod_mpm_event.c> + LoadModule mpm_event_module modules/mod_mpm_event.so +</IfModule> +</IfDefine> +<IfDefine !HTTP2> +<IfModule !mod_mpm_prefork.c> + LoadModule mpm_prefork_module modules/mod_mpm_prefork.so +</IfModule> +</IfDefine> PassEnv GIT_VALGRIND PassEnv GIT_VALGRIND_OPTIONS @@ -110,6 +125,10 @@ Alias /auth/dumb/ www/auth/dumb/ Header set Set-Cookie name=value </LocationMatch> <LocationMatch /smart_headers/> + <RequireAll> + Require expr %{HTTP:x-magic-one} == 'abra' + Require expr %{HTTP:x-magic-two} == 'cadabra' + </RequireAll> SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH} SetEnv GIT_HTTP_EXPORT_ALL </LocationMatch> @@ -122,6 +141,11 @@ Alias /auth/dumb/ www/auth/dumb/ SetEnv GIT_HTTP_EXPORT_ALL SetEnv GIT_PROTOCOL </LocationMatch> +<LocationMatch /custom_auth/> + SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH} + SetEnv GIT_HTTP_EXPORT_ALL + CGIPassAuth on +</LocationMatch> ScriptAlias /smart/incomplete_length/git-upload-pack incomplete-length-upload-pack-v2-http.sh/ ScriptAlias /smart/incomplete_body/git-upload-pack incomplete-body-upload-pack-v2-http.sh/ ScriptAlias /smart/no_report/git-receive-pack error-no-report.sh/ @@ -131,6 +155,7 @@ ScriptAlias /broken_smart/ broken-smart-http.sh/ ScriptAlias /error_smart/ error-smart-http.sh/ ScriptAlias /error/ error.sh/ ScriptAliasMatch /one_time_perl/(.*) apply-one-time-perl.sh/$1 +ScriptAliasMatch /custom_auth/(.*) nph-custom-auth.sh/$1 <Directory ${GIT_EXEC_PATH}> Options FollowSymlinks </Directory> @@ -192,18 +217,6 @@ RewriteRule ^/intern-redir/(.*)/foo$ /smart/$1 [PT] RewriteRule ^/redir-objects/(.*/info/refs)$ /dumb/$1 [PT] RewriteRule ^/redir-objects/(.*/objects/.*)$ /dumb/$1 [R=301] -# Apache 2.2 does not understand <RequireAll>, so we use RewriteCond. -# And as RewriteCond does not allow testing for non-matches, we match -# the desired case first (one has abra, two has cadabra), and let it -# pass by marking the RewriteRule as [L], "last rule, do not process -# any other matching RewriteRules after this"), and then have another -# RewriteRule that matches all other cases and lets them fail via '[F]', -# "fail the request". -RewriteCond %{HTTP:x-magic-one} =abra -RewriteCond %{HTTP:x-magic-two} =cadabra -RewriteRule ^/smart_headers/.* - [L] -RewriteRule ^/smart_headers/.* - [F] - <IfDefine SSL> LoadModule ssl_module modules/mod_ssl.so @@ -212,7 +225,6 @@ SSLCertificateKeyFile httpd.pem SSLRandomSeed startup file:/dev/urandom 512 SSLRandomSeed connect file:/dev/urandom 512 SSLSessionCache none -SSLMutex file:ssl_mutex SSLEngine On </IfDefine> diff --git a/t/lib-httpd/nph-custom-auth.sh b/t/lib-httpd/nph-custom-auth.sh new file mode 100644 index 0000000000..f5345e775e --- /dev/null +++ b/t/lib-httpd/nph-custom-auth.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +VALID_CREDS_FILE=custom-auth.valid +CHALLENGE_FILE=custom-auth.challenge + +# +# If $VALID_CREDS_FILE exists in $HTTPD_ROOT_PATH, consider each line as a valid +# credential for the current request. Each line in the file is considered a +# valid HTTP Authorization header value. For example: +# +# Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== +# +# If $CHALLENGE_FILE exists in $HTTPD_ROOT_PATH, output the contents as headers +# in a 401 response if no valid authentication credentials were included in the +# request. For example: +# +# WWW-Authenticate: Bearer authorize_uri="id.example.com" p=1 q=0 +# WWW-Authenticate: Basic realm="example.com" +# + +if test -n "$HTTP_AUTHORIZATION" && \ + grep -Fqsx "${HTTP_AUTHORIZATION}" "$VALID_CREDS_FILE" +then + # 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 +fi + +echo 'HTTP/1.1 401 Authorization Required' +if test -f "$CHALLENGE_FILE" +then + cat "$CHALLENGE_FILE" +fi +echo diff --git a/t/lib-httpd/proxy-passwd b/t/lib-httpd/proxy-passwd new file mode 100644 index 0000000000..77c25138e0 --- /dev/null +++ b/t/lib-httpd/proxy-passwd @@ -0,0 +1 @@ +proxuser:2x7tAukjAED5M diff --git a/t/lib-httpd/ssl.cnf b/t/lib-httpd/ssl.cnf index 6dab2579cb..812e8253f0 100644 --- a/t/lib-httpd/ssl.cnf +++ b/t/lib-httpd/ssl.cnf @@ -1,7 +1,7 @@ RANDFILE = $ENV::RANDFILE_PATH [ req ] -default_bits = 1024 +default_bits = 2048 distinguished_name = req_distinguished_name prompt = no [ req_distinguished_name ] diff --git a/t/lib-patch-mode.sh b/t/lib-patch-mode.sh index cfd76bf987..89ca1f7805 100644 --- a/t/lib-patch-mode.sh +++ b/t/lib-patch-mode.sh @@ -29,8 +29,12 @@ set_and_save_state () { # verify_state <path> <expected-worktree-content> <expected-index-content> verify_state () { - test "$(cat "$1")" = "$2" && - test "$(git show :"$1")" = "$3" + echo "$2" >expect && + test_cmp expect "$1" && + + echo "$3" >expect && + git show :"$1" >actual && + test_cmp expect actual } # verify_saved_state <path> @@ -46,5 +50,6 @@ save_head () { } verify_saved_head () { - test "$(cat _head)" = "$(git rev-parse HEAD)" + git rev-parse HEAD >actual && + test_cmp _head actual } diff --git a/t/lib-rebase.sh b/t/lib-rebase.sh index b57541356b..7ca5b918f0 100644 --- a/t/lib-rebase.sh +++ b/t/lib-rebase.sh @@ -60,7 +60,7 @@ set_fake_editor () { ">") echo >> "$1";; bad) - action="badcmd";; + action="pickled";; fakesha) test \& != "$action" || action=pick echo "$action XXXXXXX False commit" >> "$1" @@ -211,6 +211,9 @@ check_reworded_commits () { # usage: set_replace_editor <file> # # Replace the todo file with the exact contents of the given file. +# N.B. sets GIT_SEQUENCE_EDITOR rather than EDITOR so it can be +# combined with set_fake_editor to reword commits and replace the +# todo list set_replace_editor () { cat >script <<-\EOF && cat FILENAME >"$1" @@ -219,6 +222,7 @@ set_replace_editor () { cat "$1" EOF - sed -e "s/FILENAME/$1/g" <script | write_script fake-editor.sh && - test_set_editor "$(pwd)/fake-editor.sh" + sed -e "s/FILENAME/$1/g" script | + write_script fake-sequence-editor.sh && + test_set_sequence_editor "$(pwd)/fake-sequence-editor.sh" } diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh index 2d31fcfda1..dee14992c5 100644 --- a/t/lib-submodule-update.sh +++ b/t/lib-submodule-update.sh @@ -168,20 +168,16 @@ replace_gitfile_with_git_dir () { # Note that this only supports submodules at the root level of the # superproject, with the default name, i.e. same as its path. test_git_directory_is_unchanged () { - ( - cd ".git/modules/$1" && - # does core.worktree point at the right place? - test "$(git config core.worktree)" = "../../../$1" && - # remove it temporarily before comparing, as - # "$1/.git/config" lacks it... - git config --unset core.worktree - ) && + # does core.worktree point at the right place? + echo "../../../$1" >expect && + git -C ".git/modules/$1" config core.worktree >actual && + test_cmp expect actual && + # remove it temporarily before comparing, as + # "$1/.git/config" lacks it... + git -C ".git/modules/$1" config --unset core.worktree && diff -r ".git/modules/$1" "$1/.git" && - ( - # ... and then restore. - cd ".git/modules/$1" && - git config core.worktree "../../../$1" - ) + # ... and then restore. + git -C ".git/modules/$1" config core.worktree "../../../$1" } test_git_directory_exists () { @@ -189,7 +185,9 @@ test_git_directory_exists () { if test -f sub1/.git then # does core.worktree point at the right place? - test "$(git -C .git/modules/$1 config core.worktree)" = "../../../$1" + echo "../../../$1" >expect && + git -C ".git/modules/$1" config core.worktree >actual && + test_cmp expect actual fi } diff --git a/t/perf/p0006-read-tree-checkout.sh b/t/perf/p0006-read-tree-checkout.sh index c481c012d2..325566e18e 100755 --- a/t/perf/p0006-read-tree-checkout.sh +++ b/t/perf/p0006-read-tree-checkout.sh @@ -49,6 +49,14 @@ test_perf "read-tree br_base br_ballast ($nr_files)" ' git read-tree -n -m br_base br_ballast ' +test_perf "read-tree br_ballast_plus_1 ($nr_files)" ' + # Run read-tree 100 times for clearer performance results & comparisons + for i in $(test_seq 100) + do + git read-tree -n -m br_ballast_plus_1 || return 1 + done +' + test_perf "switch between br_base br_ballast ($nr_files)" ' git checkout -q br_base && git checkout -q br_ballast diff --git a/t/perf/p0090-cache-tree.sh b/t/perf/p0090-cache-tree.sh new file mode 100755 index 0000000000..a8eabca2c4 --- /dev/null +++ b/t/perf/p0090-cache-tree.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +test_description="Tests performance of cache tree update operations" + +. ./perf-lib.sh + +test_perf_large_repo +test_checkout_worktree + +count=100 + +test_expect_success 'setup cache tree' ' + git write-tree +' + +test_cache_tree () { + test_perf "$1, $3" " + for i in \$(test_seq $count) + do + test-tool cache-tree $4 $2 + done + " +} + +test_cache_tree_update_functions () { + test_cache_tree 'no-op' 'control' "$1" "$2" + test_cache_tree 'prime_cache_tree' 'prime' "$1" "$2" + test_cache_tree 'cache_tree_update' 'update' "$1" "$2" +} + +test_cache_tree_update_functions "clean" "" +test_cache_tree_update_functions "invalidate 2" "--invalidate 2" +test_cache_tree_update_functions "invalidate 50" "--invalidate 50" +test_cache_tree_update_functions "empty" "--empty" + +test_done diff --git a/t/perf/p2000-sparse-operations.sh b/t/perf/p2000-sparse-operations.sh index fce8151d41..3242cfe91a 100755 --- a/t/perf/p2000-sparse-operations.sh +++ b/t/perf/p2000-sparse-operations.sh @@ -124,5 +124,6 @@ test_perf_on_all git read-tree -mu HEAD test_perf_on_all git checkout-index -f --all test_perf_on_all git update-index --add --remove $SPARSE_CONE/a test_perf_on_all "git rm -f $SPARSE_CONE/a && git checkout HEAD -- $SPARSE_CONE/a" +test_perf_on_all git grep --cached --sparse bogus -- "f2/f1/f1/*" test_done diff --git a/t/perf/p7102-reset.sh b/t/perf/p7102-reset.sh new file mode 100755 index 0000000000..9b039e8691 --- /dev/null +++ b/t/perf/p7102-reset.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +test_description='performance of reset' +. ./perf-lib.sh + +test_perf_default_repo +test_checkout_worktree + +test_perf 'reset --hard with change in tree' ' + base=$(git rev-parse HEAD) && + test_commit --no-tag A && + new=$(git rev-parse HEAD) && + + for i in $(test_seq 10) + do + git reset --hard $new && + git reset --hard $base || return $? + done +' + +test_done diff --git a/t/perf/p7822-grep-perl-character.sh b/t/perf/p7822-grep-perl-character.sh new file mode 100755 index 0000000000..87009c60df --- /dev/null +++ b/t/perf/p7822-grep-perl-character.sh @@ -0,0 +1,42 @@ +#!/bin/sh + +test_description="git-grep's perl regex + +If GIT_PERF_GREP_THREADS is set to a list of threads (e.g. '1 4 8' +etc.) we will test the patterns under those numbers of threads. +" + +. ./perf-lib.sh + +test_perf_large_repo +test_checkout_worktree + +if test -n "$GIT_PERF_GREP_THREADS" +then + test_set_prereq PERF_GREP_ENGINES_THREADS +fi + +for pattern in \ + '\\bhow' \ + '\\bÆvar' \ + '\\d+ \\bÆvar' \ + '\\bBelón\\b' \ + '\\w{12}\\b' +do + echo '$pattern' >pat + if ! test_have_prereq PERF_GREP_ENGINES_THREADS + then + test_perf "grep -P '$pattern'" --prereq PCRE " + git -P grep -f pat || : + " + else + for threads in $GIT_PERF_GREP_THREADS + do + test_perf "grep -P '$pattern' with $threads threads" --prereq PTHREADS,PCRE " + git -c grep.threads=$threads -P grep -f pat || : + " + done + fi +done + +test_done diff --git a/t/perf/run b/t/perf/run index 33da4d2aba..34115edec3 100755 --- a/t/perf/run +++ b/t/perf/run @@ -232,10 +232,10 @@ then ) elif test -n "$GIT_PERF_SUBSECTION" then - egrep "^$GIT_PERF_SUBSECTION\$" "$TEST_RESULTS_DIR"/run_subsections.names >/dev/null || + grep -E "^$GIT_PERF_SUBSECTION\$" "$TEST_RESULTS_DIR"/run_subsections.names >/dev/null || die "subsection '$GIT_PERF_SUBSECTION' not found in '$GIT_PERF_CONFIG_FILE'" - egrep "^$GIT_PERF_SUBSECTION\$" "$TEST_RESULTS_DIR"/run_subsections.names | while read -r subsec + grep -E "^$GIT_PERF_SUBSECTION\$" "$TEST_RESULTS_DIR"/run_subsections.names | while read -r subsec do ( GIT_PERF_SUBSECTION="$subsec" diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 502b4bcf9e..8ea31d187a 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -815,7 +815,8 @@ test_expect_success 'test_oid provides sane info by default' ' grep "^00*\$" actual && rawsz="$(test_oid rawsz)" && hexsz="$(test_oid hexsz)" && - test "$hexsz" -eq $(wc -c <actual) && + # +1 accounts for the trailing newline + test $(( $hexsz + 1)) -eq $(wc -c <actual) && test $(( $rawsz * 2)) -eq "$hexsz" ' @@ -826,7 +827,7 @@ test_expect_success 'test_oid can look up data for SHA-1' ' grep "^00*\$" actual && rawsz="$(test_oid rawsz)" && hexsz="$(test_oid hexsz)" && - test $(wc -c <actual) -eq 40 && + test $(wc -c <actual) -eq 41 && test "$rawsz" -eq 20 && test "$hexsz" -eq 40 ' @@ -838,7 +839,7 @@ test_expect_success 'test_oid can look up data for SHA-256' ' grep "^00*\$" actual && rawsz="$(test_oid rawsz)" && hexsz="$(test_oid hexsz)" && - test $(wc -c <actual) -eq 64 && + test $(wc -c <actual) -eq 65 && test "$rawsz" -eq 32 && test "$hexsz" -eq 64 ' diff --git a/t/t0001-init.sh b/t/t0001-init.sh index d479303efa..30a6edca1d 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -598,9 +598,14 @@ test_expect_success 'invalid default branch name' ' test_expect_success 'branch -m with the initial branch' ' git init rename-initial && git -C rename-initial branch -m renamed && - test renamed = $(git -C rename-initial symbolic-ref --short HEAD) && + echo renamed >expect && + git -C rename-initial symbolic-ref --short HEAD >actual && + test_cmp expect actual && + git -C rename-initial branch -m renamed again && - test again = $(git -C rename-initial symbolic-ref --short HEAD) + echo again >expect && + git -C rename-initial symbolic-ref --short HEAD >actual && + test_cmp expect actual ' test_done diff --git a/t/t0002-gitfile.sh b/t/t0002-gitfile.sh index 26eaca095a..e013d38f48 100755 --- a/t/t0002-gitfile.sh +++ b/t/t0002-gitfile.sh @@ -33,7 +33,9 @@ test_expect_success 'bad setup: invalid .git file path' ' test_expect_success 'final setup + check rev-parse --git-dir' ' echo "gitdir: $REAL" >.git && - test "$REAL" = "$(git rev-parse --git-dir)" + echo "$REAL" >expect && + git rev-parse --git-dir >actual && + test_cmp expect actual ' test_expect_success 'check hash-object' ' diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh index d0284fe2d7..89b306cb11 100755 --- a/t/t0003-attributes.sh +++ b/t/t0003-attributes.sh @@ -25,7 +25,15 @@ attr_check_quote () { git check-attr test -- "$path" >actual && echo "\"$quoted_path\": test: $expect" >expect && test_cmp expect actual +} + +attr_check_source () { + path="$1" expect="$2" source="$3" git_opts="$4" && + git $git_opts check-attr --source $source test -- "$path" >actual 2>err && + echo "$path: test: $expect" >expect && + test_cmp expect actual && + test_must_be_empty err } test_expect_success 'open-quoted pathname' ' @@ -33,7 +41,6 @@ test_expect_success 'open-quoted pathname' ' attr_check a unspecified ' - test_expect_success 'setup' ' mkdir -p a/b/d a/c b && ( @@ -80,12 +87,23 @@ test_expect_success 'setup' ' EOF ' +test_expect_success 'setup branches' ' + mkdir -p foo/bar && + test_commit --printf "add .gitattributes" foo/bar/.gitattributes \ + "f test=f\na/i test=n\n" tag-1 && + test_commit --printf "add .gitattributes" foo/bar/.gitattributes \ + "g test=g\na/i test=m\n" tag-2 && + rm foo/bar/.gitattributes +' + test_expect_success 'command line checks' ' test_must_fail git check-attr && test_must_fail git check-attr -- && test_must_fail git check-attr test && test_must_fail git check-attr test -- && test_must_fail git check-attr -- f && + test_must_fail git check-attr --source && + test_must_fail git check-attr --source not-a-valid-ref && echo "f" | test_must_fail git check-attr --stdin && echo "f" | test_must_fail git check-attr --stdin -- f && echo "f" | test_must_fail git check-attr --stdin test -- f && @@ -203,9 +221,12 @@ test_expect_success 'attribute test: read paths from stdin' ' test_cmp expect actual ' -test_expect_success 'attribute test: --all option' ' +test_expect_success 'setup --all option' ' grep -v unspecified <expect-all | sort >specified-all && - sed -e "s/:.*//" <expect-all | uniq >stdin-all && + sed -e "s/:.*//" <expect-all | uniq >stdin-all +' + +test_expect_success 'attribute test: --all option' ' git check-attr --stdin --all <stdin-all >tmp && sort tmp >actual && test_cmp specified-all actual @@ -284,6 +305,15 @@ test_expect_success 'using --git-dir and --work-tree' ' ) ' +test_expect_success 'using --source' ' + attr_check_source foo/bar/f f tag-1 && + attr_check_source foo/bar/a/i n tag-1 && + attr_check_source foo/bar/f unspecified tag-2 && + attr_check_source foo/bar/a/i m tag-2 && + attr_check_source foo/bar/g g tag-2 && + attr_check_source foo/bar/g unspecified tag-1 +' + test_expect_success 'setup bare' ' git clone --template= --bare . bare.git ' @@ -303,6 +333,18 @@ test_expect_success 'bare repository: check that .gitattribute is ignored' ' ) ' +test_expect_success 'bare repository: with --source' ' + ( + cd bare.git && + attr_check_source foo/bar/f f tag-1 && + attr_check_source foo/bar/a/i n tag-1 && + attr_check_source foo/bar/f unspecified tag-2 && + attr_check_source foo/bar/a/i m tag-2 && + attr_check_source foo/bar/g g tag-2 && + attr_check_source foo/bar/g unspecified tag-1 + ) +' + test_expect_success 'bare repository: check that --cached honors index' ' ( cd bare.git && @@ -400,7 +442,7 @@ test_expect_success 'large attributes line ignores trailing content in tree' ' test_expect_success EXPENSIVE 'large attributes file ignored in tree' ' test_when_finished "rm .gitattributes" && - dd if=/dev/zero of=.gitattributes bs=101M count=1 2>/dev/null && + dd if=/dev/zero of=.gitattributes bs=1048576 count=101 2>/dev/null && git check-attr --all path >/dev/null 2>err && echo "warning: ignoring overly large gitattributes file ${SQ}.gitattributes${SQ}" >expect && test_cmp expect err @@ -428,7 +470,7 @@ test_expect_success 'large attributes line ignores trailing content in index' ' test_expect_success EXPENSIVE 'large attributes file ignored in index' ' test_when_finished "git update-index --remove .gitattributes" && - blob=$(dd if=/dev/zero bs=101M count=1 2>/dev/null | git hash-object -w --stdin) && + 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 && git check-attr --cached --all path >/dev/null 2>err && echo "warning: ignoring overly large gitattributes blob ${SQ}.gitattributes${SQ}" >expect && diff --git a/t/t0006-date.sh b/t/t0006-date.sh index 2490162071..e18b160286 100755 --- a/t/t0006-date.sh +++ b/t/t0006-date.sh @@ -88,6 +88,13 @@ check_parse 2008-02-14 bad check_parse '2008-02-14 20:30:45' '2008-02-14 20:30:45 +0000' check_parse '2008-02-14 20:30:45 -0500' '2008-02-14 20:30:45 -0500' check_parse '2008.02.14 20:30:45 -0500' '2008-02-14 20:30:45 -0500' +check_parse '20080214T20:30:45' '2008-02-14 20:30:45 +0000' +check_parse '20080214T20:30' '2008-02-14 20:30:00 +0000' +check_parse '20080214T20' '2008-02-14 20:00:00 +0000' +check_parse '20080214T203045' '2008-02-14 20:30:45 +0000' +check_parse '20080214T2030' '2008-02-14 20:30:00 +0000' +check_parse '20080214T000000.20' '2008-02-14 00:00:00 +0000' +check_parse '20080214T00:00:00.20' '2008-02-14 00:00:00 +0000' check_parse '20080214T203045-04:00' '2008-02-14 20:30:45 -0400' check_parse '20080214T203045 -04:00' '2008-02-14 20:30:45 -0400' check_parse '20080214T203045.019-04:00' '2008-02-14 20:30:45 -0400' @@ -99,6 +106,7 @@ check_parse '2008-02-14 20:30:45 -05' '2008-02-14 20:30:45 -0500' check_parse '2008-02-14 20:30:45 -:30' '2008-02-14 20:30:45 +0000' 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_approxidate() { echo "$1 -> $2 +0000" >expect diff --git a/t/t0007-git-var.sh b/t/t0007-git-var.sh index e56f4b9ac5..eeb8539c1b 100755 --- a/t/t0007-git-var.sh +++ b/t/t0007-git-var.sh @@ -5,6 +5,12 @@ test_description='basic sanity checks for git var' TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh +sane_unset_all_editors () { + sane_unset GIT_EDITOR && + sane_unset VISUAL && + sane_unset EDITOR +} + test_expect_success 'get GIT_AUTHOR_IDENT' ' test_tick && echo "$GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE" >expect && @@ -47,6 +53,100 @@ test_expect_success 'get GIT_DEFAULT_BRANCH with configuration' ' ) ' +test_expect_success 'get GIT_EDITOR without configuration' ' + ( + sane_unset_all_editors && + test_expect_code 1 git var GIT_EDITOR >out && + test_must_be_empty out + ) +' + +test_expect_success 'get GIT_EDITOR with configuration' ' + test_config core.editor foo && + ( + sane_unset_all_editors && + echo foo >expect && + git var GIT_EDITOR >actual && + test_cmp expect actual + ) +' + +test_expect_success 'get GIT_EDITOR with environment variable GIT_EDITOR' ' + ( + sane_unset_all_editors && + echo bar >expect && + GIT_EDITOR=bar git var GIT_EDITOR >actual && + test_cmp expect actual + ) +' + +test_expect_success 'get GIT_EDITOR with environment variable EDITOR' ' + ( + sane_unset_all_editors && + echo bar >expect && + EDITOR=bar git var GIT_EDITOR >actual && + test_cmp expect actual + ) +' + +test_expect_success 'get GIT_EDITOR with configuration and environment variable GIT_EDITOR' ' + test_config core.editor foo && + ( + sane_unset_all_editors && + echo bar >expect && + GIT_EDITOR=bar git var GIT_EDITOR >actual && + test_cmp expect actual + ) +' + +test_expect_success 'get GIT_EDITOR with configuration and environment variable EDITOR' ' + test_config core.editor foo && + ( + sane_unset_all_editors && + echo foo >expect && + EDITOR=bar git var GIT_EDITOR >actual && + test_cmp expect actual + ) +' + +test_expect_success 'get GIT_SEQUENCE_EDITOR without configuration' ' + ( + sane_unset GIT_SEQUENCE_EDITOR && + git var GIT_EDITOR >expect && + git var GIT_SEQUENCE_EDITOR >actual && + test_cmp expect actual + ) +' + +test_expect_success 'get GIT_SEQUENCE_EDITOR with configuration' ' + test_config sequence.editor foo && + ( + sane_unset GIT_SEQUENCE_EDITOR && + echo foo >expect && + git var GIT_SEQUENCE_EDITOR >actual && + test_cmp expect actual + ) +' + +test_expect_success 'get GIT_SEQUENCE_EDITOR with environment variable' ' + ( + sane_unset GIT_SEQUENCE_EDITOR && + echo bar >expect && + GIT_SEQUENCE_EDITOR=bar git var GIT_SEQUENCE_EDITOR >actual && + test_cmp expect actual + ) +' + +test_expect_success 'get GIT_SEQUENCE_EDITOR with configuration and environment variable' ' + test_config sequence.editor foo && + ( + sane_unset GIT_SEQUENCE_EDITOR && + echo bar >expect && + GIT_SEQUENCE_EDITOR=bar git var GIT_SEQUENCE_EDITOR >actual && + test_cmp expect actual + ) +' + # For git var -l, we check only a representative variable; # testing the whole output would make our test too brittle with # respect to unrelated changes in the test suite's environment. diff --git a/t/t0013-sha1dc.sh b/t/t0013-sha1dc.sh index 9ad76080aa..5324047689 100755 --- a/t/t0013-sha1dc.sh +++ b/t/t0013-sha1dc.sh @@ -6,9 +6,11 @@ TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh TEST_DATA="$TEST_DIRECTORY/t0013" -if test -z "$DC_SHA1" +test_lazy_prereq SHA1_IS_SHA1DC 'test-tool sha1-is-sha1dc' + +if ! test_have_prereq SHA1_IS_SHA1DC then - skip_all='skipping sha1 collision tests, DC_SHA1 not set' + skip_all='skipping sha1 collision tests, not using sha1collisiondetection' test_done fi diff --git a/t/t0017-env-helper.sh b/t/t0017-env-helper.sh index 2e42fba956..fc14ba091c 100755 --- a/t/t0017-env-helper.sh +++ b/t/t0017-env-helper.sh @@ -1,87 +1,87 @@ #!/bin/sh -test_description='test env--helper' +test_description='test test-tool env-helper' TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh -test_expect_success 'env--helper usage' ' - test_must_fail git env--helper && - test_must_fail git env--helper --type=bool && - test_must_fail git env--helper --type=ulong && - test_must_fail git env--helper --type=bool && - test_must_fail git env--helper --type=bool --default && - test_must_fail git env--helper --type=bool --default= && - test_must_fail git env--helper --defaultxyz +test_expect_success 'test-tool env-helper usage' ' + test_must_fail test-tool env-helper && + test_must_fail test-tool env-helper --type=bool && + test_must_fail test-tool env-helper --type=ulong && + test_must_fail test-tool env-helper --type=bool && + test_must_fail test-tool env-helper --type=bool --default && + test_must_fail test-tool env-helper --type=bool --default= && + test_must_fail test-tool env-helper --defaultxyz ' -test_expect_success 'env--helper bad default values' ' - test_must_fail git env--helper --type=bool --default=1xyz MISSING && - test_must_fail git env--helper --type=ulong --default=1xyz MISSING +test_expect_success 'test-tool env-helper bad default values' ' + test_must_fail test-tool env-helper --type=bool --default=1xyz MISSING && + test_must_fail test-tool env-helper --type=ulong --default=1xyz MISSING ' -test_expect_success 'env--helper --type=bool' ' +test_expect_success 'test-tool env-helper --type=bool' ' # Test various --default bool values echo true >expected && - git env--helper --type=bool --default=1 MISSING >actual && + test-tool env-helper --type=bool --default=1 MISSING >actual && test_cmp expected actual && - git env--helper --type=bool --default=yes MISSING >actual && + test-tool env-helper --type=bool --default=yes MISSING >actual && test_cmp expected actual && - git env--helper --type=bool --default=true MISSING >actual && + test-tool env-helper --type=bool --default=true MISSING >actual && test_cmp expected actual && echo false >expected && - test_must_fail git env--helper --type=bool --default=0 MISSING >actual && + test_must_fail test-tool env-helper --type=bool --default=0 MISSING >actual && test_cmp expected actual && - test_must_fail git env--helper --type=bool --default=no MISSING >actual && + test_must_fail test-tool env-helper --type=bool --default=no MISSING >actual && test_cmp expected actual && - test_must_fail git env--helper --type=bool --default=false MISSING >actual && + test_must_fail test-tool env-helper --type=bool --default=false MISSING >actual && test_cmp expected actual && # No output with --exit-code - git env--helper --type=bool --default=true --exit-code MISSING >actual.out 2>actual.err && + test-tool env-helper --type=bool --default=true --exit-code MISSING >actual.out 2>actual.err && test_must_be_empty actual.out && test_must_be_empty actual.err && - test_must_fail git env--helper --type=bool --default=false --exit-code MISSING >actual.out 2>actual.err && + test_must_fail test-tool env-helper --type=bool --default=false --exit-code MISSING >actual.out 2>actual.err && test_must_be_empty actual.out && test_must_be_empty actual.err && # Existing variable - EXISTS=true git env--helper --type=bool --default=false --exit-code EXISTS >actual.out 2>actual.err && + EXISTS=true test-tool env-helper --type=bool --default=false --exit-code EXISTS >actual.out 2>actual.err && test_must_be_empty actual.out && test_must_be_empty actual.err && test_must_fail \ env EXISTS=false \ - git env--helper --type=bool --default=true --exit-code EXISTS >actual.out 2>actual.err && + test-tool env-helper --type=bool --default=true --exit-code EXISTS >actual.out 2>actual.err && test_must_be_empty actual.out && test_must_be_empty actual.err ' -test_expect_success 'env--helper --type=ulong' ' +test_expect_success 'test-tool env-helper --type=ulong' ' echo 1234567890 >expected && - git env--helper --type=ulong --default=1234567890 MISSING >actual.out 2>actual.err && + test-tool env-helper --type=ulong --default=1234567890 MISSING >actual.out 2>actual.err && test_cmp expected actual.out && test_must_be_empty actual.err && echo 0 >expected && - test_must_fail git env--helper --type=ulong --default=0 MISSING >actual && + test_must_fail test-tool env-helper --type=ulong --default=0 MISSING >actual && test_cmp expected actual && - git env--helper --type=ulong --default=1234567890 --exit-code MISSING >actual.out 2>actual.err && + test-tool env-helper --type=ulong --default=1234567890 --exit-code MISSING >actual.out 2>actual.err && test_must_be_empty actual.out && test_must_be_empty actual.err && - EXISTS=1234567890 git env--helper --type=ulong --default=0 EXISTS --exit-code >actual.out 2>actual.err && + EXISTS=1234567890 test-tool env-helper --type=ulong --default=0 EXISTS --exit-code >actual.out 2>actual.err && test_must_be_empty actual.out && test_must_be_empty actual.err && echo 1234567890 >expected && - EXISTS=1234567890 git env--helper --type=ulong --default=0 EXISTS >actual.out 2>actual.err && + EXISTS=1234567890 test-tool env-helper --type=ulong --default=0 EXISTS >actual.out 2>actual.err && test_cmp expected actual.out && test_must_be_empty actual.err ' -test_expect_success 'env--helper reads config thanks to trace2' ' +test_expect_success 'test-tool env-helper reads config thanks to trace2' ' mkdir home && git config -f home/.gitconfig include.path cycle && git config -f home/cycle include.path .gitconfig && @@ -93,7 +93,7 @@ test_expect_success 'env--helper reads config thanks to trace2' ' test_must_fail \ env HOME="$(pwd)/home" GIT_TEST_ENV_HELPER=true \ - git -C cycle env--helper --type=bool --default=0 --exit-code GIT_TEST_ENV_HELPER 2>err && + test-tool -C cycle env-helper --type=bool --default=0 --exit-code GIT_TEST_ENV_HELPER 2>err && grep "exceeded maximum include depth" err ' diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh index abecd75e4e..46abbeed68 100755 --- a/t/t0021-conversion.sh +++ b/t/t0021-conversion.sh @@ -8,8 +8,8 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME . ./test-lib.sh . "$TEST_DIRECTORY"/lib-terminal.sh -TEST_ROOT="$PWD" -PATH=$TEST_ROOT:$PATH +PATH=$PWD:$PATH +TEST_ROOT="$(pwd)" write_script <<\EOF "$TEST_ROOT/rot13.sh" tr \ diff --git a/t/t0023-crlf-am.sh b/t/t0023-crlf-am.sh index f9bbb91f64..575805513a 100755 --- a/t/t0023-crlf-am.sh +++ b/t/t0023-crlf-am.sh @@ -2,6 +2,7 @@ test_description='Test am with auto.crlf' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh cat >patchfile <<\EOF diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh index a94ac1eae3..2f57c8669c 100755 --- a/t/t0027-auto-crlf.sh +++ b/t/t0027-auto-crlf.sh @@ -70,7 +70,8 @@ create_NNO_MIX_files () { cp CRLF ${pfx}_CRLF.txt && cp CRLF_mix_LF ${pfx}_CRLF_mix_LF.txt && cp LF_mix_CR ${pfx}_LF_mix_CR.txt && - cp CRLF_nul ${pfx}_CRLF_nul.txt + cp CRLF_nul ${pfx}_CRLF_nul.txt || + return 1 done done done @@ -101,7 +102,8 @@ commit_check_warn () { do fname=${pfx}_$f.txt && cp $f $fname && - git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err" + git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err" || + return 1 done && git commit -m "core.autocrlf $crlf" && check_warning "$lfname" ${pfx}_LF.err && @@ -121,15 +123,19 @@ commit_chk_wrnNNO () { lfmixcr=$1 ; shift crlfnul=$1 ; shift pfx=NNO_attr_${attr}_aeol_${aeol}_${crlf} - #Commit files on top of existing file - create_gitattributes "$attr" $aeol && - for f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul - do - fname=${pfx}_$f.txt && - cp $f $fname && - printf Z >>"$fname" && - git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err" - done + + test_expect_success 'setup commit NNO files' ' + #Commit files on top of existing file + create_gitattributes "$attr" $aeol && + for f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul + do + fname=${pfx}_$f.txt && + cp $f $fname && + printf Z >>"$fname" && + git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err" || + return 1 + done + ' test_expect_success "commit NNO files crlf=$crlf attr=$attr LF" ' check_warning "$lfwarn" ${pfx}_LF.err @@ -163,15 +169,19 @@ commit_MIX_chkwrn () { lfmixcr=$1 ; shift crlfnul=$1 ; shift pfx=MIX_attr_${attr}_aeol_${aeol}_${crlf} - #Commit file with CLRF_mix_LF on top of existing file - create_gitattributes "$attr" $aeol && - for f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul - do - fname=${pfx}_$f.txt && - cp CRLF_mix_LF $fname && - printf Z >>"$fname" && - git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err" - done + + test_expect_success 'setup commit file with mixed EOL' ' + #Commit file with CLRF_mix_LF on top of existing file + create_gitattributes "$attr" $aeol && + for f in LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul + do + fname=${pfx}_$f.txt && + cp CRLF_mix_LF $fname && + printf Z >>"$fname" && + git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err" || + return 1 + done + ' test_expect_success "commit file with mixed EOL onto LF crlf=$crlf attr=$attr" ' check_warning "$lfwarn" ${pfx}_LF.err @@ -289,17 +299,17 @@ checkout_files () { lfmixcrlf=$1 ; shift lfmixcr=$1 ; shift crlfnul=$1 ; shift - create_gitattributes "$attr" $ident $aeol && - git config core.autocrlf $crlf && + test_expect_success "setup config for checkout attr=$attr ident=$ident aeol=$aeol core.autocrlf=$crlf" ' + create_gitattributes "$attr" $ident $aeol && + git config core.autocrlf $crlf + ' pfx=eol_${ceol}_crlf_${crlf}_attr_${attr}_ && for f in LF CRLF LF_mix_CR CRLF_mix_LF LF_nul do - rm crlf_false_attr__$f.txt && - if test -z "$ceol"; then - git checkout -- crlf_false_attr__$f.txt - else - git -c core.eol=$ceol checkout -- crlf_false_attr__$f.txt - fi + test_expect_success "setup $f checkout ${ceol:+ with -c core.eol=$ceol}" ' + rm -f crlf_false_attr__$f.txt && + git ${ceol:+-c core.eol=$ceol} checkout -- crlf_false_attr__$f.txt + ' done test_expect_success "ls-files --eol attr=$attr $ident aeol=$aeol core.autocrlf=$crlf core.eol=$ceol" ' diff --git a/t/t0033-safe-directory.sh b/t/t0033-safe-directory.sh index aecb308cf6..dc3496897a 100755 --- a/t/t0033-safe-directory.sh +++ b/t/t0033-safe-directory.sh @@ -71,4 +71,13 @@ test_expect_success 'safe.directory=*, but is reset' ' expect_rejected_dir ' +test_expect_success 'safe.directory in included file' ' + cat >gitconfig-include <<-EOF && + [safe] + directory = "$(pwd)" + EOF + git config --global --add include.path "$(pwd)/gitconfig-include" && + git status +' + test_done diff --git a/t/t0035-safe-bare-repository.sh b/t/t0035-safe-bare-repository.sh index ecbdc8238d..11c15a48aa 100755 --- a/t/t0035-safe-bare-repository.sh +++ b/t/t0035-safe-bare-repository.sh @@ -51,4 +51,13 @@ test_expect_success 'safe.bareRepository on the command line' ' -c safe.bareRepository=all ' +test_expect_success 'safe.bareRepository in included file' ' + cat >gitconfig-include <<-\EOF && + [safe] + bareRepository = explicit + EOF + git config --global --add include.path "$(pwd)/gitconfig-include" && + expect_rejected -C outer-repo/bare-repo +' + test_done diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index 5cc62306e3..7d7ecfd571 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -709,4 +709,16 @@ test_expect_success 'subcommands are incompatible with KEEP_DASHDASH unless in c grep ^BUG err ' +test_expect_success 'negative magnitude' ' + test_must_fail test-tool parse-options --magnitude -1 >out 2>err && + grep "non-negative integer" err && + test_must_be_empty out +' + +test_expect_success 'magnitude with units but no numbers' ' + test_must_fail test-tool parse-options --magnitude m >out 2>err && + grep "non-negative integer" err && + test_must_be_empty out +' + test_done diff --git a/t/t0055-beyond-symlinks.sh b/t/t0055-beyond-symlinks.sh index 6bada37022..c3eb1158ef 100755 --- a/t/t0055-beyond-symlinks.sh +++ b/t/t0055-beyond-symlinks.sh @@ -15,12 +15,22 @@ test_expect_success SYMLINKS setup ' test_expect_success SYMLINKS 'update-index --add beyond symlinks' ' test_must_fail git update-index --add c/d && - ! ( git ls-files | grep c/d ) + cat >expect <<-\EOF && + a + b/d + EOF + git ls-files >actual && + test_cmp expect actual ' test_expect_success SYMLINKS 'add beyond symlinks' ' test_must_fail git add c/d && - ! ( git ls-files | grep c/d ) + cat >expect <<-\EOF && + a + b/d + EOF + git ls-files >actual && + test_cmp expect actual ' test_done diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh index 68e29c904a..0afa3d0d31 100755 --- a/t/t0060-path-utils.sh +++ b/t/t0060-path-utils.sh @@ -10,20 +10,27 @@ TEST_PASSES_SANITIZE_LEAK=true norm_path() { expected=$(test-tool path-utils print_path "$2") - test_expect_success $3 "normalize path: $1 => $2" \ - "test \"\$(test-tool path-utils normalize_path_copy '$1')\" = '$expected'" + test_expect_success $3 "normalize path: $1 => $2" " + echo '$expected' >expect && + test-tool path-utils normalize_path_copy '$1' >actual && + test_cmp expect actual + " } relative_path() { expected=$(test-tool path-utils print_path "$3") - test_expect_success $4 "relative path: $1 $2 => $3" \ - "test \"\$(test-tool path-utils relative_path '$1' '$2')\" = '$expected'" + test_expect_success $4 "relative path: $1 $2 => $3" " + echo '$expected' >expect && + test-tool path-utils relative_path '$1' '$2' >actual && + test_cmp expect actual + " } test_submodule_relative_url() { test_expect_success "test_submodule_relative_url: $1 $2 $3 => $4" " - actual=\$(test-tool submodule resolve-relative-url '$1' '$2' '$3') && - test \"\$actual\" = '$4' + echo '$4' >expect && + test-tool submodule resolve-relative-url '$1' '$2' '$3' >actual && + test_cmp expect actual " } @@ -64,9 +71,11 @@ ancestor() { expected=$(($expected-$rootslash+$rootoff)) ;; esac - test_expect_success $4 "longest ancestor: $1 $2 => $expected" \ - "actual=\$(test-tool path-utils longest_ancestor_length '$1' '$2') && - test \"\$actual\" = '$expected'" + test_expect_success $4 "longest ancestor: $1 $2 => $expected" " + echo '$expected' >expect && + test-tool path-utils longest_ancestor_length '$1' '$2' >actual && + test_cmp expect actual + " } # Some absolute path tests should be skipped on Windows due to path mangling @@ -166,8 +175,10 @@ ancestor D:/Users/me C:/ -1 MINGW ancestor //server/share/my-directory //server/share/ 14 MINGW test_expect_success 'strip_path_suffix' ' - test c:/msysgit = $(test-tool path-utils strip_path_suffix \ - c:/msysgit/libexec//git-core libexec/git-core) + echo c:/msysgit >expect && + test-tool path-utils strip_path_suffix \ + c:/msysgit/libexec//git-core libexec/git-core >actual && + test_cmp expect actual ' test_expect_success 'absolute path rejects the empty string' ' @@ -188,35 +199,61 @@ test_expect_success 'real path rejects the empty string' ' ' test_expect_success POSIX 'real path works on absolute paths 1' ' + echo / >expect && + test-tool path-utils real_path "/" >actual && + test_cmp expect actual && + nopath="hopefully-absent-path" && - test "/" = "$(test-tool path-utils real_path "/")" && - test "/$nopath" = "$(test-tool path-utils real_path "/$nopath")" + echo "/$nopath" >expect && + test-tool path-utils real_path "/$nopath" >actual && + test_cmp expect actual ' test_expect_success 'real path works on absolute paths 2' ' - nopath="hopefully-absent-path" && # Find an existing top-level directory for the remaining tests: d=$(pwd -P | sed -e "s|^\([^/]*/[^/]*\)/.*|\1|") && - test "$d" = "$(test-tool path-utils real_path "$d")" && - test "$d/$nopath" = "$(test-tool path-utils real_path "$d/$nopath")" + echo "$d" >expect && + test-tool path-utils real_path "$d" >actual && + test_cmp expect actual && + + nopath="hopefully-absent-path" && + echo "$d/$nopath" >expect && + test-tool path-utils real_path "$d/$nopath" >actual && + test_cmp expect actual ' test_expect_success POSIX 'real path removes extra leading slashes' ' + echo "/" >expect && + test-tool path-utils real_path "///" >actual && + test_cmp expect actual && + nopath="hopefully-absent-path" && - test "/" = "$(test-tool path-utils real_path "///")" && - test "/$nopath" = "$(test-tool path-utils real_path "///$nopath")" && + echo "/$nopath" >expect && + test-tool path-utils real_path "///$nopath" >actual && + test_cmp expect actual && + # Find an existing top-level directory for the remaining tests: d=$(pwd -P | sed -e "s|^\([^/]*/[^/]*\)/.*|\1|") && - test "$d" = "$(test-tool path-utils real_path "//$d")" && - test "$d/$nopath" = "$(test-tool path-utils real_path "//$d/$nopath")" + echo "$d" >expect && + test-tool path-utils real_path "//$d" >actual && + test_cmp expect actual && + + echo "$d/$nopath" >expect && + test-tool path-utils real_path "//$d/$nopath" >actual && + test_cmp expect actual ' test_expect_success 'real path removes other extra slashes' ' - nopath="hopefully-absent-path" && # Find an existing top-level directory for the remaining tests: d=$(pwd -P | sed -e "s|^\([^/]*/[^/]*\)/.*|\1|") && - test "$d" = "$(test-tool path-utils real_path "$d///")" && - test "$d/$nopath" = "$(test-tool path-utils real_path "$d///$nopath")" + echo "$d" >expect && + test-tool path-utils real_path "$d///" >actual && + test_cmp expect actual && + + nopath="hopefully-absent-path" && + echo "$d/$nopath" >expect && + test-tool path-utils real_path "$d///$nopath" >actual && + test_cmp expect actual ' test_expect_success SYMLINKS 'real path works on symlinks' ' @@ -227,19 +264,29 @@ test_expect_success SYMLINKS 'real path works on symlinks' ' mkdir third && dir="$(cd .git && pwd -P)" && dir2=third/../second/other/.git && - test "$dir" = "$(test-tool path-utils real_path $dir2)" && + echo "$dir" >expect && + test-tool path-utils real_path $dir2 >actual && + test_cmp expect actual && file="$dir"/index && - test "$file" = "$(test-tool path-utils real_path $dir2/index)" && + echo "$file" >expect && + test-tool path-utils real_path $dir2/index >actual && + test_cmp expect actual && basename=blub && - test "$dir/$basename" = "$(cd .git && test-tool path-utils real_path "$basename")" && + echo "$dir/$basename" >expect && + test-tool -C .git path-utils real_path "$basename" >actual && + test_cmp expect actual && ln -s ../first/file .git/syml && sym="$(cd first && pwd -P)"/file && - test "$sym" = "$(test-tool path-utils real_path "$dir2/syml")" + echo "$sym" >expect && + test-tool path-utils real_path "$dir2/syml" >actual && + test_cmp expect actual ' test_expect_success SYMLINKS 'prefix_path works with absolute paths to work tree symlinks' ' ln -s target symlink && - test "$(test-tool path-utils prefix_path prefix "$(pwd)/symlink")" = "symlink" + echo "symlink" >expect && + test-tool path-utils prefix_path prefix "$(pwd)/symlink" >actual && + test_cmp expect actual ' test_expect_success 'prefix_path works with only absolute path to work tree' ' @@ -255,7 +302,10 @@ test_expect_success 'prefix_path rejects absolute path to dir with same beginnin test_expect_success SYMLINKS 'prefix_path works with absolute path to a symlink to work tree having same beginning as work tree' ' git init repo && ln -s repo repolink && - test "a" = "$(cd repo && test-tool path-utils prefix_path prefix "$(pwd)/../repolink/a")" + echo "a" >expect && + repo_path="$(cd repo && pwd)" && + test-tool -C repo path-utils prefix_path prefix "$repo_path/../repolink/a" >actual && + test_cmp expect actual ' relative_path /foo/a/b/c/ /foo/a/b/ c/ diff --git a/t/t0061-run-command.sh b/t/t0061-run-command.sh index 7b5423eebd..e2411f6a9b 100755 --- a/t/t0061-run-command.sh +++ b/t/t0061-run-command.sh @@ -130,7 +130,8 @@ World EOF test_expect_success 'run_command runs in parallel with more jobs available than tasks' ' - test-tool run-command run-command-parallel 5 sh -c "printf \"%s\n%s\n\" Hello World" 2>actual && + test-tool run-command run-command-parallel 5 sh -c "printf \"%s\n%s\n\" Hello World" >out 2>actual && + test_must_be_empty out && test_cmp expect actual ' @@ -141,7 +142,8 @@ test_expect_success 'run_command runs ungrouped in parallel with more jobs avail ' test_expect_success 'run_command runs in parallel with as many jobs as tasks' ' - test-tool run-command run-command-parallel 4 sh -c "printf \"%s\n%s\n\" Hello World" 2>actual && + test-tool run-command run-command-parallel 4 sh -c "printf \"%s\n%s\n\" Hello World" >out 2>actual && + test_must_be_empty out && test_cmp expect actual ' @@ -152,7 +154,8 @@ test_expect_success 'run_command runs ungrouped in parallel with as many jobs as ' test_expect_success 'run_command runs in parallel with more tasks than jobs available' ' - test-tool run-command run-command-parallel 3 sh -c "printf \"%s\n%s\n\" Hello World" 2>actual && + test-tool run-command run-command-parallel 3 sh -c "printf \"%s\n%s\n\" Hello World" >out 2>actual && + test_must_be_empty out && test_cmp expect actual ' @@ -172,7 +175,8 @@ asking for a quick stop EOF test_expect_success 'run_command is asked to abort gracefully' ' - test-tool run-command run-command-abort 3 false 2>actual && + test-tool run-command run-command-abort 3 false >out 2>actual && + test_must_be_empty out && test_cmp expect actual ' @@ -187,7 +191,8 @@ no further jobs available EOF test_expect_success 'run_command outputs ' ' - test-tool run-command run-command-no-jobs 3 sh -c "printf \"%s\n%s\n\" Hello World" 2>actual && + test-tool run-command run-command-no-jobs 3 sh -c "printf \"%s\n%s\n\" Hello World" >out 2>actual && + test_must_be_empty out && test_cmp expect actual ' diff --git a/t/t0066-dir-iterator.sh b/t/t0066-dir-iterator.sh index 04b811622b..7d0a0da8c0 100755 --- a/t/t0066-dir-iterator.sh +++ b/t/t0066-dir-iterator.sh @@ -106,13 +106,7 @@ test_expect_success SYMLINKS 'setup dirs with symlinks' ' ln -s d dir4/a/e && ln -s ../b dir4/a/f && - mkdir -p dir5/a/b && - mkdir -p dir5/a/c && - ln -s ../c dir5/a/b/d && - ln -s ../ dir5/a/b/e && - ln -s ../../ dir5/a/b/f && - - ln -s dir4 dir6 + ln -s dir4 dir5 ' test_expect_success SYMLINKS 'dir-iterator should not follow symlinks by default' ' @@ -131,44 +125,10 @@ test_expect_success SYMLINKS 'dir-iterator should not follow symlinks by default test_cmp expected-no-follow-sorted-output actual-no-follow-sorted-output ' -test_expect_success SYMLINKS 'dir-iterator should follow symlinks w/ follow flag' ' - cat >expected-follow-sorted-output <<-EOF && - [d] (a) [a] ./dir4/a - [d] (a/f) [f] ./dir4/a/f - [d] (a/f/c) [c] ./dir4/a/f/c - [d] (b) [b] ./dir4/b - [d] (b/c) [c] ./dir4/b/c - [f] (a/d) [d] ./dir4/a/d - [f] (a/e) [e] ./dir4/a/e - EOF - - test-tool dir-iterator --follow-symlinks ./dir4 >out && - sort out >actual-follow-sorted-output && - - test_cmp expected-follow-sorted-output actual-follow-sorted-output -' - test_expect_success SYMLINKS 'dir-iterator does not resolve top-level symlinks' ' - test_must_fail test-tool dir-iterator ./dir6 >out && + test_must_fail test-tool dir-iterator ./dir5 >out && grep "ENOTDIR" out ' -test_expect_success SYMLINKS 'dir-iterator resolves top-level symlinks w/ follow flag' ' - cat >expected-follow-sorted-output <<-EOF && - [d] (a) [a] ./dir6/a - [d] (a/f) [f] ./dir6/a/f - [d] (a/f/c) [c] ./dir6/a/f/c - [d] (b) [b] ./dir6/b - [d] (b/c) [c] ./dir6/b/c - [f] (a/d) [d] ./dir6/a/d - [f] (a/e) [e] ./dir6/a/e - EOF - - test-tool dir-iterator --follow-symlinks ./dir6 >out && - sort out >actual-follow-sorted-output && - - test_cmp expected-follow-sorted-output actual-follow-sorted-output -' - test_done diff --git a/t/t0068-for-each-repo.sh b/t/t0068-for-each-repo.sh index 4675e85251..3648d439a8 100755 --- a/t/t0068-for-each-repo.sh +++ b/t/t0068-for-each-repo.sh @@ -2,15 +2,18 @@ test_description='git for-each-repo builtin' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'run based on configured value' ' git init one && git init two && git init three && + git init ~/four && git -C two commit --allow-empty -m "DID NOT RUN" && git config run.key "$TRASH_DIRECTORY/one" && git config --add run.key "$TRASH_DIRECTORY/three" && + git config --add run.key "~/four" && git for-each-repo --config=run.key commit --allow-empty -m "ran" && git -C one log -1 --pretty=format:%s >message && grep ran message && @@ -18,12 +21,16 @@ test_expect_success 'run based on configured value' ' ! grep ran message && git -C three log -1 --pretty=format:%s >message && grep ran message && + git -C ~/four log -1 --pretty=format:%s >message && + grep ran message && git for-each-repo --config=run.key -- commit --allow-empty -m "ran again" && git -C one log -1 --pretty=format:%s >message && grep again message && git -C two log -1 --pretty=format:%s >message && ! grep again message && git -C three log -1 --pretty=format:%s >message && + grep again message && + git -C ~/four log -1 --pretty=format:%s >message && grep again message ' diff --git a/t/t0070-fundamental.sh b/t/t0070-fundamental.sh index 8d59905ef0..574de34198 100755 --- a/t/t0070-fundamental.sh +++ b/t/t0070-fundamental.sh @@ -6,6 +6,7 @@ test_description='check that the most basic functions work Verify wrappers and compatibility functions. ' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'character classes (isspace, isalpha etc.)' ' diff --git a/t/t0100-previous.sh b/t/t0100-previous.sh index a16cc3d298..70a3223f21 100755 --- a/t/t0100-previous.sh +++ b/t/t0100-previous.sh @@ -12,7 +12,9 @@ test_expect_success 'branch -d @{-1}' ' test_commit A && git checkout -b junk && git checkout - && - test "$(git symbolic-ref HEAD)" = refs/heads/main && + echo refs/heads/main >expect && + git symbolic-ref HEAD >actual && + test_cmp expect actual && git branch -d @{-1} && test_must_fail git rev-parse --verify refs/heads/junk ' @@ -21,7 +23,9 @@ test_expect_success 'branch -d @{-12} when there is not enough switches yet' ' git reflog expire --expire=now && git checkout -b junk2 && git checkout - && - test "$(git symbolic-ref HEAD)" = refs/heads/main && + echo refs/heads/main >expect && + git symbolic-ref HEAD >actual && + test_cmp expect actual && test_must_fail git branch -d @{-12} && git rev-parse --verify refs/heads/main ' diff --git a/t/t0211-trace2-perf.sh b/t/t0211-trace2-perf.sh index 22d0845544..b4e9135118 100755 --- a/t/t0211-trace2-perf.sh +++ b/t/t0211-trace2-perf.sh @@ -173,4 +173,99 @@ test_expect_success 'using global config, perf stream, return code 0' ' test_cmp expect actual ' +# Exercise the stopwatch timers in a loop and confirm that we have +# as many start/stop intervals as expected. We cannot really test the +# actual (total, min, max) timer values, so we have to assume that they +# are good, but we can verify the interval count. +# +# The timer "test/test1" should only emit a global summary "timer" event. +# The timer "test/test2" should emit per-thread "th_timer" events and a +# global summary "timer" event. + +have_timer_event () { + thread=$1 event=$2 category=$3 name=$4 intervals=$5 file=$6 && + + pattern="d0|${thread}|${event}||||${category}|name:${name} intervals:${intervals}" && + + grep "${pattern}" ${file} +} + +test_expect_success 'stopwatch timer test/test1' ' + test_when_finished "rm trace.perf actual" && + test_config_global trace2.perfBrief 1 && + test_config_global trace2.perfTarget "$(pwd)/trace.perf" && + + # Use the timer "test1" 5 times from "main". + test-tool trace2 100timer 5 10 && + + perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <trace.perf >actual && + + have_timer_event "main" "timer" "test" "test1" 5 actual +' + +test_expect_success PTHREAD 'stopwatch timer test/test2' ' + test_when_finished "rm trace.perf actual" && + test_config_global trace2.perfBrief 1 && + test_config_global trace2.perfTarget "$(pwd)/trace.perf" && + + # Use the timer "test2" 5 times each in 3 threads. + test-tool trace2 101timer 5 10 3 && + + perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <trace.perf >actual && + + # So we should have 3 per-thread events of 5 each. + have_timer_event "th01:ut_101" "th_timer" "test" "test2" 5 actual && + have_timer_event "th02:ut_101" "th_timer" "test" "test2" 5 actual && + have_timer_event "th03:ut_101" "th_timer" "test" "test2" 5 actual && + + # And we should have 15 total uses. + have_timer_event "main" "timer" "test" "test2" 15 actual +' + +# Exercise the global counters and confirm that we get the expected values. +# +# The counter "test/test1" should only emit a global summary "counter" event. +# The counter "test/test2" could emit per-thread "th_counter" events and a +# global summary "counter" event. + +have_counter_event () { + thread=$1 event=$2 category=$3 name=$4 value=$5 file=$6 && + + pattern="d0|${thread}|${event}||||${category}|name:${name} value:${value}" && + + grep "${patern}" ${file} +} + +test_expect_success 'global counter test/test1' ' + test_when_finished "rm trace.perf actual" && + test_config_global trace2.perfBrief 1 && + test_config_global trace2.perfTarget "$(pwd)/trace.perf" && + + # Use the counter "test1" and add n integers. + test-tool trace2 200counter 1 2 3 4 5 && + + perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <trace.perf >actual && + + have_counter_event "main" "counter" "test" "test1" 15 actual +' + +test_expect_success PTHREAD 'global counter test/test2' ' + test_when_finished "rm trace.perf actual" && + test_config_global trace2.perfBrief 1 && + test_config_global trace2.perfTarget "$(pwd)/trace.perf" && + + # Add 2 integers to the counter "test2" in each of 3 threads. + test-tool trace2 201counter 7 13 3 && + + perl "$TEST_DIRECTORY/t0211/scrub_perf.perl" <trace.perf >actual && + + # So we should have 3 per-thread events of 5 each. + have_counter_event "th01:ut_201" "th_counter" "test" "test2" 20 actual && + have_counter_event "th02:ut_201" "th_counter" "test" "test2" 20 actual && + have_counter_event "th03:ut_201" "th_counter" "test" "test2" 20 actual && + + # And we should have a single event with the total across all threads. + have_counter_event "main" "counter" "test" "test2" 60 actual +' + test_done diff --git a/t/t0211/scrub_perf.perl b/t/t0211/scrub_perf.perl index 299999f0f8..7a50bae646 100644 --- a/t/t0211/scrub_perf.perl +++ b/t/t0211/scrub_perf.perl @@ -64,6 +64,12 @@ while (<>) { goto SKIP_LINE; } } + elsif ($tokens[$col_event] =~ m/timer/) { + # This also captures "th_timer" events + $tokens[$col_rest] =~ s/ total:\d+\.\d*/ total:_T_TOTAL_/; + $tokens[$col_rest] =~ s/ min:\d+\.\d*/ min:_T_MIN_/; + $tokens[$col_rest] =~ s/ max:\d+\.\d*/ max:_T_MAX_/; + } # t_abs and t_rel are either blank or a float. Replace the float # with a constant for matching the HEREDOC in the test script. diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh index 3485c0534e..c66d91e82d 100755 --- a/t/t0300-credentials.sh +++ b/t/t0300-credentials.sh @@ -35,6 +35,16 @@ test_expect_success 'setup helper scripts' ' test -z "$pass" || echo password=$pass EOF + write_script git-credential-verbatim-with-expiry <<-\EOF && + user=$1; shift + pass=$1; shift + pexpiry=$1; shift + . ./dump + test -z "$user" || echo username=$user + test -z "$pass" || echo password=$pass + test -z "$pexpiry" || echo password_expiry_utc=$pexpiry + EOF + PATH="$PWD:$PATH" ' @@ -109,6 +119,43 @@ test_expect_success 'credential_fill continues through partial response' ' EOF ' +test_expect_success 'credential_fill populates password_expiry_utc' ' + check fill "verbatim-with-expiry one two 9999999999" <<-\EOF + protocol=http + host=example.com + -- + protocol=http + host=example.com + username=one + password=two + password_expiry_utc=9999999999 + -- + verbatim-with-expiry: get + verbatim-with-expiry: protocol=http + verbatim-with-expiry: host=example.com + EOF +' + +test_expect_success 'credential_fill ignores expired password' ' + check fill "verbatim-with-expiry one two 5" "verbatim three four" <<-\EOF + protocol=http + host=example.com + -- + protocol=http + host=example.com + username=three + password=four + -- + verbatim-with-expiry: get + verbatim-with-expiry: protocol=http + verbatim-with-expiry: host=example.com + verbatim: get + verbatim: protocol=http + verbatim: host=example.com + verbatim: username=one + EOF +' + test_expect_success 'credential_fill passes along metadata' ' check fill "verbatim one two" <<-\EOF protocol=ftp @@ -149,6 +196,24 @@ test_expect_success 'credential_approve calls all helpers' ' EOF ' +test_expect_success 'credential_approve stores password expiry' ' + check approve useless <<-\EOF + protocol=http + host=example.com + username=foo + password=bar + password_expiry_utc=9999999999 + -- + -- + useless: store + useless: protocol=http + useless: host=example.com + useless: username=foo + useless: password=bar + useless: password_expiry_utc=9999999999 + EOF +' + test_expect_success 'do not bother storing password-less credential' ' check approve useless <<-\EOF protocol=http @@ -159,6 +224,17 @@ test_expect_success 'do not bother storing password-less credential' ' EOF ' +test_expect_success 'credential_approve does not store expired password' ' + check approve useless <<-\EOF + protocol=http + host=example.com + username=foo + password=bar + password_expiry_utc=5 + -- + -- + EOF +' test_expect_success 'credential_reject calls all helpers' ' check reject useless "verbatim one two" <<-\EOF @@ -181,6 +257,24 @@ test_expect_success 'credential_reject calls all helpers' ' EOF ' +test_expect_success 'credential_reject erases credential regardless of expiry' ' + check reject useless <<-\EOF + protocol=http + host=example.com + username=foo + password=bar + password_expiry_utc=5 + -- + -- + useless: erase + useless: protocol=http + useless: host=example.com + useless: username=foo + useless: password=bar + useless: password_expiry_utc=5 + EOF +' + test_expect_success 'usernames can be preserved' ' check fill "verbatim \"\" three" <<-\EOF protocol=http diff --git a/t/t0410-partial-clone.sh b/t/t0410-partial-clone.sh index 1e864cf317..5b7bee888d 100755 --- a/t/t0410-partial-clone.sh +++ b/t/t0410-partial-clone.sh @@ -215,6 +215,20 @@ test_expect_success 'fetching of missing objects' ' grep "$HASH" out ' +test_expect_success 'fetching of a promised object that promisor remote no longer has' ' + rm -f err && + test_create_repo unreliable-server && + git -C unreliable-server config uploadpack.allowanysha1inwant 1 && + git -C unreliable-server config uploadpack.allowfilter 1 && + test_commit -C unreliable-server foo && + + git clone --filter=blob:none --no-checkout "file://$(pwd)/unreliable-server" unreliable-client && + + rm -rf unreliable-server/.git/objects/* && + test_must_fail git -C unreliable-client checkout HEAD 2>err && + grep "could not fetch.*from promisor remote" err +' + test_expect_success 'fetching of missing objects works with ref-in-want enabled' ' # ref-in-want requires protocol version 2 git -C server config protocol.version 2 && diff --git a/t/t0450-txt-doc-vs-help.sh b/t/t0450-txt-doc-vs-help.sh new file mode 100755 index 0000000000..cd3969e852 --- /dev/null +++ b/t/t0450-txt-doc-vs-help.sh @@ -0,0 +1,172 @@ +#!/bin/sh + +test_description='assert (unbuilt) Documentation/*.txt and -h output + +Run this with --debug to see a summary of where we still fail to make +the two versions consistent with one another.' + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +test_expect_success 'setup: list of builtins' ' + git --list-cmds=builtins >builtins +' + +test_expect_success 'list of txt and help mismatches is sorted' ' + sort -u "$TEST_DIRECTORY"/t0450/txt-help-mismatches >expect && + if ! test_cmp expect "$TEST_DIRECTORY"/t0450/txt-help-mismatches + then + BUG "please keep the list of txt and help mismatches sorted" + fi +' + +help_to_synopsis () { + builtin="$1" && + out_dir="out/$builtin" && + out="$out_dir/help.synopsis" && + if test -f "$out" + then + echo "$out" && + return 0 + fi && + mkdir -p "$out_dir" && + test_expect_code 129 git $builtin -h >"$out.raw" 2>&1 && + sed -n \ + -e '1,/^$/ { + /^$/d; + s/^usage: //; + s/^ *or: //; + p; + }' <"$out.raw" >"$out" && + echo "$out" +} + +builtin_to_txt () { + echo "$GIT_BUILD_DIR/Documentation/git-$1.txt" +} + +txt_to_synopsis () { + builtin="$1" && + out_dir="out/$builtin" && + out="$out_dir/txt.synopsis" && + if test -f "$out" + then + echo "$out" && + return 0 + fi && + b2t="$(builtin_to_txt "$builtin")" && + sed -n \ + -e '/^\[verse\]$/,/^$/ { + /^$/d; + /^\[verse\]$/d; + + s/{litdd}/--/g; + s/'\''\(git[ a-z-]*\)'\''/\1/g; + + p; + }' \ + <"$b2t" >"$out" && + echo "$out" +} + +check_dashed_labels () { + ! grep -E "<[^>_-]+_" "$1" +} + +HT=" " + +align_after_nl () { + builtin="$1" && + len=$(printf "git %s " "$builtin" | wc -c) && + pad=$(printf "%${len}s" "") && + + sed "s/^[ $HT][ $HT]*/$pad/" +} + +test_debug '>failing' +while read builtin +do + # -h output assertions + test_expect_success "$builtin -h output has no \t" ' + h2s="$(help_to_synopsis "$builtin")" && + ! grep "$HT" "$h2s" + ' + + test_expect_success "$builtin -h output has dashed labels" ' + check_dashed_labels "$(help_to_synopsis "$builtin")" + ' + + test_expect_success "$builtin -h output has consistent spacing" ' + h2s="$(help_to_synopsis "$builtin")" && + sed -n \ + -e "/^ / { + s/[^ ].*//; + p; + }" \ + <"$h2s" >help && + sort -u help >help.ws && + if test -s help.ws + then + test_line_count = 1 help.ws + fi + ' + + txt="$(builtin_to_txt "$builtin")" && + preq="$(echo BUILTIN_TXT_$builtin | tr '[:lower:]-' '[:upper:]_')" && + + if test -f "$txt" + then + test_set_prereq "$preq" + fi && + + # *.txt output assertions + test_expect_success "$preq" "$builtin *.txt SYNOPSIS has dashed labels" ' + check_dashed_labels "$(txt_to_synopsis "$builtin")" + ' + + # *.txt output consistency assertions + result= + if grep -q "^$builtin$" "$TEST_DIRECTORY"/t0450/txt-help-mismatches + then + result=failure + else + result=success + fi && + test_expect_$result "$preq" "$builtin -h output and SYNOPSIS agree" ' + t2s="$(txt_to_synopsis "$builtin")" && + if test "$builtin" = "merge-tree" + then + test_when_finished "rm -f t2s.new" && + sed -e '\''s/ (deprecated)$//g'\'' <"$t2s" >t2s.new + t2s=t2s.new + fi && + h2s="$(help_to_synopsis "$builtin")" && + + # The *.txt and -h use different spacing for the + # alignment of continued usage output, normalize it. + align_after_nl "$builtin" <"$t2s" >txt && + align_after_nl "$builtin" <"$h2s" >help && + test_cmp txt help + ' + + if test_have_prereq "$preq" && test -e txt && test -e help + then + test_debug ' + if test_cmp txt help >cmp 2>/dev/null + then + echo "=== DONE: $builtin ===" + else + echo "=== TODO: $builtin ===" && + cat cmp + fi >>failing + ' + + # Not in test_expect_success in case --run is being + # used with --debug + rm -f txt help tmp 2>/dev/null + fi +done <builtins + +test_debug 'say "$(cat failing)"' + +test_done diff --git a/t/t0450/txt-help-mismatches b/t/t0450/txt-help-mismatches new file mode 100644 index 0000000000..a0777acd66 --- /dev/null +++ b/t/t0450/txt-help-mismatches @@ -0,0 +1,58 @@ +add +am +apply +archive +bisect +blame +branch +check-ref-format +checkout +checkout-index +clone +column +config +credential +credential-cache +credential-store +fast-export +fast-import +fetch-pack +fmt-merge-msg +for-each-ref +format-patch +fsck-objects +fsmonitor--daemon +gc +grep +index-pack +init-db +log +ls-files +ls-tree +mailinfo +mailsplit +maintenance +merge +merge-file +merge-index +merge-one-file +multi-pack-index +name-rev +notes +pack-objects +push +range-diff +rebase +remote +remote-ext +remote-fd +repack +reset +restore +rev-parse +show +stage +switch +update-index +update-ref +whatchanged diff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh index 516a6112fd..3fb1b0c162 100755 --- a/t/t1001-read-tree-m-2way.sh +++ b/t/t1001-read-tree-m-2way.sh @@ -370,7 +370,7 @@ test_expect_success 'read-tree supports the super-prefix' ' cat <<-EOF >expect && error: Updating '\''fictional/a'\'' would lose untracked files in it EOF - test_must_fail git --super-prefix fictional/ read-tree -u -m "$treeH" "$treeM" 2>actual && + test_must_fail git read-tree --super-prefix fictional/ -u -m "$treeH" "$treeM" 2>actual && test_cmp expect actual ' diff --git a/t/t1002-read-tree-m-u-2way.sh b/t/t1002-read-tree-m-u-2way.sh index bd5313caec..cdc077ce12 100755 --- a/t/t1002-read-tree-m-u-2way.sh +++ b/t/t1002-read-tree-m-u-2way.sh @@ -154,7 +154,7 @@ test_expect_success \ read_tree_u_must_succeed --reset -u $treeH && echo frotz frotz >frotz && git update-index --add frotz && - if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi' + ! read_tree_u_must_succeed -m -u $treeH $treeM' test_expect_success \ '9 - conflicting addition.' \ @@ -163,7 +163,7 @@ test_expect_success \ echo frotz frotz >frotz && git update-index --add frotz && echo frotz >frotz && - if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi' + ! read_tree_u_must_succeed -m -u $treeH $treeM' test_expect_success \ '10 - path removed.' \ @@ -186,7 +186,7 @@ test_expect_success \ echo rezrov >rezrov && git update-index --add rezrov && echo rezrov rezrov >rezrov && - if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi' + ! read_tree_u_must_succeed -m -u $treeH $treeM' test_expect_success \ '12 - unmatching local changes being removed.' \ @@ -194,7 +194,7 @@ test_expect_success \ read_tree_u_must_succeed --reset -u $treeH && echo rezrov rezrov >rezrov && git update-index --add rezrov && - if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi' + ! read_tree_u_must_succeed -m -u $treeH $treeM' test_expect_success \ '13 - unmatching local changes being removed.' \ @@ -203,7 +203,7 @@ test_expect_success \ echo rezrov rezrov >rezrov && git update-index --add rezrov && echo rezrov >rezrov && - if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi' + ! read_tree_u_must_succeed -m -u $treeH $treeM' cat >expected <<EOF -100644 X 0 nitfol @@ -251,7 +251,7 @@ test_expect_success \ read_tree_u_must_succeed --reset -u $treeH && echo bozbar bozbar >bozbar && git update-index --add bozbar && - if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi' + ! read_tree_u_must_succeed -m -u $treeH $treeM' test_expect_success \ '17 - conflicting local change.' \ @@ -260,7 +260,7 @@ test_expect_success \ echo bozbar bozbar >bozbar && git update-index --add bozbar && echo bozbar bozbar bozbar >bozbar && - if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi' + ! read_tree_u_must_succeed -m -u $treeH $treeM' test_expect_success \ '18 - local change already having a good result.' \ @@ -316,7 +316,7 @@ test_expect_success \ echo bozbar >bozbar && git update-index --add bozbar && echo gnusto gnusto >bozbar && - if read_tree_u_must_succeed -m -u $treeH $treeM; then false; else :; fi' + ! read_tree_u_must_succeed -m -u $treeH $treeM' # Also make sure we did not break DF vs DF/DF case. test_expect_success \ diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh index 23b8942edb..2d875b17d8 100755 --- a/t/t1006-cat-file.sh +++ b/t/t1006-cat-file.sh @@ -292,8 +292,8 @@ commit_message="Initial commit" commit_sha1=$(echo_without_newline "$commit_message" | git commit-tree $tree_sha1) commit_size=$(($(test_oid hexsz) + 137)) commit_content="tree $tree_sha1 -author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> 0000000000 +0000 -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 0000000000 +0000 +author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> 0 +0000 +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 0 +0000 $commit_message" @@ -304,7 +304,7 @@ type blob tag hellotag tagger $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" tag_description="This is a tag" -tag_content="$tag_header_without_timestamp 0000000000 +0000 +tag_content="$tag_header_without_timestamp 0 +0000 $tag_description" diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh index ac5ad8c740..ac3d173767 100755 --- a/t/t1007-hash-object.sh +++ b/t/t1007-hash-object.sh @@ -203,23 +203,34 @@ done test_expect_success 'too-short tree' ' echo abc >malformed-tree && test_must_fail git hash-object -t tree malformed-tree 2>err && - test_i18ngrep "too-short tree object" err + grep "too-short tree object" err ' test_expect_success 'malformed mode in tree' ' - hex_sha1=$(echo foo | git hash-object --stdin -w) && - bin_sha1=$(echo $hex_sha1 | hex2oct) && - printf "9100644 \0$bin_sha1" >tree-with-malformed-mode && + hex_oid=$(echo foo | git hash-object --stdin -w) && + bin_oid=$(echo $hex_oid | hex2oct) && + printf "9100644 \0$bin_oid" >tree-with-malformed-mode && test_must_fail git hash-object -t tree tree-with-malformed-mode 2>err && - test_i18ngrep "malformed mode in tree entry" err + grep "malformed mode in tree entry" err ' test_expect_success 'empty filename in tree' ' - hex_sha1=$(echo foo | git hash-object --stdin -w) && - bin_sha1=$(echo $hex_sha1 | hex2oct) && - printf "100644 \0$bin_sha1" >tree-with-empty-filename && + hex_oid=$(echo foo | git hash-object --stdin -w) && + bin_oid=$(echo $hex_oid | hex2oct) && + printf "100644 \0$bin_oid" >tree-with-empty-filename && test_must_fail git hash-object -t tree tree-with-empty-filename 2>err && - test_i18ngrep "empty filename in tree entry" err + grep "empty filename in tree entry" err +' + +test_expect_success 'duplicate filename in tree' ' + hex_oid=$(echo foo | git hash-object --stdin -w) && + bin_oid=$(echo $hex_oid | hex2oct) && + { + printf "100644 file\0$bin_oid" && + printf "100644 file\0$bin_oid" + } >tree-with-duplicate-filename && + test_must_fail git hash-object -t tree tree-with-duplicate-filename 2>err && + grep "duplicateEntries" err ' test_expect_success 'corrupt commit' ' diff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh index 742f0fa909..595b24c0ad 100755 --- a/t/t1011-read-tree-sparse-checkout.sh +++ b/t/t1011-read-tree-sparse-checkout.sh @@ -12,6 +12,7 @@ test_description='sparse checkout tests ' TEST_CREATE_REPO_NO_TEMPLATE=1 +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-read-tree.sh diff --git a/t/t1022-read-tree-partial-clone.sh b/t/t1022-read-tree-partial-clone.sh index a9953b6a71..cca4380e43 100755 --- a/t/t1022-read-tree-partial-clone.sh +++ b/t/t1022-read-tree-partial-clone.sh @@ -3,7 +3,7 @@ test_description='git read-tree in partial clones' TEST_NO_CREATE_REPO=1 - +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'read-tree in partial clone prefetches in one batch' ' @@ -19,7 +19,7 @@ test_expect_success 'read-tree in partial clone prefetches in one batch' ' git -C server config uploadpack.allowfilter 1 && git -C server config uploadpack.allowanysha1inwant 1 && git clone --bare --filter=blob:none "file://$(pwd)/server" client && - GIT_TRACE_PACKET="$(pwd)/trace" git -C client read-tree $TREE && + GIT_TRACE_PACKET="$(pwd)/trace" git -C client read-tree $TREE $TREE && # "done" marks the end of negotiation (once per fetch). Expect that # only one fetch occurs. diff --git a/t/t1050-large.sh b/t/t1050-large.sh index 4f3aa17c99..c71932b024 100755 --- a/t/t1050-large.sh +++ b/t/t1050-large.sh @@ -5,6 +5,12 @@ test_description='adding and checking out large blobs' . ./test-lib.sh +test_expect_success 'core.bigFileThreshold must be non-negative' ' + test_must_fail git -c core.bigFileThreshold=-1 rev-parse >out 2>err && + grep "bad numeric config value" err && + test_must_be_empty out +' + test_expect_success setup ' # clone does not allow us to pass core.bigfilethreshold to # new repos, so set core.bigfilethreshold globally diff --git a/t/t1091-sparse-checkout-builtin.sh b/t/t1091-sparse-checkout-builtin.sh index b563d6c263..627267be15 100755 --- a/t/t1091-sparse-checkout-builtin.sh +++ b/t/t1091-sparse-checkout-builtin.sh @@ -238,7 +238,7 @@ test_expect_success 'cone mode: match patterns' ' test_expect_success 'cone mode: warn on bad pattern' ' test_when_finished mv sparse-checkout repo/.git/info/ && cp repo/.git/info/sparse-checkout . && - echo "!/deep/deeper/*" >>repo/.git/info/sparse-checkout && + echo "!/deep/deeper/*/" >>repo/.git/info/sparse-checkout && git -C repo read-tree -mu HEAD 2>err && test_i18ngrep "unrecognized negative pattern" err ' @@ -667,6 +667,15 @@ test_expect_success 'pattern-checks: starting "*"' ' check_read_tree_errors repo "a deep" "disabling cone pattern matching" ' +test_expect_success 'pattern-checks: non directory pattern' ' + cat >repo/.git/info/sparse-checkout <<-\EOF && + /deep/deeper1/a + EOF + check_read_tree_errors repo deep "disabling cone pattern matching" && + check_files repo/deep deeper1 && + check_files repo/deep/deeper1 a +' + test_expect_success 'pattern-checks: contained glob characters' ' for c in "[a]" "\\" "?" "*" do diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh index 4844922e57..801919009e 100755 --- a/t/t1092-sparse-checkout-compatibility.sh +++ b/t/t1092-sparse-checkout-compatibility.sh @@ -162,6 +162,19 @@ init_repos () { git -C sparse-index sparse-checkout set deep } +init_repos_as_submodules () { + git reset --hard && + init_repos && + git submodule add ./full-checkout && + git submodule add ./sparse-checkout && + git submodule add ./sparse-index && + + git submodule status >actual && + grep full-checkout actual && + grep sparse-checkout actual && + grep sparse-index actual +} + run_on_sparse () { ( cd sparse-checkout && @@ -1983,4 +1996,63 @@ test_expect_success 'sparse index is not expanded: rm' ' ensure_not_expanded rm -r deep ' +test_expect_success 'grep with and --cached' ' + init_repos && + + test_all_match git grep --cached a && + test_all_match git grep --cached a -- "folder1/*" +' + +test_expect_success 'grep is not expanded' ' + init_repos && + + ensure_not_expanded grep a && + ensure_not_expanded grep a -- deep/* && + + # All files within the folder1/* pathspec are sparse, + # so this command does not find any matches + ensure_not_expanded ! grep a -- folder1/* && + + # test out-of-cone pathspec with or without wildcard + ensure_not_expanded grep --cached a -- "folder1/a" && + ensure_not_expanded grep --cached a -- "folder1/*" && + + # test in-cone pathspec with or without wildcard + ensure_not_expanded grep --cached a -- "deep/a" && + ensure_not_expanded grep --cached a -- "deep/*" +' + +# NEEDSWORK: when running `grep` in the superproject with --recurse-submodules, +# Git expands the index of the submodules unexpectedly. Even though `grep` +# builtin is marked as "command_requires_full_index = 0", this config is only +# useful for the superproject. Namely, the submodules have their own configs, +# which are _not_ populated by the one-time sparse-index feature switch. +test_expect_failure 'grep within submodules is not expanded' ' + init_repos_as_submodules && + + # do not use ensure_not_expanded() here, becasue `grep` should be + # run in the superproject, not in "./sparse-index" + GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ + git grep --cached --recurse-submodules a -- "*/folder1/*" && + test_region ! index ensure_full_index trace2.txt +' + +# NEEDSWORK: this test is not actually testing the code. The design purpose +# of this test is to verify the grep result when the submodules are using a +# sparse-index. Namely, we want "folder1/" as a tree (a sparse directory); but +# because of the index expansion, we are now grepping the "folder1/a" blob. +# Because of the problem stated above 'grep within submodules is not expanded', +# we don't have the ideal test environment yet. +test_expect_success 'grep sparse directory within submodules' ' + init_repos_as_submodules && + + cat >expect <<-\EOF && + full-checkout/folder1/a:a + sparse-checkout/folder1/a:a + sparse-index/folder1/a:a + EOF + git grep --cached --recurse-submodules a -- "*/folder1/*" >actual && + test_cmp actual expect +' + test_done diff --git a/t/t1300-config.sh b/t/t1300-config.sh index c6661e61af..2575279ab8 100755 --- a/t/t1300-config.sh +++ b/t/t1300-config.sh @@ -2228,6 +2228,12 @@ test_expect_success '--type rejects unknown specifiers' ' test_i18ngrep "unrecognized --type argument" error ' +test_expect_success '--type=int requires at least one digit' ' + test_must_fail git config --type int --default m some.key >out 2>error && + grep "bad numeric config value" error && + test_must_be_empty out +' + test_expect_success '--replace-all does not invent newlines' ' q_to_tab >.git/config <<-\EOF && [abc]key diff --git a/t/t1301-shared-repo.sh b/t/t1301-shared-repo.sh index 93a2f91f8a..1b6437ec07 100755 --- a/t/t1301-shared-repo.sh +++ b/t/t1301-shared-repo.sh @@ -8,6 +8,8 @@ test_description='Test shared repository initialization' 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 # Remove a default ACL from the test dir if possible. @@ -25,6 +27,7 @@ test_expect_success 'shared = 0400 (faulty permission u-w)' ' for u in 002 022 do test_expect_success POSIXPERM "shared=1 does not clear bits preset by umask $u" ' + test_when_finished "rm -rf sub" && mkdir sub && ( cd sub && umask $u && @@ -42,12 +45,9 @@ do ;; esac ' - rm -rf sub done test_expect_success 'shared=all' ' - mkdir sub && - cd sub && git init --template= --shared=all && test 2 = $(git config core.sharedrepository) ' @@ -132,6 +132,7 @@ test_expect_success POSIXPERM 'git reflog expire honors core.sharedRepository' ' ' test_expect_success POSIXPERM 'forced modes' ' + test_when_finished "rm -rf new" && mkdir -p templates/hooks && echo update-server-info >templates/hooks/post-update && chmod +x templates/hooks/post-update && @@ -140,7 +141,8 @@ test_expect_success POSIXPERM 'forced modes' ' ( cd new && umask 002 && - git init --shared=0660 --template=templates && + git init --shared=0660 --template=../templates && + test_path_is_file .git/hooks/post-update && >frotz && git add frotz && git commit -a -m initial && @@ -173,6 +175,7 @@ test_expect_success POSIXPERM 'forced modes' ' ' test_expect_success POSIXPERM 'remote init does not use config from cwd' ' + test_when_finished "rm -rf child.git" && git config core.sharedrepository 0666 && umask 0022 && git init --bare child.git && @@ -192,7 +195,7 @@ test_expect_success POSIXPERM 're-init respects core.sharedrepository (local)' ' ' test_expect_success POSIXPERM 're-init respects core.sharedrepository (remote)' ' - rm -rf child.git && + test_when_finished "rm -rf child.git" && umask 0022 && git init --bare --shared=0666 child.git && test_path_is_missing child.git/foo && @@ -203,7 +206,7 @@ test_expect_success POSIXPERM 're-init respects core.sharedrepository (remote)' ' test_expect_success POSIXPERM 'template can set core.sharedrepository' ' - rm -rf child.git && + test_when_finished "rm -rf child.git" && umask 0022 && git config core.sharedrepository 0666 && cp .git/config templates/config && diff --git a/t/t1302-repo-version.sh b/t/t1302-repo-version.sh index 0acabb6d11..70389fa2eb 100755 --- a/t/t1302-repo-version.sh +++ b/t/t1302-repo-version.sh @@ -5,6 +5,7 @@ test_description='Test repository version check' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' @@ -27,7 +28,7 @@ test_expect_success 'setup' ' ' test_expect_success 'gitdir selection on normal repos' ' - echo $(test_oid version) >expect && + test_oid version >expect && git config core.repositoryformatversion >actual && git -C test config core.repositoryformatversion >actual2 && test_cmp expect actual && diff --git a/t/t1304-default-acl.sh b/t/t1304-default-acl.sh index 335d3f3211..31b89dd969 100755 --- a/t/t1304-default-acl.sh +++ b/t/t1304-default-acl.sh @@ -9,6 +9,7 @@ test_description='Test repository with default ACL' # => this must come before . ./test-lib.sh umask 077 +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # We need an arbitrary other user give permission to using ACLs. root @@ -18,7 +19,7 @@ test_expect_success 'checking for a working acl setup' ' if setfacl -m d:m:rwx -m u:root:rwx . && getfacl . | grep user:root:rwx && touch should-have-readable-acl && - getfacl should-have-readable-acl | egrep "mask::?rw-" + getfacl should-have-readable-acl | grep -E "mask::?rw-" then test_set_prereq SETFACL fi @@ -34,7 +35,7 @@ check_perms_and_acl () { getfacl "$1" > actual && grep -q "user:root:rwx" actual && grep -q "user:${LOGNAME}:rwx" actual && - egrep "mask::?r--" actual > /dev/null 2>&1 && + grep -E "mask::?r--" actual > /dev/null 2>&1 && grep -q "group::---" actual || false } diff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh index 0c204089b8..c7745e1bf6 100755 --- a/t/t1401-symbolic-ref.sh +++ b/t/t1401-symbolic-ref.sh @@ -33,7 +33,8 @@ test_expect_success 'symbolic-ref refuses non-ref for HEAD' ' reset_to_sane test_expect_success 'symbolic-ref refuses bare sha1' ' - test_must_fail git symbolic-ref HEAD $(git rev-parse HEAD) + rev=$(git rev-parse HEAD) && + test_must_fail git symbolic-ref HEAD "$rev" ' reset_to_sane @@ -175,4 +176,52 @@ test_expect_success 'symbolic-ref allows top-level target for non-HEAD' ' test_cmp_rev top-level HEAD ' +test_expect_success 'symbolic-ref pointing at another' ' + git update-ref refs/heads/maint-2.37 HEAD && + git symbolic-ref refs/heads/maint refs/heads/maint-2.37 && + git checkout maint && + + git symbolic-ref HEAD >actual && + echo refs/heads/maint-2.37 >expect && + test_cmp expect actual && + + git symbolic-ref --no-recurse HEAD >actual && + echo refs/heads/maint >expect && + test_cmp expect actual +' + +test_expect_success 'symbolic-ref --short handles complex utf8 case' ' + name="测试-加-增加-加-增加" && + git symbolic-ref TEST_SYMREF "refs/heads/$name" && + # In the real world, we saw problems with this case only + # when the locale includes UTF-8. Set it here to try to make things as + # hard as possible for us to pass, but in practice we should do the + # right thing regardless (and of course some platforms may not even + # have this locale). + LC_ALL=en_US.UTF-8 git symbolic-ref --short TEST_SYMREF >actual && + echo "$name" >expect && + test_cmp expect actual +' + +test_expect_success 'symbolic-ref --short handles name with suffix' ' + git symbolic-ref TEST_SYMREF "refs/remotes/origin/HEAD" && + git symbolic-ref --short TEST_SYMREF >actual && + echo "origin" >expect && + test_cmp expect actual +' + +test_expect_success 'symbolic-ref --short handles almost-matching name' ' + git symbolic-ref TEST_SYMREF "refs/headsXfoo" && + git symbolic-ref --short TEST_SYMREF >actual && + echo "headsXfoo" >expect && + test_cmp expect actual +' + +test_expect_success 'symbolic-ref --short handles name with percent' ' + git symbolic-ref TEST_SYMREF "refs/heads/%foo" && + git symbolic-ref --short TEST_SYMREF >actual && + echo "%foo" >expect && + test_cmp expect actual +' + test_done diff --git a/t/t1404-update-ref-errors.sh b/t/t1404-update-ref-errors.sh index 13c2b43bba..b5606d93b5 100755 --- a/t/t1404-update-ref-errors.sh +++ b/t/t1404-update-ref-errors.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='Test git update-ref error handling' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Create some references, perhaps run pack-refs --all, then try to diff --git a/t/t1408-packed-refs.sh b/t/t1408-packed-refs.sh index 41ba1f1d7f..9469c79a58 100755 --- a/t/t1408-packed-refs.sh +++ b/t/t1408-packed-refs.sh @@ -5,6 +5,7 @@ test_description='packed-refs entries are covered by loose refs' 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/t1409-avoid-packing-refs.sh b/t/t1409-avoid-packing-refs.sh index be12fb6350..f23c0152a8 100755 --- a/t/t1409-avoid-packing-refs.sh +++ b/t/t1409-avoid-packing-refs.sh @@ -2,6 +2,7 @@ test_description='avoid rewriting packed-refs unnecessarily' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Add an identifying mark to the packed-refs file header line. This diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh index aa59954f6c..6c45965b1e 100755 --- a/t/t1410-reflog.sh +++ b/t/t1410-reflog.sh @@ -7,6 +7,7 @@ test_description='Test prune and reflog expiration' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh check_have () { diff --git a/t/t1413-reflog-detach.sh b/t/t1413-reflog-detach.sh index 934688a1ee..d2a4822d46 100755 --- a/t/t1413-reflog-detach.sh +++ b/t/t1413-reflog-detach.sh @@ -4,6 +4,7 @@ test_description='Test reflog interaction with detached HEAD' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh reset_state () { diff --git a/t/t1416-ref-transaction-hooks.sh b/t/t1416-ref-transaction-hooks.sh index 27731722a5..b32ca798f9 100755 --- a/t/t1416-ref-transaction-hooks.sh +++ b/t/t1416-ref-transaction-hooks.sh @@ -5,6 +5,7 @@ test_description='reference transaction hooks' 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/t1450-fsck.sh b/t/t1450-fsck.sh index de0f6d5e7f..bca46378b2 100755 --- a/t/t1450-fsck.sh +++ b/t/t1450-fsck.sh @@ -212,7 +212,7 @@ test_expect_success 'email without @ is okay' ' test_expect_success 'email with embedded > is not okay' ' git cat-file commit HEAD >basis && sed "s/@[a-z]/&>/" basis >bad-email && - new=$(git hash-object -t commit -w --stdin <bad-email) && + new=$(git hash-object --literally -t commit -w --stdin <bad-email) && test_when_finished "remove_object $new" && git update-ref refs/heads/bogus "$new" && test_when_finished "git update-ref -d refs/heads/bogus" && @@ -223,7 +223,7 @@ test_expect_success 'email with embedded > is not okay' ' test_expect_success 'missing < email delimiter is reported nicely' ' git cat-file commit HEAD >basis && sed "s/<//" basis >bad-email-2 && - new=$(git hash-object -t commit -w --stdin <bad-email-2) && + new=$(git hash-object --literally -t commit -w --stdin <bad-email-2) && test_when_finished "remove_object $new" && git update-ref refs/heads/bogus "$new" && test_when_finished "git update-ref -d refs/heads/bogus" && @@ -234,7 +234,7 @@ test_expect_success 'missing < email delimiter is reported nicely' ' test_expect_success 'missing email is reported nicely' ' git cat-file commit HEAD >basis && sed "s/[a-z]* <[^>]*>//" basis >bad-email-3 && - new=$(git hash-object -t commit -w --stdin <bad-email-3) && + new=$(git hash-object --literally -t commit -w --stdin <bad-email-3) && test_when_finished "remove_object $new" && git update-ref refs/heads/bogus "$new" && test_when_finished "git update-ref -d refs/heads/bogus" && @@ -245,7 +245,7 @@ test_expect_success 'missing email is reported nicely' ' test_expect_success '> in name is reported' ' git cat-file commit HEAD >basis && sed "s/ </> </" basis >bad-email-4 && - new=$(git hash-object -t commit -w --stdin <bad-email-4) && + new=$(git hash-object --literally -t commit -w --stdin <bad-email-4) && test_when_finished "remove_object $new" && git update-ref refs/heads/bogus "$new" && test_when_finished "git update-ref -d refs/heads/bogus" && @@ -258,7 +258,7 @@ test_expect_success 'integer overflow in timestamps is reported' ' git cat-file commit HEAD >basis && sed "s/^\\(author .*>\\) [0-9]*/\\1 18446744073709551617/" \ <basis >bad-timestamp && - new=$(git hash-object -t commit -w --stdin <bad-timestamp) && + new=$(git hash-object --literally -t commit -w --stdin <bad-timestamp) && test_when_finished "remove_object $new" && git update-ref refs/heads/bogus "$new" && test_when_finished "git update-ref -d refs/heads/bogus" && @@ -269,7 +269,7 @@ test_expect_success 'integer overflow in timestamps is reported' ' test_expect_success 'commit with NUL in header' ' git cat-file commit HEAD >basis && sed "s/author ./author Q/" <basis | q_to_nul >commit-NUL-header && - new=$(git hash-object -t commit -w --stdin <commit-NUL-header) && + new=$(git hash-object --literally -t commit -w --stdin <commit-NUL-header) && test_when_finished "remove_object $new" && git update-ref refs/heads/bogus "$new" && test_when_finished "git update-ref -d refs/heads/bogus" && @@ -292,7 +292,7 @@ test_expect_success 'tree object with duplicate entries' ' git cat-file tree $T && git cat-file tree $T ) | - git hash-object -w -t tree --stdin + git hash-object --literally -w -t tree --stdin ) && test_must_fail git fsck 2>out && test_i18ngrep "error in tree .*contains duplicate file entries" out @@ -426,7 +426,7 @@ test_expect_success 'tag with incorrect tag name & missing tagger' ' This is an invalid tag. EOF - tag=$(git hash-object -t tag -w --stdin <wrong-tag) && + tag=$(git hash-object --literally -t tag -w --stdin <wrong-tag) && test_when_finished "remove_object $tag" && echo $tag >.git/refs/tags/wrong && test_when_finished "git update-ref -d refs/tags/wrong" && @@ -558,7 +558,7 @@ test_expect_success 'rev-list --verify-objects with commit graph (parent)' ' test_expect_success 'force fsck to ignore double author' ' git cat-file commit HEAD >basis && sed "s/^author .*/&,&/" <basis | tr , \\n >multiple-authors && - new=$(git hash-object -t commit -w --stdin <multiple-authors) && + new=$(git hash-object --literally -t commit -w --stdin <multiple-authors) && test_when_finished "remove_object $new" && git update-ref refs/heads/bogus "$new" && test_when_finished "git update-ref -d refs/heads/bogus" && @@ -573,7 +573,7 @@ test_expect_success 'fsck notices blob entry pointing to null sha1' ' (git init null-blob && cd null-blob && sha=$(printf "100644 file$_bz$_bzoid" | - git hash-object -w --stdin -t tree) && + git hash-object --literally -w --stdin -t tree) && git fsck 2>out && test_i18ngrep "warning.*null sha1" out ) @@ -583,7 +583,7 @@ test_expect_success 'fsck notices submodule entry pointing to null sha1' ' (git init null-commit && cd null-commit && sha=$(printf "160000 submodule$_bz$_bzoid" | - git hash-object -w --stdin -t tree) && + git hash-object --literally -w --stdin -t tree) && git fsck 2>out && test_i18ngrep "warning.*null sha1" out ) @@ -648,7 +648,7 @@ test_expect_success 'NUL in commit' ' git commit --allow-empty -m "initial commitQNUL after message" && git cat-file commit HEAD >original && q_to_nul <original >munged && - git hash-object -w -t commit --stdin <munged >name && + git hash-object --literally -w -t commit --stdin <munged >name && git branch bad $(cat name) && test_must_fail git -c fsck.nulInCommit=error fsck 2>warn.1 && @@ -794,8 +794,8 @@ test_expect_success 'fsck errors in packed objects' ' git cat-file commit HEAD >basis && sed "s/</one/" basis >one && sed "s/</foo/" basis >two && - one=$(git hash-object -t commit -w one) && - two=$(git hash-object -t commit -w two) && + one=$(git hash-object --literally -t commit -w one) && + two=$(git hash-object --literally -t commit -w two) && pack=$( { echo $one && @@ -1023,4 +1023,34 @@ test_expect_success 'fsck error on gitattributes with excessive size' ' test_cmp expected actual ' +test_expect_success 'fsck detects problems in worktree index' ' + test_when_finished "git worktree remove -f wt" && + git worktree add wt && + + echo "this will be removed to break the worktree index" >wt/file && + git -C wt add file && + blob=$(git -C wt rev-parse :file) && + remove_object $blob && + + test_must_fail git fsck --name-objects >actual 2>&1 && + cat >expect <<-EOF && + missing blob $blob (.git/worktrees/wt/index:file) + EOF + test_cmp expect actual +' + +test_expect_success 'fsck reports problems in main index without filename' ' + test_when_finished "rm -f .git/index && git read-tree HEAD" && + echo "this object will be removed to break the main index" >file && + git add file && + blob=$(git rev-parse :file) && + remove_object $blob && + + test_must_fail git fsck --name-objects >actual 2>&1 && + cat >expect <<-EOF && + missing blob $blob (:file) + EOF + test_cmp expect actual +' + test_done diff --git a/t/t1451-fsck-buffer.sh b/t/t1451-fsck-buffer.sh new file mode 100755 index 0000000000..3413da40e4 --- /dev/null +++ b/t/t1451-fsck-buffer.sh @@ -0,0 +1,142 @@ +#!/bin/sh + +test_description='fsck on buffers without NUL termination + +The goal here is to make sure that the various fsck parsers never look +past the end of the buffer they are given, even when encountering broken +or truncated objects. + +We have to use "hash-object" for this because most code paths that read objects +append an extra NUL for safety after the buffer. But hash-object, since it is +reading straight from a file (and possibly even mmap-ing it) cannot always do +so. + +These tests _might_ catch such overruns in normal use, but should be run with +ASan or valgrind for more confidence. +' + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +# the general idea for tags and commits is to build up the "base" file +# progressively, and then test new truncations on top of it. +reset () { + test_expect_success 'reset input to empty' ' + >base + ' +} + +add () { + content="$1" + type=${content%% *} + test_expect_success "add $type line" ' + echo "$content" >>base + ' +} + +check () { + type=$1 + fsck=$2 + content=$3 + test_expect_success "truncated $type ($fsck, \"$content\")" ' + # do not pipe into hash-object here; we want to increase + # the chance that it uses a fixed-size buffer or mmap, + # and a pipe would be read into a strbuf. + { + cat base && + echo "$content" + } >input && + test_must_fail git hash-object -t "$type" input 2>err && + grep "$fsck" err + ' +} + +test_expect_success 'create valid objects' ' + git commit --allow-empty -m foo && + commit=$(git rev-parse --verify HEAD) && + tree=$(git rev-parse --verify HEAD^{tree}) +' + +reset +check commit missingTree "" +check commit missingTree "tr" +check commit missingTree "tree" +check commit badTreeSha1 "tree " +check commit badTreeSha1 "tree 1234" +add "tree $tree" + +# these expect missingAuthor because "parent" is optional +check commit missingAuthor "" +check commit missingAuthor "par" +check commit missingAuthor "parent" +check commit badParentSha1 "parent " +check commit badParentSha1 "parent 1234" +add "parent $commit" + +check commit missingAuthor "" +check commit missingAuthor "au" +check commit missingAuthor "author" +ident_checks () { + check $1 missingEmail "$2 " + check $1 missingEmail "$2 name" + check $1 badEmail "$2 name <" + check $1 badEmail "$2 name <email" + check $1 missingSpaceBeforeDate "$2 name <email>" + check $1 badDate "$2 name <email> " + check $1 badDate "$2 name <email> 1234" + check $1 badTimezone "$2 name <email> 1234 " + check $1 badTimezone "$2 name <email> 1234 +" +} +ident_checks commit author +add "author name <email> 1234 +0000" + +check commit missingCommitter "" +check commit missingCommitter "co" +check commit missingCommitter "committer" +ident_checks commit committer +add "committer name <email> 1234 +0000" + +reset +check tag missingObject "" +check tag missingObject "obj" +check tag missingObject "object" +check tag badObjectSha1 "object " +check tag badObjectSha1 "object 1234" +add "object $commit" + +check tag missingType "" +check tag missingType "ty" +check tag missingType "type" +check tag badType "type " +check tag badType "type com" +add "type commit" + +check tag missingTagEntry "" +check tag missingTagEntry "ta" +check tag missingTagEntry "tag" +check tag badTagName "tag " +add "tag foo" + +check tag missingTagger "" +check tag missingTagger "ta" +check tag missingTagger "tagger" +ident_checks tag tagger + +# trees are a binary format and can't use our earlier helpers +test_expect_success 'truncated tree (short hash)' ' + printf "100644 foo\0\1\1\1\1" >input && + test_must_fail git hash-object -t tree input 2>err && + grep badTree err +' + +test_expect_success 'truncated tree (missing nul)' ' + # these two things are indistinguishable to the parser. The important + # thing about this is example is that there are enough bytes to + # make up a hash, and that there is no NUL (and we confirm that the + # parser does not walk past the end of the buffer). + printf "100644 a long filename, or a hash with missing nul?" >input && + test_must_fail git hash-object -t tree input 2>err && + grep badTree err +' + +test_done diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh index 81de584ea2..37ee5091b5 100755 --- a/t/t1500-rev-parse.sh +++ b/t/t1500-rev-parse.sh @@ -195,7 +195,7 @@ test_expect_success 'rev-parse --is-shallow-repository in non-shallow repo' ' ' test_expect_success 'rev-parse --show-object-format in repo' ' - echo "$(test_oid algo)" >expect && + test_oid algo >expect && git rev-parse --show-object-format >actual && test_cmp expect actual && git rev-parse --show-object-format=storage >actual && diff --git a/t/t1501-work-tree.sh b/t/t1501-work-tree.sh index b75558040f..ae6528aece 100755 --- a/t/t1501-work-tree.sh +++ b/t/t1501-work-tree.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test separate work tree' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t1504-ceiling-dirs.sh b/t/t1504-ceiling-dirs.sh index 0fafcf9dde..c1679e31d8 100755 --- a/t/t1504-ceiling-dirs.sh +++ b/t/t1504-ceiling-dirs.sh @@ -6,8 +6,12 @@ TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_prefix() { - test_expect_success "$1" \ - "test '$2' = \"\$(git rev-parse --show-prefix)\"" + local expect="$2" && + test_expect_success "$1: git rev-parse --show-prefix is '$2'" ' + echo "$expect" >expect && + git rev-parse --show-prefix >actual && + test_cmp expect actual + ' } test_fail() { diff --git a/t/t1509-root-work-tree.sh b/t/t1509-root-work-tree.sh index 553a3f601b..c799f5b6ac 100755 --- a/t/t1509-root-work-tree.sh +++ b/t/t1509-root-work-tree.sh @@ -221,7 +221,8 @@ test_expect_success 'setup' ' rm -rf /.git && echo "Initialized empty Git repository in /.git/" > expected && git init > result && - test_cmp expected result + test_cmp expected result && + git config --global --add safe.directory / ' test_vars 'auto gitdir, root' ".git" "/" "" @@ -242,7 +243,7 @@ say "auto bare gitdir" # DESTROYYYYY!!!!! test_expect_success 'setup' ' rm -rf /refs /objects /info /hooks && - rm -f /expected /ls.expected /me /result && + rm -f /HEAD /expected /ls.expected /me /result && cd / && echo "Initialized empty Git repository in /" > expected && git init --bare > result && @@ -255,4 +256,9 @@ test_expect_success 'go to /foo' 'cd /foo' test_vars 'auto gitdir, root' "/" "" "" +test_expect_success 'cleanup root' ' + rm -rf /.git /refs /objects /info /hooks /branches /foo && + rm -f /HEAD /config /description /expected /ls.expected /me /result +' + test_done diff --git a/t/t1600-index.sh b/t/t1600-index.sh index 010989f90e..9368d82f7d 100755 --- a/t/t1600-index.sh +++ b/t/t1600-index.sh @@ -65,6 +65,37 @@ test_expect_success 'out of bounds index.version issues warning' ' ) ' +test_expect_success 'index.skipHash config option' ' + rm -f .git/index && + git -c index.skipHash=true add a && + test_trailing_hash .git/index >hash && + echo $(test_oid zero) >expect && + test_cmp expect hash && + git fsck && + + rm -f .git/index && + git -c feature.manyFiles=true add a && + test_trailing_hash .git/index >hash && + cmp expect hash && + + rm -f .git/index && + git -c feature.manyFiles=true \ + -c index.skipHash=false add a && + test_trailing_hash .git/index >hash && + ! cmp expect hash && + + test_commit start && + git -c protocol.file.allow=always submodule add ./ sub && + git config index.skipHash false && + git -C sub config index.skipHash true && + rm -f .git/modules/sub/index && + >sub/file && + git -C sub add a && + test_trailing_hash .git/modules/sub/index >hash && + test_cmp expect hash && + git -C sub fsck +' + test_index_version () { INDEX_VERSION_CONFIG=$1 && FEATURE_MANY_FILES=$2 && diff --git a/t/t1800-hook.sh b/t/t1800-hook.sh index 43fcb7c0bf..3506f627b6 100755 --- a/t/t1800-hook.sh +++ b/t/t1800-hook.sh @@ -95,7 +95,7 @@ test_expect_success 'git hook run -- out-of-repo runs excluded' ' test_expect_success 'git -c core.hooksPath=<PATH> hook run' ' mkdir my-hooks && write_script my-hooks/test-hook <<-\EOF && - echo Hook ran $1 >>actual + echo Hook ran $1 EOF cat >expect <<-\EOF && @@ -177,4 +177,22 @@ test_expect_success 'git hook run a hook with a bad shebang' ' test_cmp expect actual ' +test_expect_success 'stdin to hooks' ' + write_script .git/hooks/test-hook <<-\EOF && + echo BEGIN stdin + cat + echo END stdin + EOF + + cat >expect <<-EOF && + BEGIN stdin + hello + END stdin + EOF + + echo hello >input && + git hook run --to-stdin=input test-hook 2>actual && + test_cmp expect actual +' + test_done diff --git a/t/t2005-checkout-index-symlinks.sh b/t/t2005-checkout-index-symlinks.sh index 112682a45a..67d18cfa10 100755 --- a/t/t2005-checkout-index-symlinks.sh +++ b/t/t2005-checkout-index-symlinks.sh @@ -22,8 +22,10 @@ test_expect_success \ git checkout-index symlink && test -f symlink' -test_expect_success \ -'the file must be the blob we added during the setup' ' -test "$(git hash-object -t blob symlink)" = $l' +test_expect_success 'the file must be the blob we added during the setup' ' + echo "$l" >expect && + git hash-object -t blob symlink >actual && + test_cmp expect actual +' test_done diff --git a/t/t2012-checkout-last.sh b/t/t2012-checkout-last.sh index 1f6c4ed042..4b6372f4c3 100755 --- a/t/t2012-checkout-last.sh +++ b/t/t2012-checkout-last.sh @@ -5,6 +5,7 @@ test_description='checkout can switch to last branch and merge base' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t2015-checkout-unborn.sh b/t/t2015-checkout-unborn.sh index 9425aae639..fb0e13881c 100755 --- a/t/t2015-checkout-unborn.sh +++ b/t/t2015-checkout-unborn.sh @@ -9,11 +9,12 @@ TEST_PASSES_SANITIZE_LEAK=true test_expect_success 'setup' ' mkdir parent && - (cd parent && - git init && - echo content >file && - git add file && - git commit -m base + ( + cd parent && + git init && + echo content >file && + git add file && + git commit -m base ) && git fetch parent main:origin ' diff --git a/t/t2016-checkout-patch.sh b/t/t2016-checkout-patch.sh index a5822e41af..747eb5563e 100755 --- a/t/t2016-checkout-patch.sh +++ b/t/t2016-checkout-patch.sh @@ -4,12 +4,6 @@ test_description='git checkout --patch' . ./lib-patch-mode.sh -if ! test_have_prereq ADD_I_USE_BUILTIN && ! test_have_prereq PERL -then - skip_all='skipping interactive add tests, PERL not set' - test_done -fi - test_expect_success 'setup' ' mkdir dir && echo parent > dir/foo && diff --git a/t/t2018-checkout-branch.sh b/t/t2018-checkout-branch.sh index 771c3c3c50..8581ad3437 100755 --- a/t/t2018-checkout-branch.sh +++ b/t/t2018-checkout-branch.sh @@ -3,6 +3,7 @@ test_description='checkout' TEST_CREATE_REPO_NO_TEMPLATE=1 +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Arguments: [!] <branch> <oid> [<checkout options>] diff --git a/t/t2021-checkout-overwrite.sh b/t/t2021-checkout-overwrite.sh index 713c3fa603..034f62c13c 100755 --- a/t/t2021-checkout-overwrite.sh +++ b/t/t2021-checkout-overwrite.sh @@ -50,10 +50,13 @@ test_expect_success 'checkout commit with dir must not remove untracked a/b' ' test_expect_success SYMLINKS 'the symlink remained' ' - test_when_finished "rm a/b" && test -h a/b ' +test_expect_success 'cleanup after previous symlink tests' ' + rm a/b +' + test_expect_success SYMLINKS 'checkout -f must not follow symlinks when removing entries' ' git checkout -f start && mkdir dir && @@ -66,4 +69,15 @@ test_expect_success SYMLINKS 'checkout -f must not follow symlinks when removing test_path_is_file untracked/f ' +test_expect_success 'checkout --overwrite-ignore should succeed if only ignored files in the way' ' + git checkout -b df_conflict && + test_commit contents some_dir && + git checkout start && + mkdir some_dir && + echo autogenerated information >some_dir/ignore && + echo ignore >.git/info/exclude && + git checkout --overwrite-ignore df_conflict && + ! test_path_is_dir some_dir +' + test_done diff --git a/t/t2025-checkout-no-overlay.sh b/t/t2025-checkout-no-overlay.sh index 8f13341cf8..3832c3de81 100755 --- a/t/t2025-checkout-no-overlay.sh +++ b/t/t2025-checkout-no-overlay.sh @@ -2,6 +2,7 @@ test_description='checkout --no-overlay <tree-ish> -- <pathspec>' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t2401-worktree-prune.sh b/t/t2401-worktree-prune.sh index 3d28c7f06b..568a47ec42 100755 --- a/t/t2401-worktree-prune.sh +++ b/t/t2401-worktree-prune.sh @@ -5,6 +5,7 @@ test_description='prune $GIT_DIR/worktrees' 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 ' diff --git a/t/t2402-worktree-list.sh b/t/t2402-worktree-list.sh index 79e0fce2d9..9ad9be0c20 100755 --- a/t/t2402-worktree-list.sh +++ b/t/t2402-worktree-list.sh @@ -5,6 +5,7 @@ test_description='test git worktree list' 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/t2406-worktree-repair.sh b/t/t2406-worktree-repair.sh index 5c44453e1c..8970780efc 100755 --- a/t/t2406-worktree-repair.sh +++ b/t/t2406-worktree-repair.sh @@ -2,6 +2,7 @@ test_description='test git worktree repair' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t3009-ls-files-others-nonsubmodule.sh b/t/t3009-ls-files-others-nonsubmodule.sh index 963f3462b7..14218b3424 100755 --- a/t/t3009-ls-files-others-nonsubmodule.sh +++ b/t/t3009-ls-files-others-nonsubmodule.sh @@ -18,6 +18,7 @@ This test runs git ls-files --others with the following working tree: git repository with a commit and an untracked file ' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup: directories' ' diff --git a/t/t3010-ls-files-killed-modified.sh b/t/t3010-ls-files-killed-modified.sh index 580e158f99..054178703d 100755 --- a/t/t3010-ls-files-killed-modified.sh +++ b/t/t3010-ls-files-killed-modified.sh @@ -41,6 +41,8 @@ Also for modification test, the cache and working tree have: We should report path0, path1, path2/file2, path3/file3, path7 and path8 modified without reporting path9 and path10. submod1 is also modified. ' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'git update-index --add to add various paths.' ' diff --git a/t/t3050-subprojects-fetch.sh b/t/t3050-subprojects-fetch.sh index f1f09abdd9..3884694165 100755 --- a/t/t3050-subprojects-fetch.sh +++ b/t/t3050-subprojects-fetch.sh @@ -2,6 +2,7 @@ test_description='fetching and pushing project with subproject' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t3060-ls-files-with-tree.sh b/t/t3060-ls-files-with-tree.sh index 52f76f7b57..c4a72ae446 100755 --- a/t/t3060-ls-files-with-tree.sh +++ b/t/t3060-ls-files-with-tree.sh @@ -8,6 +8,8 @@ test_description='git ls-files test (--with-tree). This test runs git ls-files --with-tree and in particular in a scenario known to trigger a crash with some versions of git. ' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t3104-ls-tree-format.sh b/t/t3104-ls-tree-format.sh index 383896667b..3adb206a93 100755 --- a/t/t3104-ls-tree-format.sh +++ b/t/t3104-ls-tree-format.sh @@ -20,7 +20,6 @@ test_ls_tree_format () { format=$1 && opts=$2 && fmtopts=$3 && - shift 2 && test_expect_success "ls-tree '--format=<$format>' is like options '$opts $fmtopts'" ' git ls-tree $opts -r HEAD >expect && @@ -36,6 +35,12 @@ test_ls_tree_format () { ' } +test_expect_success "ls-tree --format='%(path) %(path) %(path)' HEAD top-file" ' + git ls-tree --format="%(path) %(path) %(path)" HEAD top-file.t >actual && + echo top-file.t top-file.t top-file.t >expect && + test_cmp expect actual +' + test_ls_tree_format \ "%(objectmode) %(objecttype) %(objectname)%x09%(path)" \ "" diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index c7ec1c7520..5a8a48287c 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -201,8 +201,8 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou test_expect_success 'git branch -M baz bam should add entries to .git/logs/HEAD' ' msg="Branch: renamed refs/heads/baz to refs/heads/bam" && - grep " 0\{40\}.*$msg$" .git/logs/HEAD && - grep "^0\{40\}.*$msg$" .git/logs/HEAD + grep " $ZERO_OID.*$msg$" .git/logs/HEAD && + grep "^$ZERO_OID.*$msg$" .git/logs/HEAD ' test_expect_success 'git branch -M should leave orphaned HEAD alone' ' @@ -245,9 +245,13 @@ test_expect_success 'git branch -M baz bam should succeed within a worktree in w ( cd bazdir && git branch -M baz bam && - test $(git rev-parse --abbrev-ref HEAD) = bam + echo bam >expect && + git rev-parse --abbrev-ref HEAD >actual && + test_cmp expect actual ) && - test $(git rev-parse --abbrev-ref HEAD) = bam && + echo bam >expect && + git rev-parse --abbrev-ref HEAD >actual && + test_cmp expect actual && rm -r bazdir && git worktree prune ' @@ -268,6 +272,53 @@ test_expect_success 'git branch -M topic topic should work when main is checked git branch -M topic topic ' +test_expect_success 'git branch -M and -C fail on detached HEAD' ' + git checkout HEAD^{} && + test_when_finished git checkout - && + echo "fatal: cannot rename the current branch while not on any." >expect && + test_must_fail git branch -M must-fail 2>err && + test_cmp expect err && + echo "fatal: cannot copy the current branch while not on any." >expect && + test_must_fail git branch -C must-fail 2>err && + test_cmp expect err +' + +test_expect_success 'git branch -d on orphan HEAD (merged)' ' + test_when_finished git checkout main && + git checkout --orphan orphan && + test_when_finished "rm -rf .git/objects/commit-graph*" && + git commit-graph write --reachable && + git branch --track to-delete main && + git branch -d to-delete +' + +test_expect_success 'git branch -d on orphan HEAD (merged, graph)' ' + test_when_finished git checkout main && + git checkout --orphan orphan && + git branch --track to-delete main && + git branch -d to-delete +' + +test_expect_success 'git branch -d on orphan HEAD (unmerged)' ' + test_when_finished git checkout main && + git checkout --orphan orphan && + test_when_finished "git branch -D to-delete" && + git branch to-delete main && + test_must_fail git branch -d to-delete 2>err && + grep "not fully merged" err +' + +test_expect_success 'git branch -d on orphan HEAD (unmerged, graph)' ' + test_when_finished git checkout main && + git checkout --orphan orphan && + test_when_finished "git branch -D to-delete" && + git branch to-delete main && + test_when_finished "rm -rf .git/objects/commit-graph*" && + git commit-graph write --reachable && + test_must_fail git branch -d to-delete 2>err && + grep "not fully merged" err +' + test_expect_success 'git branch -v -d t should work' ' git branch t && git rev-parse --verify refs/heads/t && @@ -1383,7 +1434,7 @@ test_expect_success 'branch --delete --force removes dangling branch' ' test_expect_success 'use --edit-description' ' EDITOR=: git branch --edit-description && - test_must_fail git config branch.main.description && + test_expect_code 1 git config branch.main.description && write_script editor <<-\EOF && echo "New contents" >"$1" diff --git a/t/t3204-branch-name-interpretation.sh b/t/t3204-branch-name-interpretation.sh index 993a6b5eff..3399344f25 100755 --- a/t/t3204-branch-name-interpretation.sh +++ b/t/t3204-branch-name-interpretation.sh @@ -57,6 +57,16 @@ test_expect_success 'create branch with pseudo-qualified name' ' expect_branch refs/heads/refs/heads/qualified two ' +test_expect_success 'force-copy a branch to itself via @{-1} is no-op' ' + git branch -t copiable main && + git checkout copiable && + git checkout - && + git branch -C @{-1} copiable && + git config --get-all branch.copiable.merge >actual && + echo refs/heads/main >expect && + test_cmp expect actual +' + test_expect_success 'delete branch via @{-1}' ' git branch previous-del && @@ -133,4 +143,28 @@ test_expect_success 'checkout does not treat remote @{upstream} as a branch' ' expect_branch HEAD one ' +test_expect_success 'edit-description via @{-1}' ' + git checkout -b desc-branch && + git checkout -b non-desc-branch && + write_script editor <<-\EOF && + echo "Branch description" >"$1" + EOF + EDITOR=./editor git branch --edit-description @{-1} && + test_must_fail git config branch.non-desc-branch.description && + git config branch.desc-branch.description >actual && + printf "Branch description\n\n" >expect && + test_cmp expect actual +' + +test_expect_success 'modify branch upstream via "@{-1}" and "@{-1}@{upstream}"' ' + git checkout -b upstream-branch && + git checkout -b upstream-other -t upstream-branch && + git branch --set-upstream-to upstream-other @{-1} && + git config branch.upstream-branch.merge >actual && + echo "refs/heads/upstream-other" >expect && + test_cmp expect actual && + git branch --unset-upstream @{-1}@{upstream} && + test_must_fail git config branch.upstream-other.merge +' + test_done diff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh index 84dd0cd26d..b5f4d6a653 100755 --- a/t/t3206-range-diff.sh +++ b/t/t3206-range-diff.sh @@ -33,6 +33,26 @@ test_expect_success 'setup' ' u3 sha256:736c4bc u4 sha256:673e77d + # topic (abbrev=10) + t1_abbrev sha1:4de457d2c0 + t2_abbrev sha1:fccce22f8c + t3_abbrev sha1:147e64ef53 + t4_abbrev sha1:a63e992599 + t1_abbrev sha256:b89f8b9092 + t2_abbrev sha256:5f12aadf34 + t3_abbrev sha256:ea8b273a6c + t4_abbrev sha256:14b73361fc + + # unmodified (abbrev=10) + u1_abbrev sha1:35b9b25f76 + u2_abbrev sha1:de345ab3de + u3_abbrev sha1:9af6654000 + u4_abbrev sha1:2901f773f3 + u1_abbrev sha256:e3731be242 + u2_abbrev sha256:14fadf8cee + u3_abbrev sha256:736c4bcb44 + u4_abbrev sha256:673e77d589 + # reordered r1 sha1:aca177a r2 sha1:14ad629 @@ -153,6 +173,18 @@ test_expect_success 'simple A B C (unmodified)' ' test_cmp expect actual ' +test_expect_success 'simple A..B A..C (unmodified) with --abbrev' ' + git range-diff --no-color --abbrev=10 main..topic main..unmodified \ + >actual && + cat >expect <<-EOF && + 1: $(test_oid t1_abbrev) = 1: $(test_oid u1_abbrev) s/5/A/ + 2: $(test_oid t2_abbrev) = 2: $(test_oid u2_abbrev) s/4/A/ + 3: $(test_oid t3_abbrev) = 3: $(test_oid u3_abbrev) s/11/B/ + 4: $(test_oid t4_abbrev) = 4: $(test_oid u4_abbrev) s/12/B/ + EOF + test_cmp expect actual +' + test_expect_success 'A^! and A^-<n> (unmodified)' ' git range-diff --no-color topic^! unmodified^-1 >actual && cat >expect <<-EOF && diff --git a/t/t3210-pack-refs.sh b/t/t3210-pack-refs.sh index 577f32dc71..07a0ff93de 100755 --- a/t/t3210-pack-refs.sh +++ b/t/t3210-pack-refs.sh @@ -12,6 +12,7 @@ semantic is still the same. 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 'enable reflogs' ' diff --git a/t/t3305-notes-fanout.sh b/t/t3305-notes-fanout.sh index 22ffe5bcb9..1ec1fb6715 100755 --- a/t/t3305-notes-fanout.sh +++ b/t/t3305-notes-fanout.sh @@ -9,7 +9,7 @@ path_has_fanout() { path=$1 && fanout=$2 && after_last_slash=$(($(test_oid hexsz) - $fanout * 2)) && - echo $path | grep -q "^\([0-9a-f]\{2\}/\)\{$fanout\}[0-9a-f]\{$after_last_slash\}$" + echo $path | grep -q -E "^([0-9a-f]{2}/){$fanout}[0-9a-f]{$after_last_slash}$" } touched_one_note_with_fanout() { diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index f0a0a54fba..ff0afad63e 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -1244,9 +1244,9 @@ test_expect_success 'short commit ID collide' ' test $colliding_id = "$(git rev-parse HEAD | cut -c 1-4)" && grep "^pick $colliding_id " \ .git/rebase-merge/git-rebase-todo.tmp && - grep "^pick [0-9a-f]\{$hexsz\}" \ + grep -E "^pick [0-9a-f]{$hexsz}" \ .git/rebase-merge/git-rebase-todo && - grep "^pick [0-9a-f]\{$hexsz\}" \ + grep -E "^pick [0-9a-f]{$hexsz}" \ .git/rebase-merge/git-rebase-todo.backup && git rebase --continue ) && @@ -1261,7 +1261,7 @@ test_expect_success 'respect core.abbrev' ' set_cat_todo_editor && test_must_fail git rebase -i HEAD~4 >todo-list ) && - test 4 = $(grep -c "pick [0-9a-f]\{12,\}" todo-list) + test 4 = $(grep -c -E "pick [0-9a-f]{12,}" todo-list) ' test_expect_success 'todo count' ' @@ -1449,14 +1449,15 @@ test_expect_success 'rebase --edit-todo respects rebase.missingCommitsCheck = ig test_expect_success 'rebase --edit-todo respects rebase.missingCommitsCheck = warn' ' cat >expect <<-EOF && - error: invalid line 1: badcmd $(git rev-list --pretty=oneline --abbrev-commit -1 primary~4) + error: invalid command '\''pickled'\'' + error: invalid line 1: pickled $(git rev-list --pretty=oneline --abbrev-commit -1 primary~4) Warning: some commits may have been dropped accidentally. Dropped commits (newer to older): - $(git rev-list --pretty=oneline --abbrev-commit -1 primary) - $(git rev-list --pretty=oneline --abbrev-commit -1 primary~4) To avoid this message, use "drop" to explicitly remove a commit. EOF - head -n4 expect >expect.2 && + head -n5 expect >expect.2 && tail -n1 expect >>expect.2 && tail -n4 expect.2 >expect.3 && test_config rebase.missingCommitsCheck warn && @@ -1467,7 +1468,7 @@ test_expect_success 'rebase --edit-todo respects rebase.missingCommitsCheck = wa git rebase -i --root && cp .git/rebase-merge/git-rebase-todo.backup orig && FAKE_LINES="2 3 4" git rebase --edit-todo 2>actual.2 && - head -n6 actual.2 >actual && + head -n7 actual.2 >actual && test_cmp expect actual && cp orig .git/rebase-merge/git-rebase-todo && FAKE_LINES="1 2 3 4" git rebase --edit-todo 2>actual.2 && @@ -1483,7 +1484,8 @@ test_expect_success 'rebase --edit-todo respects rebase.missingCommitsCheck = wa test_expect_success 'rebase --edit-todo respects rebase.missingCommitsCheck = error' ' cat >expect <<-EOF && - error: invalid line 1: badcmd $(git rev-list --pretty=oneline --abbrev-commit -1 primary~4) + error: invalid command '\''pickled'\'' + error: invalid line 1: pickled $(git rev-list --pretty=oneline --abbrev-commit -1 primary~4) Warning: some commits may have been dropped accidentally. Dropped commits (newer to older): - $(git rev-list --pretty=oneline --abbrev-commit -1 primary) @@ -1583,7 +1585,7 @@ test_expect_success 'static check of bad command' ' set_fake_editor && test_must_fail env FAKE_LINES="1 2 3 bad 4 5" \ git rebase -i --root 2>actual && - test_i18ngrep "badcmd $(git rev-list --oneline -1 primary~1)" \ + test_i18ngrep "pickled $(git rev-list --oneline -1 primary~1)" \ actual && test_i18ngrep "You can fix this with .git rebase --edit-todo.." \ actual && @@ -2072,6 +2074,7 @@ test_expect_success '--update-refs: --edit-todo with no update-ref lines' ' ' test_expect_success '--update-refs: check failed ref update' ' + test_when_finished "test_might_fail git rebase --abort" && git checkout -B update-refs-error no-conflict-branch && git branch -f base HEAD~4 && git branch -f first HEAD~3 && @@ -2123,6 +2126,28 @@ test_expect_success '--update-refs: check failed ref update' ' test_cmp expect err.trimmed ' +test_expect_success 'bad labels and refs rejected when parsing todo list' ' + test_when_finished "test_might_fail git rebase --abort" && + cat >todo <<-\EOF && + exec >execed + label # + label :invalid + update-ref :bad + update-ref topic + EOF + rm -f execed && + ( + set_replace_editor todo && + test_must_fail git rebase -i HEAD 2>err + ) && + grep "'\''#'\'' is not a valid label" err && + grep "'\'':invalid'\'' is not a valid label" err && + grep "'\'':bad'\'' is not a valid refname" err && + grep "update-ref requires a fully qualified refname e.g. refs/heads/topic" \ + err && + test_path_is_missing execed +' + # This must be the last test in this file test_expect_success '$EDITOR and friends are unchanged' ' test_editor_unchanged diff --git a/t/t3405-rebase-malformed.sh b/t/t3405-rebase-malformed.sh index 2524331861..8979bc3407 100755 --- a/t/t3405-rebase-malformed.sh +++ b/t/t3405-rebase-malformed.sh @@ -5,6 +5,7 @@ test_description='rebase should handle arbitrary git message' 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/t3406-rebase-message.sh b/t/t3406-rebase-message.sh index d17b450e81..ceca160005 100755 --- a/t/t3406-rebase-message.sh +++ b/t/t3406-rebase-message.sh @@ -10,10 +10,16 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME test_expect_success 'setup' ' test_commit O fileO && test_commit X fileX && + git branch fast-forward && test_commit A fileA && test_commit B fileB && test_commit Y fileY && + git checkout -b conflicts O && + test_commit P && + test_commit conflict-X fileX && + test_commit Q && + git checkout -b topic O && git cherry-pick A B && test_commit Z fileZ && @@ -79,54 +85,165 @@ test_expect_success 'error out early upon -C<n> or --whitespace=<bad>' ' test_i18ngrep "Invalid whitespace option" err ' -test_expect_success 'GIT_REFLOG_ACTION' ' - git checkout start && - test_commit reflog-onto && - git checkout -b reflog-topic start && - test_commit reflog-to-rebase && +write_reflog_expect () { + if test $mode = --apply + then + sed 's/(continue)/(pick)/' + else + cat + fi >expect +} - git rebase reflog-onto && - git log -g --format=%gs -3 >actual && - cat >expect <<-\EOF && - rebase (finish): returning to refs/heads/reflog-topic - rebase (pick): reflog-to-rebase - rebase (start): checkout reflog-onto +test_reflog () { + mode=$1 + reflog_action="$2" + + test_expect_success "rebase $mode reflog${reflog_action:+ GIT_REFLOG_ACTION=$reflog_action}" ' + git checkout conflicts && + test_when_finished "git reset --hard Q" && + + ( + if test -n "$reflog_action" + then + GIT_REFLOG_ACTION="$reflog_action" && + export GIT_REFLOG_ACTION + fi && + test_must_fail git rebase $mode main && + echo resolved >fileX && + git add fileX && + git rebase --continue + ) && + + git log -g --format=%gs -5 >actual && + write_reflog_expect <<-EOF && + ${reflog_action:-rebase} (finish): returning to refs/heads/conflicts + ${reflog_action:-rebase} (pick): Q + ${reflog_action:-rebase} (continue): conflict-X + ${reflog_action:-rebase} (pick): P + ${reflog_action:-rebase} (start): checkout main EOF test_cmp expect actual && - git checkout -b reflog-prefix reflog-to-rebase && - GIT_REFLOG_ACTION=change-the-reflog git rebase reflog-onto && - git log -g --format=%gs -3 >actual && - cat >expect <<-\EOF && - change-the-reflog (finish): returning to refs/heads/reflog-prefix - change-the-reflog (pick): reflog-to-rebase - change-the-reflog (start): checkout reflog-onto + git log -g --format=%gs -1 conflicts >actual && + write_reflog_expect <<-EOF && + ${reflog_action:-rebase} (finish): refs/heads/conflicts onto $(git rev-parse main) + EOF + test_cmp expect actual && + + # check there is only one new entry in the branch reflog + test_cmp_rev conflicts@{1} Q + ' + + test_expect_success "rebase $mode fast-forward reflog${reflog_action:+ GIT_REFLOG_ACTION=$reflog_action}" ' + git checkout fast-forward && + test_when_finished "git reset --hard X" && + + ( + if test -n "$reflog_action" + then + GIT_REFLOG_ACTION="$reflog_action" && + export GIT_REFLOG_ACTION + fi && + git rebase $mode main + ) && + + git log -g --format=%gs -2 >actual && + write_reflog_expect <<-EOF && + ${reflog_action:-rebase} (finish): returning to refs/heads/fast-forward + ${reflog_action:-rebase} (start): checkout main + EOF + test_cmp expect actual && + + git log -g --format=%gs -1 fast-forward >actual && + write_reflog_expect <<-EOF && + ${reflog_action:-rebase} (finish): refs/heads/fast-forward onto $(git rev-parse main) + EOF + test_cmp expect actual && + + # check there is only one new entry in the branch reflog + test_cmp_rev fast-forward@{1} X + ' + + test_expect_success "rebase $mode --skip reflog${reflog_action:+ GIT_REFLOG_ACTION=$reflog_action}" ' + git checkout conflicts && + test_when_finished "git reset --hard Q" && + + ( + if test -n "$reflog_action" + then + GIT_REFLOG_ACTION="$reflog_action" && + export GIT_REFLOG_ACTION + fi && + test_must_fail git rebase $mode main && + git rebase --skip + ) && + + git log -g --format=%gs -4 >actual && + write_reflog_expect <<-EOF && + ${reflog_action:-rebase} (finish): returning to refs/heads/conflicts + ${reflog_action:-rebase} (pick): Q + ${reflog_action:-rebase} (pick): P + ${reflog_action:-rebase} (start): checkout main EOF test_cmp expect actual -' + ' -test_expect_success 'rebase --apply reflog' ' - git checkout -b reflog-apply start && - old_head_reflog="$(git log -g --format=%gs -1 HEAD)" && + test_expect_success "rebase $mode --abort reflog${reflog_action:+ GIT_REFLOG_ACTION=$reflog_action}" ' + git checkout conflicts && + test_when_finished "git reset --hard Q" && - git rebase --apply Y && + git log -g -1 conflicts >branch-expect && + ( + if test -n "$reflog_action" + then + GIT_REFLOG_ACTION="$reflog_action" && + export GIT_REFLOG_ACTION + fi && + test_must_fail git rebase $mode main && + git rebase --abort + ) && - git log -g --format=%gs -4 HEAD >actual && - cat >expect <<-EOF && - rebase finished: returning to refs/heads/reflog-apply - rebase: Z - rebase: checkout Y - $old_head_reflog + git log -g --format=%gs -3 >actual && + write_reflog_expect <<-EOF && + ${reflog_action:-rebase} (abort): returning to refs/heads/conflicts + ${reflog_action:-rebase} (pick): P + ${reflog_action:-rebase} (start): checkout main EOF test_cmp expect actual && - git log -g --format=%gs -2 reflog-apply >actual && - cat >expect <<-EOF && - rebase finished: refs/heads/reflog-apply onto $(git rev-parse Y) - branch: Created from start + # check branch reflog is unchanged + git log -g -1 conflicts >branch-actual && + test_cmp branch-expect branch-actual + ' + + test_expect_success "rebase $mode --abort detached HEAD reflog${reflog_action:+ GIT_REFLOG_ACTION=$reflog_action}" ' + git checkout Q && + test_when_finished "git reset --hard Q" && + + ( + if test -n "$reflog_action" + then + GIT_REFLOG_ACTION="$reflog_action" && + export GIT_REFLOG_ACTION + fi && + test_must_fail git rebase $mode main && + git rebase --abort + ) && + + git log -g --format=%gs -3 >actual && + write_reflog_expect <<-EOF && + ${reflog_action:-rebase} (abort): returning to $(git rev-parse Q) + ${reflog_action:-rebase} (pick): P + ${reflog_action:-rebase} (start): checkout main EOF test_cmp expect actual -' + ' +} + +test_reflog --merge +test_reflog --merge my-reflog-action +test_reflog --apply +test_reflog --apply my-reflog-action test_expect_success 'rebase -i onto unrelated history' ' git init unrelated && diff --git a/t/t3409-rebase-environ.sh b/t/t3409-rebase-environ.sh index 83ffb39d9f..acaf5558db 100755 --- a/t/t3409-rebase-environ.sh +++ b/t/t3409-rebase-environ.sh @@ -2,6 +2,7 @@ test_description='git rebase interactive environment' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh index 58371d8a54..e75b3d0e07 100755 --- a/t/t3412-rebase-root.sh +++ b/t/t3412-rebase-root.sh @@ -7,6 +7,7 @@ Tests if git rebase --root --onto <newparent> can rebase the root commit. GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh log_with_names () { diff --git a/t/t3413-rebase-hook.sh b/t/t3413-rebase-hook.sh index 9fab0d779b..e8456831e8 100755 --- a/t/t3413-rebase-hook.sh +++ b/t/t3413-rebase-hook.sh @@ -5,6 +5,7 @@ test_description='git rebase with its hook(s)' 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/t3416-rebase-onto-threedots.sh b/t/t3416-rebase-onto-threedots.sh index 3e04802cb0..f8c4ed78c9 100755 --- a/t/t3416-rebase-onto-threedots.sh +++ b/t/t3416-rebase-onto-threedots.sh @@ -5,6 +5,7 @@ test_description='git rebase --onto A...B' 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" @@ -79,8 +80,10 @@ test_expect_success 'rebase -i --onto main...topic' ' git reset --hard && git checkout topic && git reset --hard G && - set_fake_editor && - EXPECT_COUNT=1 git rebase -i --onto main...topic F && + ( + set_fake_editor && + EXPECT_COUNT=1 git rebase -i --onto main...topic F + ) && git rev-parse HEAD^1 >actual && git rev-parse C^0 >expect && test_cmp expect actual @@ -90,20 +93,22 @@ test_expect_success 'rebase -i --onto main...' ' git reset --hard && git checkout topic && git reset --hard G && - set_fake_editor && - EXPECT_COUNT=1 git rebase -i --onto main... F && + ( + set_fake_editor && + EXPECT_COUNT=1 git rebase -i --onto main... F + ) && git rev-parse HEAD^1 >actual && git rev-parse C^0 >expect && test_cmp expect actual ' -test_expect_success 'rebase -i --onto main...side' ' +test_expect_success 'rebase --onto main...side requires a single merge-base' ' git reset --hard && git checkout side && git reset --hard K && - set_fake_editor && - test_must_fail git rebase -i --onto main...side J + test_must_fail git rebase -i --onto main...side J 2>err && + grep "need exactly one merge base" err ' test_expect_success 'rebase --keep-base --onto incompatible' ' @@ -156,8 +161,10 @@ test_expect_success 'rebase -i --keep-base main from topic' ' git checkout topic && git reset --hard G && - set_fake_editor && - EXPECT_COUNT=2 git rebase -i --keep-base main && + ( + set_fake_editor && + EXPECT_COUNT=2 git rebase -i --keep-base main + ) && git rev-parse C >base.expect && git merge-base main HEAD >base.actual && test_cmp base.expect base.actual && @@ -171,8 +178,10 @@ test_expect_success 'rebase -i --keep-base main topic from main' ' git checkout main && git branch -f topic G && - set_fake_editor && - EXPECT_COUNT=2 git rebase -i --keep-base main topic && + ( + set_fake_editor && + EXPECT_COUNT=2 git rebase -i --keep-base main topic + ) && git rev-parse C >base.expect && git merge-base main HEAD >base.actual && test_cmp base.expect base.actual && @@ -182,13 +191,39 @@ test_expect_success 'rebase -i --keep-base main topic from main' ' test_cmp expect actual ' -test_expect_success 'rebase -i --keep-base main from side' ' +test_expect_success 'rebase --keep-base requires a single merge base' ' git reset --hard && git checkout side && git reset --hard K && - set_fake_editor && - test_must_fail git rebase -i --keep-base main + test_must_fail git rebase -i --keep-base main 2>err && + grep "need exactly one merge base with branch" err +' + +test_expect_success 'rebase --keep-base keeps cherry picks' ' + git checkout -f -B main E && + git cherry-pick F && + ( + set_fake_editor && + EXPECT_COUNT=2 git rebase -i --keep-base HEAD G + ) && + test_cmp_rev HEAD G +' + +test_expect_success 'rebase --keep-base --no-reapply-cherry-picks' ' + git checkout -f -B main E && + git cherry-pick F && + ( + set_fake_editor && + EXPECT_COUNT=1 git rebase -i --keep-base \ + --no-reapply-cherry-picks HEAD G + ) && + test_cmp_rev HEAD^ C +' + +# This must be the last test in this file +test_expect_success '$EDITOR and friends are unchanged' ' + test_editor_unchanged ' test_done diff --git a/t/t3419-rebase-patch-id.sh b/t/t3419-rebase-patch-id.sh index 295040f2fe..6c61f240cf 100755 --- a/t/t3419-rebase-patch-id.sh +++ b/t/t3419-rebase-patch-id.sh @@ -5,6 +5,7 @@ test_description='git rebase - test patch id computation' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh scramble () { @@ -43,15 +44,26 @@ test_expect_success 'setup: 500 lines' ' git add newfile && git commit -q -m "add small file" && - git cherry-pick main >/dev/null 2>&1 -' + git cherry-pick main >/dev/null 2>&1 && + + git branch -f squashed main && + git checkout -q -f squashed && + git reset -q --soft HEAD~2 && + git commit -q -m squashed && + + git branch -f mode main && + git checkout -q -f mode && + test_chmod +x file && + git commit -q -a --amend && -test_expect_success 'setup attributes' ' - echo "file binary" >.gitattributes + git branch -f modeother other && + git checkout -q -f modeother && + test_chmod +x file && + git commit -q -a --amend ' test_expect_success 'detect upstream patch' ' - git checkout -q main && + git checkout -q main^{} && scramble file && git add file && git commit -q -m "change big file again" && @@ -61,14 +73,46 @@ test_expect_success 'detect upstream patch' ' test_must_be_empty revs ' +test_expect_success 'detect upstream patch binary' ' + echo "file binary" >.gitattributes && + git checkout -q other^{} && + git rebase main && + git rev-list main...HEAD~ >revs && + test_must_be_empty revs && + test_when_finished "rm .gitattributes" +' + +test_expect_success 'detect upstream patch modechange' ' + git checkout -q modeother^{} && + git rebase mode && + git rev-list mode...HEAD~ >revs && + test_must_be_empty revs +' + test_expect_success 'do not drop patch' ' - git branch -f squashed main && - git checkout -q -f squashed && - git reset -q --soft HEAD~2 && - git commit -q -m squashed && git checkout -q other^{} && test_must_fail git rebase squashed && - git rebase --quit + test_when_finished "git rebase --abort" +' + +test_expect_success 'do not drop patch binary' ' + echo "file binary" >.gitattributes && + git checkout -q other^{} && + test_must_fail git rebase squashed && + test_when_finished "git rebase --abort" && + test_when_finished "rm .gitattributes" +' + +test_expect_success 'do not drop patch modechange' ' + git checkout -q modeother^{} && + git rebase other && + cat >expected <<-\EOF && + diff --git a/file b/file + old mode 100644 + new mode 100755 + EOF + git diff HEAD~ >modediff && + test_cmp expected modediff ' test_done diff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh index 6dabb05a2a..4711b37a28 100755 --- a/t/t3422-rebase-incompatible-options.sh +++ b/t/t3422-rebase-incompatible-options.sh @@ -25,11 +25,11 @@ test_expect_success 'setup' ' ' # -# Rebase has lots of useful options like --whitepsace=fix, which are -# actually all built in terms of flags to git-am. Since neither -# --merge nor --interactive (nor any options that imply those two) use -# git-am, using them together will result in flags like --whitespace=fix -# being ignored. Make sure rebase warns the user and aborts instead. +# Rebase has a couple options which are specific to the apply backend, +# and several options which are specific to the merge backend. Flags +# from the different sets cannot work together, and we do not want to +# just ignore one of the sets of flags. Make sure rebase warns the +# user and aborts instead. # test_rebase_am_only () { @@ -50,6 +50,11 @@ test_rebase_am_only () { test_must_fail git rebase $opt --strategy-option=ours A " + test_expect_success "$opt incompatible with --autosquash" " + git checkout B^0 && + test_must_fail git rebase $opt --autosquash A + " + test_expect_success "$opt incompatible with --interactive" " git checkout B^0 && test_must_fail git rebase $opt --interactive A @@ -60,9 +65,65 @@ test_rebase_am_only () { test_must_fail git rebase $opt --exec 'true' A " + test_expect_success "$opt incompatible with --keep-empty" " + git checkout B^0 && + test_must_fail git rebase $opt --keep-empty A + " + + test_expect_success "$opt incompatible with --empty=..." " + git checkout B^0 && + test_must_fail git rebase $opt --empty=ask A + " + + test_expect_success "$opt incompatible with --no-reapply-cherry-picks" " + git checkout B^0 && + test_must_fail git rebase $opt --no-reapply-cherry-picks A + " + + test_expect_success "$opt incompatible with --reapply-cherry-picks" " + git checkout B^0 && + test_must_fail git rebase $opt --reapply-cherry-picks A + " + + test_expect_success "$opt incompatible with --update-refs" " + git checkout B^0 && + test_must_fail git rebase $opt --update-refs A + " + + test_expect_success "$opt incompatible with --root without --onto" " + git checkout B^0 && + test_must_fail git rebase $opt --root A + " + + test_expect_success "$opt incompatible with rebase.autosquash" " + git checkout B^0 && + test_must_fail git -c rebase.autosquash=true rebase $opt A 2>err && + grep -e --no-autosquash err + " + + test_expect_success "$opt incompatible with rebase.updateRefs" " + git checkout B^0 && + test_must_fail git -c rebase.updateRefs=true rebase $opt A 2>err && + grep -e --no-update-refs err + " + + test_expect_success "$opt okay with overridden rebase.autosquash" " + test_when_finished \"git reset --hard B^0\" && + git checkout B^0 && + git -c rebase.autosquash=true rebase --no-autosquash $opt A + " + + test_expect_success "$opt okay with overridden rebase.updateRefs" " + test_when_finished \"git reset --hard B^0\" && + git checkout B^0 && + git -c rebase.updateRefs=true rebase --no-update-refs $opt A + " } +# Check options which imply --apply test_rebase_am_only --whitespace=fix test_rebase_am_only -C4 +# Also check an explicit --apply +test_rebase_am_only --apply test_done diff --git a/t/t3423-rebase-reword.sh b/t/t3423-rebase-reword.sh index 4859bb8f72..2fab703d61 100755 --- a/t/t3423-rebase-reword.sh +++ b/t/t3423-rebase-reword.sh @@ -2,6 +2,7 @@ test_description='git rebase interactive with rewording' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-rebase.sh diff --git a/t/t3425-rebase-topology-merges.sh b/t/t3425-rebase-topology-merges.sh index 63acc1ea4d..a16428bdf5 100755 --- a/t/t3425-rebase-topology-merges.sh +++ b/t/t3425-rebase-topology-merges.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='rebase topology tests with merges' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-rebase.sh diff --git a/t/t3428-rebase-signoff.sh b/t/t3428-rebase-signoff.sh index f6993b7e14..e1b1e94764 100755 --- a/t/t3428-rebase-signoff.sh +++ b/t/t3428-rebase-signoff.sh @@ -5,6 +5,7 @@ test_description='git rebase --signoff This test runs git rebase --signoff and make sure that it works. ' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # A simple file to commit diff --git a/t/t3429-rebase-edit-todo.sh b/t/t3429-rebase-edit-todo.sh index abd66f3602..8e0d03969a 100755 --- a/t/t3429-rebase-edit-todo.sh +++ b/t/t3429-rebase-edit-todo.sh @@ -2,6 +2,7 @@ test_description='rebase should reread the todo file if an exec modifies it' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-rebase.sh diff --git a/t/t3430-rebase-merges.sh b/t/t3430-rebase-merges.sh index f351701fec..fa2a06c19f 100755 --- a/t/t3430-rebase-merges.sh +++ b/t/t3430-rebase-merges.sh @@ -138,6 +138,23 @@ test_expect_success '`reset` refuses to overwrite untracked files' ' git rebase --abort ' +test_expect_success '`reset` rejects trees' ' + test_when_finished "test_might_fail git rebase --abort" && + test_must_fail env GIT_SEQUENCE_EDITOR="echo reset A^{tree} >" \ + git rebase -i B C >out 2>err && + grep "object .* is a tree" err && + test_must_be_empty out +' + +test_expect_success '`reset` only looks for labels under refs/rewritten/' ' + test_when_finished "test_might_fail git rebase --abort" && + git branch refs/rewritten/my-label A && + test_must_fail env GIT_SEQUENCE_EDITOR="echo reset my-label >" \ + git rebase -i B C >out 2>err && + grep "could not resolve ${SQ}my-label${SQ}" err && + test_must_be_empty out +' + test_expect_success 'failed `merge -C` writes patch (may be rescheduled, too)' ' test_when_finished "test_might_fail git rebase --abort" && git checkout -b conflicting-merge A && diff --git a/t/t3431-rebase-fork-point.sh b/t/t3431-rebase-fork-point.sh index 1d0b15380e..4bfc779bb8 100755 --- a/t/t3431-rebase-fork-point.sh +++ b/t/t3431-rebase-fork-point.sh @@ -8,6 +8,7 @@ test_description='git rebase --fork-point test' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # A---B---D---E (main) @@ -50,7 +51,7 @@ test_rebase () { test_rebase 'G F E D B A' test_rebase 'G F D B A' --onto D -test_rebase 'G F B A' --keep-base +test_rebase 'G F C B A' --keep-base test_rebase 'G F C E D B A' --no-fork-point test_rebase 'G F C D B A' --no-fork-point --onto D test_rebase 'G F C B A' --no-fork-point --keep-base diff --git a/t/t3432-rebase-fast-forward.sh b/t/t3432-rebase-fast-forward.sh index 5086e14c02..7f1a5dd3de 100755 --- a/t/t3432-rebase-fast-forward.sh +++ b/t/t3432-rebase-fast-forward.sh @@ -8,6 +8,7 @@ test_description='ensure rebase fast-forwards commits when possible' 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/t3433-rebase-across-mode-change.sh b/t/t3433-rebase-across-mode-change.sh index 05df964670..c8172b0852 100755 --- a/t/t3433-rebase-across-mode-change.sh +++ b/t/t3433-rebase-across-mode-change.sh @@ -2,6 +2,7 @@ test_description='git rebase across mode change' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t3437-rebase-fixup-options.sh b/t/t3437-rebase-fixup-options.sh index c023fefd68..dd3b301fa7 100755 --- a/t/t3437-rebase-fixup-options.sh +++ b/t/t3437-rebase-fixup-options.sh @@ -14,6 +14,7 @@ to the "fixup" command that works with "fixup!", "fixup -C" works with "amend!" upon --autosquash. ' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-rebase.sh @@ -50,6 +51,7 @@ test_expect_success 'setup' ' body EOF + test_commit initial && test_commit A A && test_commit B B && get_author HEAD >expected-author && @@ -208,4 +210,29 @@ test_expect_success 'fixup -C works upon --autosquash with amend!' ' actual-squash-message ' +test_expect_success 'fixup -[Cc]<commit> works' ' + test_when_finished "test_might_fail git rebase --abort" && + cat >todo <<-\EOF && + pick A + fixup -CA1 + pick B + fixup -cA2 + EOF + ( + set_replace_editor todo && + FAKE_COMMIT_MESSAGE="edited and fixed up" \ + git rebase -i initial initial + ) && + git log --pretty=format:%B initial.. >actual && + cat >expect <<-EOF && + edited and fixed up + $EMPTY + new subject + $EMPTY + new + body + EOF + test_cmp expect actual +' + test_done diff --git a/t/t3438-rebase-broken-files.sh b/t/t3438-rebase-broken-files.sh index b92a3ce46b..c614c4f2e4 100755 --- a/t/t3438-rebase-broken-files.sh +++ b/t/t3438-rebase-broken-files.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='rebase behavior when on-disk files are broken' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'set up conflicting branches' ' diff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh index 1f4cfc3744..2f3e3e2416 100755 --- a/t/t3501-revert-cherry-pick.sh +++ b/t/t3501-revert-cherry-pick.sh @@ -13,6 +13,7 @@ test_description='test cherry-pick and revert with renames 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/t3502-cherry-pick-merge.sh b/t/t3502-cherry-pick-merge.sh index 5495eacfec..1b2c0d6aca 100755 --- a/t/t3502-cherry-pick-merge.sh +++ b/t/t3502-cherry-pick-merge.sh @@ -11,6 +11,7 @@ test_description='cherry picking and reverting a merge 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/t3503-cherry-pick-root.sh b/t/t3503-cherry-pick-root.sh index 95fe4feaee..76d393dc8a 100755 --- a/t/t3503-cherry-pick-root.sh +++ b/t/t3503-cherry-pick-root.sh @@ -5,6 +5,7 @@ test_description='test cherry-picking (and reverting) a root 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/t3506-cherry-pick-ff.sh b/t/t3506-cherry-pick-ff.sh index 7e11bd4a4c..b71bad17b8 100755 --- a/t/t3506-cherry-pick-ff.sh +++ b/t/t3506-cherry-pick-ff.sh @@ -5,6 +5,7 @@ test_description='test cherry-picking with --ff option' 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/t3511-cherry-pick-x.sh b/t/t3511-cherry-pick-x.sh index 84a587daf3..dd5d92ef30 100755 --- a/t/t3511-cherry-pick-x.sh +++ b/t/t3511-cherry-pick-x.sh @@ -2,6 +2,7 @@ test_description='Test cherry-pick -x and -s' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh pristine_detach () { diff --git a/t/t3700-add.sh b/t/t3700-add.sh index 8689b48589..82dd768944 100755 --- a/t/t3700-add.sh +++ b/t/t3700-add.sh @@ -106,24 +106,32 @@ test_expect_success '.gitignore test setup' ' test_expect_success '.gitignore is honored' ' git add . && - ! (git ls-files | grep "\\.ig") + git ls-files >files && + sed -n "/\\.ig/p" <files >actual && + test_must_be_empty actual ' test_expect_success 'error out when attempting to add ignored ones without -f' ' test_must_fail git add a.?? && - ! (git ls-files | grep "\\.ig") + git ls-files >files && + sed -n "/\\.ig/p" <files >actual && + test_must_be_empty actual ' test_expect_success 'error out when attempting to add ignored ones without -f' ' test_must_fail git add d.?? && - ! (git ls-files | grep "\\.ig") + git ls-files >files && + sed -n "/\\.ig/p" <files >actual && + test_must_be_empty actual ' test_expect_success 'error out when attempting to add ignored ones but add others' ' touch a.if && test_must_fail git add a.?? && - ! (git ls-files | grep "\\.ig") && - (git ls-files | grep a.if) + git ls-files >files && + sed -n "/\\.ig/p" <files >actual && + test_must_be_empty actual && + grep a.if files ' test_expect_success 'add ignored ones with -f' ' @@ -291,7 +299,7 @@ test_expect_success BSLASHPSPEC "git add 'fo\\[ou\\]bar' ignores foobar" ' git reset --hard && touch fo\[ou\]bar foobar && git add '\''fo\[ou\]bar'\'' && - git ls-files fo\[ou\]bar | fgrep fo\[ou\]bar && + git ls-files fo\[ou\]bar | grep -F fo\[ou\]bar && ! ( git ls-files foobar | grep foobar ) ' diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh index 5841f280fb..032b61ce21 100755 --- a/t/t3701-add-interactive.sh +++ b/t/t3701-add-interactive.sh @@ -7,7 +7,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME . ./test-lib.sh . "$TEST_DIRECTORY"/lib-terminal.sh -if test_have_prereq !ADD_I_USE_BUILTIN,!PERL +if test_have_prereq !PERL then skip_all='skipping add -i (scripted) tests, perl not available' test_done @@ -46,6 +46,21 @@ 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. + 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 +' + test_expect_success 'setup (initial)' ' echo content >file && git add file && @@ -296,9 +311,11 @@ test_expect_success FILEMODE 'stage mode and hunk' ' echo content >>file && chmod +x file && printf "y\\ny\\n" | git add -p && - git diff --cached file | grep "new mode" && - git diff --cached file | grep "+content" && - test -z "$(git diff file)" + git diff --cached file >out && + grep "new mode" out && + grep "+content" out && + git diff file >out && + test_must_be_empty out ' # end of tests disabled when filemode is not usable @@ -547,15 +564,7 @@ test_expect_success 'split hunk "add -p (edit)"' ' ! grep "^+15" actual ' -test_expect_success 'setup ADD_I_USE_BUILTIN check' ' - result=success && - if ! test_have_prereq ADD_I_USE_BUILTIN - then - result=failure - fi -' - -test_expect_$result 'split hunk "add -p (no, yes, edit)"' ' +test_expect_success 'split hunk "add -p (no, yes, edit)"' ' test_write_lines 5 10 20 21 30 31 40 50 60 >test && git reset && # test sequence is s(plit), n(o), y(es), e(dit) @@ -579,7 +588,7 @@ test_expect_success 'split hunk with incomplete line at end' ' test_must_fail git grep --cached before ' -test_expect_$result 'edit, adding lines to the first hunk' ' +test_expect_success 'edit, adding lines to the first hunk' ' test_write_lines 10 11 20 30 40 50 51 60 >test && git reset && tr _ " " >patch <<-EOF && diff --git a/t/t3702-add-edit.sh b/t/t3702-add-edit.sh index a1801a8cbd..82bfb2fd2a 100755 --- a/t/t3702-add-edit.sh +++ b/t/t3702-add-edit.sh @@ -100,7 +100,7 @@ EOF echo "#!$SHELL_PATH" >fake-editor.sh cat >> fake-editor.sh <<\EOF -egrep -v '^index' "$1" >orig-patch && +grep -E -v '^index' "$1" >orig-patch && mv -f patch "$1" EOF diff --git a/t/t3800-mktag.sh b/t/t3800-mktag.sh index e3cf0ffbe5..d3e428ff46 100755 --- a/t/t3800-mktag.sh +++ b/t/t3800-mktag.sh @@ -4,6 +4,7 @@ test_description='git mktag: tag object verify test' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh ########################################################### diff --git a/t/t3920-crlf-messages.sh b/t/t3920-crlf-messages.sh index 4c661d4d54..67fd2345af 100755 --- a/t/t3920-crlf-messages.sh +++ b/t/t3920-crlf-messages.sh @@ -12,7 +12,7 @@ create_crlf_ref () { cat >.crlf-orig-$branch.txt && cat .crlf-orig-$branch.txt | append_cr >.crlf-message-$branch.txt && grep 'Subject' .crlf-orig-$branch.txt | tr '\n' ' ' | sed 's/[ ]*$//' | tr -d '\n' >.crlf-subject-$branch.txt && - grep 'Body' .crlf-message-$branch.txt >.crlf-body-$branch.txt || true && + grep 'Body' .crlf-orig-$branch.txt | append_cr >.crlf-body-$branch.txt && LIB_CRLF_BRANCHES="${LIB_CRLF_BRANCHES} ${branch}" && test_tick && hash=$(git commit-tree HEAD^{tree} -p HEAD -F .crlf-message-${branch}.txt) && diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh index c509143c81..c64d9d2f40 100755 --- a/t/t4012-diff-binary.sh +++ b/t/t4012-diff-binary.sh @@ -113,20 +113,20 @@ test_expect_success 'diff --no-index with binary creation' ' ' cat >expect <<EOF - binfile | Bin 0 -> 1026 bytes - textfile | 10000 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + binfilë | Bin 0 -> 1026 bytes + tëxtfilë | 10000 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ EOF test_expect_success 'diff --stat with binary files and big change count' ' - printf "\01\00%1024d" 1 >binfile && - git add binfile && + printf "\01\00%1024d" 1 >binfilë && + git add binfilë && i=0 && while test $i -lt 10000; do echo $i && i=$(($i + 1)) || return 1 - done >textfile && - git add textfile && - git diff --cached --stat binfile textfile >output && + done >tëxtfilë && + git add tëxtfilë && + git -c core.quotepath=false diff --cached --stat binfilë tëxtfilë >output && grep " | " output >actual && test_cmp expect actual ' diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index ad5c029279..f3313b8c58 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -1457,7 +1457,7 @@ append_signoff() C=$(git commit-tree HEAD^^{tree} -p HEAD) && git format-patch --stdout --signoff $C^..$C >append_signoff.patch && sed -n -e "1,/^---$/p" append_signoff.patch | - egrep -n "^Subject|Sign|^$" + grep -E -n "^Subject|Sign|^$" } test_expect_success 'signoff: commit with no body' ' @@ -2274,14 +2274,32 @@ test_expect_success 'format-patch --base with --attach' ' test_expect_success 'format-patch --attach cover-letter only is non-multipart' ' test_when_finished "rm -fr patches" && git format-patch -o patches --cover-letter --attach=mimemime --base=HEAD~ -1 && - ! egrep "^--+mimemime" patches/0000*.patch && - egrep "^--+mimemime$" patches/0001*.patch >output && + ! grep -E "^--+mimemime" patches/0000*.patch && + grep -E "^--+mimemime$" patches/0001*.patch >output && test_line_count = 2 output && - egrep "^--+mimemime--$" patches/0001*.patch >output && + grep -E "^--+mimemime--$" patches/0001*.patch >output && test_line_count = 1 output ' -test_expect_success 'format-patch --pretty=mboxrd' ' +test_expect_success 'format-patch with format.attach' ' + test_when_finished "rm -fr patches" && + separator=attachment-separator && + test_config format.attach "$separator" && + filename=$(git format-patch -o patches -1) && + grep "^Content-Type: multipart/.*$separator" "$filename" +' + +test_expect_success 'format-patch with format.attach=disabled' ' + test_when_finished "rm -fr patches" && + separator=attachment-separator && + test_config_global format.attach "$separator" && + test_config format.attach "" && + filename=$(git format-patch -o patches -1) && + # The output should not even declare content type for text/plain. + ! grep "^Content-Type: multipart/" "$filename" +' + +test_expect_success '-c format.mboxrd format-patch' ' sp=" " && cat >msg <<-INPUT_END && mboxrd should escape the body @@ -2316,7 +2334,9 @@ test_expect_success 'format-patch --pretty=mboxrd' ' INPUT_END C=$(git commit-tree HEAD^^{tree} -p HEAD <msg) && - git format-patch --pretty=mboxrd --stdout -1 $C~1..$C >patch && + git -c format.mboxrd format-patch --stdout -1 $C~1..$C >patch && + git format-patch --pretty=mboxrd --stdout -1 $C~1..$C >compat && + test_cmp patch compat && git grep -h --no-index -A11 \ "^>From could trip up a loose mbox parser" patch >actual && test_cmp expect actual diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index f3e20dd5bb..b298f220e0 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -1638,7 +1638,7 @@ test_expect_success 'no effect on diff from --color-moved with --word-diff' ' test_cmp expect actual ' -test_expect_success !SANITIZE_LEAK 'no effect on show from --color-moved with --word-diff' ' +test_expect_success 'no effect on show from --color-moved with --word-diff' ' git show --color-moved --word-diff >actual && git show --word-diff >expect && test_cmp expect actual @@ -2024,7 +2024,7 @@ test_expect_success '--color-moved rewinds for MIN_ALNUM_COUNT' ' test_cmp expected actual ' -test_expect_success !SANITIZE_LEAK 'move detection with submodules' ' +test_expect_success 'move detection with submodules' ' test_create_repo bananas && echo ripe >bananas/recipe && git -C bananas add recipe && diff --git a/t/t4018/java-class-brace-on-separate-line b/t/t4018/java-class-brace-on-separate-line new file mode 100644 index 0000000000..8795acd4cf --- /dev/null +++ b/t/t4018/java-class-brace-on-separate-line @@ -0,0 +1,6 @@ +class RIGHT +{ + static int ONE; + static int TWO; + static int ChangeMe; +} diff --git a/t/t4018/java-class-space-before-type-parameters b/t/t4018/java-class-space-before-type-parameters new file mode 100644 index 0000000000..0bdef1dfbe --- /dev/null +++ b/t/t4018/java-class-space-before-type-parameters @@ -0,0 +1,6 @@ +class RIGHT <TYPE, PARAMS, AFTER, SPACE> { + static int ONE; + static int TWO; + static int THREE; + private A ChangeMe; +} diff --git a/t/t4018/java-class-type-parameters b/t/t4018/java-class-type-parameters new file mode 100644 index 0000000000..579aa7af21 --- /dev/null +++ b/t/t4018/java-class-type-parameters @@ -0,0 +1,6 @@ +class RIGHT<A, B> { + static int ONE; + static int TWO; + static int THREE; + private A ChangeMe; +} diff --git a/t/t4018/java-class-type-parameters-implements b/t/t4018/java-class-type-parameters-implements new file mode 100644 index 0000000000..b8038b1866 --- /dev/null +++ b/t/t4018/java-class-type-parameters-implements @@ -0,0 +1,6 @@ +class RIGHT<A, B> implements List<A> { + static int ONE; + static int TWO; + static int THREE; + private A ChangeMe; +} diff --git a/t/t4018/java-interface-type-parameters b/t/t4018/java-interface-type-parameters new file mode 100644 index 0000000000..a4baa1ae68 --- /dev/null +++ b/t/t4018/java-interface-type-parameters @@ -0,0 +1,6 @@ +interface RIGHT<A, B> { + static int ONE; + static int TWO; + static int THREE; + public B foo(A ChangeMe); +} diff --git a/t/t4018/java-interface-type-parameters-extends b/t/t4018/java-interface-type-parameters-extends new file mode 100644 index 0000000000..31d7fb3244 --- /dev/null +++ b/t/t4018/java-interface-type-parameters-extends @@ -0,0 +1,6 @@ +interface RIGHT<A, B> extends Function<A, B> { + static int ONE; + static int TWO; + static int THREE; + public B foo(A ChangeMe); +} diff --git a/t/t4018/java-non-sealed b/t/t4018/java-non-sealed new file mode 100644 index 0000000000..069087c1c6 --- /dev/null +++ b/t/t4018/java-non-sealed @@ -0,0 +1,8 @@ +public abstract sealed class SealedClass { + public static non-sealed class RIGHT extends SealedClass { + static int ONE; + static int TWO; + static int THREE; + private int ChangeMe; + } +} diff --git a/t/t4018/java-record b/t/t4018/java-record new file mode 100644 index 0000000000..97aa819dd8 --- /dev/null +++ b/t/t4018/java-record @@ -0,0 +1,6 @@ +public record RIGHT(int comp1, double comp2, String comp3) { + static int ONE; + static int TWO; + static int THREE; + static int ChangeMe; +} diff --git a/t/t4018/java-record-space-before-components b/t/t4018/java-record-space-before-components new file mode 100644 index 0000000000..9827f22583 --- /dev/null +++ b/t/t4018/java-record-space-before-components @@ -0,0 +1,6 @@ +public record RIGHT (String components, String after, String space) { + static int ONE; + static int TWO; + static int THREE; + static int ChangeMe; +} diff --git a/t/t4018/java-record-type-parameters b/t/t4018/java-record-type-parameters new file mode 100644 index 0000000000..f62a035cc8 --- /dev/null +++ b/t/t4018/java-record-type-parameters @@ -0,0 +1,6 @@ +public record RIGHT<A, N extends Number>(A comp1, N comp2, int comp3) { + static int ONE; + static int TWO; + static int THREE; + static int ChangeMe; +} diff --git a/t/t4018/java-sealed b/t/t4018/java-sealed new file mode 100644 index 0000000000..785fbc62bc --- /dev/null +++ b/t/t4018/java-sealed @@ -0,0 +1,7 @@ +public abstract sealed class Sealed { // RIGHT + static int ONE; + static int TWO; + static int THREE; + public final class ChangeMe extends Sealed { + } +} diff --git a/t/t4018/java-sealed-permits b/t/t4018/java-sealed-permits new file mode 100644 index 0000000000..18dd4894cf --- /dev/null +++ b/t/t4018/java-sealed-permits @@ -0,0 +1,6 @@ +public abstract sealed class RIGHT permits PermittedA, PermittedB { + static int ONE; + static int TWO; + static int THREE; + private int ChangeMe; +} diff --git a/t/t4018/java-sealed-type-parameters b/t/t4018/java-sealed-type-parameters new file mode 100644 index 0000000000..e6530c47c3 --- /dev/null +++ b/t/t4018/java-sealed-type-parameters @@ -0,0 +1,6 @@ +public abstract sealed class RIGHT<A, B> { + static int ONE; + static int TWO; + static int THREE; + private int ChangeMe; +} diff --git a/t/t4018/java-sealed-type-parameters-implements-permits b/t/t4018/java-sealed-type-parameters-implements-permits new file mode 100644 index 0000000000..bd6e6d3582 --- /dev/null +++ b/t/t4018/java-sealed-type-parameters-implements-permits @@ -0,0 +1,6 @@ +public abstract sealed class RIGHT<A, B> implements List<A> permits PermittedA, PermittedB { + static int ONE; + static int TWO; + static int THREE; + private int ChangeMe; +} diff --git a/t/t4018/java-sealed-type-parameters-permits b/t/t4018/java-sealed-type-parameters-permits new file mode 100644 index 0000000000..25a0da6442 --- /dev/null +++ b/t/t4018/java-sealed-type-parameters-permits @@ -0,0 +1,6 @@ +public abstract sealed class RIGHT<A, B> permits PermittedA, PermittedB { + static int ONE; + static int TWO; + static int THREE; + private int ChangeMe; +} diff --git a/t/t4023-diff-rename-typechange.sh b/t/t4023-diff-rename-typechange.sh index 7cb9909293..787605ce3f 100755 --- a/t/t4023-diff-rename-typechange.sh +++ b/t/t4023-diff-rename-typechange.sh @@ -52,8 +52,8 @@ test_expect_success setup ' ' test_expect_success 'cross renames to be detected for regular files' ' - - git diff-tree five six -r --name-status -B -M | sort >actual && + git diff-tree five six -r --name-status -B -M >out && + sort out >actual && { echo "R100 foo bar" && echo "R100 bar foo" @@ -63,8 +63,8 @@ test_expect_success 'cross renames to be detected for regular files' ' ' test_expect_success 'cross renames to be detected for typechange' ' - - git diff-tree one two -r --name-status -B -M | sort >actual && + git diff-tree one two -r --name-status -B -M >out && + sort out >actual && { echo "R100 foo bar" && echo "R100 bar foo" @@ -74,8 +74,8 @@ test_expect_success 'cross renames to be detected for typechange' ' ' test_expect_success 'moves and renames' ' - - git diff-tree three four -r --name-status -B -M | sort >actual && + git diff-tree three four -r --name-status -B -M >out && + sort out >actual && { # see -B -M (#6) in t4008 echo "C100 foo bar" && diff --git a/t/t4038-diff-combined.sh b/t/t4038-diff-combined.sh index 9a292bac70..2ce26e585c 100755 --- a/t/t4038-diff-combined.sh +++ b/t/t4038-diff-combined.sh @@ -80,11 +80,21 @@ test_expect_success 'check combined output (1)' ' verify_helper sidewithone ' +test_expect_success 'check combined output (1) with git diff <rev>^!' ' + git diff sidewithone^! -- >sidewithone && + verify_helper sidewithone +' + test_expect_success 'check combined output (2)' ' git show sidesansone -- >sidesansone && verify_helper sidesansone ' +test_expect_success 'check combined output (2) with git diff <rev>^!' ' + git diff sidesansone^! -- >sidesansone && + verify_helper sidesansone +' + test_expect_success 'diagnose truncated file' ' >file && git add file && diff --git a/t/t4044-diff-index-unique-abbrev.sh b/t/t4044-diff-index-unique-abbrev.sh index 29e49d2290..9f6043daba 100755 --- a/t/t4044-diff-index-unique-abbrev.sh +++ b/t/t4044-diff-index-unique-abbrev.sh @@ -34,12 +34,12 @@ test_expect_success 'setup' ' 100644 blob $(test_oid hash2) foo EOF - echo "$(test_oid val1)" > foo && + test_oid val1 > foo && git add foo && git commit -m "initial" && git cat-file -p HEAD: > actual && test_cmp expect_initial actual && - echo "$(test_oid val2)" > foo && + test_oid val2 > foo && git commit -a -m "update" && git cat-file -p HEAD: > actual && test_cmp expect_update actual diff --git a/t/t4045-diff-relative.sh b/t/t4045-diff-relative.sh index fab351b48a..9b46c4c1be 100755 --- a/t/t4045-diff-relative.sh +++ b/t/t4045-diff-relative.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='diff --relative tests' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' @@ -162,6 +164,35 @@ check_diff_relative_option subdir file2 true --no-relative --relative check_diff_relative_option . file2 false --no-relative --relative=subdir check_diff_relative_option . file2 true --no-relative --relative=subdir +test_expect_success 'external diff with --relative' ' + test_when_finished "git reset --hard" && + echo changed >file1 && + echo changed >subdir/file2 && + + write_script mydiff <<-\EOF && + # hacky pretend diff; the goal here is just to make sure we got + # passed sensible input that we _could_ diff, without relying on + # the specific output of a system diff tool. + echo "diff a/$1 b/$1" && + echo "--- a/$1" && + echo "+++ b/$1" && + echo "@@ -1 +0,0 @@" && + sed "s/^/-/" "$2" && + sed "s/^/+/" "$5" + EOF + + cat >expect <<-\EOF && + diff a/file2 b/file2 + --- a/file2 + +++ b/file2 + @@ -1 +0,0 @@ + -other content + +changed + EOF + GIT_EXTERNAL_DIFF=./mydiff git diff --relative=subdir >actual && + test_cmp expect actual +' + test_expect_success 'setup diff --relative unmerged' ' test_commit zero file0 && test_commit base subdir/file0 && diff --git a/t/t4046-diff-unmerged.sh b/t/t4046-diff-unmerged.sh index 0ae0cd3a52..ffaf69335f 100755 --- a/t/t4046-diff-unmerged.sh +++ b/t/t4046-diff-unmerged.sh @@ -86,4 +86,14 @@ test_expect_success 'diff-files -3' ' test_cmp diff-files-3.expect diff-files-3.actual ' +test_expect_success 'diff --stat' ' + for path in $paths + do + echo " $path | Unmerged" || return 1 + done >diff-stat.expect && + echo " 0 files changed" >>diff-stat.expect && + git diff --cached --stat >diff-stat.actual && + test_cmp diff-stat.expect diff-stat.actual +' + test_done diff --git a/t/t4052-stat-output.sh b/t/t4052-stat-output.sh index b5c281edaa..3ee27e277d 100755 --- a/t/t4052-stat-output.sh +++ b/t/t4052-stat-output.sh @@ -8,6 +8,7 @@ test_description='test --stat output of various commands' 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/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh index 3feadf0e35..4e9fa0403d 100755 --- a/t/t4053-diff-no-index.sh +++ b/t/t4053-diff-no-index.sh @@ -2,6 +2,7 @@ test_description='diff --no-index' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t4054-diff-bogus-tree.sh b/t/t4054-diff-bogus-tree.sh index 294fb55313..05c88f8cdf 100755 --- a/t/t4054-diff-bogus-tree.sh +++ b/t/t4054-diff-bogus-tree.sh @@ -10,7 +10,7 @@ test_expect_success 'create bogus tree' ' bogus_tree=$( printf "100644 fooQ$name" | q_to_nul | - git hash-object -w --stdin -t tree + git hash-object --literally -w --stdin -t tree ) ' diff --git a/t/t4058-diff-duplicates.sh b/t/t4058-diff-duplicates.sh index 54614b814d..2501c89c1c 100755 --- a/t/t4058-diff-duplicates.sh +++ b/t/t4058-diff-duplicates.sh @@ -29,7 +29,7 @@ make_tree () { make_tree_entry "$1" "$2" "$3" shift; shift; shift done | - git hash-object -w -t tree --stdin + git hash-object --literally -w -t tree --stdin } # this is kind of a convoluted setup, but matches diff --git a/t/t4067-diff-partial-clone.sh b/t/t4067-diff-partial-clone.sh index 28f42a4046..f60f5cbd65 100755 --- a/t/t4067-diff-partial-clone.sh +++ b/t/t4067-diff-partial-clone.sh @@ -2,6 +2,7 @@ test_description='behavior of diff when reading objects in a partial clone' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'git show batches blobs' ' diff --git a/t/t4111-apply-subdir.sh b/t/t4111-apply-subdir.sh index 1618a6dbc7..e9a87d761d 100755 --- a/t/t4111-apply-subdir.sh +++ b/t/t4111-apply-subdir.sh @@ -2,6 +2,7 @@ test_description='patching from inconvenient places' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t4135-apply-weird-filenames.sh b/t/t4135-apply-weird-filenames.sh index 6bc3fb97a7..d3502c6fdd 100755 --- a/t/t4135-apply-weird-filenames.sh +++ b/t/t4135-apply-weird-filenames.sh @@ -2,6 +2,7 @@ test_description='git apply with weird postimage filenames' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t4141-apply-too-large.sh b/t/t4141-apply-too-large.sh new file mode 100755 index 0000000000..58742d4fc5 --- /dev/null +++ b/t/t4141-apply-too-large.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +test_description='git apply with too-large patch' + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +test_expect_success EXPENSIVE 'git apply rejects patches that are too large' ' + sz=$((1024 * 1024 * 1023)) && + { + cat <<-\EOF && + diff --git a/file b/file + new file mode 100644 + --- /dev/null + +++ b/file + @@ -0,0 +1 @@ + EOF + test-tool genzeros + } | test_copy_bytes $sz | test_must_fail git apply 2>err && + grep "git apply: failed to read" err +' + +test_done diff --git a/t/t4150-am.sh b/t/t4150-am.sh index cdad4b6880..78cf1c880e 100755 --- a/t/t4150-am.sh +++ b/t/t4150-am.sh @@ -345,6 +345,21 @@ test_expect_success 'am with failing applypatch-msg hook' ' test_cmp_rev first HEAD ' +test_expect_success 'am with failing applypatch-msg hook (no verify)' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + test_hook applypatch-msg <<-\EOF && + echo hook-message >"$1" + exit 1 + EOF + git am --no-verify patch1 && + test_path_is_missing .git/rebase-apply && + git diff --exit-code second && + git log -1 --format=format:%B >actual && + test_cmp msg actual +' + test_expect_success 'am with pre-applypatch hook' ' rm -fr .git/rebase-apply && git reset --hard && @@ -374,6 +389,23 @@ test_expect_success 'am with failing pre-applypatch hook' ' test_cmp_rev first HEAD ' +test_expect_success 'am with failing pre-applypatch hook (no verify)' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout first && + touch empty-file && + test_hook pre-applypatch <<-\EOF && + rm empty-file + exit 1 + EOF + git am --no-verify patch1 && + test_path_is_missing .git/rebase-apply && + test_path_is_file empty-file && + git diff --exit-code second && + git log -1 --format=format:%B >actual && + test_cmp msg actual +' + test_expect_success 'am with post-applypatch hook' ' rm -fr .git/rebase-apply && git reset --hard && @@ -1033,7 +1065,7 @@ test_expect_success 'am --patch-format=mboxrd handles mboxrd' ' >From extra escape for reversibility INPUT_END git commit -F msg && - git format-patch --pretty=mboxrd --stdout -1 >mboxrd1 && + git -c format.mboxrd format-patch --stdout -1 >mboxrd1 && grep "^>From could trip up a loose mbox parser" mboxrd1 && git checkout -f first && git am --patch-format=mboxrd mboxrd1 && diff --git a/t/t4152-am-subjects.sh b/t/t4152-am-subjects.sh index 4c68245aca..9f2edba1f8 100755 --- a/t/t4152-am-subjects.sh +++ b/t/t4152-am-subjects.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test subject preservation with format-patch | am' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh make_patches() { diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh index 3095b1b2ff..8e4effebdb 100755 --- a/t/t4201-shortlog.sh +++ b/t/t4201-shortlog.sh @@ -83,6 +83,13 @@ test_expect_success 'pretty format' ' test_cmp expect log.predictable ' +test_expect_success 'pretty format (with --date)' ' + sed "s/SUBJECT/2005-04-07 OBJECT_NAME/" expect.template >expect && + git shortlog --format="%ad %H" --date=short HEAD >log && + fuzz log >log.predictable && + test_cmp expect log.predictable +' + test_expect_success '--abbrev' ' sed s/SUBJECT/OBJID/ expect.template >expect && git shortlog --format="%h" --abbrev=35 HEAD >log && @@ -237,6 +244,26 @@ test_expect_success 'shortlog --group=trailer:signed-off-by' ' test_cmp expect actual ' +test_expect_success 'shortlog --group=format' ' + git shortlog -s --date="format:%Y" --group="format:%cN (%cd)" \ + HEAD >actual && + cat >expect <<-\EOF && + 4 C O Mitter (2005) + 1 Sin Nombre (2005) + EOF + test_cmp expect actual +' + +test_expect_success 'shortlog --group=<format> DWIM' ' + git shortlog -s --date="format:%Y" --group="%cN (%cd)" HEAD >actual && + test_cmp expect actual +' + +test_expect_success 'shortlog bogus --group' ' + test_must_fail git shortlog --group=bogus HEAD 2>err && + grep "unknown group type" err +' + test_expect_success 'trailer idents are split' ' cat >expect <<-\EOF && 2 C O Mitter @@ -319,6 +346,18 @@ test_expect_success 'shortlog can match multiple groups' ' test_cmp expect actual ' +test_expect_success 'shortlog can match multiple format groups' ' + GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME" \ + git commit --allow-empty -m "identical names" && + test_tick && + cat >expect <<-\EOF && + 2 A U Thor + 1 C O Mitter + EOF + git shortlog -ns --group="%cn" --group="%an" -2 HEAD >actual && + test_cmp expect actual +' + test_expect_success 'set up option selection tests' ' git commit --allow-empty -F - <<-\EOF subject diff --git a/t/t4202-log.sh b/t/t4202-log.sh index cc15cb4ff6..2ce2b41174 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -249,6 +249,15 @@ test_expect_success 'log --grep' ' test_cmp expect actual ' +for noop_opt in --invert-grep --all-match +do + test_expect_success "log $noop_opt without --grep is a NOOP" ' + git log >expect && + git log $noop_opt >actual && + test_cmp expect actual + ' +done + cat > expect << EOF second initial diff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh index cd1cab3e54..fa7f987284 100755 --- a/t/t4203-mailmap.sh +++ b/t/t4203-mailmap.sh @@ -1022,4 +1022,69 @@ test_expect_success '--mailmap enables mailmap in cat-file for annotated tag obj test_cmp expect actual ' +test_expect_success 'git cat-file -s returns correct size with --use-mailmap' ' + test_when_finished "rm .mailmap" && + cat >.mailmap <<-\EOF && + C O Mitter <committer@example.com> Orig <orig@example.com> + EOF + git cat-file commit HEAD >commit.out && + echo $(wc -c <commit.out) >expect && + git cat-file --use-mailmap commit HEAD >commit.out && + echo $(wc -c <commit.out) >>expect && + git cat-file -s HEAD >actual && + git cat-file --use-mailmap -s HEAD >>actual && + test_cmp expect actual +' + +test_expect_success 'git cat-file -s returns correct size with --use-mailmap for tag objects' ' + test_when_finished "rm .mailmap" && + cat >.mailmap <<-\EOF && + Orig <orig@example.com> C O Mitter <committer@example.com> + EOF + git tag -a -m "annotated tag" v3 && + git cat-file tag v3 >tag.out && + echo $(wc -c <tag.out) >expect && + git cat-file --use-mailmap tag v3 >tag.out && + echo $(wc -c <tag.out) >>expect && + git cat-file -s v3 >actual && + git cat-file --use-mailmap -s v3 >>actual && + test_cmp expect actual +' + +test_expect_success 'git cat-file --batch-check returns correct size with --use-mailmap' ' + test_when_finished "rm .mailmap" && + cat >.mailmap <<-\EOF && + C O Mitter <committer@example.com> Orig <orig@example.com> + EOF + git cat-file commit HEAD >commit.out && + commit_size=$(wc -c <commit.out) && + commit_sha=$(git rev-parse HEAD) && + echo $commit_sha commit $commit_size >expect && + git cat-file --use-mailmap commit HEAD >commit.out && + commit_size=$(wc -c <commit.out) && + echo $commit_sha commit $commit_size >>expect && + echo "HEAD" >in && + git cat-file --batch-check <in >actual && + git cat-file --use-mailmap --batch-check <in >>actual && + test_cmp expect actual +' + +test_expect_success 'git cat-file --batch-command returns correct size with --use-mailmap' ' + test_when_finished "rm .mailmap" && + cat >.mailmap <<-\EOF && + C O Mitter <committer@example.com> Orig <orig@example.com> + EOF + git cat-file commit HEAD >commit.out && + commit_size=$(wc -c <commit.out) && + commit_sha=$(git rev-parse HEAD) && + echo $commit_sha commit $commit_size >expect && + git cat-file --use-mailmap commit HEAD >commit.out && + commit_size=$(wc -c <commit.out) && + echo $commit_sha commit $commit_size >>expect && + echo "info HEAD" >in && + git cat-file --batch-command <in >actual && + git cat-file --use-mailmap --batch-command <in >>actual && + test_cmp expect actual +' + test_done diff --git a/t/t4204-patch-id.sh b/t/t4204-patch-id.sh index a730c0db98..a7fa94ce0a 100755 --- a/t/t4204-patch-id.sh +++ b/t/t4204-patch-id.sh @@ -8,13 +8,13 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME . ./test-lib.sh test_expect_success 'setup' ' - as="a a a a a a a a" && # eight a - test_write_lines $as >foo && - test_write_lines $as >bar && + str="ab cd ef gh ij kl mn op" && + test_write_lines $str >foo && + test_write_lines $str >bar && git add foo bar && git commit -a -m initial && - test_write_lines $as b >foo && - test_write_lines $as b >bar && + test_write_lines $str b >foo && + test_write_lines $str b >bar && git commit -a -m first && git checkout -b same main && git commit --amend -m same-msg && @@ -22,8 +22,23 @@ test_expect_success 'setup' ' echo c >foo && echo c >bar && git commit --amend -a -m notsame-msg && + git checkout -b with_space main~ && + cat >foo <<-\EOF && + a b + c d + e f + g h + i j + k l + m n + op + EOF + cp foo bar && + git add foo bar && + git commit --amend -m "with spaces" && test_write_lines bar foo >bar-then-foo && test_write_lines foo bar >foo-then-bar + ' test_expect_success 'patch-id output is well-formed' ' @@ -42,7 +57,7 @@ calc_patch_id () { } get_top_diff () { - git log -p -1 "$@" -O bar-then-foo -- + git log -p -1 "$@" -O bar-then-foo --full-index -- } get_patch_id () { @@ -61,6 +76,33 @@ test_expect_success 'patch-id detects inequality' ' get_patch_id notsame && ! test_cmp patch-id_main patch-id_notsame ' +test_expect_success 'patch-id detects equality binary' ' + cat >.gitattributes <<-\EOF && + foo binary + bar binary + EOF + get_patch_id main && + get_patch_id same && + git log -p -1 --binary main >top-diff.output && + calc_patch_id <top-diff.output main_binpatch && + git log -p -1 --binary same >top-diff.output && + calc_patch_id <top-diff.output same_binpatch && + test_cmp patch-id_main patch-id_main_binpatch && + test_cmp patch-id_same patch-id_same_binpatch && + test_cmp patch-id_main patch-id_same && + test_when_finished "rm .gitattributes" +' + +test_expect_success 'patch-id detects inequality binary' ' + cat >.gitattributes <<-\EOF && + foo binary + bar binary + EOF + get_patch_id main && + get_patch_id notsame && + ! test_cmp patch-id_main patch-id_notsame && + test_when_finished "rm .gitattributes" +' test_expect_success 'patch-id supports git-format-patch output' ' get_patch_id main && @@ -101,9 +143,21 @@ test_patch_id_file_order () { git format-patch -1 --stdout -O foo-then-bar >format-patch.output && calc_patch_id <format-patch.output "ordered-$name" "$@" && cmp_patch_id $relevant "$name" "ordered-$name" +} +test_patch_id_whitespace () { + relevant="$1" + shift + name="ws-${1}-$relevant" + shift + get_top_diff "main~" >top-diff.output && + calc_patch_id <top-diff.output "$name" "$@" && + get_top_diff "with_space" >top-diff.output && + calc_patch_id <top-diff.output "ws-$name" "$@" && + cmp_patch_id $relevant "$name" "ws-$name" } + # combined test for options: add more tests here to make them # run with all options test_patch_id () { @@ -119,6 +173,14 @@ test_expect_success 'file order is relevant with --unstable' ' test_patch_id_file_order relevant --unstable --unstable ' +test_expect_success 'whitespace is relevant with --verbatim' ' + test_patch_id_whitespace relevant --verbatim --verbatim +' + +test_expect_success 'whitespace is irrelevant without --verbatim' ' + test_patch_id_whitespace irrelevant --stable --stable +' + #Now test various option combinations. test_expect_success 'default is unstable' ' test_patch_id relevant default @@ -134,6 +196,17 @@ test_expect_success 'patchid.stable = false is unstable' ' test_patch_id relevant patchid.stable=false ' +test_expect_success 'patchid.verbatim = true is correct and stable' ' + test_config patchid.verbatim true && + test_patch_id_whitespace relevant patchid.verbatim=true && + test_patch_id irrelevant patchid.verbatim=true +' + +test_expect_success 'patchid.verbatim = false is unstable' ' + test_config patchid.verbatim false && + test_patch_id relevant patchid.verbatim=false +' + test_expect_success '--unstable overrides patchid.stable = true' ' test_config patchid.stable true && test_patch_id relevant patchid.stable=true--unstable --unstable @@ -144,6 +217,11 @@ test_expect_success '--stable overrides patchid.stable = false' ' test_patch_id irrelevant patchid.stable=false--stable --stable ' +test_expect_success '--verbatim overrides patchid.stable = false' ' + test_config patchid.stable false && + test_patch_id_whitespace relevant stable=false--verbatim --verbatim +' + test_expect_success 'patch-id supports git-format-patch MIME output' ' get_patch_id main && git checkout same && @@ -198,7 +276,10 @@ test_expect_success 'patch-id handles no-nl-at-eof markers' ' EOF calc_patch_id nonl <nonl && calc_patch_id withnl <withnl && - test_cmp patch-id_nonl patch-id_withnl + test_cmp patch-id_nonl patch-id_withnl && + calc_patch_id nonl-inc-ws --verbatim <nonl && + calc_patch_id withnl-inc-ws --verbatim <withnl && + ! test_cmp patch-id_nonl-inc-ws patch-id_withnl-inc-ws ' test_expect_success 'patch-id handles diffs with one line of before/after' ' diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh index fedb7ca749..4cf8a77667 100755 --- a/t/t4205-log-pretty-formats.sh +++ b/t/t4205-log-pretty-formats.sh @@ -156,7 +156,7 @@ test_expect_success 'NUL termination with --reflog --pretty=oneline' ' for r in $revs do git show -s --pretty=oneline "$r" >raw && - cat raw | lf_to_nul || exit 1 + cat raw | lf_to_nul || return 1 done >expect && # the trailing NUL is already produced so we do not need to # output another one @@ -1094,4 +1094,31 @@ test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit mes test_cmp expect error ' +# pretty-formats note wide char limitations, and add tests +test_expect_failure 'wide and decomposed characters column counting' ' + +# from t/lib-unicode-nfc-nfd.sh hex values converted to octal + utf8_nfc=$(printf "\303\251") && # e acute combined. + utf8_nfd=$(printf "\145\314\201") && # e with a combining acute (i.e. decomposed) + utf8_emoji=$(printf "\360\237\221\250") && + +# replacement character when requesting a wide char fits in a single display colum. +# "half wide" alternative could be a plain ASCII dot `.` + utf8_vert_ell=$(printf "\342\213\256") && + +# use ${xxx} here! + nfc10="${utf8_nfc}${utf8_nfc}${utf8_nfc}${utf8_nfc}${utf8_nfc}${utf8_nfc}${utf8_nfc}${utf8_nfc}${utf8_nfc}${utf8_nfc}" && + nfd10="${utf8_nfd}${utf8_nfd}${utf8_nfd}${utf8_nfd}${utf8_nfd}${utf8_nfd}${utf8_nfd}${utf8_nfd}${utf8_nfd}${utf8_nfd}" && + emoji5="${utf8_emoji}${utf8_emoji}${utf8_emoji}${utf8_emoji}${utf8_emoji}" && +# emoji5 uses 10 display columns + + test_commit "abcdefghij" && + test_commit --no-tag "${nfc10}" && + test_commit --no-tag "${nfd10}" && + test_commit --no-tag "${emoji5}" && + printf "${utf8_emoji}..${utf8_emoji}${utf8_vert_ell}\n${utf8_nfd}..${utf8_nfd}${utf8_nfd}\n${utf8_nfc}..${utf8_nfc}${utf8_nfc}\na..ij\n" >expected && + git log --format="%<(5,mtrunc)%s" -4 >actual && + test_cmp expected actual +' + test_done diff --git a/t/t4211-line-log.sh b/t/t4211-line-log.sh index ac9e4d0928..c6540e822f 100755 --- a/t/t4211-line-log.sh +++ b/t/t4211-line-log.sh @@ -315,4 +315,26 @@ test_expect_success 'line-log with --before' ' test_cmp expect actual ' +test_expect_success 'setup tests for zero-width regular expressions' ' + cat >expect <<-EOF + Modify func1() in file.c + Add func1() and func2() in file.c + EOF +' + +test_expect_success 'zero-width regex $ matches any function name' ' + git log --format="%s" --no-patch "-L:$:file.c" >actual && + test_cmp expect actual +' + +test_expect_success 'zero-width regex ^ matches any function name' ' + git log --format="%s" --no-patch "-L:^:file.c" >actual && + test_cmp expect actual +' + +test_expect_success 'zero-width regex .* matches any function name' ' + git log --format="%s" --no-patch "-L:.*:file.c" >actual && + test_cmp expect actual +' + test_done diff --git a/t/t4212-log-corrupt.sh b/t/t4212-log-corrupt.sh index 30a219894b..e89e1f54b6 100755 --- a/t/t4212-log-corrupt.sh +++ b/t/t4212-log-corrupt.sh @@ -10,7 +10,7 @@ test_expect_success 'setup' ' git cat-file commit HEAD | sed "/^author /s/>/>-<>/" >broken_email.commit && - git hash-object -w -t commit broken_email.commit >broken_email.hash && + git hash-object --literally -w -t commit broken_email.commit >broken_email.hash && git update-ref refs/heads/broken_email $(cat broken_email.hash) ' @@ -46,7 +46,7 @@ test_expect_success 'git log --format with broken author email' ' munge_author_date () { git cat-file commit "$1" >commit.orig && sed "s/^\(author .*>\) [0-9]*/\1 $2/" <commit.orig >commit.munge && - git hash-object -w -t commit commit.munge + git hash-object --literally -w -t commit commit.munge } test_expect_success 'unparsable dates produce sentinel value' ' diff --git a/t/t4213-log-tabexpand.sh b/t/t4213-log-tabexpand.sh index 53a4af3244..590fce95e9 100755 --- a/t/t4213-log-tabexpand.sh +++ b/t/t4213-log-tabexpand.sh @@ -2,6 +2,7 @@ test_description='log/show --expand-tabs' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh HT=" " diff --git a/t/t4254-am-corrupt.sh b/t/t4254-am-corrupt.sh index 54be7da161..45f1d4f95e 100755 --- a/t/t4254-am-corrupt.sh +++ b/t/t4254-am-corrupt.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='git am with corrupt input' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh make_mbox_with_nul () { diff --git a/t/t4256-am-format-flowed.sh b/t/t4256-am-format-flowed.sh index 2369c4e17a..1015273bc8 100755 --- a/t/t4256-am-format-flowed.sh +++ b/t/t4256-am-format-flowed.sh @@ -2,6 +2,7 @@ test_description='test format=flowed support of git am' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t4257-am-interactive.sh b/t/t4257-am-interactive.sh index aed8f4de3d..f26d7fd2db 100755 --- a/t/t4257-am-interactive.sh +++ b/t/t4257-am-interactive.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='am --interactive tests' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'set up patches to apply' ' diff --git a/t/t4301-merge-tree-write-tree.sh b/t/t4301-merge-tree-write-tree.sh index 013b77144b..250f721795 100755 --- a/t/t4301-merge-tree-write-tree.sh +++ b/t/t4301-merge-tree-write-tree.sh @@ -141,7 +141,7 @@ test_expect_success 'test conflict notices and such' ' # Commit O: foo, olddir/{a,b,c} # Commit A: modify foo, newdir/{a,b,c} # Commit B: modify foo differently & rename foo -> olddir/bar -# Expected: CONFLICT(content) for for newdir/bar (not olddir/bar or foo) +# Expected: CONFLICT(content) for newdir/bar (not olddir/bar or foo) test_expect_success 'directory rename + content conflict' ' # Setup @@ -653,7 +653,7 @@ test_expect_success 'mod6: chains of rename/rename(1to2) and add/add via collidi # Commit O: foo, olddir/{a,b,c} # Commit A: delete foo, rename olddir/ -> newdir/, add newdir/bar/file # Commit B: modify foo & rename foo -> olddir/bar -# Expected: CONFLICT(content) for for newdir/bar (not olddir/bar or foo) +# Expected: CONFLICT(content) for newdir/bar (not olddir/bar or foo) test_expect_success 'directory rename + rename/delete + modify/delete + directory/file conflict' ' # Setup @@ -819,4 +819,107 @@ test_expect_success SANITY 'merge-ort fails gracefully in a read-only repository test_must_fail git -C read-only merge-tree side1 side2 ' +test_expect_success '--stdin with both a successful and a conflicted merge' ' + printf "side1 side3\nside1 side2" | git merge-tree --stdin >actual && + + git checkout side1^0 && + git merge side3 && + + printf "1\0" >expect && + git rev-parse HEAD^{tree} | lf_to_nul >>expect && + printf "\0" >>expect && + + git checkout side1^0 && + test_must_fail git merge side2 && + sed s/HEAD/side1/ greeting >tmp && + mv tmp greeting && + git add -u && + git mv whatever~HEAD whatever~side1 && + + printf "0\0" >>expect && + git write-tree | lf_to_nul >>expect && + + cat <<-EOF | q_to_tab | lf_to_nul >>expect && + 100644 $(git rev-parse side1~1:greeting) 1Qgreeting + 100644 $(git rev-parse side1:greeting) 2Qgreeting + 100644 $(git rev-parse side2:greeting) 3Qgreeting + 100644 $(git rev-parse side1~1:whatever) 1Qwhatever~side1 + 100644 $(git rev-parse side1:whatever) 2Qwhatever~side1 + EOF + + q_to_nul <<-EOF >>expect && + Q1QgreetingQAuto-mergingQAuto-merging greeting + Q1QgreetingQCONFLICT (contents)QCONFLICT (content): Merge conflict in greeting + Q1QnumbersQAuto-mergingQAuto-merging numbers + Q2Qwhatever~side1QwhateverQCONFLICT (file/directory)QCONFLICT (file/directory): directory in the way of whatever from side1; moving it to whatever~side1 instead. + Q1Qwhatever~side1QCONFLICT (modify/delete)QCONFLICT (modify/delete): whatever~side1 deleted in side2 and modified in side1. Version side1 of whatever~side1 left in tree. + EOF + + printf "\0\0" >>expect && + + test_cmp expect actual +' + + +test_expect_success '--merge-base is incompatible with --stdin' ' + test_must_fail git merge-tree --merge-base=side1 --stdin 2>expect && + + grep "^fatal: --merge-base is incompatible with --stdin" expect +' + +# specify merge-base as parent of branch2 +# git merge-tree --write-tree --merge-base=c2 c1 c3 +# Commit c1: add file1 +# Commit c2: add file2 after c1 +# Commit c3: add file3 after c2 +# Expected: add file3, and file2 does NOT appear + +test_expect_success 'specify merge-base as parent of branch2' ' + # Setup + test_when_finished "rm -rf base-b2-p" && + git init base-b2-p && + test_commit -C base-b2-p c1 file1 && + test_commit -C base-b2-p c2 file2 && + test_commit -C base-b2-p c3 file3 && + + # Testing + TREE_OID=$(git -C base-b2-p merge-tree --write-tree --merge-base=c2 c1 c3) && + + q_to_tab <<-EOF >expect && + 100644 blob $(git -C base-b2-p rev-parse c1:file1)Qfile1 + 100644 blob $(git -C base-b2-p rev-parse c3:file3)Qfile3 + EOF + + git -C base-b2-p ls-tree $TREE_OID >actual && + test_cmp expect actual +' + +# Since the earlier tests have verified that individual merge-tree calls +# are doing the right thing, this test case is only used to verify that +# we can also trigger merges via --stdin, and that when we do we get +# the same answer as running a bunch of separate merges. + +test_expect_success 'check the input format when --stdin is passed' ' + test_when_finished "rm -rf repo" && + git init repo && + test_commit -C repo c1 && + test_commit -C repo c2 && + test_commit -C repo c3 && + printf "c1 c3\nc2 -- c1 c3\nc2 c3" | git -C repo merge-tree --stdin >actual && + + printf "1\0" >expect && + git -C repo merge-tree --write-tree -z c1 c3 >>expect && + printf "\0" >>expect && + + printf "1\0" >>expect && + git -C repo merge-tree --write-tree -z --merge-base=c2 c1 c3 >>expect && + printf "\0" >>expect && + + printf "1\0" >>expect && + git -C repo merge-tree --write-tree -z c2 c3 >>expect && + printf "\0" >>expect && + + test_cmp expect actual +' + test_done diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index eaa0b22ece..918a2fc7c6 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -105,6 +105,18 @@ check_added() { ' } +check_mtime() { + dir=$1 + path_in_archive=$2 + mtime=$3 + + test_expect_success " validate mtime of $path_in_archive" ' + test-tool chmtime --get $dir/$path_in_archive >actual.mtime && + echo $mtime >expect.mtime && + test_cmp expect.mtime actual.mtime + ' +} + test_expect_success 'setup' ' test_oid_cache <<-EOF obj sha1:19f9c8273ec45a8938e6999cb59b3ff66739902a @@ -174,6 +186,13 @@ test_expect_success 'git archive' ' check_tar b +test_expect_success 'git archive --mtime' ' + git archive --mtime=2002-02-02T02:02:02-0200 HEAD >with_mtime.tar +' + +check_tar with_mtime +check_mtime with_mtime a/a 1012622522 + test_expect_success 'git archive --prefix=prefix/' ' git archive --prefix=prefix/ HEAD >with_prefix.tar ' @@ -342,6 +361,13 @@ test_expect_success 'only enabled filters are available remotely' ' test_cmp_bin remote.bar config.bar ' +test_expect_success 'invalid filter is reported only once' ' + test_must_fail git -c tar.invalid.command= archive --format=invalid \ + HEAD >out 2>err && + test_must_be_empty out && + test_line_count = 1 err +' + test_expect_success 'git archive --format=tgz' ' git archive --format=tgz HEAD >j.tgz ' @@ -395,11 +421,11 @@ test_expect_success GZIP 'extract tgz file (external gzip)' ' test_expect_success 'archive and :(glob)' ' git archive -v HEAD -- ":(glob)**/sh" >/dev/null 2>actual && - cat >expect <<EOF && -a/ -a/bin/ -a/bin/sh -EOF + cat >expect <<-\EOF && + a/ + a/bin/ + a/bin/sh + EOF test_cmp expect actual ' diff --git a/t/t5001-archive-attr.sh b/t/t5001-archive-attr.sh index 2f6eef5e37..04d300eeda 100755 --- a/t/t5001-archive-attr.sh +++ b/t/t5001-archive-attr.sh @@ -3,6 +3,7 @@ test_description='git archive attribute tests' TEST_CREATE_REPO_NO_TEMPLATE=1 +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh SUBSTFORMAT='%H (%h)%n' diff --git a/t/t5004-archive-corner-cases.sh b/t/t5004-archive-corner-cases.sh index ae508e2162..9f2c6da80e 100755 --- a/t/t5004-archive-corner-cases.sh +++ b/t/t5004-archive-corner-cases.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test corner cases of git-archive' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # the 10knuls.tar file is used to test for an empty git generated tar diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh index b0095ab41d..f89809be53 100755 --- a/t/t5302-pack-index.sh +++ b/t/t5302-pack-index.sh @@ -4,6 +4,8 @@ # test_description='pack index with 64-bit offsets and object CRC' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' @@ -263,7 +265,7 @@ tag guten tag This is an invalid tag. EOF - tag=$(git hash-object -t tag -w --stdin <wrong-tag) && + tag=$(git hash-object -t tag -w --stdin --literally <wrong-tag) && pack1=$(echo $tag $sha | git pack-objects tag-test) && echo remove tag object && thirtyeight=${tag#??} && diff --git a/t/t5304-prune.sh b/t/t5304-prune.sh index 8ae314af58..d65a5f94b4 100755 --- a/t/t5304-prune.sh +++ b/t/t5304-prune.sh @@ -29,6 +29,14 @@ test_expect_success setup ' git gc ' +test_expect_success 'bare repo prune is quiet without $GIT_DIR/objects/pack' ' + git clone -q --shared --template= --bare . bare.git && + rmdir bare.git/objects/pack && + git --git-dir=bare.git prune --no-progress 2>prune.err && + test_must_be_empty prune.err && + rm -r bare.git prune.err +' + test_expect_success 'prune stale packs' ' orig_pack=$(echo .git/objects/pack/*.pack) && >.git/objects/tmp_1.pack && diff --git a/t/t5306-pack-nobase.sh b/t/t5306-pack-nobase.sh index 51973f4a51..846c5ca7d3 100755 --- a/t/t5306-pack-nobase.sh +++ b/t/t5306-pack-nobase.sh @@ -6,6 +6,8 @@ test_description='git-pack-object with missing base ' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Create A-B chain diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh index 6d693eef82..7d8dee41b0 100755 --- a/t/t5310-pack-bitmaps.sh +++ b/t/t5310-pack-bitmaps.sh @@ -428,8 +428,9 @@ test_bitmap_cases () { test_line_count = 2 packs && test_line_count = 2 bitmaps && - git rev-list --use-bitmap-index HEAD 2>err && - grep "ignoring extra bitmap file" err + GIT_TRACE2_EVENT=$(pwd)/trace2.txt git rev-list --use-bitmap-index HEAD && + grep "opened bitmap" trace2.txt && + grep "ignoring extra bitmap" trace2.txt ) ' } diff --git a/t/t5312-prune-corruption.sh b/t/t5312-prune-corruption.sh index 9d8e249ae8..230cb38712 100755 --- a/t/t5312-prune-corruption.sh +++ b/t/t5312-prune-corruption.sh @@ -14,6 +14,7 @@ what currently happens. If that changes, these tests should be revisited. 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 'disable reflogs' ' diff --git a/t/t5313-pack-bounds-checks.sh b/t/t5313-pack-bounds-checks.sh index cc4cfaa9d3..ceaa6700a2 100755 --- a/t/t5313-pack-bounds-checks.sh +++ b/t/t5313-pack-bounds-checks.sh @@ -59,7 +59,7 @@ test_expect_success 'setup' ' test_expect_success 'set up base packfile and variables' ' # the hash of this content starts with ff, which # makes some later computations much simpler - echo $(test_oid oidfff) >file && + test_oid oidfff >file && git add file && git commit -m base && git repack -ad && diff --git a/t/t5314-pack-cycle-detection.sh b/t/t5314-pack-cycle-detection.sh index 73a241743a..82734b9a3c 100755 --- a/t/t5314-pack-cycle-detection.sh +++ b/t/t5314-pack-cycle-detection.sh @@ -63,13 +63,16 @@ TEST_PASSES_SANITIZE_LEAK=true # Note that the two variants of "file" must be similar enough to convince git # to create the delta. make_pack () { - { - printf '%s\n' "-$(git rev-parse $2)" - printf '%s dummy\n' "$(git rev-parse $1:dummy)" - printf '%s file\n' "$(git rev-parse $1:file)" - } | - git pack-objects --stdout | - git index-pack --stdin --fix-thin + ln1=$(git rev-parse "$2") && + ln2=$(git rev-parse "$1:dummy") && + ln3=$(git rev-parse "$1:file") && + cat >list <<-EOF + -$ln1 + $ln2 dummy + $ln3 file + EOF + git pack-objects --stdout <list >pack && + git index-pack --stdin --fix-thin <pack } test_expect_success 'setup' ' diff --git a/t/t5317-pack-objects-filter-objects.sh b/t/t5317-pack-objects-filter-objects.sh index bb633c9b09..b26d476c64 100755 --- a/t/t5317-pack-objects-filter-objects.sh +++ b/t/t5317-pack-objects-filter-objects.sh @@ -5,6 +5,7 @@ test_description='git pack-objects using object filtering' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Test blob:none filter. @@ -24,8 +25,9 @@ parse_verify_pack_blob_oid () { } test_expect_success 'verify blob count in normal packfile' ' - git -C r1 ls-files -s file.1 file.2 file.3 file.4 file.5 | - test_parse_ls_files_stage_oids | + git -C r1 ls-files -s file.1 file.2 file.3 file.4 file.5 \ + >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | sort >expected && git -C r1 pack-objects --revs --stdout >all.pack <<-EOF && @@ -123,8 +125,8 @@ test_expect_success 'setup r2' ' ' test_expect_success 'verify blob count in normal packfile' ' - git -C r2 ls-files -s large.1000 large.10000 | - test_parse_ls_files_stage_oids | + git -C r2 ls-files -s large.1000 large.10000 >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | sort >expected && git -C r2 pack-objects --revs --stdout >all.pack <<-EOF && @@ -161,8 +163,8 @@ test_expect_success 'verify blob:limit=1000' ' ' test_expect_success 'verify blob:limit=1001' ' - git -C r2 ls-files -s large.1000 | - test_parse_ls_files_stage_oids | + git -C r2 ls-files -s large.1000 >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | sort >expected && git -C r2 pack-objects --revs --stdout --filter=blob:limit=1001 >filter.pack <<-EOF && @@ -179,8 +181,8 @@ test_expect_success 'verify blob:limit=1001' ' ' test_expect_success 'verify blob:limit=10001' ' - git -C r2 ls-files -s large.1000 large.10000 | - test_parse_ls_files_stage_oids | + git -C r2 ls-files -s large.1000 large.10000 >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | sort >expected && git -C r2 pack-objects --revs --stdout --filter=blob:limit=10001 >filter.pack <<-EOF && @@ -197,8 +199,8 @@ test_expect_success 'verify blob:limit=10001' ' ' test_expect_success 'verify blob:limit=1k' ' - git -C r2 ls-files -s large.1000 | - test_parse_ls_files_stage_oids | + git -C r2 ls-files -s large.1000 >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | sort >expected && git -C r2 pack-objects --revs --stdout --filter=blob:limit=1k >filter.pack <<-EOF && @@ -215,8 +217,8 @@ test_expect_success 'verify blob:limit=1k' ' ' test_expect_success 'verify explicitly specifying oversized blob in input' ' - git -C r2 ls-files -s large.1000 large.10000 | - test_parse_ls_files_stage_oids | + git -C r2 ls-files -s large.1000 large.10000 >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | sort >expected && echo HEAD >objects && @@ -233,8 +235,8 @@ test_expect_success 'verify explicitly specifying oversized blob in input' ' ' test_expect_success 'verify blob:limit=1m' ' - git -C r2 ls-files -s large.1000 large.10000 | - test_parse_ls_files_stage_oids | + git -C r2 ls-files -s large.1000 large.10000 >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | sort >expected && git -C r2 pack-objects --revs --stdout --filter=blob:limit=1m >filter.pack <<-EOF && @@ -264,6 +266,44 @@ test_expect_success 'verify normal and blob:limit packfiles have same commits/tr test_cmp expected observed ' +test_expect_success 'verify small limit and big limit results in small limit' ' + git -C r2 ls-files -s large.1000 >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | + sort >expected && + + git -C r2 pack-objects --revs --stdout --filter=blob:limit=1001 \ + --filter=blob:limit=10001 >filter.pack <<-EOF && + HEAD + EOF + git -C r2 index-pack ../filter.pack && + + git -C r2 verify-pack -v ../filter.pack >verify_result && + grep blob verify_result | + parse_verify_pack_blob_oid | + sort >observed && + + test_cmp expected observed +' + +test_expect_success 'verify big limit and small limit results in small limit' ' + git -C r2 ls-files -s large.1000 >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | + sort >expected && + + git -C r2 pack-objects --revs --stdout --filter=blob:limit=10001 \ + --filter=blob:limit=1001 >filter.pack <<-EOF && + HEAD + EOF + git -C r2 index-pack ../filter.pack && + + git -C r2 verify-pack -v ../filter.pack >verify_result && + grep blob verify_result | + parse_verify_pack_blob_oid | + sort >observed && + + test_cmp expected observed +' + # Test sparse:path=<path> filter. # !!!! # NOTE: sparse:path filter support has been dropped for security reasons, @@ -289,8 +329,9 @@ test_expect_success 'setup r3' ' ' test_expect_success 'verify blob count in normal packfile' ' - git -C r3 ls-files -s sparse1 sparse2 dir1/sparse1 dir1/sparse2 | - test_parse_ls_files_stage_oids | + git -C r3 ls-files -s sparse1 sparse2 dir1/sparse1 dir1/sparse2 \ + >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | sort >expected && git -C r3 pack-objects --revs --stdout >all.pack <<-EOF && @@ -341,8 +382,9 @@ test_expect_success 'setup r4' ' ' test_expect_success 'verify blob count in normal packfile' ' - git -C r4 ls-files -s pattern sparse1 sparse2 dir1/sparse1 dir1/sparse2 | - test_parse_ls_files_stage_oids | + git -C r4 ls-files -s pattern sparse1 sparse2 dir1/sparse1 dir1/sparse2 \ + >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | sort >expected && git -C r4 pack-objects --revs --stdout >all.pack <<-EOF && @@ -359,8 +401,8 @@ test_expect_success 'verify blob count in normal packfile' ' ' test_expect_success 'verify sparse:oid=OID' ' - git -C r4 ls-files -s dir1/sparse1 dir1/sparse2 | - test_parse_ls_files_stage_oids | + git -C r4 ls-files -s dir1/sparse1 dir1/sparse2 >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | sort >expected && git -C r4 ls-files -s pattern >staged && @@ -379,8 +421,8 @@ test_expect_success 'verify sparse:oid=OID' ' ' test_expect_success 'verify sparse:oid=oid-ish' ' - git -C r4 ls-files -s dir1/sparse1 dir1/sparse2 | - test_parse_ls_files_stage_oids | + git -C r4 ls-files -s dir1/sparse1 dir1/sparse2 >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | sort >expected && git -C r4 pack-objects --revs --stdout --filter=sparse:oid=main:pattern >filter.pack <<-EOF && @@ -400,8 +442,9 @@ test_expect_success 'verify sparse:oid=oid-ish' ' # This models previously omitted objects that we did not receive. test_expect_success 'setup r1 - delete loose blobs' ' - git -C r1 ls-files -s file.1 file.2 file.3 file.4 file.5 | - test_parse_ls_files_stage_oids | + git -C r1 ls-files -s file.1 file.2 file.3 file.4 file.5 \ + >ls_files_result && + test_parse_ls_files_stage_oids <ls_files_result | sort >expected && for id in `cat expected | sed "s|..|&/|"` diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh index b5f9b10922..499d5d4c78 100755 --- a/t/t5319-multi-pack-index.sh +++ b/t/t5319-multi-pack-index.sh @@ -1015,4 +1015,20 @@ test_expect_success 'complains when run outside of a repository' ' grep "not a git repository" err ' +test_expect_success 'repack with delta islands' ' + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + + test_commit first && + git repack && + test_commit second && + git repack && + + git multi-pack-index write && + git -c repack.useDeltaIslands=true multi-pack-index repack + ) +' + test_done diff --git a/t/t5320-delta-islands.sh b/t/t5320-delta-islands.sh index 124d47603d..406363381f 100755 --- a/t/t5320-delta-islands.sh +++ b/t/t5320-delta-islands.sh @@ -134,7 +134,7 @@ test_expect_success 'island core places core objects first' ' repack -adfi && git verify-pack -v .git/objects/pack/*.pack | cut -d" " -f1 | - egrep "$root|$two" >actual && + grep -E "$root|$two" >actual && test_cmp expect actual ' diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh index ad6eea5fa0..0882cbb6e4 100755 --- a/t/t5326-multi-pack-bitmaps.sh +++ b/t/t5326-multi-pack-bitmaps.sh @@ -410,4 +410,28 @@ test_expect_success 'preferred pack change with existing MIDX bitmap' ' ) ' +test_expect_success 'tagged commits are selected for bitmapping' ' + rm -fr repo && + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + + test_commit --annotate base && + git repack -d && + + # Remove refs/heads/main which points at the commit directly, + # leaving only a reference to the annotated tag. + git branch -M main && + git checkout base && + git branch -d main && + + git multi-pack-index write --bitmap && + + git rev-parse HEAD >want && + test-tool bitmap list-commits >actual && + grep $(cat want) actual + ) +' + test_done diff --git a/t/t5330-no-lazy-fetch-with-commit-graph.sh b/t/t5330-no-lazy-fetch-with-commit-graph.sh index 2cc7fd7a47..5eb28f0512 100755 --- a/t/t5330-no-lazy-fetch-with-commit-graph.sh +++ b/t/t5330-no-lazy-fetch-with-commit-graph.sh @@ -2,6 +2,7 @@ test_description='test for no lazy fetch with the commit-graph' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup: prepare a repository with a commit' ' diff --git a/t/t5403-post-checkout-hook.sh b/t/t5403-post-checkout-hook.sh index 978f240cda..cfaae54739 100755 --- a/t/t5403-post-checkout-hook.sh +++ b/t/t5403-post-checkout-hook.sh @@ -7,6 +7,7 @@ test_description='Test the post-checkout 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/t5405-send-pack-rewind.sh b/t/t5405-send-pack-rewind.sh index 11f03239a0..1686ac13aa 100755 --- a/t/t5405-send-pack-rewind.sh +++ b/t/t5405-send-pack-rewind.sh @@ -5,6 +5,7 @@ test_description='forced push to replace commit we do not have' 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/t5406-remote-rejects.sh b/t/t5406-remote-rejects.sh index dcbeb42082..d6a9946633 100755 --- a/t/t5406-remote-rejects.sh +++ b/t/t5406-remote-rejects.sh @@ -2,6 +2,7 @@ test_description='remote push rejects are reported by client' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t5502-quickfetch.sh b/t/t5502-quickfetch.sh index b160f8b7fb..7b3ff21b98 100755 --- a/t/t5502-quickfetch.sh +++ b/t/t5502-quickfetch.sh @@ -5,6 +5,7 @@ test_description='test quickfetch from local' 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/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh index ac4099ca89..0b8ab4afdb 100755 --- a/t/t5504-fetch-receive-strict.sh +++ b/t/t5504-fetch-receive-strict.sh @@ -4,6 +4,7 @@ test_description='fetch/receive strict mode' 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 and inject "corrupt or missing" object' ' @@ -138,7 +139,7 @@ This commit object intentionally broken EOF test_expect_success 'setup bogus commit' ' - commit="$(git hash-object -t commit -w --stdin <bogus-commit)" + commit="$(git hash-object --literally -t commit -w --stdin <bogus-commit)" ' test_expect_success 'fsck with no skipList input' ' diff --git a/t/t5506-remote-groups.sh b/t/t5506-remote-groups.sh index 5bac03ede8..0e176175a3 100755 --- a/t/t5506-remote-groups.sh +++ b/t/t5506-remote-groups.sh @@ -99,4 +99,13 @@ test_expect_success 'updating remote name updates that remote' ' ! repo_fetched two ' +test_expect_success 'updating group in parallel with a duplicate remote does not fail (fetch)' ' + mark fetch-group-duplicate && + update_repo one && + git config --add remotes.duplicate one && + git config --add remotes.duplicate one && + git -c fetch.parallel=2 remote update duplicate && + repo_fetched one +' + test_done diff --git a/t/t5507-remote-environment.sh b/t/t5507-remote-environment.sh index e6149295b1..c6a6957c50 100755 --- a/t/t5507-remote-environment.sh +++ b/t/t5507-remote-environment.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='check environment showed to remote side of transports' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'set up "remote" push situation' ' diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index c0b745e33b..dc44da9c79 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -806,6 +806,14 @@ test_expect_success 'fetch.writeCommitGraph with submodules' ' ) ' +# fetches from first configured url +test_expect_success 'fetch from multiple configured URLs in single remote' ' + git init url1 && + git remote add multipleurls url1 && + git remote set-url --add multipleurls url2 && + git fetch multipleurls +' + # configured prune tests set_config_tristate () { @@ -1163,6 +1171,15 @@ test_expect_success '--no-show-forced-updates' ' ) ' +for section in fetch transfer +do + test_expect_success "$section.hideRefs affects connectivity check" ' + GIT_TRACE="$PWD"/trace git -c $section.hideRefs=refs -c \ + $section.hideRefs="!refs/tags/" fetch && + grep "git rev-list .*--exclude-hidden=fetch" trace + ' +done + setup_negotiation_tip () { SERVER="$1" URL="$2" diff --git a/t/t5514-fetch-multiple.sh b/t/t5514-fetch-multiple.sh index 511ba3bd45..54f422ced3 100755 --- a/t/t5514-fetch-multiple.sh +++ b/t/t5514-fetch-multiple.sh @@ -197,4 +197,9 @@ test_expect_success 'parallel' ' test_i18ngrep "could not fetch .two.*128" err ' +test_expect_success 'git fetch --multiple --jobs=0 picks a default' ' + (cd test && + git fetch --multiple --jobs=0) +' + test_done diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 79dc470c01..98a27a2948 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -1853,55 +1853,24 @@ test_expect_success 'refuse to push a hidden ref, and make sure do not pollute t test_dir_is_empty testrepo/.git/objects/pack ' -test_expect_success LIBCURL 'fetch warns or fails when using username:password' ' - message="URL '\''https://username:<redacted>@localhost/'\'' uses plaintext credentials" && - test_must_fail git -c transfer.credentialsInUrl=allow fetch https://username:password@localhost 2>err && - ! grep "$message" err && - - test_must_fail git -c transfer.credentialsInUrl=warn fetch https://username:password@localhost 2>err && - grep "warning: $message" err >warnings && - test_line_count = 3 warnings && - - test_must_fail git -c transfer.credentialsInUrl=die fetch https://username:password@localhost 2>err && - grep "fatal: $message" err >warnings && - test_line_count = 1 warnings && - - test_must_fail git -c transfer.credentialsInUrl=die fetch https://username:@localhost 2>err && - grep "fatal: $message" err >warnings && - test_line_count = 1 warnings -' - - -test_expect_success LIBCURL 'push warns or fails when using username:password' ' - message="URL '\''https://username:<redacted>@localhost/'\'' uses plaintext credentials" && - test_must_fail git -c transfer.credentialsInUrl=allow push https://username:password@localhost 2>err && - ! grep "$message" err && - - test_must_fail git -c transfer.credentialsInUrl=warn push https://username:password@localhost 2>err && - grep "warning: $message" err >warnings && - test_must_fail git -c transfer.credentialsInUrl=die push https://username:password@localhost 2>err && - grep "fatal: $message" err >warnings && - test_line_count = 1 warnings -' - test_expect_success 'push with config push.useBitmaps' ' mk_test testrepo heads/main && git checkout main && test_unconfig push.useBitmaps && GIT_TRACE2_EVENT="$PWD/default" \ - git push testrepo main:test && + git push --quiet testrepo main:test && test_subcommand git pack-objects --all-progress-implied --revs --stdout \ --thin --delta-base-offset -q <default && test_config push.useBitmaps true && GIT_TRACE2_EVENT="$PWD/true" \ - git push testrepo main:test2 && + git push --quiet testrepo main:test2 && test_subcommand git pack-objects --all-progress-implied --revs --stdout \ --thin --delta-base-offset -q <true && test_config push.useBitmaps false && GIT_TRACE2_EVENT="$PWD/false" \ - git push testrepo main:test3 && + git push --quiet testrepo main:test3 && test_subcommand git pack-objects --all-progress-implied --revs --stdout \ --thin --delta-base-offset -q --no-use-bitmap-index <false ' diff --git a/t/t5522-pull-symlink.sh b/t/t5522-pull-symlink.sh index bcff460d0a..cc5496e28f 100755 --- a/t/t5522-pull-symlink.sh +++ b/t/t5522-pull-symlink.sh @@ -2,6 +2,7 @@ test_description='pulling from symlinked subdir' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # The scenario we are building: @@ -78,7 +79,9 @@ test_expect_success SYMLINKS 'pushing from symlinked subdir' ' git commit -m push ./file && git push ) && - test push = $(git show HEAD:subdir/file) + echo push >expect && + git show HEAD:subdir/file >actual && + test_cmp expect actual ' test_done diff --git a/t/t5523-push-upstream.sh b/t/t5523-push-upstream.sh index fdb4292056..c9acc07635 100755 --- a/t/t5523-push-upstream.sh +++ b/t/t5523-push-upstream.sh @@ -4,6 +4,7 @@ test_description='push with --set-upstream' 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/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh index 3c44f19612..b9546ef8e5 100755 --- a/t/t5526-fetch-submodules.sh +++ b/t/t5526-fetch-submodules.sh @@ -178,6 +178,7 @@ test_expect_success "submodule.recurse option triggers recursive fetch" ' ' test_expect_success "fetch --recurse-submodules -j2 has the same output behaviour" ' + test_when_finished "rm -f trace.out" && add_submodule_commits && ( cd downstream && @@ -705,17 +706,30 @@ test_expect_success "'fetch.recurseSubmodules=on-demand' works also without .git test_expect_success 'fetching submodules respects parallel settings' ' git config fetch.recurseSubmodules true && + test_when_finished "rm -f downstream/trace.out" && ( cd downstream && GIT_TRACE=$(pwd)/trace.out git fetch && grep "1 tasks" trace.out && + >trace.out && + GIT_TRACE=$(pwd)/trace.out git fetch --jobs 7 && grep "7 tasks" trace.out && + >trace.out && + git config submodule.fetchJobs 8 && GIT_TRACE=$(pwd)/trace.out git fetch && grep "8 tasks" trace.out && + >trace.out && + GIT_TRACE=$(pwd)/trace.out git fetch --jobs 9 && - grep "9 tasks" trace.out + grep "9 tasks" trace.out && + >trace.out && + + GIT_TRACE=$(pwd)/trace.out git -c submodule.fetchJobs=0 fetch && + grep "preparing to run up to [0-9]* tasks" trace.out && + ! grep "up to 0 tasks" trace.out && + >trace.out ) ' diff --git a/t/t5527-fetch-odd-refs.sh b/t/t5527-fetch-odd-refs.sh index e2770e4541..98ece27c6a 100755 --- a/t/t5527-fetch-odd-refs.sh +++ b/t/t5527-fetch-odd-refs.sh @@ -4,6 +4,7 @@ test_description='test fetching of oddly-named refs' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # afterwards we will have: diff --git a/t/t5529-push-errors.sh b/t/t5529-push-errors.sh index ce85fd30ad..0247137cb3 100755 --- a/t/t5529-push-errors.sh +++ b/t/t5529-push-errors.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='detect some push errors early (before contacting remote)' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup commits' ' diff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh index 3f58b515ce..302e4cbdba 100755 --- a/t/t5531-deep-submodule-push.sh +++ b/t/t5531-deep-submodule-push.sh @@ -512,6 +512,56 @@ test_expect_success 'push only unpushed submodules recursively' ' test_cmp expected_pub actual_pub ' +setup_subsub () { + git init upstream && + git init upstream/sub && + git init upstream/sub/deepsub && + test_commit -C upstream/sub/deepsub innermost && + git -C upstream/sub submodule add ./deepsub deepsub && + git -C upstream/sub commit -m middle && + git -C upstream submodule add ./sub sub && + git -C upstream commit -m outermost && + + git -c protocol.file.allow=always clone --recurse-submodules upstream downstream && + git -C downstream/sub/deepsub checkout -b downstream-branch && + git -C downstream/sub checkout -b downstream-branch && + git -C downstream checkout -b downstream-branch +} + +new_downstream_commits () { + test_commit -C downstream/sub/deepsub new-innermost && + git -C downstream/sub add deepsub && + git -C downstream/sub commit -m new-middle && + git -C downstream add sub && + git -C downstream commit -m new-outermost +} + +test_expect_success 'push with push.recurseSubmodules=only on superproject' ' + test_when_finished rm -rf upstream downstream && + setup_subsub && + new_downstream_commits && + git -C downstream config push.recurseSubmodules only && + git -C downstream push origin downstream-branch && + + test_must_fail git -C upstream rev-parse refs/heads/downstream-branch && + git -C upstream/sub rev-parse refs/heads/downstream-branch && + test_must_fail git -C upstream/sub/deepsub rev-parse refs/heads/downstream-branch +' + +test_expect_success 'push with push.recurseSubmodules=only on superproject and top-level submodule' ' + test_when_finished rm -rf upstream downstream && + setup_subsub && + new_downstream_commits && + git -C downstream config push.recurseSubmodules only && + git -C downstream/sub config push.recurseSubmodules only && + git -C downstream push origin downstream-branch 2> err && + + test_must_fail git -C upstream rev-parse refs/heads/downstream-branch && + git -C upstream/sub rev-parse refs/heads/downstream-branch && + git -C upstream/sub/deepsub rev-parse refs/heads/downstream-branch && + grep "recursing into submodule with push.recurseSubmodules=only; using on-demand instead" err +' + test_expect_success 'push propagating the remotes name to a submodule' ' git -C work remote add origin ../pub.git && git -C work remote add pub ../pub.git && diff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh index fbad2d5ff5..d0211cd8be 100755 --- a/t/t5541-http-push-smart.sh +++ b/t/t5541-http-push-smart.sh @@ -36,28 +36,6 @@ test_expect_success 'setup remote repository' ' setup_askpass_helper -cat >exp <<EOF -GET /smart/test_repo.git/info/refs?service=git-upload-pack HTTP/1.1 200 -POST /smart/test_repo.git/git-upload-pack HTTP/1.1 200 -EOF -test_expect_success 'no empty path components' ' - # Clear the log, so that it does not affect the "used receive-pack - # service" test which reads the log too. - test_when_finished ">\"\$HTTPD_ROOT_PATH\"/access.log" && - - # In the URL, add a trailing slash, and see if git appends yet another - # slash. - cd "$ROOT_PATH" && - git clone $HTTPD_URL/smart/test_repo.git/ test_repo_clone && - - # NEEDSWORK: If the overspecification of the expected result is reduced, we - # might be able to run this test in all protocol versions. - if test "$GIT_TEST_PROTOCOL_VERSION" = 0 - then - check_access_log exp - fi -' - test_expect_success 'clone remote repository' ' rm -rf test_repo_clone && git clone $HTTPD_URL/smart/test_repo.git test_repo_clone && @@ -67,6 +45,10 @@ test_expect_success 'clone remote repository' ' ' test_expect_success 'push to remote repository (standard)' ' + # Clear the log, so that the "used receive-pack service" test below + # sees just what we did here. + >"$HTTPD_ROOT_PATH"/access.log && + cd "$ROOT_PATH"/test_repo_clone && : >path2 && git add path2 && @@ -80,6 +62,15 @@ test_expect_success 'push to remote repository (standard)' ' test $HEAD = $(git rev-parse --verify HEAD)) ' +test_expect_success 'used receive-pack service' ' + cat >exp <<-\EOF && + GET /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200 + POST /smart/test_repo.git/git-receive-pack HTTP/1.1 200 + EOF + + check_access_log exp +' + test_expect_success 'push to remote repository (standard) with sending Accept-Language' ' cat >exp <<-\EOF && => Send header: Accept-Language: ko-KR, *;q=0.9 @@ -141,28 +132,6 @@ test_expect_success 'rejected update prints status' ' ' rm -f "$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update" -cat >exp <<EOF -GET /smart/test_repo.git/info/refs?service=git-upload-pack HTTP/1.1 200 -POST /smart/test_repo.git/git-upload-pack HTTP/1.1 200 -GET /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200 -POST /smart/test_repo.git/git-receive-pack HTTP/1.1 200 -GET /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200 -GET /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200 -POST /smart/test_repo.git/git-receive-pack HTTP/1.1 200 -GET /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200 -POST /smart/test_repo.git/git-receive-pack HTTP/1.1 200 -GET /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200 -POST /smart/test_repo.git/git-receive-pack HTTP/1.1 200 -EOF -test_expect_success 'used receive-pack service' ' - # NEEDSWORK: If the overspecification of the expected result is reduced, we - # might be able to run this test in all protocol versions. - if test "$GIT_TEST_PROTOCOL_VERSION" = 0 - then - check_access_log exp - fi -' - test_http_push_nonff "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git \ "$ROOT_PATH"/test_repo_clone main success diff --git a/t/t5544-pack-objects-hook.sh b/t/t5544-pack-objects-hook.sh index 54f54f8d2e..1a9e14bbcc 100755 --- a/t/t5544-pack-objects-hook.sh +++ b/t/t5544-pack-objects-hook.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test custom script in place of pack-objects' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'create some history to fetch' ' diff --git a/t/t5546-receive-limits.sh b/t/t5546-receive-limits.sh index 0b0e987fdb..eed3c9d81a 100755 --- a/t/t5546-receive-limits.sh +++ b/t/t5546-receive-limits.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='check receive input limits' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Let's run tests with different unpack limits: 1 and 10000 diff --git a/t/t5547-push-quarantine.sh b/t/t5547-push-quarantine.sh index 1876fb34e5..9f899b8c7d 100755 --- a/t/t5547-push-quarantine.sh +++ b/t/t5547-push-quarantine.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='check quarantine of objects during push' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'create picky dest repo' ' diff --git a/t/t5550-http-fetch-dumb.sh b/t/t5550-http-fetch-dumb.sh index d7cf85ffea..8f182a3cbf 100755 --- a/t/t5550-http-fetch-dumb.sh +++ b/t/t5550-http-fetch-dumb.sh @@ -234,7 +234,7 @@ test_expect_success 'http-fetch --packfile' ' --index-pack-arg=--keep \ "$HTTPD_URL"/dumb/repo_pack.git/$p >out && - grep "^keep.[0-9a-f]\{16,\}$" out && + grep -E "^keep.[0-9a-f]{16,}$" out && cut -c6- out >packhash && # Ensure that the expected files are generated diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh index 6a38294a47..0908534f25 100755 --- a/t/t5551-http-fetch-smart.sh +++ b/t/t5551-http-fetch-smart.sh @@ -1,13 +1,19 @@ #!/bin/sh -test_description='test smart fetching over http via http-backend' +: ${HTTP_PROTO:=HTTP/1.1} +test_description="test smart fetching over http via http-backend ($HTTP_PROTO)" GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME . ./test-lib.sh . "$TEST_DIRECTORY"/lib-httpd.sh +test "$HTTP_PROTO" = "HTTP/2" && enable_http2 start_httpd +test_expect_success HTTP2 'enable client-side http/2' ' + git config --global http.version HTTP/2 +' + test_expect_success 'setup repository' ' git config push.default matching && echo content >file && @@ -27,35 +33,71 @@ test_expect_success 'create http-accessible bare repository' ' setup_askpass_helper test_expect_success 'clone http repository' ' - cat >exp <<-\EOF && - > GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1 - > Accept: */* - > Accept-Encoding: ENCODINGS - > Accept-Language: ko-KR, *;q=0.9 - > Pragma: no-cache - < HTTP/1.1 200 OK - < Pragma: no-cache - < Cache-Control: no-cache, max-age=0, must-revalidate - < Content-Type: application/x-git-upload-pack-advertisement - > POST /smart/repo.git/git-upload-pack HTTP/1.1 - > Accept-Encoding: ENCODINGS - > Content-Type: application/x-git-upload-pack-request - > Accept: application/x-git-upload-pack-result - > Accept-Language: ko-KR, *;q=0.9 - > Content-Length: xxx - < HTTP/1.1 200 OK - < Pragma: no-cache - < Cache-Control: no-cache, max-age=0, must-revalidate - < Content-Type: application/x-git-upload-pack-result + if test_have_prereq HTTP2 && test "$HTTPD_PROTO" = "https" + then + # ALPN lets us immediately use HTTP/2; likewise, POSTs with + # bodies can use it because they do not need to upgrade + INITIAL_PROTO=HTTP/2 + else + # either we are not using HTTP/2, or the initial + # request is sent via HTTP/1.1 and asks for upgrade + INITIAL_PROTO=HTTP/1.1 + fi && + + cat >exp.raw <<-EOF && + > GET /smart/repo.git/info/refs?service=git-upload-pack $INITIAL_PROTO + > accept: */* + > accept-encoding: ENCODINGS + > accept-language: ko-KR, *;q=0.9 + > pragma: no-cache + {V2} > git-protocol: version=2 + < $HTTP_PROTO 200 OK + < pragma: no-cache + < cache-control: no-cache, max-age=0, must-revalidate + < content-type: application/x-git-upload-pack-advertisement + > POST /smart/repo.git/git-upload-pack $INITIAL_PROTO + > accept-encoding: ENCODINGS + > content-type: application/x-git-upload-pack-request + > accept: application/x-git-upload-pack-result + > accept-language: ko-KR, *;q=0.9 + {V2} > git-protocol: version=2 + > content-length: xxx + < $INITIAL_PROTO 200 OK + < pragma: no-cache + < cache-control: no-cache, max-age=0, must-revalidate + < content-type: application/x-git-upload-pack-result + {V2} > POST /smart/repo.git/git-upload-pack $INITIAL_PROTO + {V2} > accept-encoding: ENCODINGS + {V2} > content-type: application/x-git-upload-pack-request + {V2} > accept: application/x-git-upload-pack-result + {V2} > accept-language: ko-KR, *;q=0.9 + {V2} > git-protocol: version=2 + {V2} > content-length: xxx + {V2} < $INITIAL_PROTO 200 OK + {V2} < pragma: no-cache + {V2} < cache-control: no-cache, max-age=0, must-revalidate + {V2} < content-type: application/x-git-upload-pack-result EOF - GIT_TRACE_CURL=true GIT_TEST_PROTOCOL_VERSION=0 LANGUAGE="ko_KR.UTF-8" \ + if test "$GIT_TEST_PROTOCOL_VERSION" = 0 + then + sed "/^{V2}/d" <exp.raw >exp + else + sed "s/^{V2} //" <exp.raw >exp + fi && + + GIT_TRACE_CURL=true LANGUAGE="ko_KR.UTF-8" \ git clone --quiet $HTTPD_URL/smart/repo.git clone 2>err && test_cmp file clone/file && tr '\''\015'\'' Q <err | + perl -pe '\'' + s/(Send|Recv) header: ([A-Za-z0-9-]+):/ + "$1 header: " . lc($2) . ":" + /e; + '\'' | sed -e " s/Q\$// - /^[*] /d + /^[^<=]/d /^== Info:/d /^=> Send header, /d /^=> Send header:$/d @@ -65,6 +107,8 @@ test_expect_success 'clone http repository' ' s/= Recv header:// /^<= Recv data/d /^=> Send data/d + /^<= Recv SSL data/d + /^=> Send SSL data/d /^$/d /^< $/d @@ -72,36 +116,35 @@ test_expect_success 'clone http repository' ' s/^/> / } - /^> User-Agent: /d - /^> Host: /d + /^< HTTP/ { + s/200$/200 OK/ + } + /^< HTTP\\/1.1 101/d + /^[><] connection: /d + /^[><] upgrade: /d + /^> http2-settings: /d + + /^> user-agent: /d + /^> host: /d /^> POST /,$ { /^> Accept: [*]\\/[*]/d } - s/^> Content-Length: .*/> Content-Length: xxx/ + s/^> content-length: .*/> content-length: xxx/ /^> 00..want /d /^> 00.*done/d - /^< Server: /d - /^< Expires: /d - /^< Date: /d - /^< Content-Length: /d - /^< Transfer-Encoding: /d + /^< server: /d + /^< expires: /d + /^< date: /d + /^< content-length: /d + /^< transfer-encoding: /d " >actual && - # NEEDSWORK: If the overspecification of the expected result is reduced, we - # might be able to run this test in all protocol versions. - if test "$GIT_TEST_PROTOCOL_VERSION" = 0 - then - sed -e "s/^> Accept-Encoding: .*/> Accept-Encoding: ENCODINGS/" \ - actual >actual.smudged && - test_cmp exp actual.smudged && - - grep "Accept-Encoding:.*gzip" actual >actual.gzip && - test_line_count = 2 actual.gzip && + sed -e "s/^> accept-encoding: .*/> accept-encoding: ENCODINGS/" \ + actual >actual.smudged && + test_cmp exp actual.smudged && - grep "Accept-Language: ko-KR, *" actual >actual.language && - test_line_count = 2 actual.language - fi + grep "accept-encoding:.*gzip" actual >actual.gzip ' test_expect_success 'fetch changes via http' ' @@ -113,19 +156,9 @@ test_expect_success 'fetch changes via http' ' ' test_expect_success 'used upload-pack service' ' - cat >exp <<-\EOF && - GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1 200 - POST /smart/repo.git/git-upload-pack HTTP/1.1 200 - GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1 200 - POST /smart/repo.git/git-upload-pack HTTP/1.1 200 - EOF - - # NEEDSWORK: If the overspecification of the expected result is reduced, we - # might be able to run this test in all protocol versions. - if test "$GIT_TEST_PROTOCOL_VERSION" = 0 - then - check_access_log exp - fi + strip_access_log >log && + grep "GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/[0-9.]* 200" log && + grep "POST /smart/repo.git/git-upload-pack HTTP/[0-9.]* 200" log ' test_expect_success 'follow redirects (301)' ' @@ -274,21 +307,23 @@ test_expect_success 'cookies stored in http.cookiefile when http.savecookies set 127.0.0.1 FALSE /smart_cookies/ FALSE 0 othername othervalue EOF sort >expect_cookies.txt <<-\EOF && - 127.0.0.1 FALSE /smart_cookies/ FALSE 0 othername othervalue + 127.0.0.1 FALSE /smart_cookies/repo.git/ FALSE 0 name value 127.0.0.1 FALSE /smart_cookies/repo.git/info/ FALSE 0 name value EOF git config http.cookiefile cookies.txt && git config http.savecookies true && - git ls-remote $HTTPD_URL/smart_cookies/repo.git main && - # NEEDSWORK: If the overspecification of the expected result is reduced, we - # might be able to run this test in all protocol versions. - if test "$GIT_TEST_PROTOCOL_VERSION" = 0 - then - tail -3 cookies.txt | sort >cookies_tail.txt && - test_cmp expect_cookies.txt cookies_tail.txt - fi + test_when_finished " + git --git-dir=\"\$HTTPD_DOCUMENT_ROOT_PATH/repo.git\" \ + tag -d cookie-tag + " && + git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \ + tag -m "foo" cookie-tag && + git fetch $HTTPD_URL/smart_cookies/repo.git cookie-tag && + + grep "^[^#]" cookies.txt | sort >cookies_stripped.txt && + test_cmp expect_cookies.txt cookies_stripped.txt ' test_expect_success 'transfer.hiderefs works over smart-http' ' @@ -347,7 +382,10 @@ test_expect_success CMDLINE_LIMIT \ test_expect_success 'large fetch-pack requests can be sent using chunked encoding' ' GIT_TRACE_CURL=true git -c http.postbuffer=65536 \ clone --bare "$HTTPD_URL/smart/repo.git" split.git 2>err && - grep "^=> Send header: Transfer-Encoding: chunked" err + { + test_have_prereq HTTP2 || + grep "^=> Send header: Transfer-Encoding: chunked" err + } ' test_expect_success 'test allowreachablesha1inwant' ' @@ -580,4 +618,90 @@ test_expect_success 'passing hostname resolution information works' ' git -c "http.curloptResolve=$BOGUS_HOST:$LIB_HTTPD_PORT:127.0.0.1" ls-remote "$BOGUS_HTTPD_URL/smart/repo.git" >/dev/null ' +# here user%40host is the URL-encoded version of user@host, +# which is our intentionally-odd username to catch parsing errors +url_user=$HTTPD_URL_USER/auth/smart/repo.git +url_userpass=$HTTPD_URL_USER_PASS/auth/smart/repo.git +url_userblank=$HTTPD_PROTO://user%40host:@$HTTPD_DEST/auth/smart/repo.git +message="URL .*:<redacted>@.* uses plaintext credentials" + +test_expect_success 'clone warns or fails when using username:password' ' + test_when_finished "rm -rf attempt*" && + + git -c transfer.credentialsInUrl=allow \ + clone $url_userpass attempt1 2>err && + ! grep "$message" err && + + git -c transfer.credentialsInUrl=warn \ + clone $url_userpass attempt2 2>err && + grep "warning: $message" err >warnings && + test_line_count -ge 1 warnings && + + test_must_fail git -c transfer.credentialsInUrl=die \ + clone $url_userpass attempt3 2>err && + grep "fatal: $message" err >warnings && + test_line_count -ge 1 warnings && + + test_must_fail git -c transfer.credentialsInUrl=die \ + clone $url_userblank attempt4 2>err && + grep "fatal: $message" err >warnings && + test_line_count -ge 1 warnings +' + +test_expect_success 'clone does not detect username:password when it is https://username@domain:port/' ' + test_when_finished "rm -rf attempt1" && + + # we are relying on lib-httpd for url construction, so document our + # assumptions + case "$HTTPD_URL_USER" in + *:[0-9]*) : ok ;; + *) BUG "httpd url does not have port: $HTTPD_URL_USER" + esac && + + git -c transfer.credentialsInUrl=warn clone $url_user attempt1 2>err && + ! grep "uses plaintext credentials" err +' + +test_expect_success 'fetch warns or fails when using username:password' ' + git -c transfer.credentialsInUrl=allow fetch $url_userpass 2>err && + ! grep "$message" err && + + git -c transfer.credentialsInUrl=warn fetch $url_userpass 2>err && + grep "warning: $message" err >warnings && + test_line_count -ge 1 warnings && + + test_must_fail git -c transfer.credentialsInUrl=die \ + fetch $url_userpass 2>err && + grep "fatal: $message" err >warnings && + test_line_count -ge 1 warnings && + + test_must_fail git -c transfer.credentialsInUrl=die \ + fetch $url_userblank 2>err && + grep "fatal: $message" err >warnings && + test_line_count -ge 1 warnings +' + + +test_expect_success 'push warns or fails when using username:password' ' + git -c transfer.credentialsInUrl=allow push $url_userpass 2>err && + ! grep "$message" err && + + git -c transfer.credentialsInUrl=warn push $url_userpass 2>err && + grep "warning: $message" err >warnings && + + test_must_fail git -c transfer.credentialsInUrl=die \ + push $url_userpass 2>err && + grep "fatal: $message" err >warnings && + test_line_count -ge 1 warnings +' + +test_expect_success 'no empty path components' ' + # In the URL, add a trailing slash, and see if git appends yet another + # slash. + git clone $HTTPD_URL/smart/repo.git/ clone-with-slash && + + strip_access_log >log && + ! grep "//" log +' + test_done diff --git a/t/t5554-noop-fetch-negotiator.sh b/t/t5554-noop-fetch-negotiator.sh index 2ac7b5859e..06991e8e8a 100755 --- a/t/t5554-noop-fetch-negotiator.sh +++ b/t/t5554-noop-fetch-negotiator.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test noop fetch negotiator' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'noop negotiator does not emit any "have"' ' diff --git a/t/t5558-clone-bundle-uri.sh b/t/t5558-clone-bundle-uri.sh index ad666a2d28..afd56926c5 100755 --- a/t/t5558-clone-bundle-uri.sh +++ b/t/t5558-clone-bundle-uri.sh @@ -41,6 +41,215 @@ test_expect_success 'clone with file:// bundle' ' test_cmp expect actual ' +# To get interesting tests for bundle lists, we need to construct a +# somewhat-interesting commit history. +# +# ---------------- bundle-4 +# +# 4 +# / \ +# ----|---|------- bundle-3 +# | | +# | 3 +# | | +# ----|---|------- bundle-2 +# | | +# 2 | +# | | +# ----|---|------- bundle-1 +# \ / +# 1 +# | +# (previous commits) +test_expect_success 'construct incremental bundle list' ' + ( + cd clone-from && + git checkout -b base && + test_commit 1 && + git checkout -b left && + test_commit 2 && + git checkout -b right base && + test_commit 3 && + git checkout -b merge left && + git merge right -m "4" && + + git bundle create bundle-1.bundle base && + git bundle create bundle-2.bundle base..left && + git bundle create bundle-3.bundle base..right && + git bundle create bundle-4.bundle merge --not left right + ) +' + +test_expect_success 'clone bundle list (file, no heuristic)' ' + 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 + + [bundle "bundle-3"] + uri = file://$(pwd)/clone-from/bundle-3.bundle + + [bundle "bundle-4"] + uri = file://$(pwd)/clone-from/bundle-4.bundle + EOF + + git clone --bundle-uri="file://$(pwd)/bundle-list" \ + clone-from clone-list-file 2>err && + ! grep "Repository lacks these prerequisite commits" err && + + git -C clone-from for-each-ref --format="%(objectname)" >oids && + git -C clone-list-file cat-file --batch-check <oids && + + git -C clone-list-file for-each-ref --format="%(refname)" >refs && + grep "refs/bundles/" refs >actual && + cat >expect <<-\EOF && + refs/bundles/base + refs/bundles/left + refs/bundles/merge + refs/bundles/right + EOF + test_cmp expect actual +' + +test_expect_success 'clone bundle list (file, all mode, some failures)' ' + cat >bundle-list <<-EOF && + [bundle] + version = 1 + mode = all + + # Does not exist. Should be skipped. + [bundle "bundle-0"] + uri = file://$(pwd)/clone-from/bundle-0.bundle + + [bundle "bundle-1"] + uri = file://$(pwd)/clone-from/bundle-1.bundle + + [bundle "bundle-2"] + uri = file://$(pwd)/clone-from/bundle-2.bundle + + # No bundle-3 means bundle-4 will not apply. + + [bundle "bundle-4"] + uri = file://$(pwd)/clone-from/bundle-4.bundle + + # Does not exist. Should be skipped. + [bundle "bundle-5"] + uri = file://$(pwd)/clone-from/bundle-5.bundle + EOF + + GIT_TRACE2_PERF=1 \ + git clone --bundle-uri="file://$(pwd)/bundle-list" \ + clone-from clone-all-some 2>err && + ! grep "Repository lacks these prerequisite commits" err && + ! grep "fatal" err && + grep "warning: failed to download bundle from URI" err && + + git -C clone-from for-each-ref --format="%(objectname)" >oids && + git -C clone-all-some cat-file --batch-check <oids && + + git -C clone-all-some 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 +' + +test_expect_success 'clone bundle list (file, all mode, all failures)' ' + cat >bundle-list <<-EOF && + [bundle] + version = 1 + mode = all + + # Does not exist. Should be skipped. + [bundle "bundle-0"] + uri = file://$(pwd)/clone-from/bundle-0.bundle + + # Does not exist. Should be skipped. + [bundle "bundle-5"] + uri = file://$(pwd)/clone-from/bundle-5.bundle + EOF + + git clone --bundle-uri="file://$(pwd)/bundle-list" \ + clone-from clone-all-fail 2>err && + ! grep "Repository lacks these prerequisite commits" err && + ! grep "fatal" err && + grep "warning: failed to download bundle from URI" err && + + git -C clone-from for-each-ref --format="%(objectname)" >oids && + git -C clone-all-fail cat-file --batch-check <oids && + + git -C clone-all-fail for-each-ref --format="%(refname)" >refs && + ! grep "refs/bundles/" refs +' + +test_expect_success 'clone bundle list (file, any mode)' ' + cat >bundle-list <<-EOF && + [bundle] + version = 1 + mode = any + + # Does not exist. Should be skipped. + [bundle "bundle-0"] + uri = file://$(pwd)/clone-from/bundle-0.bundle + + [bundle "bundle-1"] + uri = file://$(pwd)/clone-from/bundle-1.bundle + + # Does not exist. Should be skipped. + [bundle "bundle-5"] + uri = file://$(pwd)/clone-from/bundle-5.bundle + EOF + + git clone --bundle-uri="file://$(pwd)/bundle-list" \ + clone-from clone-any-file 2>err && + ! grep "Repository lacks these prerequisite commits" err && + + git -C clone-from for-each-ref --format="%(objectname)" >oids && + git -C clone-any-file cat-file --batch-check <oids && + + git -C clone-any-file for-each-ref --format="%(refname)" >refs && + grep "refs/bundles/" refs >actual && + cat >expect <<-\EOF && + refs/bundles/base + EOF + test_cmp expect actual +' + +test_expect_success 'clone bundle list (file, any mode, all failures)' ' + cat >bundle-list <<-EOF && + [bundle] + version = 1 + mode = any + + # Does not exist. Should be skipped. + [bundle "bundle-0"] + uri = $HTTPD_URL/bundle-0.bundle + + # Does not exist. Should be skipped. + [bundle "bundle-5"] + uri = $HTTPD_URL/bundle-5.bundle + EOF + + git clone --bundle-uri="file://$(pwd)/bundle-list" \ + clone-from clone-any-fail 2>err && + ! grep "fatal" err && + grep "warning: failed to download bundle from URI" err && + + git -C clone-from for-each-ref --format="%(objectname)" >oids && + git -C clone-any-fail cat-file --batch-check <oids && + + git -C clone-any-fail for-each-ref --format="%(refname)" >refs && + ! grep "refs/bundles/" refs +' + ######################################################################### # HTTP tests begin here @@ -75,6 +284,740 @@ test_expect_success 'clone HTTP bundle' ' test_config -C clone-http log.excludedecoration refs/bundle/ ' +test_expect_success 'clone bundle list (HTTP, no heuristic)' ' + test_when_finished rm -f trace*.txt && + + cp clone-from/bundle-*.bundle "$HTTPD_DOCUMENT_ROOT_PATH/" && + cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle] + version = 1 + mode = all + + [bundle "bundle-1"] + uri = $HTTPD_URL/bundle-1.bundle + + [bundle "bundle-2"] + uri = $HTTPD_URL/bundle-2.bundle + + [bundle "bundle-3"] + uri = $HTTPD_URL/bundle-3.bundle + + [bundle "bundle-4"] + uri = $HTTPD_URL/bundle-4.bundle + EOF + + GIT_TRACE2_EVENT="$(pwd)/trace-clone.txt" \ + git clone --bundle-uri="$HTTPD_URL/bundle-list" \ + clone-from clone-list-http 2>err && + ! grep "Repository lacks these prerequisite commits" err && + + git -C clone-from for-each-ref --format="%(objectname)" >oids && + git -C clone-list-http cat-file --batch-check <oids && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-1.bundle + $HTTPD_URL/bundle-2.bundle + $HTTPD_URL/bundle-3.bundle + $HTTPD_URL/bundle-4.bundle + $HTTPD_URL/bundle-list + EOF + + # Sort the list, since the order is not well-defined + # without a heuristic. + test_remote_https_urls <trace-clone.txt | sort >actual && + test_cmp expect actual +' + +test_expect_success 'clone bundle list (HTTP, any mode)' ' + cp clone-from/bundle-*.bundle "$HTTPD_DOCUMENT_ROOT_PATH/" && + cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle] + version = 1 + mode = any + + # Does not exist. Should be skipped. + [bundle "bundle-0"] + uri = $HTTPD_URL/bundle-0.bundle + + [bundle "bundle-1"] + uri = $HTTPD_URL/bundle-1.bundle + + # Does not exist. Should be skipped. + [bundle "bundle-5"] + uri = $HTTPD_URL/bundle-5.bundle + EOF + + git clone --bundle-uri="$HTTPD_URL/bundle-list" \ + clone-from clone-any-http 2>err && + ! grep "fatal" err && + grep "warning: failed to download bundle from URI" err && + + git -C clone-from for-each-ref --format="%(objectname)" >oids && + git -C clone-any-http cat-file --batch-check <oids && + + git -C clone-list-file for-each-ref --format="%(refname)" >refs && + grep "refs/bundles/" refs >actual && + cat >expect <<-\EOF && + refs/bundles/base + refs/bundles/left + refs/bundles/merge + refs/bundles/right + EOF + test_cmp expect actual +' + +test_expect_success 'clone bundle list (http, creationToken)' ' + test_when_finished rm -f trace*.txt && + + cp clone-from/bundle-*.bundle "$HTTPD_DOCUMENT_ROOT_PATH/" && + cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "bundle-1"] + uri = bundle-1.bundle + creationToken = 1 + + [bundle "bundle-2"] + uri = bundle-2.bundle + creationToken = 2 + + [bundle "bundle-3"] + uri = bundle-3.bundle + creationToken = 3 + + [bundle "bundle-4"] + uri = bundle-4.bundle + creationToken = 4 + EOF + + GIT_TRACE2_EVENT="$(pwd)/trace-clone.txt" git \ + clone --bundle-uri="$HTTPD_URL/bundle-list" \ + "$HTTPD_URL/smart/fetch.git" clone-list-http-2 && + + git -C clone-from for-each-ref --format="%(objectname)" >oids && + git -C clone-list-http-2 cat-file --batch-check <oids && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + $HTTPD_URL/bundle-4.bundle + $HTTPD_URL/bundle-3.bundle + $HTTPD_URL/bundle-2.bundle + $HTTPD_URL/bundle-1.bundle + EOF + + test_remote_https_urls <trace-clone.txt >actual && + test_cmp expect actual +' + +test_expect_success 'clone incomplete bundle list (http, creationToken)' ' + test_when_finished rm -f trace*.txt && + + cp clone-from/bundle-*.bundle "$HTTPD_DOCUMENT_ROOT_PATH/" && + cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "bundle-1"] + uri = bundle-1.bundle + creationToken = 1 + EOF + + GIT_TRACE2_EVENT=$(pwd)/trace-clone.txt \ + git clone --bundle-uri="$HTTPD_URL/bundle-list" \ + --single-branch --branch=base --no-tags \ + "$HTTPD_URL/smart/fetch.git" clone-token-http && + + test_cmp_config -C clone-token-http "$HTTPD_URL/bundle-list" fetch.bundleuri && + test_cmp_config -C clone-token-http 1 fetch.bundlecreationtoken && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + $HTTPD_URL/bundle-1.bundle + EOF + + test_remote_https_urls <trace-clone.txt >actual && + test_cmp expect actual && + + # We now have only one bundle ref. + git -C clone-token-http for-each-ref --format="%(refname)" "refs/bundles/*" >refs && + cat >expect <<-\EOF && + refs/bundles/base + EOF + test_cmp expect refs && + + # Add remaining bundles, exercising the "deepening" strategy + # for downloading via the creationToken heurisitc. + cat >>"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle "bundle-2"] + uri = bundle-2.bundle + creationToken = 2 + + [bundle "bundle-3"] + uri = bundle-3.bundle + creationToken = 3 + + [bundle "bundle-4"] + uri = bundle-4.bundle + creationToken = 4 + EOF + + GIT_TRACE2_EVENT="$(pwd)/trace1.txt" \ + git -C clone-token-http fetch origin --no-tags \ + refs/heads/merge:refs/heads/merge && + test_cmp_config -C clone-token-http 4 fetch.bundlecreationtoken && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + $HTTPD_URL/bundle-4.bundle + $HTTPD_URL/bundle-3.bundle + $HTTPD_URL/bundle-2.bundle + EOF + + test_remote_https_urls <trace1.txt >actual && + test_cmp expect actual && + + # We now have all bundle refs. + git -C clone-token-http for-each-ref --format="%(refname)" "refs/bundles/*" >refs && + + cat >expect <<-\EOF && + refs/bundles/base + refs/bundles/left + refs/bundles/merge + refs/bundles/right + EOF + test_cmp expect refs +' + +test_expect_success 'http clone with bundle.heuristic creates fetch.bundleURI' ' + test_when_finished rm -rf fetch-http-4 trace*.txt && + + cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "bundle-1"] + uri = bundle-1.bundle + creationToken = 1 + EOF + + GIT_TRACE2_EVENT="$(pwd)/trace-clone.txt" \ + git clone --single-branch --branch=base \ + --bundle-uri="$HTTPD_URL/bundle-list" \ + "$HTTPD_URL/smart/fetch.git" fetch-http-4 && + + test_cmp_config -C fetch-http-4 "$HTTPD_URL/bundle-list" fetch.bundleuri && + test_cmp_config -C fetch-http-4 1 fetch.bundlecreationtoken && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + $HTTPD_URL/bundle-1.bundle + EOF + + test_remote_https_urls <trace-clone.txt >actual && + test_cmp expect actual && + + # only received base ref from bundle-1 + git -C fetch-http-4 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && + cat >expect <<-\EOF && + refs/bundles/base + EOF + test_cmp expect refs && + + cat >>"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle "bundle-2"] + uri = bundle-2.bundle + creationToken = 2 + EOF + + # Fetch the objects for bundle-2 _and_ bundle-3. + GIT_TRACE2_EVENT="$(pwd)/trace1.txt" \ + git -C fetch-http-4 fetch origin --no-tags \ + refs/heads/left:refs/heads/left \ + refs/heads/right:refs/heads/right && + test_cmp_config -C fetch-http-4 2 fetch.bundlecreationtoken && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + $HTTPD_URL/bundle-2.bundle + EOF + + test_remote_https_urls <trace1.txt >actual && + test_cmp expect actual && + + # received left from bundle-2 + git -C fetch-http-4 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && + cat >expect <<-\EOF && + refs/bundles/base + refs/bundles/left + EOF + test_cmp expect refs && + + # No-op fetch + GIT_TRACE2_EVENT="$(pwd)/trace1b.txt" \ + git -C fetch-http-4 fetch origin --no-tags \ + refs/heads/left:refs/heads/left \ + refs/heads/right:refs/heads/right && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + EOF + test_remote_https_urls <trace1b.txt >actual && + test_cmp expect actual && + + cat >>"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle "bundle-3"] + uri = bundle-3.bundle + creationToken = 3 + + [bundle "bundle-4"] + uri = bundle-4.bundle + creationToken = 4 + EOF + + # This fetch should skip bundle-3.bundle, since its objects are + # already local (we have the requisite commits for bundle-4.bundle). + GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ + git -C fetch-http-4 fetch origin --no-tags \ + refs/heads/merge:refs/heads/merge && + test_cmp_config -C fetch-http-4 4 fetch.bundlecreationtoken && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + $HTTPD_URL/bundle-4.bundle + EOF + + test_remote_https_urls <trace2.txt >actual && + test_cmp expect actual && + + # received merge ref from bundle-4, but right is missing + # because we did not download bundle-3. + git -C fetch-http-4 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && + + cat >expect <<-\EOF && + refs/bundles/base + refs/bundles/left + refs/bundles/merge + EOF + test_cmp expect refs && + + # No-op fetch + GIT_TRACE2_EVENT="$(pwd)/trace2b.txt" \ + git -C fetch-http-4 fetch origin && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + EOF + test_remote_https_urls <trace2b.txt >actual && + test_cmp expect actual +' + +test_expect_success 'creationToken heuristic with failed downloads (clone)' ' + test_when_finished rm -rf download-* trace*.txt && + + # Case 1: base bundle does not exist, nothing can unbundle + cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "bundle-1"] + uri = fake.bundle + creationToken = 1 + + [bundle "bundle-2"] + uri = bundle-2.bundle + creationToken = 2 + + [bundle "bundle-3"] + uri = bundle-3.bundle + creationToken = 3 + + [bundle "bundle-4"] + uri = bundle-4.bundle + creationToken = 4 + EOF + + GIT_TRACE2_EVENT="$(pwd)/trace-clone-1.txt" \ + git clone --single-branch --branch=base \ + --bundle-uri="$HTTPD_URL/bundle-list" \ + "$HTTPD_URL/smart/fetch.git" download-1 && + + # Bundle failure does not set these configs. + test_must_fail git -C download-1 config fetch.bundleuri && + test_must_fail git -C download-1 config fetch.bundlecreationtoken && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + $HTTPD_URL/bundle-4.bundle + $HTTPD_URL/bundle-3.bundle + $HTTPD_URL/bundle-2.bundle + $HTTPD_URL/fake.bundle + EOF + test_remote_https_urls <trace-clone-1.txt >actual && + test_cmp expect actual && + + # All bundles failed to unbundle + git -C download-1 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && + test_must_be_empty refs && + + # Case 2: middle bundle does not exist, only two bundles can unbundle + cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "bundle-1"] + uri = bundle-1.bundle + creationToken = 1 + + [bundle "bundle-2"] + uri = fake.bundle + creationToken = 2 + + [bundle "bundle-3"] + uri = bundle-3.bundle + creationToken = 3 + + [bundle "bundle-4"] + uri = bundle-4.bundle + creationToken = 4 + EOF + + GIT_TRACE2_EVENT="$(pwd)/trace-clone-2.txt" \ + git clone --single-branch --branch=base \ + --bundle-uri="$HTTPD_URL/bundle-list" \ + "$HTTPD_URL/smart/fetch.git" download-2 && + + # Bundle failure does not set these configs. + test_must_fail git -C download-2 config fetch.bundleuri && + test_must_fail git -C download-2 config fetch.bundlecreationtoken && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + $HTTPD_URL/bundle-4.bundle + $HTTPD_URL/bundle-3.bundle + $HTTPD_URL/fake.bundle + $HTTPD_URL/bundle-1.bundle + EOF + test_remote_https_urls <trace-clone-2.txt >actual && + test_cmp expect actual && + + # bundle-1 and bundle-3 could unbundle, but bundle-4 could not + git -C download-2 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && + cat >expect <<-EOF && + refs/bundles/base + refs/bundles/right + EOF + test_cmp expect refs && + + # Case 3: top bundle does not exist, rest unbundle fine. + cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "bundle-1"] + uri = bundle-1.bundle + creationToken = 1 + + [bundle "bundle-2"] + uri = bundle-2.bundle + creationToken = 2 + + [bundle "bundle-3"] + uri = bundle-3.bundle + creationToken = 3 + + [bundle "bundle-4"] + uri = fake.bundle + creationToken = 4 + EOF + + GIT_TRACE2_EVENT="$(pwd)/trace-clone-3.txt" \ + git clone --single-branch --branch=base \ + --bundle-uri="$HTTPD_URL/bundle-list" \ + "$HTTPD_URL/smart/fetch.git" download-3 && + + # As long as we have continguous successful downloads, + # we _do_ set these configs. + test_cmp_config -C download-3 "$HTTPD_URL/bundle-list" fetch.bundleuri && + test_cmp_config -C download-3 3 fetch.bundlecreationtoken && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + $HTTPD_URL/fake.bundle + $HTTPD_URL/bundle-3.bundle + $HTTPD_URL/bundle-2.bundle + $HTTPD_URL/bundle-1.bundle + EOF + test_remote_https_urls <trace-clone-3.txt >actual && + test_cmp expect actual && + + # fake.bundle did not unbundle, but the others did. + git -C download-3 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && + cat >expect <<-EOF && + refs/bundles/base + refs/bundles/left + refs/bundles/right + EOF + test_cmp expect refs +' + +# Expand the bundle list to include other interesting shapes, specifically +# interesting for use when fetching from a previous state. +# +# ---------------- bundle-7 +# 7 +# _/|\_ +# ---/--|--\------ bundle-6 +# 5 | 6 +# --|---|---|----- bundle-4 +# | 4 | +# | / \ / +# --|-|---|/------ bundle-3 (the client will be caught up to this point.) +# \ | 3 +# ---\|---|------- bundle-2 +# 2 | +# ----|---|------- bundle-1 +# \ / +# 1 +# | +# (previous commits) +test_expect_success 'expand incremental bundle list' ' + ( + cd clone-from && + git checkout -b lefter left && + test_commit 5 && + git checkout -b righter right && + test_commit 6 && + git checkout -b top lefter && + git merge -m "7" merge righter && + + git bundle create bundle-6.bundle lefter righter --not left right && + git bundle create bundle-7.bundle top --not lefter merge righter && + + cp bundle-*.bundle "$HTTPD_DOCUMENT_ROOT_PATH/" + ) && + git -C "$HTTPD_DOCUMENT_ROOT_PATH/fetch.git" fetch origin +refs/heads/*:refs/heads/* +' + +test_expect_success 'creationToken heuristic with failed downloads (fetch)' ' + test_when_finished rm -rf download-* trace*.txt && + + cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "bundle-1"] + uri = bundle-1.bundle + creationToken = 1 + + [bundle "bundle-2"] + uri = bundle-2.bundle + creationToken = 2 + + [bundle "bundle-3"] + uri = bundle-3.bundle + creationToken = 3 + EOF + + git clone --single-branch --branch=left \ + --bundle-uri="$HTTPD_URL/bundle-list" \ + "$HTTPD_URL/smart/fetch.git" fetch-base && + test_cmp_config -C fetch-base "$HTTPD_URL/bundle-list" fetch.bundleURI && + test_cmp_config -C fetch-base 3 fetch.bundleCreationToken && + + # Case 1: all bundles exist: successful unbundling of all bundles + cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "bundle-1"] + uri = bundle-1.bundle + creationToken = 1 + + [bundle "bundle-2"] + uri = bundle-2.bundle + creationToken = 2 + + [bundle "bundle-3"] + uri = bundle-3.bundle + creationToken = 3 + + [bundle "bundle-4"] + uri = bundle-4.bundle + creationToken = 4 + + [bundle "bundle-6"] + uri = bundle-6.bundle + creationToken = 6 + + [bundle "bundle-7"] + uri = bundle-7.bundle + creationToken = 7 + EOF + + cp -r fetch-base fetch-1 && + GIT_TRACE2_EVENT="$(pwd)/trace-fetch-1.txt" \ + git -C fetch-1 fetch origin && + test_cmp_config -C fetch-1 7 fetch.bundlecreationtoken && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + $HTTPD_URL/bundle-7.bundle + $HTTPD_URL/bundle-6.bundle + $HTTPD_URL/bundle-4.bundle + EOF + test_remote_https_urls <trace-fetch-1.txt >actual && + test_cmp expect actual && + + # Check which bundles have unbundled by refs + git -C fetch-1 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && + cat >expect <<-EOF && + refs/bundles/base + refs/bundles/left + refs/bundles/lefter + refs/bundles/merge + refs/bundles/right + refs/bundles/righter + refs/bundles/top + EOF + test_cmp expect refs && + + # Case 2: middle bundle does not exist, only bundle-4 can unbundle + cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "bundle-1"] + uri = bundle-1.bundle + creationToken = 1 + + [bundle "bundle-2"] + uri = bundle-2.bundle + creationToken = 2 + + [bundle "bundle-3"] + uri = bundle-3.bundle + creationToken = 3 + + [bundle "bundle-4"] + uri = bundle-4.bundle + creationToken = 4 + + [bundle "bundle-6"] + uri = fake.bundle + creationToken = 6 + + [bundle "bundle-7"] + uri = bundle-7.bundle + creationToken = 7 + EOF + + cp -r fetch-base fetch-2 && + GIT_TRACE2_EVENT="$(pwd)/trace-fetch-2.txt" \ + git -C fetch-2 fetch origin && + + # Since bundle-7 fails to unbundle, do not update creation token. + test_cmp_config -C fetch-2 3 fetch.bundlecreationtoken && + + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + $HTTPD_URL/bundle-7.bundle + $HTTPD_URL/fake.bundle + $HTTPD_URL/bundle-4.bundle + EOF + test_remote_https_urls <trace-fetch-2.txt >actual && + test_cmp expect actual && + + # Check which bundles have unbundled by refs + git -C fetch-2 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && + cat >expect <<-EOF && + refs/bundles/base + refs/bundles/left + refs/bundles/merge + refs/bundles/right + EOF + test_cmp expect refs && + + # Case 3: top bundle does not exist, rest unbundle fine. + cat >"$HTTPD_DOCUMENT_ROOT_PATH/bundle-list" <<-EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "bundle-1"] + uri = bundle-1.bundle + creationToken = 1 + + [bundle "bundle-2"] + uri = bundle-2.bundle + creationToken = 2 + + [bundle "bundle-3"] + uri = bundle-3.bundle + creationToken = 3 + + [bundle "bundle-4"] + uri = bundle-4.bundle + creationToken = 4 + + [bundle "bundle-6"] + uri = bundle-6.bundle + creationToken = 6 + + [bundle "bundle-7"] + uri = fake.bundle + creationToken = 7 + EOF + + cp -r fetch-base fetch-3 && + GIT_TRACE2_EVENT="$(pwd)/trace-fetch-3.txt" \ + git -C fetch-3 fetch origin && + + # As long as we have continguous successful downloads, + # we _do_ set the maximum creation token. + test_cmp_config -C fetch-3 6 fetch.bundlecreationtoken && + + # NOTE: the fetch skips bundle-4 since bundle-6 successfully + # unbundles itself and bundle-7 failed to download. + cat >expect <<-EOF && + $HTTPD_URL/bundle-list + $HTTPD_URL/fake.bundle + $HTTPD_URL/bundle-6.bundle + EOF + test_remote_https_urls <trace-fetch-3.txt >actual && + test_cmp expect actual && + + # Check which bundles have unbundled by refs + git -C fetch-3 for-each-ref --format="%(refname)" "refs/bundles/*" >refs && + cat >expect <<-EOF && + refs/bundles/base + refs/bundles/left + refs/bundles/lefter + refs/bundles/right + refs/bundles/righter + EOF + test_cmp expect refs +' + # Do not add tests here unless they use the HTTP server, as they will # not run unless the HTTP dependencies exist. diff --git a/t/t5559-http-fetch-smart-http2.sh b/t/t5559-http-fetch-smart-http2.sh new file mode 100755 index 0000000000..54aa9d3bff --- /dev/null +++ b/t/t5559-http-fetch-smart-http2.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +HTTP_PROTO=HTTP/2 +LIB_HTTPD_SSL=1 +. ./t5551-http-fetch-smart.sh diff --git a/t/t5560-http-backend-noserver.sh b/t/t5560-http-backend-noserver.sh index d30cf4f5b8..f75068de64 100755 --- a/t/t5560-http-backend-noserver.sh +++ b/t/t5560-http-backend-noserver.sh @@ -4,6 +4,7 @@ test_description='test git-http-backend-noserver' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh HTTPD_DOCUMENT_ROOT_PATH="$TRASH_DIRECTORY" diff --git a/t/t5561-http-backend.sh b/t/t5561-http-backend.sh index 9c57d84315..e1d3b8caed 100755 --- a/t/t5561-http-backend.sh +++ b/t/t5561-http-backend.sh @@ -4,6 +4,7 @@ test_description='test git-http-backend' 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 diff --git a/t/t5562-http-backend-content-length.sh b/t/t5562-http-backend-content-length.sh index b68ec22d3f..7ee9858a78 100755 --- a/t/t5562-http-backend-content-length.sh +++ b/t/t5562-http-backend-content-length.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test git-http-backend respects CONTENT_LENGTH' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_lazy_prereq GZIP 'gzip --version' diff --git a/t/t5563-simple-http-auth.sh b/t/t5563-simple-http-auth.sh new file mode 100755 index 0000000000..ccf7e54b07 --- /dev/null +++ b/t/t5563-simple-http-auth.sh @@ -0,0 +1,325 @@ +#!/bin/sh + +test_description='test http auth header and credential helper interop' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-httpd.sh + +start_httpd + +test_expect_success 'setup_credential_helper' ' + mkdir "$TRASH_DIRECTORY/bin" && + PATH=$PATH:"$TRASH_DIRECTORY/bin" && + export PATH && + + CREDENTIAL_HELPER="$TRASH_DIRECTORY/bin/git-credential-test-helper" && + write_script "$CREDENTIAL_HELPER" <<-\EOF + cmd=$1 + teefile=$cmd-query.cred + catfile=$cmd-reply.cred + sed -n -e "/^$/q" -e "p" >>$teefile + if test "$cmd" = "get" + then + cat $catfile + fi + EOF +' + +set_credential_reply () { + cat >"$TRASH_DIRECTORY/$1-reply.cred" +} + +expect_credential_query () { + cat >"$TRASH_DIRECTORY/$1-expect.cred" && + test_cmp "$TRASH_DIRECTORY/$1-expect.cred" \ + "$TRASH_DIRECTORY/$1-query.cred" +} + +per_test_cleanup () { + rm -f *.cred && + rm -f "$HTTPD_ROOT_PATH"/custom-auth.valid \ + "$HTTPD_ROOT_PATH"/custom-auth.challenge +} + +test_expect_success 'setup repository' ' + test_commit foo && + git init --bare "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + git push --mirror "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" +' + +test_expect_success 'access using basic 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 && + Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== + EOF + + cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && + 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 && + protocol=http + host=$HTTPD_DEST + wwwauth[]=Basic realm="example.com" + EOF + + expect_credential_query store <<-EOF + protocol=http + host=$HTTPD_DEST + username=alice + password=secret-passwd + EOF +' + +test_expect_success 'access using basic auth invalid credentials' ' + test_when_finished "per_test_cleanup" && + + set_credential_reply get <<-EOF && + username=baduser + password=wrong-passwd + EOF + + # Basic base64(alice:secret-passwd) + cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && + Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== + EOF + + cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && + 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 && + protocol=http + host=$HTTPD_DEST + wwwauth[]=Basic realm="example.com" + EOF + + expect_credential_query erase <<-EOF + protocol=http + host=$HTTPD_DEST + username=baduser + password=wrong-passwd + wwwauth[]=Basic realm="example.com" + EOF +' + +test_expect_success 'access using basic auth with extra challenges' ' + 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 && + 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" + EOF + + test_config_global credential.helper test-helper && + git ls-remote "$HTTPD_URL/custom_auth/repo.git" && + + expect_credential_query get <<-EOF && + 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 + protocol=http + host=$HTTPD_DEST + username=alice + password=secret-passwd + EOF +' + +test_expect_success 'access using basic auth mixed-case wwwauth header name' ' + 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 && + 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" + EOF + + test_config_global credential.helper test-helper && + git ls-remote "$HTTPD_URL/custom_auth/repo.git" && + + expect_credential_query get <<-EOF && + 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 + protocol=http + host=$HTTPD_DEST + username=alice + password=secret-passwd + EOF +' + +test_expect_success 'access using basic auth with wwwauth header continuations' ' + 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 && + 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" + EOF + + test_config_global credential.helper test-helper && + git ls-remote "$HTTPD_URL/custom_auth/repo.git" && + + expect_credential_query get <<-EOF && + 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 + protocol=http + host=$HTTPD_DEST + username=alice + password=secret-passwd + EOF +' + +test_expect_success 'access using basic auth with wwwauth header empty continuations' ' + 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 && + 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 "">$CHALLENGE && + 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 && + + test_config_global credential.helper test-helper && + git ls-remote "$HTTPD_URL/custom_auth/repo.git" && + + expect_credential_query get <<-EOF && + 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 + protocol=http + host=$HTTPD_DEST + username=alice + password=secret-passwd + EOF +' + +test_expect_success 'access using basic auth with wwwauth header mixed line-endings' ' + 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 && + 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 "">$CHALLENGE && + 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 && + + test_config_global credential.helper test-helper && + git ls-remote "$HTTPD_URL/custom_auth/repo.git" && + + expect_credential_query get <<-EOF && + protocol=http + host=$HTTPD_DEST + wwwauth[]=FooBar param1="value1" param2="value2" + wwwauth[]=Basic realm="example.com" + EOF + + expect_credential_query store <<-EOF + protocol=http + host=$HTTPD_DEST + username=alice + password=secret-passwd + EOF +' + +test_done diff --git a/t/t5564-http-proxy.sh b/t/t5564-http-proxy.sh new file mode 100755 index 0000000000..9da5134614 --- /dev/null +++ b/t/t5564-http-proxy.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +test_description="test fetching through http proxy" + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-httpd.sh + +LIB_HTTPD_PROXY=1 +start_httpd + +test_expect_success 'setup repository' ' + test_commit foo && + git init --bare "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + git push --mirror "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" +' + +setup_askpass_helper + +# sanity check that our test setup is correctly using proxy +test_expect_success 'proxy requires password' ' + test_config_global http.proxy $HTTPD_DEST && + test_must_fail git clone $HTTPD_URL/smart/repo.git 2>err && + grep "error.*407" err +' + +test_expect_success 'clone through proxy with auth' ' + test_when_finished "rm -rf clone" && + test_config_global http.proxy http://proxuser:proxpass@$HTTPD_DEST && + GIT_TRACE_CURL=$PWD/trace git clone $HTTPD_URL/smart/repo.git clone && + grep -i "Proxy-Authorization: Basic <redacted>" trace +' + +test_expect_success 'clone can prompt for proxy password' ' + test_when_finished "rm -rf clone" && + test_config_global http.proxy http://proxuser@$HTTPD_DEST && + set_askpass nobody proxpass && + GIT_TRACE_CURL=$PWD/trace git clone $HTTPD_URL/smart/repo.git clone && + expect_askpass pass proxuser +' + +test_done diff --git a/t/t5573-pull-verify-signatures.sh b/t/t5573-pull-verify-signatures.sh index a53dd8550d..1221ac0597 100755 --- a/t/t5573-pull-verify-signatures.sh +++ b/t/t5573-pull-verify-signatures.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='pull signature verification tests' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY/lib-gpg.sh" diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh index 45f0803ed4..b7d5551262 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -71,29 +71,6 @@ test_expect_success 'clone respects GIT_WORK_TREE' ' ' -test_expect_success LIBCURL 'clone warns or fails when using username:password' ' - message="URL '\''https://username:<redacted>@localhost/'\'' uses plaintext credentials" && - test_must_fail git -c transfer.credentialsInUrl=allow clone https://username:password@localhost attempt1 2>err && - ! grep "$message" err && - - test_must_fail git -c transfer.credentialsInUrl=warn clone https://username:password@localhost attempt2 2>err && - grep "warning: $message" err >warnings && - test_line_count = 2 warnings && - - test_must_fail git -c transfer.credentialsInUrl=die clone https://username:password@localhost attempt3 2>err && - grep "fatal: $message" err >warnings && - test_line_count = 1 warnings && - - test_must_fail git -c transfer.credentialsInUrl=die clone https://username:@localhost attempt3 2>err && - grep "fatal: $message" err >warnings && - test_line_count = 1 warnings -' - -test_expect_success LIBCURL 'clone does not detect username:password when it is https://username@domain:port/' ' - test_must_fail git -c transfer.credentialsInUrl=warn clone https://username@localhost:8080 attempt3 2>err && - ! grep "uses plaintext credentials" err -' - test_expect_success 'clone from hooks' ' test_create_repo r0 && @@ -795,6 +772,111 @@ test_expect_success 'reject cloning shallow repository using HTTP' ' git clone --no-reject-shallow $HTTPD_URL/smart/repo.git repo ' +test_expect_success 'auto-discover bundle URI from HTTP clone' ' + test_when_finished rm -rf trace.txt repo2 "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" && + git -C src bundle create "$HTTPD_DOCUMENT_ROOT_PATH/everything.bundle" --all && + git clone --bare --no-local src "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" && + + git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" config \ + uploadpack.advertiseBundleURIs true && + git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" config \ + bundle.version 1 && + git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" config \ + bundle.mode all && + git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" config \ + bundle.everything.uri "$HTTPD_URL/everything.bundle" && + + GIT_TRACE2_EVENT="$(pwd)/trace.txt" \ + git -c protocol.version=2 \ + -c transfer.bundleURI=true clone \ + $HTTPD_URL/smart/repo2.git repo2 && + cat >pattern <<-EOF && + "event":"child_start".*"argv":\["git-remote-https","$HTTPD_URL/everything.bundle"\] + EOF + grep -f pattern trace.txt +' + +test_expect_success 'auto-discover multiple bundles from HTTP clone' ' + test_when_finished rm -rf trace.txt repo3 "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" && + + test_commit -C src new && + git -C src bundle create "$HTTPD_DOCUMENT_ROOT_PATH/new.bundle" HEAD~1..HEAD && + git clone --bare --no-local src "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" && + + git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \ + uploadpack.advertiseBundleURIs true && + git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \ + bundle.version 1 && + git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \ + bundle.mode all && + + git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \ + bundle.everything.uri "$HTTPD_URL/everything.bundle" && + git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \ + bundle.new.uri "$HTTPD_URL/new.bundle" && + + GIT_TRACE2_EVENT="$(pwd)/trace.txt" \ + git -c protocol.version=2 \ + -c transfer.bundleURI=true clone \ + $HTTPD_URL/smart/repo3.git repo3 && + + # We should fetch _both_ bundles + cat >pattern <<-EOF && + "event":"child_start".*"argv":\["git-remote-https","$HTTPD_URL/everything.bundle"\] + EOF + grep -f pattern trace.txt && + cat >pattern <<-EOF && + "event":"child_start".*"argv":\["git-remote-https","$HTTPD_URL/new.bundle"\] + EOF + grep -f pattern trace.txt +' + +test_expect_success 'auto-discover multiple bundles from HTTP clone: creationToken heuristic' ' + test_when_finished rm -rf "$HTTPD_DOCUMENT_ROOT_PATH/repo4.git" && + test_when_finished rm -rf clone-heuristic trace*.txt && + + test_commit -C src newest && + git -C src bundle create "$HTTPD_DOCUMENT_ROOT_PATH/newest.bundle" HEAD~1..HEAD && + git clone --bare --no-local src "$HTTPD_DOCUMENT_ROOT_PATH/repo4.git" && + + cat >>"$HTTPD_DOCUMENT_ROOT_PATH/repo4.git/config" <<-EOF && + [uploadPack] + advertiseBundleURIs = true + + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "everything"] + uri = $HTTPD_URL/everything.bundle + creationtoken = 1 + + [bundle "new"] + uri = $HTTPD_URL/new.bundle + creationtoken = 2 + + [bundle "newest"] + uri = $HTTPD_URL/newest.bundle + creationtoken = 3 + EOF + + GIT_TRACE2_EVENT="$(pwd)/trace-clone.txt" \ + git -c protocol.version=2 \ + -c transfer.bundleURI=true clone \ + "$HTTPD_URL/smart/repo4.git" clone-heuristic && + + cat >expect <<-EOF && + $HTTPD_URL/newest.bundle + $HTTPD_URL/new.bundle + $HTTPD_URL/everything.bundle + EOF + + # We should fetch all bundles in the expected order. + test_remote_https_urls <trace-clone.txt >actual && + test_cmp expect actual +' + # DO NOT add non-httpd-specific tests here, because the last part of this # test script is only executed when httpd is available and enabled. diff --git a/t/t5604-clone-reference.sh b/t/t5604-clone-reference.sh index 7ccebb40c3..83e3c97861 100755 --- a/t/t5604-clone-reference.sh +++ b/t/t5604-clone-reference.sh @@ -7,6 +7,7 @@ test_description='test clone --reference' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh base_dir=$(pwd) diff --git a/t/t5605-clone-local.sh b/t/t5605-clone-local.sh index 38b850c10e..1d7b1abda1 100755 --- a/t/t5605-clone-local.sh +++ b/t/t5605-clone-local.sh @@ -15,8 +15,12 @@ test_expect_success 'preparing origin repository' ' : >file && git add . && git commit -m1 && git clone --bare . a.git && git clone --bare . x && - test "$(cd a.git && git config --bool core.bare)" = true && - test "$(cd x && git config --bool core.bare)" = true && + echo true >expect && + git -C a.git config --bool core.bare >actual && + test_cmp expect actual && + echo true >expect && + git -C x config --bool core.bare >actual && + test_cmp expect actual && git bundle create b1.bundle --all && git bundle create b2.bundle main && mkdir dir && @@ -29,7 +33,9 @@ test_expect_success 'preparing origin repository' ' test_expect_success 'local clone without .git suffix' ' git clone -l -s a b && (cd b && - test "$(git config --bool core.bare)" = false && + echo false >expect && + git config --bool core.bare >actual && + test_cmp expect actual && git fetch) ' diff --git a/t/t5606-clone-options.sh b/t/t5606-clone-options.sh index cf221e92c4..27f9f77638 100755 --- a/t/t5606-clone-options.sh +++ b/t/t5606-clone-options.sh @@ -4,6 +4,7 @@ test_description='basic clone options' 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/t5610-clone-detached.sh b/t/t5610-clone-detached.sh index a7ec21eda5..022ed3d87c 100755 --- a/t/t5610-clone-detached.sh +++ b/t/t5610-clone-detached.sh @@ -4,6 +4,7 @@ test_description='test cloning a repository with detached HEAD' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh head_is_detached() { diff --git a/t/t5611-clone-config.sh b/t/t5611-clone-config.sh index 4b3877216e..727caff443 100755 --- a/t/t5611-clone-config.sh +++ b/t/t5611-clone-config.sh @@ -4,6 +4,7 @@ test_description='tests for git clone -c key=value' 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 'clone -c sets config in cloned repo' ' diff --git a/t/t5613-info-alternate.sh b/t/t5613-info-alternate.sh index 895f46bb91..7708cbafa9 100755 --- a/t/t5613-info-alternate.sh +++ b/t/t5613-info-alternate.sh @@ -4,6 +4,8 @@ # test_description='test transitive info/alternate entries' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'preparing first repository' ' diff --git a/t/t5614-clone-submodules-shallow.sh b/t/t5614-clone-submodules-shallow.sh index 0c85ef834a..c2a2bb453e 100755 --- a/t/t5614-clone-submodules-shallow.sh +++ b/t/t5614-clone-submodules-shallow.sh @@ -2,6 +2,7 @@ test_description='Test shallow cloning of repos with submodules' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh pwd=$(pwd) diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh index 037941b95d..f519d2a87a 100755 --- a/t/t5616-partial-clone.sh +++ b/t/t5616-partial-clone.sh @@ -644,6 +644,49 @@ test_expect_success 'repack does not loosen promisor objects' ' grep "loosen_unused_packed_objects/loosened:0" trace ' +test_expect_success 'lazy-fetch in submodule succeeds' ' + # setup + test_config_global protocol.file.allow always && + + test_when_finished "rm -rf src-sub" && + git init src-sub && + git -C src-sub config uploadpack.allowfilter 1 && + git -C src-sub config uploadpack.allowanysha1inwant 1 && + + # This blob must be missing in the subsequent commit. + echo foo >src-sub/file && + git -C src-sub add file && + git -C src-sub commit -m "submodule one" && + SUB_ONE=$(git -C src-sub rev-parse HEAD) && + + echo bar >src-sub/file && + git -C src-sub add file && + git -C src-sub commit -m "submodule two" && + SUB_TWO=$(git -C src-sub rev-parse HEAD) && + + test_when_finished "rm -rf src-super" && + git init src-super && + git -C src-super config uploadpack.allowfilter 1 && + git -C src-super config uploadpack.allowanysha1inwant 1 && + git -C src-super submodule add ../src-sub src-sub && + + git -C src-super/src-sub checkout $SUB_ONE && + git -C src-super add src-sub && + git -C src-super commit -m "superproject one" && + + git -C src-super/src-sub checkout $SUB_TWO && + git -C src-super add src-sub && + git -C src-super commit -m "superproject two" && + + # the fetch + test_when_finished "rm -rf client" && + git clone --filter=blob:none --also-filter-submodules \ + --recurse-submodules "file://$(pwd)/src-super" client && + + # Trigger lazy-fetch from the superproject + git -C client restore --recurse-submodules --source=HEAD^ :/ +' + . "$TEST_DIRECTORY"/lib-httpd.sh start_httpd diff --git a/t/t5617-clone-submodules-remote.sh b/t/t5617-clone-submodules-remote.sh index 6884338249..5a4d7936a7 100755 --- a/t/t5617-clone-submodules-remote.sh +++ b/t/t5617-clone-submodules-remote.sh @@ -5,6 +5,7 @@ test_description='Test cloning repos with submodules using remote-tracking branc GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh pwd=$(pwd) diff --git a/t/t5618-alternate-refs.sh b/t/t5618-alternate-refs.sh index 3353216f09..f905db0a3f 100755 --- a/t/t5618-alternate-refs.sh +++ b/t/t5618-alternate-refs.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test handling of --alternate-refs traversal' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Avoid test_commit because we want a specific and known set of refs: diff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh index 1896f671cb..f21e5e9d33 100755 --- a/t/t5701-git-serve.sh +++ b/t/t5701-git-serve.sh @@ -13,7 +13,7 @@ test_expect_success 'test capability advertisement' ' wrong_algo sha1:sha256 wrong_algo sha256:sha1 EOF - cat >expect <<-EOF && + cat >expect.base <<-EOF && version 2 agent=git/$(git version | cut -d" " -f3) ls-refs=unborn @@ -21,8 +21,11 @@ test_expect_success 'test capability advertisement' ' server-option object-format=$(test_oid algo) object-info + EOF + cat >expect.trailer <<-EOF && 0000 EOF + cat expect.base expect.trailer >expect && GIT_TEST_SIDEBAND_ALL=0 test-tool serve-v2 \ --advertise-capabilities >out && @@ -342,4 +345,39 @@ test_expect_success 'basics of object-info' ' test_cmp expect actual ' +test_expect_success 'test capability advertisement with uploadpack.advertiseBundleURIs' ' + test_config uploadpack.advertiseBundleURIs true && + + cat >expect.extra <<-EOF && + bundle-uri + EOF + cat expect.base \ + expect.extra \ + expect.trailer >expect && + + GIT_TEST_SIDEBAND_ALL=0 test-tool serve-v2 \ + --advertise-capabilities >out && + test-tool pkt-line unpack <out >actual && + test_cmp expect actual +' + +test_expect_success 'basics of bundle-uri: dies if not enabled' ' + test-tool pkt-line pack >in <<-EOF && + command=bundle-uri + 0000 + EOF + + cat >err.expect <<-\EOF && + fatal: invalid command '"'"'bundle-uri'"'"' + EOF + + cat >expect <<-\EOF && + ERR serve: invalid command '"'"'bundle-uri'"'"' + EOF + + test_must_fail test-tool serve-v2 --stateless-rpc <in >out 2>err.actual && + test_cmp err.expect err.actual && + test_must_be_empty out +' + test_done diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh index 5d42a355a8..e4db7513f4 100755 --- a/t/t5702-protocol-v2.sh +++ b/t/t5702-protocol-v2.sh @@ -1001,7 +1001,7 @@ test_expect_success 'part of packfile response provided as URI' ' do git verify-pack --object-format=$(test_oid algo) --verbose $idx >out && { - grep "^[0-9a-f]\{16,\} " out || : + grep -E "^[0-9a-f]{16,} " out || : } >out.objectlist && if test_line_count = 1 out.objectlist then @@ -1114,7 +1114,7 @@ test_expect_success 'packfile-uri with transfer.fsckobjects fails on bad object' This commit object intentionally broken EOF - BOGUS=$(git -C "$P" hash-object -t commit -w --stdin <bogus-commit) && + BOGUS=$(git -C "$P" hash-object -t commit -w --stdin --literally <bogus-commit) && git -C "$P" branch bogus-branch "$BOGUS" && echo my-blob >"$P/my-blob" && diff --git a/t/t5705-session-id-in-capabilities.sh b/t/t5705-session-id-in-capabilities.sh index ed38c76c29..b8a722ec27 100755 --- a/t/t5705-session-id-in-capabilities.sh +++ b/t/t5705-session-id-in-capabilities.sh @@ -2,6 +2,7 @@ test_description='session ID in capabilities' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh REPO="$(pwd)/repo" diff --git a/t/t5730-protocol-v2-bundle-uri-file.sh b/t/t5730-protocol-v2-bundle-uri-file.sh new file mode 100755 index 0000000000..37bdb725bc --- /dev/null +++ b/t/t5730-protocol-v2-bundle-uri-file.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +test_description="Test bundle-uri with protocol v2 and 'file://' transport" + +TEST_NO_CREATE_REPO=1 + +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +. ./test-lib.sh + +# Test protocol v2 with 'file://' transport +# +BUNDLE_URI_PROTOCOL=file +. "$TEST_DIRECTORY"/lib-bundle-uri-protocol.sh + +test_done diff --git a/t/t5731-protocol-v2-bundle-uri-git.sh b/t/t5731-protocol-v2-bundle-uri-git.sh new file mode 100755 index 0000000000..8add1b37ab --- /dev/null +++ b/t/t5731-protocol-v2-bundle-uri-git.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +test_description="Test bundle-uri with protocol v2 and 'git://' transport" + +TEST_NO_CREATE_REPO=1 + +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +. ./test-lib.sh + +# Test protocol v2 with 'git://' transport +# +BUNDLE_URI_PROTOCOL=git +. "$TEST_DIRECTORY"/lib-bundle-uri-protocol.sh + +test_done diff --git a/t/t5732-protocol-v2-bundle-uri-http.sh b/t/t5732-protocol-v2-bundle-uri-http.sh new file mode 100755 index 0000000000..129daa0226 --- /dev/null +++ b/t/t5732-protocol-v2-bundle-uri-http.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +test_description="Test bundle-uri with protocol v2 and 'http://' transport" + +TEST_NO_CREATE_REPO=1 + +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +. ./test-lib.sh + +# Test protocol v2 with 'http://' transport +# +BUNDLE_URI_PROTOCOL=http +. "$TEST_DIRECTORY"/lib-bundle-uri-protocol.sh + +test_done diff --git a/t/t5750-bundle-uri-parse.sh b/t/t5750-bundle-uri-parse.sh new file mode 100755 index 0000000000..81bdf58b94 --- /dev/null +++ b/t/t5750-bundle-uri-parse.sh @@ -0,0 +1,290 @@ +#!/bin/sh + +test_description="Test bundle-uri bundle_uri_parse_line()" + +TEST_NO_CREATE_REPO=1 +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +test_expect_success 'bundle_uri_parse_line() just URIs' ' + cat >in <<-\EOF && + bundle.one.uri=http://example.com/bundle.bdl + bundle.two.uri=https://example.com/bundle.bdl + bundle.three.uri=file:///usr/share/git/bundle.bdl + EOF + + cat >expect <<-\EOF && + [bundle] + version = 1 + mode = all + [bundle "one"] + uri = http://example.com/bundle.bdl + [bundle "two"] + uri = https://example.com/bundle.bdl + [bundle "three"] + uri = file:///usr/share/git/bundle.bdl + EOF + + test-tool bundle-uri parse-key-values in >actual 2>err && + test_must_be_empty err && + test_cmp_config_output expect actual +' + +test_expect_success 'bundle_uri_parse_line(): relative URIs' ' + cat >in <<-\EOF && + bundle.one.uri=bundle.bdl + bundle.two.uri=../bundle.bdl + bundle.three.uri=sub/dir/bundle.bdl + EOF + + cat >expect <<-\EOF && + [bundle] + version = 1 + mode = all + [bundle "one"] + uri = <uri>/bundle.bdl + [bundle "two"] + uri = bundle.bdl + [bundle "three"] + uri = <uri>/sub/dir/bundle.bdl + EOF + + test-tool bundle-uri parse-key-values in >actual 2>err && + test_must_be_empty err && + test_cmp_config_output expect actual +' + +test_expect_success 'bundle_uri_parse_line(): relative URIs and parent paths' ' + cat >in <<-\EOF && + bundle.one.uri=bundle.bdl + bundle.two.uri=../bundle.bdl + bundle.three.uri=../../bundle.bdl + EOF + + cat >expect <<-\EOF && + [bundle] + version = 1 + mode = all + [bundle "one"] + uri = <uri>/bundle.bdl + [bundle "two"] + uri = bundle.bdl + [bundle "three"] + uri = <uri>/../bundle.bdl + EOF + + # TODO: We would prefer if parsing a bundle list would not cause + # a die() and instead would give a warning and allow the rest of + # a Git command to continue. This test_must_fail is necessary for + # now until the interface for relative_url() allows for reporting + # an error instead of die()ing. + test_must_fail test-tool bundle-uri parse-key-values in >actual 2>err && + grep "fatal: cannot strip one component off url" err +' + +test_expect_success 'bundle_uri_parse_line() parsing edge cases: empty key or value' ' + cat >in <<-\EOF && + =bogus-value + bogus-key= + EOF + + cat >err.expect <<-EOF && + error: bundle-uri: line has empty key or value + error: bad line: '\''=bogus-value'\'' + error: bundle-uri: line has empty key or value + error: bad line: '\''bogus-key='\'' + EOF + + cat >expect <<-\EOF && + [bundle] + version = 1 + mode = all + EOF + + test_must_fail test-tool bundle-uri parse-key-values in >actual 2>err && + test_cmp err.expect err && + test_cmp_config_output expect actual +' + +test_expect_success 'bundle_uri_parse_line() parsing edge cases: empty lines' ' + cat >in <<-\EOF && + bundle.one.uri=http://example.com/bundle.bdl + + bundle.two.uri=https://example.com/bundle.bdl + + bundle.three.uri=file:///usr/share/git/bundle.bdl + EOF + + cat >err.expect <<-\EOF && + error: bundle-uri: got an empty line + error: bad line: '\'''\'' + error: bundle-uri: got an empty line + error: bad line: '\'''\'' + EOF + + # We fail, but try to continue parsing regardless + cat >expect <<-\EOF && + [bundle] + version = 1 + mode = all + [bundle "one"] + uri = http://example.com/bundle.bdl + [bundle "two"] + uri = https://example.com/bundle.bdl + [bundle "three"] + uri = file:///usr/share/git/bundle.bdl + EOF + + test_must_fail test-tool bundle-uri parse-key-values in >actual 2>err && + test_cmp err.expect err && + test_cmp_config_output expect actual +' + +test_expect_success 'bundle_uri_parse_line() parsing edge cases: duplicate lines' ' + cat >in <<-\EOF && + bundle.one.uri=http://example.com/bundle.bdl + bundle.two.uri=https://example.com/bundle.bdl + bundle.one.uri=https://example.com/bundle-2.bdl + bundle.three.uri=file:///usr/share/git/bundle.bdl + EOF + + cat >err.expect <<-\EOF && + error: bad line: '\''bundle.one.uri=https://example.com/bundle-2.bdl'\'' + EOF + + # We fail, but try to continue parsing regardless + cat >expect <<-\EOF && + [bundle] + version = 1 + mode = all + [bundle "one"] + uri = http://example.com/bundle.bdl + [bundle "two"] + uri = https://example.com/bundle.bdl + [bundle "three"] + uri = file:///usr/share/git/bundle.bdl + EOF + + test_must_fail test-tool bundle-uri parse-key-values in >actual 2>err && + test_cmp err.expect err && + test_cmp_config_output expect actual +' + +test_expect_success 'parse config format: just URIs' ' + cat >expect <<-\EOF && + [bundle] + version = 1 + mode = all + [bundle "one"] + uri = http://example.com/bundle.bdl + [bundle "two"] + uri = https://example.com/bundle.bdl + [bundle "three"] + uri = file:///usr/share/git/bundle.bdl + EOF + + test-tool bundle-uri parse-config expect >actual 2>err && + test_must_be_empty err && + test_cmp_config_output expect actual +' + +test_expect_success 'parse config format: relative URIs' ' + cat >in <<-\EOF && + [bundle] + version = 1 + mode = all + [bundle "one"] + uri = bundle.bdl + [bundle "two"] + uri = ../bundle.bdl + [bundle "three"] + uri = sub/dir/bundle.bdl + EOF + + cat >expect <<-\EOF && + [bundle] + version = 1 + mode = all + [bundle "one"] + uri = <uri>/bundle.bdl + [bundle "two"] + uri = bundle.bdl + [bundle "three"] + uri = <uri>/sub/dir/bundle.bdl + EOF + + test-tool bundle-uri parse-config in >actual 2>err && + test_must_be_empty err && + test_cmp_config_output expect actual +' + +test_expect_success 'parse config format edge cases: empty key or value' ' + cat >in1 <<-\EOF && + = bogus-value + EOF + + cat >err1 <<-EOF && + error: bad config line 1 in file in1 + EOF + + cat >expect <<-\EOF && + [bundle] + version = 1 + mode = all + EOF + + test_must_fail test-tool bundle-uri parse-config in1 >actual 2>err && + test_cmp err1 err && + test_cmp_config_output expect actual && + + cat >in2 <<-\EOF && + bogus-key = + EOF + + cat >err2 <<-EOF && + error: bad config line 1 in file in2 + EOF + + test_must_fail test-tool bundle-uri parse-config in2 >actual 2>err && + test_cmp err2 err && + test_cmp_config_output expect actual +' + +test_expect_success 'parse config format: creationToken heuristic' ' + cat >expect <<-\EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + [bundle "one"] + uri = http://example.com/bundle.bdl + creationToken = 123456 + [bundle "two"] + uri = https://example.com/bundle.bdl + creationToken = 12345678901234567890 + [bundle "three"] + uri = file:///usr/share/git/bundle.bdl + creationToken = 1 + EOF + + test-tool bundle-uri parse-config expect >actual 2>err && + test_must_be_empty err && + test_cmp_config_output expect actual +' + +test_expect_success 'parse config format edge cases: creationToken heuristic' ' + cat >expect <<-\EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + [bundle "one"] + uri = http://example.com/bundle.bdl + creationToken = bogus + EOF + + test-tool bundle-uri parse-config expect >actual 2>err && + grep "could not parse bundle list key creationToken with value '\''bogus'\''" err +' + +test_done diff --git a/t/t5810-proto-disable-local.sh b/t/t5810-proto-disable-local.sh index c1ef99b85c..862610256f 100755 --- a/t/t5810-proto-disable-local.sh +++ b/t/t5810-proto-disable-local.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test disabling of local paths in clone/fetch' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY/lib-proto-disable.sh" diff --git a/t/t5813-proto-disable-ssh.sh b/t/t5813-proto-disable-ssh.sh index 3f084ee306..2e975dc70e 100755 --- a/t/t5813-proto-disable-ssh.sh +++ b/t/t5813-proto-disable-ssh.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test disabling of git-over-ssh in clone/fetch' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY/lib-proto-disable.sh" diff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh index 1f7d7dd20c..5cf2cee74d 100755 --- a/t/t6003-rev-list-topo-order.sh +++ b/t/t6003-rev-list-topo-order.sh @@ -326,19 +326,16 @@ a2 c3 EOF -# -# this test fails on --topo-order - a fix is required -# -#test_output_expect_success '--max-age=c3, --topo-order' "git rev-list --topo-order --max-age=$(commit_date c3) l5" <<EOF -#l5 -#l4 -#l3 -#a4 -#c3 -#b4 -#a3 -#a2 -#EOF +test_output_expect_success '--max-age=c3, --topo-order' "git rev-list --topo-order --max-age=$(commit_date c3) l5" <<EOF +l5 +l4 +l3 +a4 +c3 +b4 +a3 +a2 +EOF test_output_expect_success 'one specified head reachable from another a4, c3, --topo-order' "list_duplicates git rev-list --topo-order a4 c3" <<EOF EOF diff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh index bad02cf5b8..b2e422cf0f 100755 --- a/t/t6011-rev-list-with-bad-commit.sh +++ b/t/t6011-rev-list-with-bad-commit.sh @@ -2,6 +2,7 @@ test_description='git rev-list should notice bad commits' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Note: diff --git a/t/t6014-rev-list-all.sh b/t/t6014-rev-list-all.sh index c9bedd29cb..16b8bd1d09 100755 --- a/t/t6014-rev-list-all.sh +++ b/t/t6014-rev-list-all.sh @@ -2,6 +2,7 @@ test_description='--all includes detached HEADs' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh diff --git a/t/t6018-rev-list-glob.sh b/t/t6018-rev-list-glob.sh index e1abc5c2b3..67d523d405 100755 --- a/t/t6018-rev-list-glob.sh +++ b/t/t6018-rev-list-glob.sh @@ -187,6 +187,46 @@ test_expect_success 'rev-parse --exclude=ref with --remotes=glob' ' compare rev-parse "--exclude=upstream/x --remotes=upstream/*" "upstream/one upstream/two" ' +for section in fetch receive uploadpack +do + test_expect_success "rev-parse --exclude-hidden=$section with --all" ' + compare "-c transfer.hideRefs=refs/remotes/ rev-parse" "--branches --tags" "--exclude-hidden=$section --all" + ' + + test_expect_success "rev-parse --exclude-hidden=$section with --all" ' + compare "-c transfer.hideRefs=refs/heads/subspace/ rev-parse" "--exclude=refs/heads/subspace/* --all" "--exclude-hidden=$section --all" + ' + + test_expect_success "rev-parse --exclude-hidden=$section with --glob" ' + compare "-c transfer.hideRefs=refs/heads/subspace/ rev-parse" "--exclude=refs/heads/subspace/* --glob=refs/heads/*" "--exclude-hidden=$section --glob=refs/heads/*" + ' + + test_expect_success "rev-parse --exclude-hidden=$section can be passed once per pseudo-ref" ' + compare "-c transfer.hideRefs=refs/remotes/ rev-parse" "--branches --tags --branches --tags" "--exclude-hidden=$section --all --exclude-hidden=$section --all" + ' + + test_expect_success "rev-parse --exclude-hidden=$section can only be passed once per pseudo-ref" ' + echo "fatal: --exclude-hidden= passed more than once" >expected && + test_must_fail git rev-parse --exclude-hidden=$section --exclude-hidden=$section 2>err && + test_cmp expected err + ' + + for pseudoopt in branches tags remotes + do + test_expect_success "rev-parse --exclude-hidden=$section fails with --$pseudoopt" ' + echo "error: --exclude-hidden cannot be used together with --$pseudoopt" >expected && + test_must_fail git rev-parse --exclude-hidden=$section --$pseudoopt 2>err && + test_cmp expected err + ' + + test_expect_success "rev-parse --exclude-hidden=$section fails with --$pseudoopt=pattern" ' + echo "error: --exclude-hidden cannot be used together with --$pseudoopt" >expected && + test_must_fail git rev-parse --exclude-hidden=$section --$pseudoopt=pattern 2>err && + test_cmp expected err + ' + done +done + test_expect_success 'rev-list --exclude=glob with --branches=glob' ' compare rev-list "--exclude=subspace-* --branches=sub*" "subspace/one subspace/two" ' diff --git a/t/t6020-bundle-misc.sh b/t/t6020-bundle-misc.sh index 833205125a..7d40994991 100755 --- a/t/t6020-bundle-misc.sh +++ b/t/t6020-bundle-misc.sh @@ -11,6 +11,13 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME . ./test-lib.sh . "$TEST_DIRECTORY"/lib-bundle.sh +for cmd in create verify list-heads unbundle +do + test_expect_success "usage: git bundle $cmd needs an argument" ' + test_expect_code 129 git bundle $cmd + ' +done + # Create a commit or tag and set the variable with the object ID. test_commit_setvar () { notick= @@ -559,4 +566,44 @@ test_expect_success 'cloning from filtered bundle has useful error' ' grep "cannot clone from filtered bundle" err ' +test_expect_success 'verify catches unreachable, broken prerequisites' ' + test_when_finished rm -rf clone-from clone-to && + git init clone-from && + ( + cd clone-from && + git checkout -b base && + test_commit A && + git checkout -b tip && + git commit --allow-empty -m "will drop by shallow" && + git commit --allow-empty -m "will keep by shallow" && + git commit --allow-empty -m "for bundle, not clone" && + git bundle create tip.bundle tip~1..tip && + git reset --hard HEAD~1 && + git checkout base + ) && + BAD_OID=$(git -C clone-from rev-parse tip~1) && + TIP_OID=$(git -C clone-from rev-parse tip) && + git clone --depth=1 --no-single-branch \ + "file://$(pwd)/clone-from" clone-to && + ( + cd clone-to && + + # Set up broken history by removing shallow markers + git update-ref -d refs/remotes/origin/tip && + rm .git/shallow && + + # Verify should fail + test_must_fail git bundle verify \ + ../clone-from/tip.bundle 2>err && + grep "some prerequisite commits .* are not connected" err && + test_line_count = 1 err && + + # Unbundling should fail + test_must_fail git bundle unbundle \ + ../clone-from/tip.bundle 2>err && + grep "some prerequisite commits .* are not connected" err && + test_line_count = 1 err + ) +' + test_done diff --git a/t/t6021-rev-list-exclude-hidden.sh b/t/t6021-rev-list-exclude-hidden.sh new file mode 100755 index 0000000000..1a9d37e638 --- /dev/null +++ b/t/t6021-rev-list-exclude-hidden.sh @@ -0,0 +1,164 @@ +#!/bin/sh + +test_description='git rev-list --exclude-hidden test' + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +test_expect_success 'setup' ' + test_commit_bulk --id=commit --ref=refs/heads/branch 1 && + COMMIT=$(git rev-parse refs/heads/branch) && + test_commit_bulk --id=tag --ref=refs/tags/lightweight 1 && + TAG=$(git rev-parse refs/tags/lightweight) && + test_commit_bulk --id=hidden --ref=refs/hidden/commit 1 && + HIDDEN=$(git rev-parse refs/hidden/commit) && + test_commit_bulk --id=namespace --ref=refs/namespaces/namespace/refs/namespaced/commit 1 && + NAMESPACE=$(git rev-parse refs/namespaces/namespace/refs/namespaced/commit) +' + +test_expect_success 'invalid section' ' + echo "fatal: unsupported section for hidden refs: unsupported" >expected && + test_must_fail git rev-list --exclude-hidden=unsupported 2>err && + test_cmp expected err +' + +for section in fetch receive uploadpack +do + test_expect_success "$section: passed multiple times" ' + echo "fatal: --exclude-hidden= passed more than once" >expected && + test_must_fail git rev-list --exclude-hidden=$section --exclude-hidden=$section 2>err && + test_cmp expected err + ' + + test_expect_success "$section: without hiddenRefs" ' + git rev-list --exclude-hidden=$section --all >out && + cat >expected <<-EOF && + $NAMESPACE + $HIDDEN + $TAG + $COMMIT + EOF + test_cmp expected out + ' + + test_expect_success "$section: hidden via transfer.hideRefs" ' + git -c transfer.hideRefs=refs/hidden/ rev-list --exclude-hidden=$section --all >out && + cat >expected <<-EOF && + $NAMESPACE + $TAG + $COMMIT + EOF + test_cmp expected out + ' + + test_expect_success "$section: hidden via $section.hideRefs" ' + git -c $section.hideRefs=refs/hidden/ rev-list --exclude-hidden=$section --all >out && + cat >expected <<-EOF && + $NAMESPACE + $TAG + $COMMIT + EOF + test_cmp expected out + ' + + test_expect_success "$section: respects both transfer.hideRefs and $section.hideRefs" ' + git -c transfer.hideRefs=refs/tags/ -c $section.hideRefs=refs/hidden/ rev-list --exclude-hidden=$section --all >out && + cat >expected <<-EOF && + $NAMESPACE + $COMMIT + EOF + test_cmp expected out + ' + + test_expect_success "$section: negation without hidden refs marks everything as uninteresting" ' + git rev-list --all --exclude-hidden=$section --not --all >out && + test_must_be_empty out + ' + + test_expect_success "$section: negation with hidden refs marks them as interesting" ' + git -c transfer.hideRefs=refs/hidden/ rev-list --all --exclude-hidden=$section --not --all >out && + cat >expected <<-EOF && + $HIDDEN + EOF + test_cmp expected out + ' + + test_expect_success "$section: hidden refs and excludes work together" ' + git -c transfer.hideRefs=refs/hidden/ rev-list --exclude=refs/tags/* --exclude-hidden=$section --all >out && + cat >expected <<-EOF && + $NAMESPACE + $COMMIT + EOF + test_cmp expected out + ' + + test_expect_success "$section: excluded hidden refs get reset" ' + git -c transfer.hideRefs=refs/ rev-list --exclude-hidden=$section --all --all >out && + cat >expected <<-EOF && + $NAMESPACE + $HIDDEN + $TAG + $COMMIT + EOF + test_cmp expected out + ' + + test_expect_success "$section: excluded hidden refs can be used with multiple pseudo-refs" ' + git -c transfer.hideRefs=refs/ rev-list --exclude-hidden=$section --all --exclude-hidden=$section --all >out && + test_must_be_empty out + ' + + test_expect_success "$section: works with --glob" ' + git -c transfer.hideRefs=refs/hidden/ rev-list --exclude-hidden=$section --glob=refs/h* >out && + cat >expected <<-EOF && + $COMMIT + EOF + test_cmp expected out + ' + + test_expect_success "$section: operates on stripped refs by default" ' + GIT_NAMESPACE=namespace git -c transfer.hideRefs=refs/namespaced/ rev-list --exclude-hidden=$section --all >out && + cat >expected <<-EOF && + $HIDDEN + $TAG + $COMMIT + EOF + test_cmp expected out + ' + + test_expect_success "$section: does not hide namespace by default" ' + GIT_NAMESPACE=namespace git -c transfer.hideRefs=refs/namespaces/namespace/ rev-list --exclude-hidden=$section --all >out && + cat >expected <<-EOF && + $NAMESPACE + $HIDDEN + $TAG + $COMMIT + EOF + test_cmp expected out + ' + + test_expect_success "$section: can operate on unstripped refs" ' + GIT_NAMESPACE=namespace git -c transfer.hideRefs=^refs/namespaces/namespace/ rev-list --exclude-hidden=$section --all >out && + cat >expected <<-EOF && + $HIDDEN + $TAG + $COMMIT + EOF + test_cmp expected out + ' + + for pseudoopt in remotes branches tags + do + test_expect_success "$section: fails with --$pseudoopt" ' + test_must_fail git rev-list --exclude-hidden=$section --$pseudoopt 2>err && + test_i18ngrep "error: --exclude-hidden cannot be used together with --$pseudoopt" err + ' + + test_expect_success "$section: fails with --$pseudoopt=pattern" ' + test_must_fail git rev-list --exclude-hidden=$section --$pseudoopt=pattern 2>err && + test_i18ngrep "error: --exclude-hidden cannot be used together with --$pseudoopt" err + ' + done +done + +test_done diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh index 83931d482f..3ba4fdf615 100755 --- a/t/t6030-bisect-porcelain.sh +++ b/t/t6030-bisect-porcelain.sh @@ -34,6 +34,36 @@ HASH2= HASH3= HASH4= +test_bisect_usage () { + local code="$1" && + shift && + cat >expect && + test_expect_code $code "$@" >out 2>actual && + test_must_be_empty out && + test_cmp expect actual +} + +test_expect_success 'bisect usage' " + test_bisect_usage 1 git bisect reset extra1 extra2 <<-\EOF && + error: 'git bisect reset' requires either no argument or a commit + EOF + test_bisect_usage 1 git bisect terms extra1 extra2 <<-\EOF && + error: 'git bisect terms' requires 0 or 1 argument + EOF + test_bisect_usage 1 git bisect next extra1 <<-\EOF && + error: 'git bisect next' requires 0 arguments + EOF + test_bisect_usage 1 git bisect log extra1 <<-\EOF && + error: We are not bisecting. + EOF + test_bisect_usage 1 git bisect replay <<-\EOF && + error: no logfile given + EOF + test_bisect_usage 1 git bisect run <<-\EOF + error: 'git bisect run' failed: no command provided. + EOF +" + test_expect_success 'set up basic repo with 1 file (hello) and 4 commits' ' add_line_into_file "1: Hello World" hello && HASH1=$(git rev-parse --verify HEAD) && @@ -252,6 +282,124 @@ test_expect_success 'bisect skip: with commit both bad and skipped' ' grep $HASH4 my_bisect_log.txt ' +test_bisect_run_args () { + test_when_finished "rm -f run.sh actual" && + >actual && + cat >expect.args && + cat <&6 >expect.out && + cat <&7 >expect.err && + write_script run.sh <<-\EOF && + while test $# != 0 + do + echo "<$1>" && + shift + done >actual.args + EOF + + test_when_finished "git bisect reset" && + git bisect start && + git bisect good $HASH1 && + git bisect bad $HASH4 && + git bisect run ./run.sh $@ >actual.out.raw 2>actual.err && + # Prune just the log output + sed -n \ + -e '/^Author:/d' \ + -e '/^Date:/d' \ + -e '/^$/d' \ + -e '/^commit /d' \ + -e '/^ /d' \ + -e 'p' \ + <actual.out.raw >actual.out && + test_cmp expect.out actual.out && + test_cmp expect.err actual.err && + test_cmp expect.args actual.args +} + +test_expect_success 'git bisect run: args, stdout and stderr with no arguments' " + test_bisect_run_args <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR' + EOF_ARGS + running './run.sh' + $HASH4 is the first bad commit + bisect found first bad commit + EOF_OUT + EOF_ERR +" + +test_expect_success 'git bisect run: args, stdout and stderr: "--" argument' " + test_bisect_run_args -- <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR' + <--> + EOF_ARGS + running './run.sh' '--' + $HASH4 is the first bad commit + bisect found first bad commit + EOF_OUT + EOF_ERR +" + +test_expect_success 'git bisect run: args, stdout and stderr: "--log foo --no-log bar" arguments' " + test_bisect_run_args --log foo --no-log bar <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR' + <--log> + <foo> + <--no-log> + <bar> + EOF_ARGS + running './run.sh' '--log' 'foo' '--no-log' 'bar' + $HASH4 is the first bad commit + bisect found first bad commit + EOF_OUT + EOF_ERR +" + +test_expect_success 'git bisect run: args, stdout and stderr: "--bisect-start" argument' " + test_bisect_run_args --bisect-start <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR' + <--bisect-start> + EOF_ARGS + running './run.sh' '--bisect-start' + $HASH4 is the first bad commit + bisect found first bad commit + EOF_OUT + EOF_ERR +" + +test_expect_success 'git bisect run: negative exit code' " + write_script fail.sh <<-'EOF' && + exit 255 + EOF + cat <<-'EOF' >expect && + bisect run failed: exit code -1 from './fail.sh' is < 0 or >= 128 + EOF + test_when_finished 'git bisect reset' && + git bisect start && + git bisect good $HASH1 && + git bisect bad $HASH4 && + ! git bisect run ./fail.sh 2>err && + sed -En 's/.*(bisect.*code) (-?[0-9]+) (from.*)/\1 -1 \3/p' err >actual && + test_cmp expect actual +" + +test_expect_success 'git bisect run: unable to verify on good' " + write_script fail.sh <<-'EOF' && + head=\$(git rev-parse --verify HEAD) + good=\$(git rev-parse --verify $HASH1) + if test "\$head" = "\$good" + then + exit 255 + else + exit 127 + fi + EOF + cat <<-'EOF' >expect && + unable to verify './fail.sh' on good revision + EOF + test_when_finished 'git bisect reset' && + git bisect start && + git bisect good $HASH1 && + git bisect bad $HASH4 && + ! git bisect run ./fail.sh 2>err && + sed -n 's/.*\(unable to verify.*\)/\1/p' err >actual && + test_cmp expect actual +" + # We want to automatically find the commit that # added "Another" into hello. test_expect_success '"git bisect run" simple case' ' @@ -266,6 +414,16 @@ test_expect_success '"git bisect run" simple case' ' git bisect reset ' +# We want to make sure no arguments has been eaten +test_expect_success '"git bisect run" simple case' ' + git bisect start && + git bisect good $HASH1 && + git bisect bad $HASH4 && + git bisect run printf "%s %s\n" reset --bisect-skip >my_bisect_log.txt && + grep -e "reset --bisect-skip" my_bisect_log.txt && + git bisect reset +' + # We want to automatically find the commit that # added "Ciao" into hello. test_expect_success '"git bisect run" with more complex "git bisect start"' ' @@ -900,6 +1058,16 @@ test_expect_success 'bisect start with one term1 and term2' ' git bisect reset ' +test_expect_success 'bogus command does not start bisect' ' + git bisect reset && + test_must_fail git bisect --bisect-terms 1 2 2>out && + ! grep "You need to start" out && + test_must_fail git bisect --bisect-terms 2>out && + ! grep "You need to start" out && + grep "git bisect.*visualize" out && + git bisect reset +' + test_expect_success 'bisect replay with term1 and term2' ' git bisect replay log_to_replay.txt >bisect_result && grep "$HASH2 is the first term1 commit" bisect_result && @@ -990,7 +1158,6 @@ test_expect_success 'git bisect reset cleans bisection state properly' ' test_path_is_missing ".git/BISECT_LOG" && test_path_is_missing ".git/BISECT_RUN" && test_path_is_missing ".git/BISECT_TERMS" && - test_path_is_missing ".git/head-name" && test_path_is_missing ".git/BISECT_HEAD" && test_path_is_missing ".git/BISECT_START" ' @@ -1053,4 +1220,14 @@ test_expect_success 'bisect state output with bad commit' ' grep -F "waiting for good commit(s), bad commit known" output ' +test_expect_success 'verify correct error message' ' + git bisect reset && + git bisect start $HASH4 $HASH1 && + write_script test_script.sh <<-\EOF && + rm .git/BISECT* + EOF + test_must_fail git bisect run ./test_script.sh 2>error && + grep "git bisect good.*exited with error code" error +' + test_done diff --git a/t/t6060-merge-index.sh b/t/t6060-merge-index.sh index ed449abe55..1a8b64cce1 100755 --- a/t/t6060-merge-index.sh +++ b/t/t6060-merge-index.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='basic git merge-index / git-merge-one-file tests' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup diverging branches' ' diff --git a/t/t6102-rev-list-unexpected-objects.sh b/t/t6102-rev-list-unexpected-objects.sh index 4a9a4436e2..9350b5fd2c 100755 --- a/t/t6102-rev-list-unexpected-objects.sh +++ b/t/t6102-rev-list-unexpected-objects.sh @@ -121,8 +121,8 @@ test_expect_success 'setup unexpected non-blob tag' ' tag=$(git hash-object -w --literally -t tag broken-tag) ' -test_expect_success 'TODO (should fail!): traverse unexpected non-blob tag (lone)' ' - git rev-list --objects $tag +test_expect_success 'traverse unexpected non-blob tag (lone)' ' + test_must_fail git rev-list --objects $tag ' test_expect_success 'traverse unexpected non-blob tag (seen)' ' diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh index 9a35e783a7..c9afcef201 100755 --- a/t/t6120-describe.sh +++ b/t/t6120-describe.sh @@ -657,4 +657,10 @@ test_expect_success 'setup: describe commits with disjoint bases 2' ' check_describe -C disjoint2 "B-3-gHASH" HEAD +test_expect_success 'setup misleading taggerdates' ' + GIT_COMMITTER_DATE="2006-12-12 12:31" git tag -a -m "another tag" newer-tag-older-commit unique-file~1 +' + +check_describe newer-tag-older-commit~1 --contains unique-file~2 + test_done diff --git a/t/t6132-pathspec-exclude.sh b/t/t6132-pathspec-exclude.sh index cada952f9a..9fdafeb1e9 100755 --- a/t/t6132-pathspec-exclude.sh +++ b/t/t6132-pathspec-exclude.sh @@ -293,11 +293,7 @@ test_expect_success 'add with all negative' ' test_cmp expect actual ' -test_lazy_prereq ADD_I_USE_BUILTIN_OR_PERL ' - test_have_prereq ADD_I_USE_BUILTIN || test_have_prereq PERL -' - -test_expect_success ADD_I_USE_BUILTIN_OR_PERL 'add -p with all negative' ' +test_expect_success 'add -p with all negative' ' H=$(git rev-parse HEAD) && git reset --hard $H && git clean -f && diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh index dcaab7265f..c466fd989f 100755 --- a/t/t6300-for-each-ref.sh +++ b/t/t6300-for-each-ref.sh @@ -606,7 +606,7 @@ test_expect_success 'create tag without tagger' ' git tag -a -m "Broken tag" taggerless && git tag -f taggerless $(git cat-file tag taggerless | sed -e "/^tagger /d" | - git hash-object --stdin -w -t tag) + git hash-object --literally --stdin -w -t tag) ' test_atom refs/tags/taggerless type 'commit' @@ -1242,6 +1242,24 @@ test_expect_success 'basic atom: rest must fail' ' test_must_fail git for-each-ref --format="%(rest)" refs/heads/main ' +test_expect_success 'HEAD atom does not take arguments' ' + test_must_fail git for-each-ref --format="%(HEAD:foo)" 2>err && + echo "fatal: %(HEAD) does not take arguments" >expect && + test_cmp expect err +' + +test_expect_success 'subject atom rejects unknown arguments' ' + test_must_fail git for-each-ref --format="%(subject:foo)" 2>err && + echo "fatal: unrecognized %(subject) argument: foo" >expect && + test_cmp expect err +' + +test_expect_success 'refname atom rejects unknown arguments' ' + test_must_fail git for-each-ref --format="%(refname:foo)" 2>err && + echo "fatal: unrecognized %(refname) argument: foo" >expect && + test_cmp expect err +' + test_expect_success 'trailer parsing not fooled by --- line' ' git commit --allow-empty -F - <<-\EOF && this is the subject @@ -1406,4 +1424,44 @@ test_expect_success 'for-each-ref reports broken tags' ' refs/tags/broken-tag-* ' +test_expect_success 'set up tag with signature and no blank lines' ' + git tag -F - fake-sig-no-blanks <<-\EOF + this is the subject + -----BEGIN PGP SIGNATURE----- + not a real signature, but we just care about the + subject/body parsing. It is important here that + there are no blank lines in the signature. + -----END PGP SIGNATURE----- + EOF +' + +test_atom refs/tags/fake-sig-no-blanks contents:subject 'this is the subject' +test_atom refs/tags/fake-sig-no-blanks contents:body '' +test_atom refs/tags/fake-sig-no-blanks contents:signature "$sig" + +test_expect_success 'set up tag with CRLF signature' ' + append_cr <<-\EOF | + this is the subject + -----BEGIN PGP SIGNATURE----- + + not a real signature, but we just care about + the subject/body parsing. It is important here + that there is a blank line separating this + from the signature header. + -----END PGP SIGNATURE----- + EOF + git tag -F - --cleanup=verbatim fake-sig-crlf +' + +test_atom refs/tags/fake-sig-crlf contents:subject 'this is the subject' +test_atom refs/tags/fake-sig-crlf contents:body '' + +# CRLF is retained in the signature, so we have to pass our expected value +# through append_cr. But test_atom requires a shell string, which means command +# substitution, and the shell will strip trailing newlines from the output of +# the substitution. Hack around it by adding and then removing a dummy line. +sig_crlf="$(printf "%s" "$sig" | append_cr; echo dummy)" +sig_crlf=${sig_crlf%dummy} +test_atom refs/tags/fake-sig-crlf contents:signature "$sig_crlf" + test_done diff --git a/t/t6301-for-each-ref-errors.sh b/t/t6301-for-each-ref-errors.sh index 40edf9dab5..bfda1f46ad 100755 --- a/t/t6301-for-each-ref-errors.sh +++ b/t/t6301-for-each-ref-errors.sh @@ -2,6 +2,7 @@ test_description='for-each-ref errors for broken refs' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh ZEROS=$ZERO_OID diff --git a/t/t6401-merge-criss-cross.sh b/t/t6401-merge-criss-cross.sh index 9d5e992878..1962310408 100755 --- a/t/t6401-merge-criss-cross.sh +++ b/t/t6401-merge-criss-cross.sh @@ -8,6 +8,8 @@ test_description='Test criss-cross merge' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'prepare repository' ' diff --git a/t/t6406-merge-attr.sh b/t/t6406-merge-attr.sh index 8650a88c40..5e4e4dd6d9 100755 --- a/t/t6406-merge-attr.sh +++ b/t/t6406-merge-attr.sh @@ -8,6 +8,7 @@ test_description='per path merge controlled by merge attribute' 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/t6407-merge-binary.sh b/t/t6407-merge-binary.sh index e8a28717ce..0753fc95f4 100755 --- a/t/t6407-merge-binary.sh +++ b/t/t6407-merge-binary.sh @@ -5,6 +5,7 @@ test_description='ask merge-recursive to merge binary 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 ' diff --git a/t/t6415-merge-dir-to-symlink.sh b/t/t6415-merge-dir-to-symlink.sh index 2655e295f5..ae00492c76 100755 --- a/t/t6415-merge-dir-to-symlink.sh +++ b/t/t6415-merge-dir-to-symlink.sh @@ -4,6 +4,7 @@ test_description='merging when a directory was replaced with a symlink' 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 'create a commit where dir a/b changed to symlink' ' diff --git a/t/t6421-merge-partial-clone.sh b/t/t6421-merge-partial-clone.sh index 5413e5dd9d..711b709e75 100755 --- a/t/t6421-merge-partial-clone.sh +++ b/t/t6421-merge-partial-clone.sh @@ -155,7 +155,7 @@ test_setup_repo () { # Commit A: # (Rename leap->jump, rename basename/ -> basename/subdir/, rename dir/ # -> folder/, move e into newsubdir, add newfile.rs, remove f, modify -# both both Makefiles and jumps) +# both Makefiles and jumps) # general/{jump1_A, jump2_A} # basename/subdir/{numbers_A, sequence_A, values_A} # folder/subdir/{a,b,c,d,Makefile_TOP_A} @@ -343,7 +343,7 @@ test_expect_merge_algorithm failure success 'Objects downloaded when a directory # Commit A: # (Rename leap->jump, rename basename/ -> basename/subdir/, rename dir/ # -> folder/, move e into newsubdir, add newfile.rs, remove f, modify -# both both Makefiles and jumps) +# both Makefiles and jumps) # general/{jump1_A, jump2_A} # basename/subdir/{numbers_A, sequence_A, values_A} # folder/subdir/{a,b,c,d,Makefile_TOP_A} diff --git a/t/t6422-merge-rename-corner-cases.sh b/t/t6422-merge-rename-corner-cases.sh index 346253c7c8..076b6a74d5 100755 --- a/t/t6422-merge-rename-corner-cases.sh +++ b/t/t6422-merge-rename-corner-cases.sh @@ -1159,7 +1159,6 @@ test_conflicts_with_adds_and_renames() { # 4) There should not be any three~* files in the working # tree test_setup_collision_conflict () { - #test_expect_success "setup simple $sideL/$sideR conflict" ' git init simple_${sideL}_${sideR} && ( cd simple_${sideL}_${sideR} && @@ -1236,7 +1235,6 @@ test_conflicts_with_adds_and_renames() { fi && test_tick && git commit -m R ) - #' } test_expect_success "check simple $sideL/$sideR conflict" ' diff --git a/t/t6423-merge-rename-directories.sh b/t/t6423-merge-rename-directories.sh index a4941878fe..944de75b80 100755 --- a/t/t6423-merge-rename-directories.sh +++ b/t/t6423-merge-rename-directories.sh @@ -5304,6 +5304,62 @@ test_expect_merge_algorithm failure success '12l (A into B): Rename into each ot ) ' +# Testcase 12m, Directory rename, plus change of parent dir to symlink +# Commit O: dir/subdir/file +# Commit A: renamed-dir/subdir/file +# Commit B: dir/subdir +# In words: +# A: dir/subdir/ -> renamed-dir/subdir +# B: delete dir/subdir/file, add dir/subdir as symlink +# +# Expected: CONFLICT (rename/delete): renamed-dir/subdir/file, +# CONFLICT (file location): renamed-dir/subdir vs. dir/subdir +# CONFLICT (directory/file): renamed-dir/subdir symlink has +# renamed-dir/subdir in the way + +test_setup_12m () { + git init 12m && + ( + cd 12m && + + mkdir -p dir/subdir && + echo 1 >dir/subdir/file && + git add . && + git commit -m "O" && + + git branch O && + git branch A && + git branch B && + + git switch A && + git mv dir/ renamed-dir/ && + git add . && + git commit -m "A" && + + git switch B && + git rm dir/subdir/file && + mkdir dir && + ln -s /dev/null dir/subdir && + git add . && + git commit -m "B" + ) +} + +test_expect_merge_algorithm failure success '12m: Change parent of renamed-dir to symlink on other side' ' + test_setup_12m && + ( + cd 12m && + + git checkout -q A^0 && + + test_must_fail git -c merge.directoryRenames=conflict merge -s recursive B^0 && + + test_stdout_line_count = 3 git ls-files -s && + test_stdout_line_count = 2 ls -1 renamed-dir && + test_path_is_missing dir + ) +' + ########################################################################### # SECTION 13: Checking informational and conflict messages # diff --git a/t/t6426-merge-skip-unneeded-updates.sh b/t/t6426-merge-skip-unneeded-updates.sh index 2bb8e7f09b..fd21c1a486 100755 --- a/t/t6426-merge-skip-unneeded-updates.sh +++ b/t/t6426-merge-skip-unneeded-updates.sh @@ -378,42 +378,30 @@ test_expect_success '2c: Modify b & add c VS rename b->c' ' test_i18ngrep "CONFLICT (.*/add):" out && test_must_be_empty err && - # Make sure c WAS updated + git ls-files -s >index_files && + test_line_count = 2 index_files && + + # Ensure b was removed + test_path_is_missing b && + + # Make sure c WAS updated... test-tool chmtime --get c >new-mtime && - test $(cat old-mtime) -lt $(cat new-mtime) - - # FIXME: rename/add conflicts are horribly broken right now; - # when I get back to my patch series fixing it and - # rename/rename(2to1) conflicts to bring them in line with - # how add/add conflicts behave, then checks like the below - # could be added. But that patch series is waiting until - # the rename-directory-detection series lands, which this - # is part of. And in the mean time, I do not want to further - # enforce broken behavior. So for now, the main test is the - # one above that err is an empty file. - - #git ls-files -s >index_files && - #test_line_count = 2 index_files && - - #git rev-parse >actual :2:c :3:c && - #git rev-parse >expect A:b A:c && - #test_cmp expect actual && - - #git cat-file -p A:b >>merged && - #git cat-file -p A:c >>merge-me && - #>empty && - #test_must_fail git merge-file \ - # -L "Temporary merge branch 1" \ - # -L "" \ - # -L "Temporary merge branch 2" \ - # merged empty merge-me && - #sed -e "s/^\([<=>]\)/\1\1\1/" merged >merged-internal && - - #git hash-object c >actual && - #git hash-object merged-internal >expect && - #test_cmp expect actual && - - #test_path_is_missing b + test $(cat old-mtime) -lt $(cat new-mtime) && + + # ...and has correct index entries and working tree contents + git rev-parse >actual :2:c :3:c && + git rev-parse >expect A:c A:b && + test_cmp expect actual && + + git cat-file -p A:b >>merge-me && + git cat-file -p A:c >>merged && + >empty && + test_must_fail git merge-file \ + -L "HEAD" \ + -L "" \ + -L "B^0" \ + merged empty merge-me && + test_cmp merged c ) ' diff --git a/t/t6435-merge-sparse.sh b/t/t6435-merge-sparse.sh index fde4aa3cd1..78628fb248 100755 --- a/t/t6435-merge-sparse.sh +++ b/t/t6435-merge-sparse.sh @@ -3,6 +3,7 @@ test_description='merge with sparse files' TEST_CREATE_REPO_NO_TEMPLATE=1 +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # test_file $filename $content diff --git a/t/t6439-merge-co-error-msgs.sh b/t/t6439-merge-co-error-msgs.sh index 52cf0c8769..0cbec57cda 100755 --- a/t/t6439-merge-co-error-msgs.sh +++ b/t/t6439-merge-co-error-msgs.sh @@ -5,6 +5,7 @@ test_description='unpack-trees error messages' 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/t6500-gc.sh b/t/t6500-gc.sh index cd6c53360d..d9acb63951 100755 --- a/t/t6500-gc.sh +++ b/t/t6500-gc.sh @@ -202,6 +202,102 @@ test_expect_success 'one of gc.reflogExpire{Unreachable,}=never does not skip "e grep -E "^trace: (built-in|exec|run_command): git reflog expire --" trace.out ' +prepare_cruft_history () { + test_commit base && + + test_commit --no-tag foo && + test_commit --no-tag bar && + git reset HEAD^^ +} + +assert_cruft_packs () { + find .git/objects/pack -name "*.mtimes" >mtimes && + sed -e 's/\.mtimes$/\.pack/g' mtimes >packs && + + test_file_not_empty packs && + while read pack + do + test_path_is_file "$pack" || return 1 + done <packs +} + +assert_no_cruft_packs () { + find .git/objects/pack -name "*.mtimes" >mtimes && + test_must_be_empty mtimes +} + +test_expect_success 'gc --cruft generates a cruft pack' ' + test_when_finished "rm -fr crufts" && + git init crufts && + ( + cd crufts && + + prepare_cruft_history && + git gc --cruft && + assert_cruft_packs + ) +' + +test_expect_success 'gc.cruftPacks=true generates a cruft pack' ' + test_when_finished "rm -fr crufts" && + git init crufts && + ( + cd crufts && + + prepare_cruft_history && + git -c gc.cruftPacks=true gc && + assert_cruft_packs + ) +' + +test_expect_success 'feature.experimental=true generates a cruft pack' ' + git init crufts && + test_when_finished "rm -fr crufts" && + ( + cd crufts && + + prepare_cruft_history && + git -c feature.experimental=true gc && + assert_cruft_packs + ) +' + +test_expect_success 'feature.experimental=false allows explicit cruft packs' ' + git init crufts && + test_when_finished "rm -fr crufts" && + ( + cd crufts && + + prepare_cruft_history && + git -c gc.cruftPacks=true -c feature.experimental=false gc && + assert_cruft_packs + ) +' + +test_expect_success 'feature.experimental=true can be overridden' ' + git init crufts && + test_when_finished "rm -fr crufts" && + ( + cd crufts && + + prepare_cruft_history && + git -c feature.expiremental=true -c gc.cruftPacks=false gc && + assert_no_cruft_packs + ) +' + +test_expect_success 'feature.experimental=false avoids cruft packs by default' ' + git init crufts && + test_when_finished "rm -fr crufts" && + ( + cd crufts && + + prepare_cruft_history && + git -c feature.experimental=false gc && + assert_no_cruft_packs + ) +' + run_and_wait_for_auto_gc () { # We read stdout from gc for the side effect of waiting until the # background gc process exits, closing its fd 9. Furthermore, the diff --git a/t/t6501-freshen-objects.sh b/t/t6501-freshen-objects.sh index 10662456ae..3968b47ed5 100755 --- a/t/t6501-freshen-objects.sh +++ b/t/t6501-freshen-objects.sh @@ -28,6 +28,7 @@ test_description='check pruning of dependent objects' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # We care about reachability, so we do not want to use diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh index 8c37bceb33..d72cef8826 100755 --- a/t/t7001-mv.sh +++ b/t/t7001-mv.sh @@ -60,8 +60,8 @@ test_expect_success 'checking the commit' ' test_expect_success 'mv --dry-run does not move file' ' git mv -n path0/COPYING MOVED && - test -f path0/COPYING && - test ! -f MOVED + test_path_is_file path0/COPYING && + test_path_is_missing MOVED ' test_expect_success 'checking -k on non-existing file' ' @@ -71,25 +71,25 @@ test_expect_success 'checking -k on non-existing file' ' test_expect_success 'checking -k on untracked file' ' >untracked1 && git mv -k untracked1 path0 && - test -f untracked1 && - test ! -f path0/untracked1 + test_path_is_file untracked1 && + test_path_is_missing path0/untracked1 ' test_expect_success 'checking -k on multiple untracked files' ' >untracked2 && git mv -k untracked1 untracked2 path0 && - test -f untracked1 && - test -f untracked2 && - test ! -f path0/untracked1 && - test ! -f path0/untracked2 + test_path_is_file untracked1 && + test_path_is_file untracked2 && + test_path_is_missing path0/untracked1 && + test_path_is_missing path0/untracked2 ' test_expect_success 'checking -f on untracked file with existing target' ' >path0/untracked1 && test_must_fail git mv -f untracked1 path0 && - test ! -f .git/index.lock && - test -f untracked1 && - test -f path0/untracked1 + test_path_is_missing .git/index.lock && + test_path_is_file untracked1 && + test_path_is_file path0/untracked1 ' # clean up the mess in case bad things happen @@ -215,8 +215,8 @@ test_expect_success 'absolute pathname' ' git add sub/file && git mv sub "$(pwd)/in" && - ! test -d sub && - test -d in && + test_path_is_missing sub && + test_path_is_dir in && git ls-files --error-unmatch in/file ) ' @@ -234,8 +234,8 @@ test_expect_success 'absolute pathname outside should fail' ' git add sub/file && test_must_fail git mv sub "$out/out" && - test -d sub && - ! test -d ../in && + test_path_is_dir sub && + test_path_is_missing ../in && git ls-files --error-unmatch sub/file ) ' @@ -295,8 +295,8 @@ test_expect_success 'git mv should overwrite symlink to a file' ' git add moved && test_must_fail git mv moved symlink && git mv -f moved symlink && - ! test -e moved && - test -f symlink && + test_path_is_missing moved && + test_path_is_file symlink && test "$(cat symlink)" = 1 && git update-index --refresh && git diff-files --quiet @@ -312,13 +312,13 @@ test_expect_success 'git mv should overwrite file with a symlink' ' git add moved && test_must_fail git mv symlink moved && git mv -f symlink moved && - ! test -e symlink && + test_path_is_missing symlink && git update-index --refresh && git diff-files --quiet ' test_expect_success SYMLINKS 'check moved symlink' ' - test -h moved + test_path_is_symlink moved ' rm -f moved symlink @@ -352,7 +352,7 @@ test_expect_success 'git mv moves a submodule with a .git directory and no .gitm ) && mkdir mod && git mv sub mod/sub && - ! test -e sub && + test_path_is_missing sub && test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" && git -C mod/sub status && git update-index --refresh && @@ -372,7 +372,7 @@ test_expect_success 'git mv moves a submodule with a .git directory and .gitmodu ) && mkdir mod && git mv sub mod/sub && - ! test -e sub && + test_path_is_missing sub && test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" && git -C mod/sub status && echo mod/sub >expected && @@ -389,7 +389,7 @@ test_expect_success 'git mv moves a submodule with gitfile' ' entry="$(git ls-files --stage sub | cut -f 1)" && mkdir mod && git -C mod mv ../sub/ . && - ! test -e sub && + test_path_is_missing sub && test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" && git -C mod/sub status && echo mod/sub >expected && @@ -408,7 +408,7 @@ test_expect_success 'mv does not complain when no .gitmodules file is found' ' mkdir mod && git mv sub mod/sub 2>actual.err && test_must_be_empty actual.err && - ! test -e sub && + test_path_is_missing sub && test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" && git -C mod/sub status && git update-index --refresh && @@ -423,13 +423,13 @@ test_expect_success 'mv will error out on a modified .gitmodules file unless sta entry="$(git ls-files --stage sub | cut -f 1)" && mkdir mod && test_must_fail git mv sub mod/sub 2>actual.err && - test -s actual.err && - test -e sub && + test_file_not_empty actual.err && + test_path_exists sub && git diff-files --quiet -- sub && git add .gitmodules && git mv sub mod/sub 2>actual.err && test_must_be_empty actual.err && - ! test -e sub && + test_path_is_missing sub && test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" && git -C mod/sub status && git update-index --refresh && @@ -447,7 +447,7 @@ test_expect_success 'mv issues a warning when section is not found in .gitmodule mkdir mod && git mv sub mod/sub 2>actual.err && test_cmp expect.err actual.err && - ! test -e sub && + test_path_is_missing sub && test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" && git -C mod/sub status && git update-index --refresh && @@ -460,7 +460,7 @@ test_expect_success 'mv --dry-run does not touch the submodule or .gitmodules' ' git submodule update && mkdir mod && git mv -n sub mod/sub 2>actual.err && - test -f sub/.git && + test_path_is_file sub/.git && git diff-index --exit-code HEAD && git update-index --refresh && git diff-files --quiet -- sub .gitmodules @@ -474,10 +474,10 @@ test_expect_success 'checking out a commit before submodule moved needs manual u git status -s sub2 >actual && echo "?? sub2/" >expected && test_cmp expected actual && - ! test -f sub/.git && - test -f sub2/.git && + test_path_is_missing sub/.git && + test_path_is_file sub2/.git && git submodule update && - test -f sub/.git && + test_path_is_file sub/.git && rm -rf sub2 && git diff-index --exit-code HEAD && git update-index --refresh && diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh index e18a218952..f6aebe92ff 100755 --- a/t/t7003-filter-branch.sh +++ b/t/t7003-filter-branch.sh @@ -49,7 +49,7 @@ test_expect_success 'result is really identical' ' test_expect_success 'rewrite bare repository identically' ' (git config core.bare true && cd .git && git filter-branch branch > filter-output 2>&1 && - ! fgrep fatal filter-output) + ! grep fatal filter-output) ' git config core.bare false test_expect_success 'result is really identical' ' @@ -506,7 +506,7 @@ test_expect_success 'rewrite repository including refs that point at non-commit git tag -a -m "tag to a tree" treetag $new_tree && git reset --hard HEAD && git filter-branch -f -- --all >filter-output 2>&1 && - ! fgrep fatal filter-output + ! grep fatal filter-output ' test_expect_success 'filter-branch handles ref deletion' ' diff --git a/t/t7030-verify-tag.sh b/t/t7030-verify-tag.sh index 10faa64515..6f526c37c2 100755 --- a/t/t7030-verify-tag.sh +++ b/t/t7030-verify-tag.sh @@ -115,7 +115,7 @@ test_expect_success GPGSM 'verify and show signatures x509 with high minTrustLev test_expect_success GPG 'detect fudged signature' ' git cat-file tag seventh-signed >raw && - sed -e "/^tag / s/seventh/7th forged/" raw >forged1 && + sed -e "/^tag / s/seventh/7th-forged/" raw >forged1 && git hash-object -w -t tag forged1 >forged1.tag && test_must_fail git verify-tag $(cat forged1.tag) 2>actual1 && grep "BAD signature from" actual1 && diff --git a/t/t7031-verify-tag-signed-ssh.sh b/t/t7031-verify-tag-signed-ssh.sh index 1cb36b9ab8..20913b3713 100755 --- a/t/t7031-verify-tag-signed-ssh.sh +++ b/t/t7031-verify-tag-signed-ssh.sh @@ -125,7 +125,7 @@ test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'verify-tag failes with tag date ou test_expect_success GPGSSH 'detect fudged ssh signature' ' test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && git cat-file tag seventh-signed >raw && - sed -e "/^tag / s/seventh/7th forged/" raw >forged1 && + sed -e "/^tag / s/seventh/7th-forged/" raw >forged1 && git hash-object -w -t tag forged1 >forged1.tag && test_must_fail git verify-tag $(cat forged1.tag) 2>actual1 && grep "${GPGSSH_BAD_SIGNATURE}" actual1 && @@ -200,4 +200,14 @@ test_expect_success GPGSSH 'verifying a forged tag with --format should fail sil test_must_be_empty actual-forged ' +test_expect_success GPGSSH 'rev-list --format=%G' ' + test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && + git rev-list -1 --format="%G? %H" sixth-signed >actual && + cat >expect <<-EOF && + commit $(git rev-parse sixth-signed^0) + G $(git rev-parse sixth-signed^0) + EOF + test_cmp expect actual +' + test_done diff --git a/t/t7103-reset-bare.sh b/t/t7103-reset-bare.sh index a60153f9f3..18bbd9975e 100755 --- a/t/t7103-reset-bare.sh +++ b/t/t7103-reset-bare.sh @@ -63,7 +63,7 @@ test_expect_success '"mixed" reset is not allowed in bare' ' test_must_fail git reset --mixed HEAD^ ' -test_expect_success !SANITIZE_LEAK '"soft" reset is allowed in bare' ' +test_expect_success '"soft" reset is allowed in bare' ' git reset --soft HEAD^ && git show --pretty=format:%s >out && echo one >expect && diff --git a/t/t7105-reset-patch.sh b/t/t7105-reset-patch.sh index fc2a6cf5c7..9b46da7aaa 100755 --- a/t/t7105-reset-patch.sh +++ b/t/t7105-reset-patch.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='git reset --patch' + +TEST_PASSES_SANITIZE_LEAK=true . ./lib-patch-mode.sh test_expect_success PERL 'setup' ' diff --git a/t/t7106-reset-unborn-branch.sh b/t/t7106-reset-unborn-branch.sh index ecb85c3b82..a0b67a0b84 100755 --- a/t/t7106-reset-unborn-branch.sh +++ b/t/t7106-reset-unborn-branch.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='git reset should work on unborn branch' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t7107-reset-pathspec-file.sh b/t/t7107-reset-pathspec-file.sh index 523efbecde..af5ea406db 100755 --- a/t/t7107-reset-pathspec-file.sh +++ b/t/t7107-reset-pathspec-file.sh @@ -2,6 +2,7 @@ test_description='reset --pathspec-from-file' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_tick diff --git a/t/t7301-clean-interactive.sh b/t/t7301-clean-interactive.sh index a07e8b86de..d82a3210a1 100755 --- a/t/t7301-clean-interactive.sh +++ b/t/t7301-clean-interactive.sh @@ -2,6 +2,7 @@ test_description='git clean -i basic tests' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-terminal.sh diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index a989aafaf5..eae6a46ef3 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -579,6 +579,16 @@ test_expect_success 'status should be "modified" after submodule commit' ' grep "^+$rev2" list ' +test_expect_success '"submodule --cached" command forms should be identical' ' + git submodule status --cached >expect && + + git submodule --cached >actual && + test_cmp expect actual && + + git submodule --cached status >actual && + test_cmp expect actual +' + test_expect_success 'the --cached sha1 should be rev1' ' git submodule --cached status >list && grep "^+$rev1" list diff --git a/t/t7402-submodule-rebase.sh b/t/t7402-submodule-rebase.sh index ebeca12a71..2b3c363078 100755 --- a/t/t7402-submodule-rebase.sh +++ b/t/t7402-submodule-rebase.sh @@ -5,6 +5,7 @@ test_description='Test rebasing, stashing, etc. with submodules' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' @@ -55,12 +56,15 @@ chmod a+x fake-editor.sh test_expect_success 'interactive rebase with a dirty submodule' ' - test submodule = $(git diff --name-only) && + echo submodule >expect && + git diff --name-only >actual && + test_cmp expect actual && HEAD=$(git rev-parse HEAD) && GIT_EDITOR="\"$(pwd)/fake-editor.sh\"" EDITOR_TEXT="pick $HEAD" \ git rebase -i HEAD^ && - test submodule = $(git diff --name-only) - + echo submodule >expect && + git diff --name-only >actual && + test_cmp expect actual ' test_expect_success 'rebase with dirty file and submodule fails' ' @@ -82,11 +86,19 @@ test_expect_success 'stash with a dirty submodule' ' CURRENT=$(cd submodule && git rev-parse HEAD) && git stash && test new != $(cat file) && - test submodule = $(git diff --name-only) && - test $CURRENT = $(cd submodule && git rev-parse HEAD) && + echo submodule >expect && + git diff --name-only >actual && + test_cmp expect actual && + + echo "$CURRENT" >expect && + git -C submodule rev-parse HEAD >actual && + test_cmp expect actual && + git stash apply && test new = $(cat file) && - test $CURRENT = $(cd submodule && git rev-parse HEAD) + echo "$CURRENT" >expect && + git -C submodule rev-parse HEAD >actual && + test_cmp expect actual ' diff --git a/t/t7403-submodule-sync.sh b/t/t7403-submodule-sync.sh index ea92ef52a5..ff09443a0a 100755 --- a/t/t7403-submodule-sync.sh +++ b/t/t7403-submodule-sync.sh @@ -11,6 +11,7 @@ These tests exercise the "git submodule sync" subcommand. 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/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index 59bd150166..8d7b234beb 100755 --- a/t/t7407-submodule-foreach.sh +++ b/t/t7407-submodule-foreach.sh @@ -154,6 +154,11 @@ test_expect_success 'use "submodule foreach" to checkout 2nd level submodule' ' ) ' +test_expect_success 'usage: foreach -- --not-an-option' ' + test_expect_code 1 git submodule foreach -- --not-an-option && + test_expect_code 1 git -C clone2 submodule foreach -- --not-an-option +' + test_expect_success 'use "foreach --recursive" to checkout all submodules' ' ( cd clone2 && diff --git a/t/t7409-submodule-detached-work-tree.sh b/t/t7409-submodule-detached-work-tree.sh index 374ed481e9..574a6fc526 100755 --- a/t/t7409-submodule-detached-work-tree.sh +++ b/t/t7409-submodule-detached-work-tree.sh @@ -13,6 +13,7 @@ TEST_NO_CREATE_REPO=1 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/t7411-submodule-config.sh b/t/t7411-submodule-config.sh index c583c4e373..c0167944ab 100755 --- a/t/t7411-submodule-config.sh +++ b/t/t7411-submodule-config.sh @@ -137,44 +137,44 @@ test_expect_success 'error in history in fetchrecursesubmodule lets continue' ' ) ' -test_expect_success 'reading submodules config from the working tree with "submodule--helper config"' ' +test_expect_success 'reading submodules config from the working tree' ' (cd super && echo "../submodule" >expect && - git submodule--helper config submodule.submodule.url >actual && + test-tool submodule config-list submodule.submodule.url >actual && test_cmp expect actual ) ' -test_expect_success 'unsetting submodules config from the working tree with "submodule--helper config --unset"' ' +test_expect_success 'unsetting submodules config from the working tree' ' (cd super && - git submodule--helper config --unset submodule.submodule.url && - git submodule--helper config submodule.submodule.url >actual && + test-tool submodule config-unset submodule.submodule.url && + test-tool submodule config-list submodule.submodule.url >actual && test_must_be_empty actual ) ' -test_expect_success 'writing submodules config with "submodule--helper config"' ' +test_expect_success 'writing submodules config' ' (cd super && echo "new_url" >expect && - git submodule--helper config submodule.submodule.url "new_url" && - git submodule--helper config submodule.submodule.url >actual && + test-tool submodule config-set submodule.submodule.url "new_url" && + test-tool submodule config-list submodule.submodule.url >actual && test_cmp expect actual ) ' -test_expect_success 'overwriting unstaged submodules config with "submodule--helper config"' ' +test_expect_success 'overwriting unstaged submodules config' ' test_when_finished "git -C super checkout .gitmodules" && (cd super && echo "newer_url" >expect && - git submodule--helper config submodule.submodule.url "newer_url" && - git submodule--helper config submodule.submodule.url >actual && + test-tool submodule config-set submodule.submodule.url "newer_url" && + test-tool submodule config-list submodule.submodule.url >actual && test_cmp expect actual ) ' test_expect_success 'writeable .gitmodules when it is in the working tree' ' - git -C super submodule--helper config --check-writeable + test-tool -C super submodule config-writeable ' test_expect_success 'writeable .gitmodules when it is nowhere in the repository' ' @@ -183,7 +183,7 @@ test_expect_success 'writeable .gitmodules when it is nowhere in the repository' (cd super && git rm .gitmodules && git commit -m "remove .gitmodules from the current branch" && - git submodule--helper config --check-writeable + test-tool submodule config-writeable ) ' @@ -191,7 +191,7 @@ test_expect_success 'non-writeable .gitmodules when it is in the index but not i test_when_finished "git -C super checkout .gitmodules" && (cd super && rm -f .gitmodules && - test_must_fail git submodule--helper config --check-writeable + test_must_fail test-tool submodule config-writeable ) ' @@ -200,7 +200,7 @@ test_expect_success 'non-writeable .gitmodules when it is in the current branch test_when_finished "git -C super reset --hard $ORIG" && (cd super && git rm .gitmodules && - test_must_fail git submodule--helper config --check-writeable + test_must_fail test-tool submodule config-writeable ) ' @@ -208,11 +208,11 @@ test_expect_success 'reading submodules config from the index when .gitmodules i ORIG=$(git -C super rev-parse HEAD) && test_when_finished "git -C super reset --hard $ORIG" && (cd super && - git submodule--helper config submodule.submodule.url "staged_url" && + test-tool submodule config-set submodule.submodule.url "staged_url" && git add .gitmodules && rm -f .gitmodules && echo "staged_url" >expect && - git submodule--helper config submodule.submodule.url >actual && + test-tool submodule config-list submodule.submodule.url >actual && test_cmp expect actual ) ' @@ -223,7 +223,7 @@ test_expect_success 'reading submodules config from the current branch when .git (cd super && git rm .gitmodules && echo "../submodule" >expect && - git submodule--helper config submodule.submodule.url >actual && + test-tool submodule config-list submodule.submodule.url >actual && test_cmp expect actual ) ' diff --git a/t/t7412-submodule-absorbgitdirs.sh b/t/t7412-submodule-absorbgitdirs.sh index 2859695c6d..f778321857 100755 --- a/t/t7412-submodule-absorbgitdirs.sh +++ b/t/t7412-submodule-absorbgitdirs.sh @@ -10,6 +10,7 @@ TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup a real submodule' ' + cwd="$(pwd)" && git init sub1 && test_commit -C sub1 first && git submodule add ./sub1 && @@ -18,13 +19,21 @@ test_expect_success 'setup a real submodule' ' ' test_expect_success 'absorb the git dir' ' + >expect && + >actual && >expect.1 && >expect.2 && >actual.1 && >actual.2 && git status >expect.1 && git -C sub1 rev-parse HEAD >expect.2 && - git submodule absorbgitdirs && + cat >expect <<-EOF && + Migrating git directory of '\''sub1'\'' from + '\''$cwd/sub1/.git'\'' to + '\''$cwd/.git/modules/sub1'\'' + EOF + git submodule absorbgitdirs 2>actual && + test_cmp expect actual && git fsck && test -f sub1/.git && test -d .git/modules/sub1 && @@ -37,7 +46,8 @@ test_expect_success 'absorb the git dir' ' test_expect_success 'absorbing does not fail for deinitialized submodules' ' test_when_finished "git submodule update --init" && git submodule deinit --all && - git submodule absorbgitdirs && + git submodule absorbgitdirs 2>err && + test_must_be_empty err && test -d .git/modules/sub1 && test -d sub1 && ! test -e sub1/.git @@ -56,7 +66,13 @@ test_expect_success 'setup nested submodule' ' test_expect_success 'absorb the git dir in a nested submodule' ' git status >expect.1 && git -C sub1/nested rev-parse HEAD >expect.2 && - git submodule absorbgitdirs && + cat >expect <<-EOF && + Migrating git directory of '\''sub1/nested'\'' from + '\''$cwd/sub1/nested/.git'\'' to + '\''$cwd/.git/modules/sub1/modules/nested'\'' + EOF + git submodule absorbgitdirs 2>actual && + test_cmp expect actual && test -f sub1/nested/.git && test -d .git/modules/sub1/modules/nested && git status >actual.1 && @@ -87,7 +103,13 @@ test_expect_success 're-setup nested submodule' ' test_expect_success 'absorb the git dir in a nested submodule' ' git status >expect.1 && git -C sub1/nested rev-parse HEAD >expect.2 && - git submodule absorbgitdirs && + cat >expect <<-EOF && + Migrating git directory of '\''sub1'\'' from + '\''$cwd/sub1/.git'\'' to + '\''$cwd/.git/modules/sub1'\'' + EOF + git submodule absorbgitdirs 2>actual && + test_cmp expect actual && test -f sub1/.git && test -f sub1/nested/.git && test -d .git/modules/sub1/modules/nested && @@ -97,6 +119,27 @@ test_expect_success 'absorb the git dir in a nested submodule' ' test_cmp expect.2 actual.2 ' +test_expect_success 'absorb the git dir outside of primary worktree' ' + test_when_finished "rm -rf repo-bare.git" && + git clone --bare . repo-bare.git && + test_when_finished "rm -rf repo-wt" && + git -C repo-bare.git worktree add ../repo-wt && + + test_when_finished "rm -f .gitconfig" && + test_config_global protocol.file.allow always && + git -C repo-wt submodule update --init && + git init repo-wt/sub2 && + test_commit -C repo-wt/sub2 A && + git -C repo-wt submodule add ./sub2 sub2 && + cat >expect <<-EOF && + Migrating git directory of '\''sub2'\'' from + '\''$cwd/repo-wt/sub2/.git'\'' to + '\''$cwd/repo-bare.git/worktrees/repo-wt/modules/sub2'\'' + EOF + git -C repo-wt submodule absorbgitdirs 2>actual && + test_cmp expect actual +' + test_expect_success 'setup a gitlink with missing .gitmodules entry' ' git init sub2 && test_commit -C sub2 first && @@ -107,7 +150,11 @@ test_expect_success 'setup a gitlink with missing .gitmodules entry' ' test_expect_success 'absorbing the git dir fails for incomplete submodules' ' git status >expect.1 && git -C sub2 rev-parse HEAD >expect.2 && - test_must_fail git submodule absorbgitdirs && + cat >expect <<-\EOF && + fatal: could not lookup name for submodule '\''sub2'\'' + EOF + test_must_fail git submodule absorbgitdirs 2>actual && + test_cmp expect actual && git -C sub2 fsck && test -d sub2/.git && git status >actual && @@ -127,8 +174,11 @@ test_expect_success 'setup a submodule with multiple worktrees' ' ' test_expect_success 'absorbing fails for a submodule with multiple worktrees' ' - test_must_fail git submodule absorbgitdirs sub3 2>error && - test_i18ngrep "not supported" error + cat >expect <<-\EOF && + fatal: could not lookup name for submodule '\''sub2'\'' + EOF + test_must_fail git submodule absorbgitdirs 2>actual && + test_cmp expect actual ' test_done diff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh index 3ebd985981..7cf72b9a07 100755 --- a/t/t7416-submodule-dash-url.sh +++ b/t/t7416-submodule-dash-url.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='check handling of disallowed .gitmodule urls' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t7418-submodule-sparse-gitmodules.sh b/t/t7418-submodule-sparse-gitmodules.sh index d5874200fd..dde11ecce8 100755 --- a/t/t7418-submodule-sparse-gitmodules.sh +++ b/t/t7418-submodule-sparse-gitmodules.sh @@ -50,12 +50,12 @@ test_expect_success 'sparse checkout setup which hides .gitmodules' ' test_expect_success 'reading gitmodules config file when it is not checked out' ' echo "../submodule" >expect && - git -C super submodule--helper config submodule.submodule.url >actual && + test-tool -C super submodule config-list submodule.submodule.url >actual && test_cmp expect actual ' test_expect_success 'not writing gitmodules config file when it is not checked out' ' - test_must_fail git -C super submodule--helper config submodule.submodule.url newurl && + test_must_fail test-tool -C super submodule config-set submodule.submodule.url newurl && test_path_is_missing super/.gitmodules ' diff --git a/t/t7422-submodule-output.sh b/t/t7422-submodule-output.sh new file mode 100755 index 0000000000..ab946ec940 --- /dev/null +++ b/t/t7422-submodule-output.sh @@ -0,0 +1,170 @@ +#!/bin/sh + +test_description='submodule --cached, --quiet etc. output' + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-t3100.sh + +setup_sub () { + local d="$1" && + shift && + git $@ clone . "$d" && + git $@ submodule add ./"$d" +} + +normalize_status () { + sed -e 's/-g[0-9a-f]*/-gHASH/' +} + +test_expect_success 'setup' ' + test_commit A && + test_commit B && + setup_sub S && + setup_sub S.D && + setup_sub S.C && + setup_sub S.C.D && + setup_sub X && + git add S* && + test_commit C && + + # recursive in X/ + git -C X pull && + GIT_ALLOW_PROTOCOL=file git -C X submodule update --init && + + # dirty + for d in S.D X/S.D + do + echo dirty >"$d"/A.t || return 1 + done && + + # commit (for --cached) + for d in S.C* X/S.C* + do + git -C "$d" reset --hard A || return 1 + done && + + # dirty + for d in S*.D X/S*.D + do + echo dirty >"$d/C2.t" || return 1 + done && + + for ref in A B C + do + # Not different with SHA-1 and SHA-256, just (ab)using + # test_oid_cache as a variable bag to avoid using + # $(git rev-parse ...). + oid=$(git rev-parse $ref) && + test_oid_cache <<-EOF || return 1 + $ref sha1:$oid + $ref sha256:$oid + EOF + done +' + +for opts in "" "status" +do + test_expect_success "git submodule $opts" ' + sed -e "s/^>//" >expect <<-EOF && + > $(test_oid B) S (B) + >+$(test_oid A) S.C (A) + >+$(test_oid A) S.C.D (A) + > $(test_oid B) S.D (B) + >+$(test_oid C) X (C) + EOF + git submodule $opts >actual.raw && + normalize_status <actual.raw >actual && + test_cmp expect actual + ' +done + +for opts in \ + "status --recursive" +do + test_expect_success "git submodule $opts" ' + sed -e "s/^>//" >expect <<-EOF && + > $(test_oid B) S (B) + >+$(test_oid A) S.C (A) + >+$(test_oid A) S.C.D (A) + > $(test_oid B) S.D (B) + >+$(test_oid C) X (C) + > $(test_oid B) X/S (B) + >+$(test_oid A) X/S.C (A) + >+$(test_oid A) X/S.C.D (A) + > $(test_oid B) X/S.D (B) + > $(test_oid B) X/X (B) + EOF + git submodule $opts >actual.raw && + normalize_status <actual.raw >actual && + test_cmp expect actual + ' +done + +for opts in \ + "--quiet" \ + "--quiet status" \ + "status --quiet" +do + test_expect_success "git submodule $opts" ' + git submodule $opts >out && + test_must_be_empty out + ' +done + +for opts in \ + "--cached" \ + "--cached status" \ + "status --cached" +do + test_expect_success "git submodule $opts" ' + sed -e "s/^>//" >expect <<-EOF && + > $(test_oid B) S (B) + >+$(test_oid B) S.C (B) + >+$(test_oid B) S.C.D (B) + > $(test_oid B) S.D (B) + >+$(test_oid B) X (B) + EOF + git submodule $opts >actual.raw && + normalize_status <actual.raw >actual && + test_cmp expect actual + ' +done + +for opts in \ + "--cached --quiet" \ + "--cached --quiet status" \ + "--cached status --quiet" \ + "--quiet status --cached" \ + "status --cached --quiet" +do + test_expect_success "git submodule $opts" ' + git submodule $opts >out && + test_must_be_empty out + ' +done + +for opts in \ + "status --cached --recursive" \ + "--cached status --recursive" +do + test_expect_success "git submodule $opts" ' + sed -e "s/^>//" >expect <<-EOF && + > $(test_oid B) S (B) + >+$(test_oid B) S.C (B) + >+$(test_oid B) S.C.D (B) + > $(test_oid B) S.D (B) + >+$(test_oid B) X (B) + > $(test_oid B) X/S (B) + >+$(test_oid B) X/S.C (B) + >+$(test_oid B) X/S.C.D (B) + > $(test_oid B) X/S.D (B) + > $(test_oid B) X/X (B) + EOF + git submodule $opts >actual.raw && + normalize_status <actual.raw >actual && + test_cmp expect actual + ' +done + +test_done diff --git a/t/t7450-bad-git-dotfiles.sh b/t/t7450-bad-git-dotfiles.sh index ba1f569bcb..0d0c3f2c68 100755 --- a/t/t7450-bad-git-dotfiles.sh +++ b/t/t7450-bad-git-dotfiles.sh @@ -12,6 +12,8 @@ Such as: - symlinked .gitmodules, etc ' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-pack.sh diff --git a/t/t7504-commit-msg-hook.sh b/t/t7504-commit-msg-hook.sh index a39de8c112..d1255228d5 100755 --- a/t/t7504-commit-msg-hook.sh +++ b/t/t7504-commit-msg-hook.sh @@ -5,6 +5,7 @@ test_description='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 'with no hook' ' @@ -101,7 +102,9 @@ test_expect_success 'setup: commit-msg hook that always fails' ' ' commit_msg_is () { - test "$(git log --pretty=format:%s%b -1)" = "$1" + printf "%s" "$1" >expect && + git log --pretty=format:%s%b -1 >actual && + test_cmp expect actual } test_expect_success 'with failing hook' ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index 2b7ef6c41a..aed07c5b62 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -1676,4 +1676,74 @@ test_expect_success 'racy timestamps will be fixed for dirty worktree' ' ! test_is_magic_mtime .git/index ' +test_expect_success 'setup slow status advice' ' + GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main git init slowstatus && + ( + cd slowstatus && + cat >.gitignore <<-\EOF && + /actual + /expected + /out + EOF + git add .gitignore && + git commit -m "Add .gitignore" && + git config advice.statusuoption true + ) +' + +test_expect_success 'slow status advice when core.untrackedCache and fsmonitor are unset' ' + ( + cd slowstatus && + git config core.untrackedCache false && + git config core.fsmonitor false && + GIT_TEST_UF_DELAY_WARNING=1 git status >actual && + cat >expected <<-\EOF && + On branch main + + It took 3.25 seconds to enumerate untracked files. + See '\''git help status'\'' for information on how to improve this. + + nothing to commit, working tree clean + EOF + test_cmp expected actual + ) +' + +test_expect_success 'slow status advice when core.untrackedCache true, but not fsmonitor' ' + ( + cd slowstatus && + git config core.untrackedCache true && + git config core.fsmonitor false && + GIT_TEST_UF_DELAY_WARNING=1 git status >actual && + cat >expected <<-\EOF && + On branch main + + It took 3.25 seconds to enumerate untracked files. + See '\''git help status'\'' for information on how to improve this. + + nothing to commit, working tree clean + EOF + test_cmp expected actual + ) +' + +test_expect_success 'slow status advice when core.untrackedCache true, and fsmonitor' ' + ( + cd slowstatus && + git config core.untrackedCache true && + git config core.fsmonitor true && + GIT_TEST_UF_DELAY_WARNING=1 git status >actual && + cat >expected <<-\EOF && + On branch main + + It took 3.25 seconds to enumerate untracked files, + but the results were cached, and subsequent runs may be faster. + See '\''git help status'\'' for information on how to improve this. + + nothing to commit, working tree clean + EOF + test_cmp expected actual + ) +' + test_done diff --git a/t/t7509-commit-authorship.sh b/t/t7509-commit-authorship.sh index 21c668f75e..5d890949f7 100755 --- a/t/t7509-commit-authorship.sh +++ b/t/t7509-commit-authorship.sh @@ -105,7 +105,7 @@ test_expect_success '--amend option with empty author' ' test_expect_success '--amend option with missing author' ' git cat-file commit Initial >tmp && sed "s/author [^<]* </author </" tmp >malformed && - sha=$(git hash-object -t commit -w malformed) && + sha=$(git hash-object --literally -t commit -w malformed) && test_when_finished "remove_object $sha" && git checkout $sha && test_when_finished "git checkout Initial" && diff --git a/t/t7510-signed-commit.sh b/t/t7510-signed-commit.sh index 8593b7e3cb..48f86cb367 100755 --- a/t/t7510-signed-commit.sh +++ b/t/t7510-signed-commit.sh @@ -202,7 +202,7 @@ test_expect_success GPG 'detect fudged signature with NUL' ' git cat-file commit seventh-signed >raw && cat raw >forged2 && echo Qwik | tr "Q" "\000" >>forged2 && - git hash-object -w -t commit forged2 >forged2.commit && + git hash-object --literally -w -t commit forged2 >forged2.commit && test_must_fail git verify-commit $(cat forged2.commit) && git show --pretty=short --show-signature $(cat forged2.commit) >actual2 && grep "BAD signature from" actual2 && @@ -387,4 +387,48 @@ test_expect_success GPG 'verify-commit verifies multiply signed commits' ' ! grep "BAD signature from" actual ' +test_expect_success 'custom `gpg.program`' ' + write_script fake-gpg <<-\EOF && + args="$*" + + # skip uninteresting options + while case "$1" in + --status-fd=*|--keyid-format=*) ;; # skip + *) break;; + esac; do shift; done + + case "$1" in + -bsau) + test -z "$LET_GPG_PROGRAM_FAIL" || { + echo "zOMG signing failed!" >&2 + exit 1 + } + cat >sign.file + echo "[GNUPG:] SIG_CREATED $args" >&2 + echo "-----BEGIN PGP MESSAGE-----" + echo "$args" + echo "-----END PGP MESSAGE-----" + ;; + --verify) + cat "$2" >verify.file + exit 0 + ;; + *) + echo "Unhandled args: $*" >&2 + exit 1 + ;; + esac + EOF + + test_config gpg.program "$(pwd)/fake-gpg" && + git commit -S --allow-empty -m signed-commit && + test_path_exists sign.file && + git show --show-signature && + test_path_exists verify.file && + + test_must_fail env LET_GPG_PROGRAM_FAIL=1 \ + git commit -S --allow-empty -m must-fail 2>err && + grep zOMG err +' + test_done diff --git a/t/t7516-commit-races.sh b/t/t7516-commit-races.sh index f2ce14e907..2d38a16480 100755 --- a/t/t7516-commit-races.sh +++ b/t/t7516-commit-races.sh @@ -10,7 +10,8 @@ test_expect_success 'race to create orphan commit' ' test_must_fail env EDITOR=./hare-editor git commit --allow-empty -m tortoise -e && git show -s --pretty=format:%s >subject && grep hare subject && - test -z "$(git show -s --pretty=format:%P)" + git show -s --pretty=format:%P >out && + test_must_be_empty out ' test_expect_success 'race to create non-orphan commit' ' diff --git a/t/t7517-per-repo-email.sh b/t/t7517-per-repo-email.sh index 163ae80468..efc6496e2b 100755 --- a/t/t7517-per-repo-email.sh +++ b/t/t7517-per-repo-email.sh @@ -9,6 +9,7 @@ test_description='per-repo forced setting of email address' 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 a likely user.useConfigOnly use case' ' diff --git a/t/t7520-ignored-hook-warning.sh b/t/t7520-ignored-hook-warning.sh index dc57526e6f..184b258989 100755 --- a/t/t7520-ignored-hook-warning.sh +++ b/t/t7520-ignored-hook-warning.sh @@ -2,6 +2,7 @@ test_description='ignored hook warning' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh index d419085379..4c0327b2bb 100755 --- a/t/t7527-builtin-fsmonitor.sh +++ b/t/t7527-builtin-fsmonitor.sh @@ -866,27 +866,9 @@ test_expect_success 'submodule always visited' ' # the submodule, and someone does a `git submodule absorbgitdirs` # in the super, Git will recursively invoke `git submodule--helper` # to do the work and this may try to read the index. This will -# try to start the daemon in the submodule *and* pass (either -# directly or via inheritance) the `--super-prefix` arg to the -# `git fsmonitor--daemon start` command inside the submodule. -# This causes a warning because fsmonitor--daemon does take that -# global arg (see the table in git.c) -# -# This causes a warning when trying to start the daemon that is -# somewhat confusing. It does not seem to hurt anything because -# the fsmonitor code maps the query failure into a trivial response -# and does the work anyway. -# -# It would be nice to silence the warning, however. - -have_t2_error_event () { - log=$1 - msg="fsmonitor--daemon doesnQt support --super-prefix" && - - tr '\047' Q <$1 | grep -e "$msg" -} +# try to start the daemon in the submodule. -test_expect_success "stray submodule super-prefix warning" ' +test_expect_success "submodule absorbgitdirs implicitly starts daemon" ' test_when_finished "rm -rf super; \ rm -rf sub; \ rm super-sub.trace" && @@ -904,21 +886,31 @@ test_expect_success "stray submodule super-prefix warning" ' test_path_is_dir super/dir_1/dir_2/sub/.git && + cwd="$(cd super && pwd)" && + cat >expect <<-EOF && + Migrating git directory of '\''dir_1/dir_2/sub'\'' from + '\''$cwd/dir_1/dir_2/sub/.git'\'' to + '\''$cwd/.git/modules/dir_1/dir_2/sub'\'' + EOF GIT_TRACE2_EVENT="$PWD/super-sub.trace" \ - git -C super submodule absorbgitdirs && + git -C super submodule absorbgitdirs >out 2>actual && + test_cmp expect actual && + test_must_be_empty out && - ! have_t2_error_event super-sub.trace + # Confirm that the trace2 log contains a record of the + # daemon starting. + test_subcommand git fsmonitor--daemon start <super-sub.trace ' # On a case-insensitive file system, confirm that the daemon # notices when the .git directory is moved/renamed/deleted -# regardless of how it is spelled in the the FS event. +# regardless of how it is spelled in the FS event. # That is, does the FS event receive the spelling of the # operation or does it receive the spelling preserved with # the file/directory. # test_expect_success CASE_INSENSITIVE_FS 'case insensitive+preserving' ' -# test_when_finished "stop_daemon_delete_repo test_insensitive" && + test_when_finished "stop_daemon_delete_repo test_insensitive" && git init test_insensitive && @@ -930,8 +922,8 @@ test_expect_success CASE_INSENSITIVE_FS 'case insensitive+preserving' ' test_path_is_dir test_insensitive/.git && test_path_is_dir test_insensitive/.GIT && - # Rename .git using an alternate spelling to verify that that - # daemon detects it and automatically shuts down. + # Rename .git using an alternate spelling to verify that + # the daemon detects it and automatically shuts down. mv test_insensitive/.GIT test_insensitive/.FOO && # See [1] above. @@ -943,9 +935,9 @@ test_expect_success CASE_INSENSITIVE_FS 'case insensitive+preserving' ' # directories and files that we touched. We may or may not get a # trailing slash on modified directories. # - egrep "^event: abc/?$" ./insensitive.trace && - egrep "^event: abc/def/?$" ./insensitive.trace && - egrep "^event: abc/def/xyz$" ./insensitive.trace + grep -E "^event: abc/?$" ./insensitive.trace && + grep -E "^event: abc/def/?$" ./insensitive.trace && + grep -E "^event: abc/def/xyz$" ./insensitive.trace ' # The variable "unicode_debug" is defined in the following library @@ -987,20 +979,20 @@ test_expect_success !UNICODE_COMPOSITION_SENSITIVE 'Unicode nfc/nfd' ' then # We should have seen NFC event from OS. # We should not have synthesized an NFD event. - egrep "^event: nfc/c_${utf8_nfc}/?$" ./unicode.trace && - egrep -v "^event: nfc/c_${utf8_nfd}/?$" ./unicode.trace + grep -E "^event: nfc/c_${utf8_nfc}/?$" ./unicode.trace && + grep -E -v "^event: nfc/c_${utf8_nfd}/?$" ./unicode.trace else # We should have seen NFD event from OS. # We should have synthesized an NFC event. - egrep "^event: nfc/c_${utf8_nfd}/?$" ./unicode.trace && - egrep "^event: nfc/c_${utf8_nfc}/?$" ./unicode.trace + grep -E "^event: nfc/c_${utf8_nfd}/?$" ./unicode.trace && + grep -E "^event: nfc/c_${utf8_nfc}/?$" ./unicode.trace fi && # We assume UNICODE_NFD_PRESERVED. # We should have seen explicit NFD from OS. # We should have synthesized an NFC event. - egrep "^event: nfd/d_${utf8_nfd}/?$" ./unicode.trace && - egrep "^event: nfd/d_${utf8_nfc}/?$" ./unicode.trace + grep -E "^event: nfd/d_${utf8_nfd}/?$" ./unicode.trace && + grep -E "^event: nfd/d_${utf8_nfc}/?$" ./unicode.trace ' test_done diff --git a/t/t7528-signed-commit-ssh.sh b/t/t7528-signed-commit-ssh.sh index f47e995179..065f780636 100755 --- a/t/t7528-signed-commit-ssh.sh +++ b/t/t7528-signed-commit-ssh.sh @@ -270,7 +270,7 @@ test_expect_success GPGSSH 'detect fudged signature with NUL' ' git cat-file commit seventh-signed >raw && cat raw >forged2 && echo Qwik | tr "Q" "\000" >>forged2 && - git hash-object -w -t commit forged2 >forged2.commit && + git hash-object --literally -w -t commit forged2 >forged2.commit && test_must_fail git verify-commit $(cat forged2.commit) && git show --pretty=short --show-signature $(cat forged2.commit) >actual2 && grep "${GPGSSH_BAD_SIGNATURE}" actual2 && diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh index 7c3f6ed994..060e145957 100755 --- a/t/t7600-merge.sh +++ b/t/t7600-merge.sh @@ -105,7 +105,7 @@ verify_mergeheads () { test_write_lines "$@" >mergehead.expected && while read sha1 rest do - git rev-parse $sha1 + git rev-parse $sha1 || return 1 done <.git/MERGE_HEAD >mergehead.actual && test_cmp mergehead.expected mergehead.actual } diff --git a/t/t7605-merge-resolve.sh b/t/t7605-merge-resolve.sh index 5d56c38546..62d935d31c 100755 --- a/t/t7605-merge-resolve.sh +++ b/t/t7605-merge-resolve.sh @@ -4,6 +4,7 @@ test_description='git merge Testing the resolve strategy.' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh index 8cc64729ad..7b957022f1 100755 --- a/t/t7610-mergetool.sh +++ b/t/t7610-mergetool.sh @@ -33,7 +33,7 @@ test_expect_success 'setup' ' git add foo && git commit -m "Add foo" ) && - git submodule add git://example.com/submod submod && + git submodule add file:///dev/null submod && git add file1 "spaced name" file1[1-4] subdir/file3 .gitmodules submod && git commit -m "add initial versions" && @@ -614,7 +614,7 @@ test_expect_success 'submodule in subdirectory' ' ) ) && test_when_finished "rm -rf subdir/subdir_module" && - git submodule add git://example.com/subsubmodule subdir/subdir_module && + git submodule add file:///dev/null subdir/subdir_module && git add subdir/subdir_module && git commit -m "add submodule in subdirectory" && diff --git a/t/t7612-merge-verify-signatures.sh b/t/t7612-merge-verify-signatures.sh index 61330f71b1..f5c90cc22a 100755 --- a/t/t7612-merge-verify-signatures.sh +++ b/t/t7612-merge-verify-signatures.sh @@ -4,6 +4,7 @@ test_description='merge signature verification tests' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY/lib-gpg.sh" diff --git a/t/t7614-merge-signoff.sh b/t/t7614-merge-signoff.sh index fee258d4f0..cf96a35e8e 100755 --- a/t/t7614-merge-signoff.sh +++ b/t/t7614-merge-signoff.sh @@ -8,6 +8,7 @@ This test runs git merge --signoff and makes sure that it works. GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Setup test files diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh index ca45c4cd2c..4aabe98139 100755 --- a/t/t7700-repack.sh +++ b/t/t7700-repack.sh @@ -90,6 +90,22 @@ test_expect_success 'loose objects in alternate ODB are not repacked' ' test_has_duplicate_object false ' +test_expect_success SYMLINKS '--local keeps packs when alternate is objectdir ' ' + test_when_finished "rm -rf repo" && + git init repo && + test_commit -C repo A && + ( + cd repo && + git repack -a && + ls .git/objects/pack/*.pack >../expect && + ln -s objects .git/alt_objects && + echo "$(pwd)/.git/alt_objects" >.git/objects/info/alternates && + git repack -a -d -l && + ls .git/objects/pack/*.pack >../actual + ) && + test_cmp expect actual +' + test_expect_success 'packed obs in alt ODB are repacked even when local repo is packless' ' mkdir alt_objects/pack && mv .git/objects/pack/* alt_objects/pack && @@ -426,12 +442,73 @@ test_expect_success '--write-midx -b packs non-kept objects' ' ) ' +test_expect_success '--write-midx removes stale pack-based bitmaps' ' + rm -fr repo && + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + test_commit base && + GIT_TEST_MULTI_PACK_INDEX=0 git repack -Ab && + + pack_bitmap=$(ls $objdir/pack/pack-*.bitmap) && + test_path_is_file "$pack_bitmap" && + + test_commit tip && + GIT_TEST_MULTI_PACK_INDEX=0 git repack -bm && + + test_path_is_file $midx && + test_path_is_file $midx-$(midx_checksum $objdir).bitmap && + test_path_is_missing $pack_bitmap + ) +' + +test_expect_success '--write-midx with --pack-kept-objects' ' + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + + test_commit one && + test_commit two && + + one="$(echo "one" | git pack-objects --revs $objdir/pack/pack)" && + two="$(echo "one..two" | git pack-objects --revs $objdir/pack/pack)" && + + keep="$objdir/pack/pack-$one.keep" && + touch "$keep" && + + git repack --write-midx --write-bitmap-index --geometric=2 -d \ + --pack-kept-objects && + + test_path_is_file $keep && + test_path_is_file $midx && + test_path_is_file $midx-$(midx_checksum $objdir).bitmap + ) +' + test_expect_success TTY '--quiet disables progress' ' test_terminal env GIT_PROGRESS_DELAY=0 \ git -C midx repack -ad --quiet --write-midx 2>stderr && test_must_be_empty stderr ' +test_expect_success 'clean up .tmp-* packs on error' ' + test_must_fail ok=sigpipe git \ + -c repack.cruftwindow=bogus \ + repack -ad --cruft && + find $objdir/pack -name '.tmp-*' >tmpfiles && + test_must_be_empty tmpfiles +' + +test_expect_success 'repack -ad cleans up old .tmp-* packs' ' + git rev-parse HEAD >input && + git pack-objects $objdir/pack/.tmp-1234 <input && + git repack -ad && + find $objdir/pack -name '.tmp-*' >tmpfiles && + test_must_be_empty tmpfiles +' + test_expect_success 'setup for update-server-info' ' git init update-server-info && test_commit -C update-server-info message @@ -482,4 +559,125 @@ test_expect_success '-n overrides repack.updateServerInfo=true' ' test_server_info_missing ' +test_expect_success '--expire-to stores pruned objects (now)' ' + git init expire-to-now && + ( + cd expire-to-now && + + git branch -M main && + + test_commit base && + + git checkout -b cruft && + test_commit --no-tag cruft && + + git rev-list --objects --no-object-names main..cruft >moved.raw && + sort moved.raw >moved.want && + + git rev-list --all --objects --no-object-names >expect.raw && + sort expect.raw >expect && + + git checkout main && + git branch -D cruft && + git reflog expire --all --expire=all && + + git init --bare expired.git && + git repack -d \ + --cruft --cruft-expiration="now" \ + --expire-to="expired.git/objects/pack/pack" && + + expired="$(ls expired.git/objects/pack/pack-*.idx)" && + test_path_is_file "${expired%.idx}.mtimes" && + + # Since the `--cruft-expiration` is "now", the effective + # behavior is to move _all_ unreachable objects out to + # the location in `--expire-to`. + git show-index <$expired >expired.raw && + cut -d" " -f2 expired.raw | sort >expired.objects && + git rev-list --all --objects --no-object-names \ + >remaining.objects && + + # ...in other words, the combined contents of this + # repository and expired.git should be the same as the + # set of objects we started with. + cat expired.objects remaining.objects | sort >actual && + test_cmp expect actual && + + # The "moved" objects (i.e., those in expired.git) + # should be the same as the cruft objects which were + # expired in the previous step. + test_cmp moved.want expired.objects + ) +' + +test_expect_success '--expire-to stores pruned objects (5.minutes.ago)' ' + git init expire-to-5.minutes.ago && + ( + cd expire-to-5.minutes.ago && + + git branch -M main && + + test_commit base && + + # Create two classes of unreachable objects, one which + # is older than 5 minutes (stale), and another which is + # newer (recent). + for kind in stale recent + do + git checkout -b $kind main && + test_commit --no-tag $kind || return 1 + done && + + git rev-list --objects --no-object-names main..stale >in && + stale="$(git pack-objects $objdir/pack/pack <in)" && + mtime="$(test-tool chmtime --get =-600 $objdir/pack/pack-$stale.pack)" && + + # expect holds the set of objects we expect to find in + # this repository after repacking + git rev-list --objects --no-object-names recent >expect.raw && + sort expect.raw >expect && + + # moved.want holds the set of objects we expect to find + # in expired.git + git rev-list --objects --no-object-names main..stale >out && + sort out >moved.want && + + git checkout main && + git branch -D stale recent && + git reflog expire --all --expire=all && + git prune-packed && + + git init --bare expired.git && + git repack -d \ + --cruft --cruft-expiration=5.minutes.ago \ + --expire-to="expired.git/objects/pack/pack" && + + # Some of the remaining objects in this repository are + # unreachable, so use `cat-file --batch-all-objects` + # instead of `rev-list` to get their names + git cat-file --batch-all-objects --batch-check="%(objectname)" \ + >remaining.objects && + sort remaining.objects >actual && + test_cmp expect actual && + + ( + cd expired.git && + + expired="$(ls objects/pack/pack-*.mtimes)" && + test-tool pack-mtimes $(basename $expired) >out && + cut -d" " -f1 out | sort >../moved.got && + + # Ensure that there are as many objects with the + # expected mtime as were moved to expired.git. + # + # In other words, ensure that the recorded + # mtimes of any moved objects was written + # correctly. + grep " $mtime$" out >matching && + test_line_count = $(wc -l <../moved.want) matching + ) && + test_cmp moved.want moved.got + ) +' + test_done diff --git a/t/t7701-repack-unpack-unreachable.sh b/t/t7701-repack-unpack-unreachable.sh index 937f89ee8c..ebb267855f 100755 --- a/t/t7701-repack-unpack-unreachable.sh +++ b/t/t7701-repack-unpack-unreachable.sh @@ -5,6 +5,7 @@ test_description='git repack works correctly' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh fsha1= @@ -35,7 +36,7 @@ test_expect_success '-A with -d option leaves unreachable objects unpacked' ' git repack -A -d -l && # verify objects are packed in repository test 3 = $(git verify-pack -v -- .git/objects/pack/*.idx | - egrep "^($fsha1|$csha1|$tsha1) " | + grep -E "^($fsha1|$csha1|$tsha1) " | sort | uniq | wc -l) && git show $fsha1 && git show $csha1 && @@ -49,7 +50,7 @@ test_expect_success '-A with -d option leaves unreachable objects unpacked' ' git repack -A -d -l && # verify objects are retained unpacked test 0 = $(git verify-pack -v -- .git/objects/pack/*.idx | - egrep "^($fsha1|$csha1|$tsha1) " | + grep -E "^($fsha1|$csha1|$tsha1) " | sort | uniq | wc -l) && git show $fsha1 && git show $csha1 && diff --git a/t/t7703-repack-geometric.sh b/t/t7703-repack-geometric.sh index da87f8b2d8..8821fbd2dd 100755 --- a/t/t7703-repack-geometric.sh +++ b/t/t7703-repack-geometric.sh @@ -176,8 +176,12 @@ test_expect_success '--geometric ignores kept packs' ' # be repacked, too. git repack --geometric 2 -d --pack-kept-objects && + # After repacking, two packs remain: one new one (containing the + # objects in both the .keep and non-kept pack), and the .keep + # pack (since `--pack-kept-objects -d` does not actually delete + # the kept pack). find $objdir/pack -name "*.pack" >after && - test_line_count = 1 after + test_line_count = 2 after ) ' diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh index 0f937990a0..39d6d713ec 100755 --- a/t/t7810-grep.sh +++ b/t/t7810-grep.sh @@ -18,6 +18,9 @@ test_invalid_grep_expression() { ' } +LC_ALL=en_US.UTF-8 test-tool regex '^.$' '¿' && + test_set_prereq MB_REGEX + cat >hello.c <<EOF #include <assert.h> #include <stdio.h> @@ -88,6 +91,10 @@ test_expect_success setup ' echo unusual >"\"unusual\" pathname" && echo unusual >"t/nested \"unusual\" pathname" fi && + if test_have_prereq MB_REGEX + then + echo "¿" >reverse-question-mark + fi && git add . && test_tick && git commit -m initial @@ -569,6 +576,14 @@ do ' done +test_expect_success MB_REGEX 'grep exactly one char in single-char multibyte file' ' + LC_ALL=en_US.UTF-8 git grep "^.$" reverse-question-mark +' + +test_expect_success MB_REGEX 'grep two chars in single-char multibyte file' ' + LC_ALL=en_US.UTF-8 test_expect_code 1 git grep ".." reverse-question-mark +' + cat >expected <<EOF file EOF @@ -986,7 +1001,9 @@ test_expect_success 'log --committer does not search in timestamp' ' test_expect_success 'grep with CE_VALID file' ' git update-index --assume-unchanged t/t && rm t/t && - test "$(git grep test)" = "t/t:test" && + echo "t/t:test" >expect && + git grep test >actual && + test_cmp expect actual && git update-index --no-assume-unchanged t/t && git checkout t/t ' diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh index 2724a44fe3..823331e44a 100755 --- a/t/t7900-maintenance.sh +++ b/t/t7900-maintenance.sh @@ -480,6 +480,11 @@ test_expect_success 'maintenance.strategy inheritance' ' test_expect_success 'register and unregister' ' test_when_finished git config --global --unset-all maintenance.repo && + + test_must_fail git maintenance unregister 2>err && + grep "is not registered" err && + git maintenance unregister --force && + git config --global --add maintenance.repo /existing1 && git config --global --add maintenance.repo /existing2 && git config --global --get-all maintenance.repo >before && @@ -493,7 +498,30 @@ test_expect_success 'register and unregister' ' git maintenance unregister && git config --global --get-all maintenance.repo >actual && - test_cmp before actual + test_cmp before actual && + + git config --file ./other --add maintenance.repo /existing1 && + git config --file ./other --add maintenance.repo /existing2 && + git config --file ./other --get-all maintenance.repo >before && + + git maintenance register --config-file ./other && + test_cmp_config false maintenance.auto && + git config --file ./other --get-all maintenance.repo >between && + cp before expect && + pwd >>expect && + test_cmp expect between && + + git maintenance unregister --config-file ./other && + git config --file ./other --get-all maintenance.repo >actual && + test_cmp before actual && + + test_must_fail git maintenance unregister 2>err && + grep "is not registered" err && + git maintenance unregister --force && + + test_must_fail git maintenance unregister --config-file ./other 2>err && + grep "is not registered" err && + git maintenance unregister --config-file ./other --force ' test_expect_success !MINGW 'register and unregister with regex metacharacters' ' diff --git a/t/t8003-blame-corner-cases.sh b/t/t8003-blame-corner-cases.sh index d751d48b7d..8bcd39e81b 100755 --- a/t/t8003-blame-corner-cases.sh +++ b/t/t8003-blame-corner-cases.sh @@ -201,7 +201,7 @@ committer David Reiss <dreiss@facebook.com> 1234567890 +0000 some message EOF - COMMIT=$(git hash-object -t commit -w badcommit) && + COMMIT=$(git hash-object --literally -t commit -w badcommit) && git --no-pager blame $COMMIT -- uno >/dev/null ' diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 01c74b8b07..323952a572 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -1519,7 +1519,7 @@ test_expect_success $PREREQ 'asks about and fixes 8bit encodings' ' grep "do not declare a Content-Transfer-Encoding" stdout && grep email-using-8bit stdout && grep "Which 8bit encoding" stdout && - egrep "Content|MIME" msgtxt1 >actual && + grep -E "Content|MIME" msgtxt1 >actual && test_cmp content-type-decl actual ' @@ -1530,7 +1530,7 @@ test_expect_success $PREREQ 'sendemail.8bitEncoding works' ' git send-email --from=author@example.com --to=nobody@example.com \ --smtp-server="$(pwd)/fake.sendmail" \ email-using-8bit >stdout && - egrep "Content|MIME" msgtxt1 >actual && + grep -E "Content|MIME" msgtxt1 >actual && test_cmp content-type-decl actual ' @@ -1545,7 +1545,7 @@ test_expect_success $PREREQ 'sendemail.8bitEncoding in .git/config overrides --g git send-email --from=author@example.com --to=nobody@example.com \ --smtp-server="$(pwd)/fake.sendmail" \ email-using-8bit >stdout && - egrep "Content|MIME" msgtxt1 >actual && + grep -E "Content|MIME" msgtxt1 >actual && test_cmp content-type-decl actual ' @@ -1557,7 +1557,7 @@ test_expect_success $PREREQ '--8bit-encoding overrides sendemail.8bitEncoding' ' --smtp-server="$(pwd)/fake.sendmail" \ --8bit-encoding=UTF-8 \ email-using-8bit >stdout && - egrep "Content|MIME" msgtxt1 >actual && + grep -E "Content|MIME" msgtxt1 >actual && test_cmp content-type-decl actual ' @@ -2334,6 +2334,12 @@ test_expect_success $PREREQ 'test that send-email works outside a repo' ' "$(pwd)/0001-add-main.patch" ' +test_expect_success $PREREQ 'send-email relays -v 3 to format-patch' ' + test_when_finished "rm -f out" && + git send-email --dry-run -v 3 -1 >out && + grep "PATCH v3" out +' + test_expect_success $PREREQ 'test that sendmail config is rejected' ' test_config sendmail.program sendmail && test_must_fail git send-email \ diff --git a/t/t9003-help-autocorrect.sh b/t/t9003-help-autocorrect.sh index f00deaf381..14a704d0a8 100755 --- a/t/t9003-help-autocorrect.sh +++ b/t/t9003-help-autocorrect.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='help.autocorrect finding a match' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' @@ -60,4 +62,10 @@ test_expect_success 'autocorrect can be declined altogether' ' test_line_count = 1 actual ' +test_expect_success 'autocorrect works in work tree created from bare repo' ' + git clone --bare . bare.git && + git -C bare.git worktree add ../worktree && + git -C worktree -c help.autocorrect=immediate stauts +' + test_done diff --git a/t/t9106-git-svn-commit-diff-clobber.sh b/t/t9106-git-svn-commit-diff-clobber.sh index 3cab0b9720..bca496c40e 100755 --- a/t/t9106-git-svn-commit-diff-clobber.sh +++ b/t/t9106-git-svn-commit-diff-clobber.sh @@ -3,7 +3,6 @@ # Copyright (c) 2006 Eric Wong test_description='git svn commit-diff clobber' -TEST_FAILS_SANITIZE_LEAK=true . ./lib-git-svn.sh test_expect_success 'initialize repo' ' diff --git a/t/t9115-git-svn-dcommit-funky-renames.sh b/t/t9115-git-svn-dcommit-funky-renames.sh index 419f055721..743fbe1fe4 100755 --- a/t/t9115-git-svn-dcommit-funky-renames.sh +++ b/t/t9115-git-svn-dcommit-funky-renames.sh @@ -5,7 +5,6 @@ test_description='git svn dcommit can commit renames of files with ugly names' -TEST_FAILS_SANITIZE_LEAK=true . ./lib-git-svn.sh test_expect_success 'load repository with strange names' ' diff --git a/t/t9119-git-svn-info.sh b/t/t9119-git-svn-info.sh index 8201c3e808..088d1c57a8 100755 --- a/t/t9119-git-svn-info.sh +++ b/t/t9119-git-svn-info.sh @@ -28,7 +28,7 @@ test_cmp_info () { rm -f tmp.expect tmp.actual } -quoted_svnrepo="$(echo $svnrepo | sed 's/ /%20/')" +quoted_svnrepo="$(echo $svnrepo | test_uri_escape)" test_expect_success 'setup repository and import' ' mkdir info && diff --git a/t/t9133-git-svn-nested-git-repo.sh b/t/t9133-git-svn-nested-git-repo.sh index f894860867..d8d536269c 100755 --- a/t/t9133-git-svn-nested-git-repo.sh +++ b/t/t9133-git-svn-nested-git-repo.sh @@ -35,7 +35,7 @@ test_expect_success 'SVN-side change outside of .git' ' echo b >> a && svn_cmd commit -m "SVN-side change outside of .git" && svn_cmd up && - svn_cmd log -v | fgrep "SVN-side change outside of .git" + svn_cmd log -v | grep -F "SVN-side change outside of .git" ) ' @@ -59,7 +59,7 @@ test_expect_success 'SVN-side change inside of .git' ' svn_cmd add --force .git && svn_cmd commit -m "SVN-side change inside of .git" && svn_cmd up && - svn_cmd log -v | fgrep "SVN-side change inside of .git" + svn_cmd log -v | grep -F "SVN-side change inside of .git" ) ' @@ -82,7 +82,7 @@ test_expect_success 'SVN-side change in and out of .git' ' git commit -m "add a inside an SVN repo" && svn_cmd commit -m "SVN-side change in and out of .git" && svn_cmd up && - svn_cmd log -v | fgrep "SVN-side change in and out of .git" + svn_cmd log -v | grep -F "SVN-side change in and out of .git" ) ' diff --git a/t/t9134-git-svn-ignore-paths.sh b/t/t9134-git-svn-ignore-paths.sh index 4a77eb9f60..3188400226 100755 --- a/t/t9134-git-svn-ignore-paths.sh +++ b/t/t9134-git-svn-ignore-paths.sh @@ -43,7 +43,7 @@ test_expect_success 'init+fetch an SVN repository with ignored www directory' ' test_expect_success 'verify ignore-paths config saved by clone' ' ( cd g && - git config --get svn-remote.svn.ignore-paths | fgrep "www" + git config --get svn-remote.svn.ignore-paths | grep www ) ' @@ -53,7 +53,7 @@ test_expect_success 'SVN-side change outside of www' ' echo b >> qqq/test_qqq.txt && svn_cmd commit -m "SVN-side change outside of www" && svn_cmd up && - svn_cmd log -v | fgrep "SVN-side change outside of www" + svn_cmd log -v | grep "SVN-side change outside of www" ) ' @@ -85,7 +85,7 @@ test_expect_success 'SVN-side change inside of ignored www' ' echo zaq >> www/test_www.txt && svn_cmd commit -m "SVN-side change inside of www/test_www.txt" && svn_cmd up && - svn_cmd log -v | fgrep "SVN-side change inside of www/test_www.txt" + svn_cmd log -v | grep -F "SVN-side change inside of www/test_www.txt" ) ' @@ -118,7 +118,7 @@ test_expect_success 'SVN-side change in and out of ignored www' ' echo ygg >> qqq/test_qqq.txt && svn_cmd commit -m "SVN-side change in and out of ignored www" && svn_cmd up && - svn_cmd log -v | fgrep "SVN-side change in and out of ignored www" + svn_cmd log -v | grep "SVN-side change in and out of ignored www" ) ' diff --git a/t/t9140-git-svn-reset.sh b/t/t9140-git-svn-reset.sh index e855904629..a420b2a87a 100755 --- a/t/t9140-git-svn-reset.sh +++ b/t/t9140-git-svn-reset.sh @@ -43,7 +43,7 @@ test_expect_success 'fetch fails on modified hidden file' ' git svn find-rev refs/remotes/git-svn > ../expect && test_must_fail git svn fetch 2> ../errors && git svn find-rev refs/remotes/git-svn > ../expect2 ) && - fgrep "not found in commit" errors && + grep "not found in commit" errors && test_cmp expect expect2 ' @@ -59,7 +59,7 @@ test_expect_success 'refetch succeeds not ignoring any files' ' ( cd g && git svn fetch && git svn rebase && - fgrep "mod hidden" hid/hid.txt + grep "mod hidden" hid/hid.txt ) ' diff --git a/t/t9146-git-svn-empty-dirs.sh b/t/t9146-git-svn-empty-dirs.sh index 79c26ed69c..09606f1b3c 100755 --- a/t/t9146-git-svn-empty-dirs.sh +++ b/t/t9146-git-svn-empty-dirs.sh @@ -4,7 +4,6 @@ test_description='git svn creates empty directories' -TEST_FAILS_SANITIZE_LEAK=true . ./lib-git-svn.sh test_expect_success 'initialize repo' ' diff --git a/t/t9147-git-svn-include-paths.sh b/t/t9147-git-svn-include-paths.sh index 257fc8f2f8..63fa0b6732 100755 --- a/t/t9147-git-svn-include-paths.sh +++ b/t/t9147-git-svn-include-paths.sh @@ -45,7 +45,7 @@ test_expect_success 'init+fetch an SVN repository with included qqq directory' ' test_expect_success 'verify include-paths config saved by clone' ' ( cd g && - git config --get svn-remote.svn.include-paths | fgrep "qqq" + git config --get svn-remote.svn.include-paths | grep qqq ) ' @@ -55,7 +55,7 @@ test_expect_success 'SVN-side change outside of www' ' echo b >> qqq/test_qqq.txt && svn_cmd commit -m "SVN-side change outside of www" && svn_cmd up && - svn_cmd log -v | fgrep "SVN-side change outside of www" + svn_cmd log -v | grep "SVN-side change outside of www" ) ' @@ -87,7 +87,7 @@ test_expect_success 'SVN-side change inside of ignored www' ' echo zaq >> www/test_www.txt && svn_cmd commit -m "SVN-side change inside of www/test_www.txt" && svn_cmd up && - svn_cmd log -v | fgrep "SVN-side change inside of www/test_www.txt" + svn_cmd log -v | grep "SVN-side change inside of www/test_www.txt" ) ' @@ -120,7 +120,7 @@ test_expect_success 'SVN-side change in and out of included qqq' ' echo ygg >> qqq/test_qqq.txt && svn_cmd commit -m "SVN-side change in and out of ignored www" && svn_cmd up && - svn_cmd log -v | fgrep "SVN-side change in and out of ignored www" + svn_cmd log -v | grep "SVN-side change in and out of ignored www" ) ' diff --git a/t/t9148-git-svn-propset.sh b/t/t9148-git-svn-propset.sh index 6cc76a07b3..aebb28995e 100755 --- a/t/t9148-git-svn-propset.sh +++ b/t/t9148-git-svn-propset.sh @@ -5,7 +5,6 @@ test_description='git svn propset tests' -TEST_FAILS_SANITIZE_LEAK=true . ./lib-git-svn.sh test_expect_success 'setup propset via import' ' diff --git a/t/t9160-git-svn-preserve-empty-dirs.sh b/t/t9160-git-svn-preserve-empty-dirs.sh index 9cf7a1427a..36c6b1a12f 100755 --- a/t/t9160-git-svn-preserve-empty-dirs.sh +++ b/t/t9160-git-svn-preserve-empty-dirs.sh @@ -9,7 +9,6 @@ This test uses git to clone a Subversion repository that contains empty directories, and checks that corresponding directories are created in the local Git repository with placeholder files.' -TEST_FAILS_SANITIZE_LEAK=true . ./lib-git-svn.sh GIT_REPO=git-svn-repo diff --git a/t/t9164-git-svn-dcommit-concurrent.sh b/t/t9164-git-svn-dcommit-concurrent.sh index 1465156072..c8e6c0733f 100755 --- a/t/t9164-git-svn-dcommit-concurrent.sh +++ b/t/t9164-git-svn-dcommit-concurrent.sh @@ -5,7 +5,6 @@ test_description='concurrent git svn dcommit' -TEST_FAILS_SANITIZE_LEAK=true . ./lib-git-svn.sh diff --git a/t/t9210-scalar.sh b/t/t9210-scalar.sh index 14ca575a21..4432a30d10 100755 --- a/t/t9210-scalar.sh +++ b/t/t9210-scalar.sh @@ -104,6 +104,13 @@ test_expect_success FSMONITOR_DAEMON 'scalar register starts fsmon daemon' ' test_cmp_config -C test/src true core.fsmonitor ' +test_expect_success 'scalar register warns when background maintenance fails' ' + git init register-repo && + GIT_TEST_MAINT_SCHEDULER="crontab:false,launchctl:false,schtasks:false" \ + scalar register register-repo 2>err && + grep "could not turn on maintenance" err +' + test_expect_success 'scalar unregister' ' git init vanish/src && scalar register vanish/src && @@ -116,7 +123,10 @@ test_expect_success 'scalar unregister' ' test_must_fail git config --get --global --fixed-value \ maintenance.repo "$(pwd)/vanish/src" && scalar list >scalar.repos && - ! grep -F "$(pwd)/vanish/src" scalar.repos + ! grep -F "$(pwd)/vanish/src" scalar.repos && + + # scalar unregister should be idempotent + scalar unregister vanish ' test_expect_success 'set up repository to clone' ' @@ -163,6 +173,20 @@ test_expect_success 'scalar reconfigure' ' test true = "$(git -C one/src config core.preloadIndex)" ' +test_expect_success '`reconfigure -a` removes stale config entries' ' + git init stale/src && + scalar register stale && + scalar list >scalar.repos && + grep stale scalar.repos && + + grep -v stale scalar.repos >expect && + + rm -rf stale && + scalar reconfigure -a && + scalar list >scalar.repos && + test_cmp expect scalar.repos +' + test_expect_success 'scalar delete without enlistment shows a usage' ' test_expect_code 129 scalar delete ' diff --git a/t/t9211-scalar-clone.sh b/t/t9211-scalar-clone.sh index dd33d87e9b..872ad1c9c2 100755 --- a/t/t9211-scalar-clone.sh +++ b/t/t9211-scalar-clone.sh @@ -3,6 +3,7 @@ test_description='test the `scalar clone` subcommand' . ./test-lib.sh +. "${TEST_DIRECTORY}/lib-terminal.sh" GIT_TEST_MAINT_SCHEDULER="crontab:test-tool crontab cron.txt,launchctl:true,schtasks:true" export GIT_TEST_MAINT_SCHEDULER @@ -148,4 +149,35 @@ test_expect_success '--no-single-branch clones all branches' ' cleanup_clone $enlistment ' +test_expect_success TTY 'progress with tty' ' + enlistment=progress1 && + + test_config -C to-clone uploadpack.allowfilter true && + test_config -C to-clone uploadpack.allowanysha1inwant true && + + test_terminal env GIT_PROGRESS_DELAY=0 \ + scalar clone "file://$(pwd)/to-clone" "$enlistment" 2>stderr && + grep "Enumerating objects" stderr >actual && + test_line_count = 2 actual && + cleanup_clone $enlistment +' + +test_expect_success 'progress without tty' ' + enlistment=progress2 && + + test_config -C to-clone uploadpack.allowfilter true && + test_config -C to-clone uploadpack.allowanysha1inwant true && + + GIT_PROGRESS_DELAY=0 scalar clone "file://$(pwd)/to-clone" "$enlistment" 2>stderr && + ! grep "Enumerating objects" stderr && + ! grep "Updating files" stderr && + cleanup_clone $enlistment +' + +test_expect_success 'scalar clone warns when background maintenance fails' ' + GIT_TEST_MAINT_SCHEDULER="crontab:false,launchctl:false,schtasks:false" \ + scalar clone "file://$(pwd)/to-clone" maint-fail 2>err && + grep "could not turn on maintenance" err +' + test_done diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh index ff21a12ee6..26c25c0eb2 100755 --- a/t/t9350-fast-export.sh +++ b/t/t9350-fast-export.sh @@ -373,7 +373,7 @@ EOF test_expect_success 'cope with tagger-less tags' ' - TAG=$(git hash-object -t tag -w tag-content) && + TAG=$(git hash-object --literally -t tag -w tag-content) && git update-ref refs/tags/sonnenschein $TAG && git fast-export -C -C --signed-tags=strip --all > output && test $(grep -c "^tag " output) = 4 && diff --git a/t/t9700-perl-git.sh b/t/t9700-perl-git.sh index 4aa5d90d32..ccc8212d73 100755 --- a/t/t9700-perl-git.sh +++ b/t/t9700-perl-git.sh @@ -13,37 +13,40 @@ skip_all_if_no_Test_More # set up test repository -test_expect_success \ - 'set up test repository' \ - 'echo "test file 1" > file1 && - echo "test file 2" > file2 && - mkdir directory1 && - echo "in directory1" >> directory1/file && - mkdir directory2 && - echo "in directory2" >> directory2/file && - git add . && - git commit -m "first commit" && - - echo "new file in subdir 2" > directory2/file2 && - git add . && - git commit -m "commit in directory2" && - - echo "changed file 1" > file1 && - git commit -a -m "second commit" && - - git config --add color.test.slot1 green && - git config --add test.string value && - git config --add test.dupstring value1 && - git config --add test.dupstring value2 && - git config --add test.booltrue true && - git config --add test.boolfalse no && - git config --add test.boolother other && - git config --add test.int 2k && - git config --add test.path "~/foo" && - git config --add test.pathexpanded "$HOME/foo" && - git config --add test.pathmulti foo && - git config --add test.pathmulti bar - ' +test_expect_success 'set up test repository' ' + echo "test file 1" >file1 && + echo "test file 2" >file2 && + mkdir directory1 && + echo "in directory1" >>directory1/file && + mkdir directory2 && + echo "in directory2" >>directory2/file && + git add . && + git commit -m "first commit" && + + echo "new file in subdir 2" >directory2/file2 && + git add . && + git commit -m "commit in directory2" && + + echo "changed file 1" >file1 && + git commit -a -m "second commit" && + + git config --add color.test.slot1 green && + git config --add test.string value && + git config --add test.dupstring value1 && + git config --add test.dupstring value2 && + git config --add test.booltrue true && + git config --add test.boolfalse no && + git config --add test.boolother other && + git config --add test.int 2k && + git config --add test.path "~/foo" && + git config --add test.pathexpanded "$HOME/foo" && + git config --add test.pathmulti foo && + git config --add test.pathmulti bar +' + +test_expect_success 'set up bare repository' ' + git init --bare bare.git +' test_expect_success 'use t9700/test.pl to test Git.pm' ' "$PERL_PATH" "$TEST_DIRECTORY"/t9700/test.pl 2>stderr && diff --git a/t/t9700/test.pl b/t/t9700/test.pl index e046f7db76..6d753708d2 100755 --- a/t/t9700/test.pl +++ b/t/t9700/test.pl @@ -30,6 +30,18 @@ BEGIN { use_ok('Git') } # set up our $abs_repo_dir = cwd(); ok(our $r = Git->repository(Directory => "."), "open repository"); +{ + local $ENV{GIT_TEST_ASSUME_DIFFERENT_OWNER} = 1; + my $failed; + + $failed = eval { Git->repository(Directory => $abs_repo_dir) }; + ok(!$failed, "reject unsafe non-bare repository"); + like($@, qr/not a git repository/i, "unsafe error message"); + + $failed = eval { Git->repository(Directory => "$abs_repo_dir/bare.git") }; + ok(!$failed, "reject unsafe bare repository"); + like($@, qr/not a git repository/i, "unsafe error message"); +} # config is($r->config("test.string"), "value", "config scalar: string"); diff --git a/t/t9814-git-p4-rename.sh b/t/t9814-git-p4-rename.sh index 468767cbf4..2a9838f37f 100755 --- a/t/t9814-git-p4-rename.sh +++ b/t/t9814-git-p4-rename.sh @@ -216,7 +216,7 @@ test_expect_success 'detect copies' ' # variable exists, which allows admins to disable the "p4 move" command. test_lazy_prereq P4D_HAVE_CONFIGURABLE_RUN_MOVE_ALLOW ' p4 configure show run.move.allow >out && - egrep ^run.move.allow: out + grep -E ^run.move.allow: out ' # If move can be disabled, turn it off and test p4 move handling diff --git a/t/t9815-git-p4-submit-fail.sh b/t/t9815-git-p4-submit-fail.sh index 9779dc0d11..0ca9937de6 100755 --- a/t/t9815-git-p4-submit-fail.sh +++ b/t/t9815-git-p4-submit-fail.sh @@ -417,8 +417,8 @@ test_expect_success 'cleanup chmod after submit cancel' ' ! p4 fstat -T action text && test_path_is_file text+x && ! p4 fstat -T action text+x && - ls -l text | egrep ^-r-- && - ls -l text+x | egrep ^-r-x + ls -l text | grep -E ^-r-- && + ls -l text+x | grep -E ^-r-x ) ' diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 43de868b80..d6c0478d98 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -2255,6 +2255,36 @@ test_expect_success 'checkout completes ref names' ' EOF ' +test_expect_success 'checkout does not match ref names of a different case' ' + test_completion "git checkout M" "" +' + +test_expect_success 'checkout matches case insensitively with GIT_COMPLETION_IGNORE_CASE' ' + ( + GIT_COMPLETION_IGNORE_CASE=1 && + test_completion "git checkout M" <<-\EOF + main Z + mybranch Z + mytag Z + EOF + ) +' + +test_expect_success 'checkout completes pseudo refs' ' + test_completion "git checkout H" <<-\EOF + HEAD Z + EOF +' + +test_expect_success 'checkout completes pseudo refs case insensitively with GIT_COMPLETION_IGNORE_CASE' ' + ( + GIT_COMPLETION_IGNORE_CASE=1 && + test_completion "git checkout h" <<-\EOF + HEAD Z + EOF + ) +' + test_expect_success 'git -C <path> checkout uses the right repo' ' test_completion "git -C subdir -C subsubdir -C .. -C ../otherrepo checkout b" <<-\EOF branch-in-other Z diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index c6479f24eb..999d46fafe 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -32,6 +32,14 @@ test_set_editor () { export EDITOR } +# Like test_set_editor but sets GIT_SEQUENCE_EDITOR instead of EDITOR +test_set_sequence_editor () { + FAKE_SEQUENCE_EDITOR="$1" + export FAKE_SEQUENCE_EDITOR + GIT_SEQUENCE_EDITOR='"$FAKE_SEQUENCE_EDITOR"' + export GIT_SEQUENCE_EDITOR +} + test_decode_color () { awk ' function name(n) { @@ -273,13 +281,13 @@ debug () { # <file>, <contents>, and <tag> all default to <message>. test_commit () { - notick= && - echo=echo && - append= && - author= && - signoff= && - indir= && - tag=light && + local notick= && + local echo=echo && + local append= && + local author= && + local signoff= && + local indir= && + local tag=light && while test $# != 0 do case "$1" in @@ -322,7 +330,7 @@ test_commit () { shift done && indir=${indir:+"$indir"/} && - file=${2:-"$1.t"} && + local file=${2:-"$1.t"} && if test -n "$append" then $echo "${3-$1}" >>"$indir$file" @@ -897,7 +905,7 @@ test_path_is_symlink () { test_dir_is_empty () { test "$#" -ne 1 && BUG "1 param" test_path_is_dir "$1" && - if test -n "$(ls -a1 "$1" | egrep -v '^\.\.?$')" + if test -n "$(ls -a1 "$1" | grep -E -v '^\.\.?$')" then echo "Directory '$1' is not empty, it contains:" ls -la "$1" @@ -921,10 +929,6 @@ test_path_is_missing () { then echo "Path exists:" ls -ld "$1" - if test $# -ge 1 - then - echo "$*" - fi false fi } @@ -1020,7 +1024,7 @@ test_must_fail_acceptable () { fi case "$1" in - git|__git*|test-tool|test_terminal) + git|__git*|scalar|test-tool|test_terminal) return 0 ;; *) @@ -1426,7 +1430,7 @@ test_bool_env () { BUG "test_bool_env requires two parameters (variable name and default value)" fi - git env--helper --type=bool --default="$2" --exit-code "$1" + test-tool env-helper --type=bool --default="$2" --exit-code "$1" ret=$? case $ret in 0|1) # unset or valid bool value @@ -1454,72 +1458,6 @@ test_skip_or_die () { error "$2" } -# The following mingw_* functions obey POSIX shell syntax, but are actually -# bash scripts, and are meant to be used only with bash on Windows. - -# A test_cmp function that treats LF and CRLF equal and avoids to fork -# diff when possible. -mingw_test_cmp () { - # Read text into shell variables and compare them. If the results - # are different, use regular diff to report the difference. - local test_cmp_a= test_cmp_b= - - # When text came from stdin (one argument is '-') we must feed it - # to diff. - local stdin_for_diff= - - # Since it is difficult to detect the difference between an - # empty input file and a failure to read the files, we go straight - # to diff if one of the inputs is empty. - if test -s "$1" && test -s "$2" - then - # regular case: both files non-empty - mingw_read_file_strip_cr_ test_cmp_a <"$1" - mingw_read_file_strip_cr_ test_cmp_b <"$2" - elif test -s "$1" && test "$2" = - - then - # read 2nd file from stdin - mingw_read_file_strip_cr_ test_cmp_a <"$1" - mingw_read_file_strip_cr_ test_cmp_b - stdin_for_diff='<<<"$test_cmp_b"' - elif test "$1" = - && test -s "$2" - then - # read 1st file from stdin - mingw_read_file_strip_cr_ test_cmp_a - mingw_read_file_strip_cr_ test_cmp_b <"$2" - stdin_for_diff='<<<"$test_cmp_a"' - fi - test -n "$test_cmp_a" && - test -n "$test_cmp_b" && - test "$test_cmp_a" = "$test_cmp_b" || - eval "diff -u \"\$@\" $stdin_for_diff" -} - -# $1 is the name of the shell variable to fill in -mingw_read_file_strip_cr_ () { - # Read line-wise using LF as the line separator - # and use IFS to strip CR. - local line - while : - do - if IFS=$'\r' read -r -d $'\n' line - then - # good - line=$line$'\n' - else - # we get here at EOF, but also if the last line - # was not terminated by LF; in the latter case, - # some text was read - if test -z "$line" - then - # EOF, really - break - fi - fi - eval "$1=\$$1\$line" - done -} - # Like "env FOO=BAR some-program", but run inside a subshell, which means # it also works for shell functions (though those functions cannot impact # the environment outside of the test_env invocation). @@ -1686,7 +1624,7 @@ test_oid () { then BUG "undefined key '$1'" fi && - eval "printf '%s' \"\${$var}\"" + eval "printf '%s\n' \"\${$var}\"" } # Insert a slash into an object ID so it can be used to reference a location @@ -1755,6 +1693,13 @@ test_path_is_hidden () { return 1 } +# Poor man's URI escaping. Good enough for the test suite whose trash +# directory has a space in it. See 93c3fcbe4d4 (git-svn: attempt to +# mimic SVN 1.7 URL canonicalization, 2012-07-28) for prior art. +test_uri_escape() { + sed 's/ /%20/g' +} + # Check that the given command was invoked as part of the # trace2-format trace on stdin. # @@ -1830,6 +1775,14 @@ test_region () { return 0 } +# Given a GIT_TRACE2_EVENT log over stdin, writes to stdout a list of URLs +# sent to git-remote-https child processes. +test_remote_https_urls() { + grep -e '"event":"child_start".*"argv":\["git-remote-https",".*"\]' | + sed -e 's/{"event":"child_start".*"argv":\["git-remote-https","//g' \ + -e 's/"\]}//g' +} + # Print the destination of symlink(s) provided as arguments. Basically # the same as the readlink command, but it's not available everywhere. test_readlink () { @@ -1868,3 +1821,22 @@ test_is_magic_mtime () { rm -f .git/test-mtime-actual return $ret } + +# Given two filenames, parse both using 'git config --list --file' +# and compare the sorted output of those commands. Useful when +# wanting to ignore whitespace differences and sorting concerns. +test_cmp_config_output () { + git config --list --file="$1" >config-expect && + git config --list --file="$2" >config-actual && + sort config-expect >sorted-expect && + sort config-actual >sorted-actual && + test_cmp sorted-expect sorted-actual +} + +# Given a filename, extract its trailing hash as a hex string +test_trailing_hash () { + local file="$1" && + tail -c $(test_oid rawsz) "$file" | + test-tool hexdump | + sed "s/ //g" +} diff --git a/t/test-lib.sh b/t/test-lib.sh index 6ca68311eb..62136caee5 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -47,6 +47,16 @@ then echo "PANIC: Running in a $TEST_DIRECTORY that doesn't end in '/t'?" >&2 exit 1 fi +if test -f "$GIT_BUILD_DIR/GIT-BUILD-DIR" +then + GIT_BUILD_DIR="$(cat "$GIT_BUILD_DIR/GIT-BUILD-DIR")" || exit 1 + # On Windows, we must convert Windows paths lest they contain a colon + case "$(uname -s)" in + *MINGW*) + GIT_BUILD_DIR="$(cygpath -au "$GIT_BUILD_DIR")" + ;; + esac +fi # Prepend a string to a VAR using an arbitrary ":" delimiter, not # adding the delimiter if VAR or VALUE is empty. I.e. a generalized: @@ -635,12 +645,6 @@ u200c=$(printf '\342\200\214') export _x05 _x35 LF u200c EMPTY_TREE EMPTY_BLOB ZERO_OID OID_REGEX -# Each test should start with something like this, after copyright notices: -# -# test_description='Description of this test... -# This test checks if command xyzzy does the right thing... -# ' -# . ./test-lib.sh test "x$TERM" != "xdumb" && ( test -t 1 && tput bold >/dev/null 2>&1 && @@ -1532,8 +1536,8 @@ then # Normalize with test_bool_env passes_sanitize_leak= - # We need to see TEST_PASSES_SANITIZE_LEAK in "git - # env--helper" (via test_bool_env) + # We need to see TEST_PASSES_SANITIZE_LEAK in "test-tool + # env-helper" (via test_bool_env) export TEST_PASSES_SANITIZE_LEAK if test_bool_env TEST_PASSES_SANITIZE_LEAK false then @@ -1672,7 +1676,7 @@ yes () { # The GIT_TEST_FAIL_PREREQS code hooks into test_set_prereq(), and # thus needs to be set up really early, and set an internal variable # for convenience so the hot test_set_prereq() codepath doesn't need -# to call "git env--helper" (via test_bool_env). Only do that work +# to call "test-tool env-helper" (via test_bool_env). Only do that work # if needed by seeing if GIT_TEST_FAIL_PREREQS is set at all. GIT_TEST_FAIL_PREREQS_INTERNAL= if test -n "$GIT_TEST_FAIL_PREREQS" @@ -1711,7 +1715,7 @@ case $uname_s in test_set_prereq SED_STRIPS_CR test_set_prereq GREP_STRIPS_CR test_set_prereq WINDOWS - GIT_TEST_CMP=mingw_test_cmp + GIT_TEST_CMP="GIT_DIR=/dev/null git diff --no-index --ignore-cr-at-eol --" ;; *CYGWIN*) test_set_prereq POSIXPERM @@ -1927,10 +1931,6 @@ test_lazy_prereq SHA1 ' esac ' -test_lazy_prereq ADD_I_USE_BUILTIN ' - test_bool_env GIT_TEST_ADD_I_USE_BUILTIN true -' - # Ensure that no test accidentally triggers a Git command # that runs the actual maintenance scheduler, affecting a user's # system permanently. |