t: add lint-style.pl and convert grep to test_grep
PATCH v3 3/6 t: extract chainlint's parser into shared module
In reply to Michael Montalbo via GitGitGadgetFrom: Michael Montalbo <[email protected]>
Move chainlint.pl's Lexer, ShellParser, and ScriptParser into a shared module (lib-shell-parser.pl) so other lint tools can reuse the same shell parsing infrastructure. A subsequent commit adds greplint.pl, which needs the same tokenizer to correctly identify command boundaries.
ScriptParser's check_test() becomes a no-op in the shared module. chainlint.pl defines ChainlintParser (extending ScriptParser) with the &&-chain check_test() implementation.
No functional change: chainlint produces the same output and check-chainlint self-tests pass.
--- t/chainlint.pl | 529 +---------------------------------------- t/lib-shell-parser.pl | 531 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 543 insertions(+), 517 deletions(-) create mode 100644 t/lib-shell-parser.pl
t/chainlint.pl +12 -517
@@ -23,458 +23,9 @@ my $jobs = -1; my $show_stats; my $emit_all; -# Lexer tokenizes POSIX shell scripts. It is roughly modeled after section 2.3 -# "Token Recognition" of POSIX chapter 2 "Shell Command Language". Although -# similar to lexical analyzers for other languages, this one differs in a few -# substantial ways due to quirks of the shell command language. -# -# For instance, in many languages, newline is just whitespace like space or -# TAB, but in shell a newline is a command separator, thus a distinct lexical -# token. A newline is significant and returned as a distinct token even at the -# end of a shell comment. -# -# In other languages, `1+2` would typically be scanned as three tokens -# (`1`, `+`, and `2`), but in shell it is a single token. However, the similar -# `1 + 2`, which embeds whitespace, is scanned as three token in shell, as well. -# In shell, several characters with special meaning lose that meaning when not -# surrounded by whitespace. For instance, the negation operator `!` is special -# when standing alone surrounded by whitespace; whereas in `foo!uucp` it is -# just a plain character in the longer token "foo!uucp". In many other -# languages, `"string"/foo:'string'` might be scanned as five tokens ("string", -# `/`, `foo`, `:`, and 'string'), but in shell, it is just a single token. -# -# The lexical analyzer for the shell command language is also somewhat unusual -# in that it recursively invokes the parser to handle the body of `$(...)` -# expressions which can contain arbitrary shell code. Such expressions may be -# encountered both inside and outside of double-quoted strings. -# -# The lexical analyzer is responsible for consuming shell here-doc bodies which -# extend from the line following a `<<TAG` operator until a line consisting -# solely of `TAG`. Here-doc consumption begins when a newline is encountered. -# It is legal for multiple here-doc `<<TAG` operators to be present on a single -# line, in which case their bodies must be present one following the next, and -# are consumed in the (left-to-right) order the `<<TAG` operators appear on the -# line. A special complication is that the bodies of all here-docs must be -# consumed when the newline is encountered even if the parse context depth has -# changed. For instance, in `cat <<A && x=$(cat <<B &&\n`, bodies of here-docs -# "A" and "B" must be consumed even though "A" was introduced outside the -# recursive parse context in which "B" was introduced and in which the newline -# is encountered. -package Lexer; - -sub new { - my ($class, $parser, $s) = @_; - bless { - parser => $parser, - buff => $s, - lineno => 1, - heretags => [] - } => $class; -} - -sub scan_heredoc_tag { - my $self = shift @_; - ${$self->{buff}} =~ /\G(-?)/gc; - my $indented = $1; - my $token = $self->scan_token(); - return "<<$indented" unless $token; - my $tag = $token->[0]; - $tag =~ s/['"\\]//g; - $$token[0] = $indented ? "\t$tag" : "$tag"; - push(@{$self->{heretags}}, $token); - return "<<$indented$tag"; -} - -sub scan_op { - my ($self, $c) = @_; - my $b = $self->{buff}; - return $c unless $$b =~ /\G(.)/sgc; - my $cc = $c . $1; - return scan_heredoc_tag($self) if $cc eq '<<'; - return $cc if $cc =~ /^(?:&&|\|\||>>|;;|<&|>&|<>|>\|)$/; - pos($$b)--; - return $c; -} - -sub scan_sqstring { - my $self = shift @_; - ${$self->{buff}} =~ /\G([^']*'|.*\z)/sgc; - my $s = $1; - $self->{lineno} += () = $s =~ /\n/sg; - return "'" . $s; -} - -sub scan_dqstring { - my $self = shift @_; - my $b = $self->{buff}; - my $s = '"'; - while (1) { - # slurp up non-special characters - $s .= $1 if $$b =~ /\G([^"\$\\]+)/gc; - # handle special characters - last unless $$b =~ /\G(.)/sgc; - my $c = $1; - $s .= '"', last if $c eq '"'; - $s .= '$' . $self->scan_dollar(), next if $c eq '$'; - if ($c eq '\\') { - $s .= '\\', last unless $$b =~ /\G(.)/sgc; - $c = $1; - $self->{lineno}++, next if $c eq "\n"; # line splice - # backslash escapes only $, `, ", \ in dq-string - $s .= '\\' unless $c =~ /^[\$`"\\]$/; - $s .= $c; - next; - } - die("internal error scanning dq-string '$c'\n"); - } - $self->{lineno} += () = $s =~ /\n/sg; - return $s; -} - -sub scan_balanced { - my ($self, $c1, $c2) = @_; - my $b = $self->{buff}; - my $depth = 1; - my $s = $c1; - while ($$b =~ /\G([^\Q$c1$c2\E]*(?:[\Q$c1$c2\E]|\z))/gc) { - $s .= $1; - $depth++, next if $s =~ /\Q$c1\E$/; - $depth--; - last if $depth == 0; - } - $self->{lineno} += () = $s =~ /\n/sg; - return $s; -} - -sub scan_subst { - my $self = shift @_; - my @tokens = $self->{parser}->parse(qr/^\)$/); - $self->{parser}->next_token(); # closing ")" - return @tokens; -} - -sub scan_dollar { - my $self = shift @_; - my $b = $self->{buff}; - return $self->scan_balanced('(', ')') 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. - return ''; -} - -sub swallow_heredocs { - my $self = shift @_; - my $b = $self->{buff}; - my $tags = $self->{heretags}; - while (my $tag = shift @$tags) { - my $start = pos($$b); - my $indent = $$tag[0] =~ s/^\t// ? '\\s*' : ''; - $$b =~ /(?:\G|\n)$indent\Q$$tag[0]\E(?:\n|\z)/gc; - if (pos($$b) > $start) { - my $body = substr($$b, $start, pos($$b) - $start); - $self->{parser}->{heredocs}->{$$tag[0]} = { - content => substr($body, 0, length($body) - length($&)), - start_line => $self->{lineno}, - }; - $self->{lineno} += () = $body =~ /\n/sg; - next; - } - push(@{$self->{parser}->{problems}}, ['HEREDOC', $tag]); - $$b =~ /(?:\G|\n).*\z/gc; # consume rest of input - my $body = substr($$b, $start, pos($$b) - $start); - $self->{lineno} += () = $body =~ /\n/sg; - last; - } -} - -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) - $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; - 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->{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; - $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, $start, pos($$b), $startln, $self->{lineno}] : undef; -} - -# ShellParser parses POSIX shell scripts (with minor extensions for Bash). It -# is a recursive descent parser very roughly modeled after section 2.10 "Shell -# Grammar" of POSIX chapter 2 "Shell Command Language". -package ShellParser; - -sub new { - my ($class, $s) = @_; - my $self = bless { - buff => [], - stop => [], - output => [], - heredocs => {}, - insubshell => 0, - } => $class; - $self->{lexer} = Lexer->new($self, $s); - return $self; -} - -sub next_token { - my $self = shift @_; - return pop(@{$self->{buff}}) if @{$self->{buff}}; - return $self->{lexer}->scan_token(); -} - -sub untoken { - my $self = shift @_; - push(@{$self->{buff}}, @_); -} - -sub peek { - my $self = shift @_; - my $token = $self->next_token(); - return undef unless defined($token); - $self->untoken($token); - return $token; -} - -sub stop_at { - my ($self, $token) = @_; - return 1 unless defined($token); - my $stop = ${$self->{stop}}[-1] if @{$self->{stop}}; - return defined($stop) && $token->[0] =~ $stop; -} - -sub expect { - my ($self, $expect) = @_; - my $token = $self->next_token(); - 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 (); -} - -sub optional_newlines { - my $self = shift @_; - my @tokens; - while (my $token = $self->peek()) { - last unless $token->[0] eq "\n"; - push(@tokens, $self->next_token()); - } - return @tokens; -} - -sub parse_group { - my $self = shift @_; - return ($self->parse(qr/^}$/), - $self->expect('}')); -} - -sub parse_subshell { - my $self = shift @_; - $self->{insubshell}++; - my @tokens = ($self->parse(qr/^\)$/), - $self->expect(')')); - $self->{insubshell}--; - return @tokens; -} - -sub parse_case_pattern { - my $self = shift @_; - my @tokens; - while (defined(my $token = $self->next_token())) { - push(@tokens, $token); - last if $token->[0] eq ')'; - } - return @tokens; -} - -sub parse_case { - my $self = shift @_; - my @tokens; - push(@tokens, - $self->next_token(), # subject - $self->optional_newlines(), - $self->expect('in'), - $self->optional_newlines()); - while (1) { - my $token = $self->peek(); - 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->[0] ne 'esac'; - push(@tokens, - $self->expect(';;'), - $self->optional_newlines()); - } - push(@tokens, $self->expect('esac')); - return @tokens; -} - -sub parse_for { - my $self = shift @_; - my @tokens; - push(@tokens, - $self->next_token(), # variable - $self->optional_newlines()); - my $token = $self->peek(); - if (defined($token) && $token->[0] eq 'in') { - push(@tokens, - $self->expect('in'), - $self->optional_newlines()); - } - push(@tokens, - $self->parse(qr/^do$/), # items - $self->expect('do'), - $self->optional_newlines(), - $self->parse_loop_body(), - $self->expect('done')); - return @tokens; -} - -sub parse_if { - my $self = shift @_; - my @tokens; - while (1) { - push(@tokens, - $self->parse(qr/^then$/), # if/elif condition - $self->expect('then'), - $self->optional_newlines(), - $self->parse(qr/^(?:elif|else|fi)$/)); # if/elif body - my $token = $self->peek(); - last unless defined($token) && $token->[0] eq 'elif'; - push(@tokens, $self->expect('elif')); - } - my $token = $self->peek(); - if (defined($token) && $token->[0] eq 'else') { - push(@tokens, - $self->expect('else'), - $self->optional_newlines(), - $self->parse(qr/^fi$/)); # else body - } - push(@tokens, $self->expect('fi')); - return @tokens; -} - -sub parse_loop_body { - my $self = shift @_; - return $self->parse(qr/^done$/); -} - -sub parse_loop { - my $self = shift @_; - return ($self->parse(qr/^do$/), # condition - $self->expect('do'), - $self->optional_newlines(), - $self->parse_loop_body(), - $self->expect('done')); -} - -sub parse_func { - my $self = shift @_; - return ($self->expect('('), - $self->expect(')'), - $self->optional_newlines(), - $self->parse_cmd()); # body -} - -sub parse_bash_array_assignment { - my $self = shift @_; - my @tokens = $self->expect('('); - while (defined(my $token = $self->next_token())) { - push(@tokens, $token); - last if $token->[0] eq ')'; - } - return @tokens; -} - -my %compound = ( - '{' => \&parse_group, - '(' => \&parse_subshell, - 'case' => \&parse_case, - 'for' => \&parse_for, - 'if' => \&parse_if, - 'until' => \&parse_loop, - 'while' => \&parse_loop); - -sub parse_cmd { - my $self = shift @_; - my $cmd = $self->next_token(); - return () unless defined($cmd); - return $cmd if $cmd->[0] eq "\n"; - - my $token; - my @tokens = $cmd; - if ($cmd->[0] eq '!') { - push(@tokens, $self->parse_cmd()); - return @tokens; - } elsif (my $f = $compound{$cmd->[0]}) { - push(@tokens, $self->$f()); - } elsif (defined($token = $self->peek()) && $token->[0] eq '(') { - if ($cmd->[0] !~ /\w=$/) { - push(@tokens, $self->parse_func()); - return @tokens; - } - 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->[0] =~ /^(?:[;&\n|]|&&|\|\|)$/; - } - push(@tokens, $self->next_token()) if $tokens[-1]->[0] ne "\n" && defined($token = $self->peek()) && $token->[0] eq "\n"; - return @tokens; -} - -sub accumulate { - my ($self, $tokens, $cmd) = @_; - push(@$tokens, @$cmd); -} - -sub parse { - my ($self, $stop) = @_; - push(@{$self->{stop}}, $stop); - goto DONE if $self->stop_at($self->peek()); - my @tokens; - while (my @cmd = $self->parse_cmd()) { - $self->accumulate(\@tokens, \@cmd); - last if $self->stop_at($self->peek()); - } -DONE: - pop(@{$self->{stop}}); - return @tokens; -} +use File::Basename; +do(dirname($0) . "/lib-shell-parser.pl") + or die "$0: failed to load lib-shell-parser.pl: $@$!\n"; # TestParser is a subclass of ShellParser which, beyond parsing shell script # code, is also imbued with semantic knowledge of test construction, and checks
@@ -482,9 +33,10 @@ DONE: # the tests themselves or in behaviors being exercised by the tests. As such, # TestParser is only called upon to parse test bodies, not the top-level # scripts in which the tests are defined. + package TestParser; -use base 'ShellParser'; +our @ISA = ('ShellParser'); sub new { my $class = shift @_;
@@ -578,51 +130,10 @@ DONE: $self->SUPER::accumulate($tokens, $cmd); } -# ScriptParser is a subclass of ShellParser which identifies individual test -# definitions within test scripts, and passes each test body through TestParser -# to identify possible problems. ShellParser detects test definitions not only -# at the top-level of test scripts but also within compound commands such as -# loops and function definitions. -package ScriptParser; - -use base 'ShellParser'; - -sub new { - my $class = shift @_; - my $self = $class->SUPER::new(@_); - $self->{ntests} = 0; - $self->{nerrs} = 0; - return $self; -} +# ChainlintParser extends ScriptParser with &&-chain checking +package ChainlintParser; -# extract the raw content of a token, which may be a single string or a -# 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 @_ : $_)->[0]; - # simple case: 'sqstring' or "dqstring" - return $token if $token =~ s/^'([^']*)'$/$1/; - return $token if $token =~ s/^"([^"]*)"$/$1/; - - # composite case - my ($s, $q, $escaped); - while (1) { - # slurp up non-special characters - $s .= $1 if $token =~ /\G([^\\'"]*)/gc; - # handle special characters - last unless $token =~ /\G(.)/sgc; - my $c = $1; - $q = undef, next if defined($q) && $c eq $q; - $q = $c, next if !defined($q) && $c =~ /^['"]$/; - if ($c eq '\\') { - last unless $token =~ /\G(.)/sgc; - $c = $1; - $s .= '\\' if $c eq "\n"; # preserve line splice - } - $s .= $c; - } - return $s -} +our @ISA = ('ScriptParser'); sub format_problem { local $_ = shift;
@@ -635,10 +146,10 @@ sub format_problem { sub check_test { my $self = shift @_; - my $title = unwrap(shift @_); + my $title = ScriptParser::unwrap(shift @_); my $body = shift @_; my $lineno = $body->[3]; - $body = unwrap($body); + $body = ScriptParser::unwrap($body); if ($body eq '-') { my $herebody = shift @_; $body = $herebody->{content};
@@ -673,24 +184,8 @@ sub check_test { push(@{$self->{output}}, "$c->{blue}# chainlint: $title$c->{reset}\n$checked"); } -sub parse_cmd { - my $self = shift @_; - my @tokens = $self->SUPER::parse_cmd(); - return @tokens unless @tokens && $tokens[0]->[0] =~ /^test_expect_(?:success|failure)$/; - my $n = $#tokens; - $n-- while $n >= 0 && $tokens[$n]->[0] =~ /^(?:[;&\n|]|&&|\|\|)$/; - my $herebody; - if ($n >= 2 && $tokens[$n-1]->[0] eq '-' && $tokens[$n]->[0] =~ /^<<-?(.+)$/) { - $herebody = $self->{heredocs}->{$1}; - $n--; - } - $self->check_test($tokens[1], $tokens[2], $herebody) if $n == 2; # title body - $self->check_test($tokens[2], $tokens[3], $herebody) if $n > 2; # prereq title body - return @tokens; -} - # main contains high-level functionality for processing command-line switches, -# feeding input test scripts to ScriptParser, and reporting results. +# feeding input test scripts to ChainlintParser, and reporting results. package main; my $getnow = sub { return time(); };
@@ -803,7 +298,7 @@ sub check_script { } my $s = do { local $/; <$fh> }; close($fh); - my $parser = ScriptParser->new(\$s); + my $parser = ChainlintParser->new(\$s); 1 while $parser->parse_cmd(); if (@{$parser->{output}}) { my $c = fd_colors(1);
t/lib-shell-parser.pl new file +531 -0
531 lines not on this page · raw message
Signature · 1 line
gitgitgadget
PATCH v3 4/6 t: fix Lexer line count for $() inside double-quoted strings
In reply to Michael Montalbo via GitGitGadgetFrom: Michael Montalbo <[email protected]>
scan_dqstring's post-loop newline counter re-counts newlines that were already counted during recursive parsing of $() bodies. This happens because scan_dollar returns text containing newlines (from multi-line command substitutions), and the catch-all counter at the end of scan_dqstring counts all of them again.
Fix this by counting newlines inline as non-special characters are consumed, and removing the post-loop catch-all. Each newline is now counted exactly once: literal newlines at the inline match, line splices at the backslash handler, and $() newlines by scan_token during the recursive parse.
This is a latent bug: any consumer that relies on token line numbers rather than byte offsets would get incorrect results for tokens following a multi-line $() inside a double-quoted string. chainlint is not affected because it annotates the original body text using byte offsets, not token line numbers.
--- t/lib-shell-parser.pl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
t/lib-shell-parser.pl +6 -3
@@ -93,8 +93,12 @@ sub scan_dqstring { my $b = $self->{buff}; my $s = '"'; while (1) { - # slurp up non-special characters - $s .= $1 if $$b =~ /\G([^"\$\\]+)/gc; + # Slurp non-special characters; count newlines here because + # newlines inside $() are already counted by the recursive parse. + if ($$b =~ /\G([^"\$\\]+)/gc) { + $s .= $1; + $self->{lineno} += $1 =~ tr/\n//; + } # handle special characters last unless $$b =~ /\G(.)/sgc; my $c = $1;
@@ -111,7 +115,6 @@ sub scan_dqstring { } die("internal error scanning dq-string '$c'\n"); } - $self->{lineno} += () = $s =~ /\n/sg; return $s; }
Signature · 1 line
gitgitgadget
PATCH v3 5/6 t: convert grep assertions to test_grep
In reply to Michael Montalbo via GitGitGadgetFrom: Michael Montalbo <[email protected]>
Replace bare grep with test_grep in test assertions across the suite, including sourced test helpers (lib-*.sh, *-tests.sh). test_grep prints the contents of the file being searched on failure, making debugging easier than a bare grep which fails silently.
Only assertion-style greps are converted: grep used as a filter in pipelines, command substitutions, conditionals, or with redirected I/O is left as-is with a "# lint-ok" annotation. Existing '! test_grep' calls are rewritten to 'test_grep !' so that the diagnostic output is preserved on failure.
test_grep requires the file it reads to exist, so '! grep' assertions that inspect a file whose presence is conditional need care. In t5537 the '.git/shallow' file is still present after the repack (the client remains shallow), so the assertion is converted like any other. In t1400 the '.git/packed-refs' file exists only with the files backend, so its check is guarded with a REFFILES prerequisite; the backend-agnostic 'git show-ref' check that follows still runs under every backend. In t7450 'git~2' is the NTFS 8.3 short name of a decoy '..git' file and only exists when 8.3 short-name generation is enabled; that '! grep' tolerates the missing file on purpose, so it is left as-is with a "# lint-ok" annotation rather than converted (a plain test_grep would BUG when the short name is absent).
The conversion was generated using a grep-assertion linter (greplint.pl, added in the following commit) to identify bare grep calls at command position. To reproduce, from the t/ directory:
# Step 1: annotate the two data-filter greps (grep produces
# data, not a verdict) so the linter skips them.
sed -i '/grep -vf before commits\.raw/s/$/ # lint-ok: data filter/' \
t5326-multi-pack-bitmaps.sh
sed -i '/grep -E "^\[0-9a-f\].*|| :/s/$/ # lint-ok: data filter/' \
t5702-protocol-v2.sh
# Step 1b: two '! grep' assertions need more than a mechanical
# conversion; handle them by hand before the linter-driven steps
# below so it leaves them alone.
#
# t1400: '.git/packed-refs' is absent under reftable, so guard the
# check with REFFILES (a plain test_grep would BUG on the missing
# file):
#
# git update-ref -d HEAD $B &&
# - ! grep "$m" .git/packed-refs &&
# + if test_have_prereq REFFILES
# + then
# + test_grep ! "$m" .git/packed-refs
# + fi &&
# test_must_fail git show-ref --verify -q $m
#
# t7450: git~2 is an NTFS 8.3 short name that exists only when
# short-name generation is enabled, so this stays a missing-file-
# tolerant '! grep'; add a comment plus "# lint-ok" so the linter
# skips it.
# Step 2: reorder pre-existing '! test_grep' to 'test_grep !'
# (must come before steps 3-4 so greplint does not see them)
sed -i 's/! test_grep/test_grep !/' t0031-lockfile-pid.sh
sed -i 's/! test_grep/test_grep !/' t5300-pack-object.sh
sed -i 's/! test_grep/test_grep !/' t5319-multi-pack-index.sh
# Step 3: convert '! grep' -> 'test_grep !'
perl greplint.pl *.sh 2>&1 | cut -d: -f1,2 |
while IFS=: read f l; do
sed -i "${l}s/! *grep/test_grep !/" "$f"
done
# Step 4: convert remaining 'grep' -> 'test_grep'
perl greplint.pl *.sh 2>&1 | cut -d: -f1,2 |
while IFS=: read f l; do
sed -i "${l}s/grep/test_grep/" "$f"
doneTo verify, run: make -C t test-greplint
--- t/for-each-ref-tests.sh | 12 +- t/lib-bitmap.sh | 12 +- t/lib-bundle-uri-protocol.sh | 26 +- t/lib-httpd.sh | 2 +- t/pack-refs-tests.sh | 2 +- t/show-ref-exists-tests.sh | 2 +- t/t0000-basic.sh | 16 +- t/t0001-init.sh | 18 +- t/t0008-ignores.sh | 8 +- t/t0009-git-dir-validation.sh | 6 +- t/t0012-help.sh | 4 +- t/t0013-sha1dc.sh | 2 +- t/t0017-env-helper.sh | 4 +- t/t0021-conversion.sh | 18 +- t/t0029-core-unsetenvvars.sh | 4 +- t/t0030-stripspace.sh | 4 +- t/t0031-lockfile-pid.sh | 2 +- t/t0040-parse-options.sh | 52 +-- t/t0041-usage.sh | 2 +- t/t0052-simple-ipc.sh | 10 +- t/t0061-run-command.sh | 2 +- t/t0066-dir-iterator.sh | 2 +- t/t0068-for-each-repo.sh | 16 +- t/t0070-fundamental.sh | 6 +- t/t0081-find-pack.sh | 12 +- t/t0091-bugreport.sh | 18 +- t/t0092-diagnose.sh | 12 +- t/t0100-previous.sh | 2 +- t/t0200-gettext-basic.sh | 14 +- t/t0203-gettext-setlocale-sanity.sh | 4 +- t/t0204-gettext-reencode-sanity.sh | 8 +- t/t0210-trace2-normal.sh | 6 +- t/t0211-trace2-perf.sh | 80 ++--- t/t0212-trace2-event.sh | 8 +- t/t0300-credentials.sh | 4 +- t/t0410-partial-clone.sh | 82 ++--- t/t0450-txt-doc-vs-help.sh | 2 +- t/t0500-progress-display.sh | 18 +- t/t0610-reftable-basics.sh | 8 +- t/t1004-read-tree-m-u-wf.sh | 8 +- t/t1006-cat-file.sh | 18 +- t/t1007-hash-object.sh | 8 +- t/t1011-read-tree-sparse-checkout.sh | 10 +- t/t1050-large.sh | 6 +- t/t1091-sparse-checkout-builtin.sh | 24 +- t/t1092-sparse-checkout-compatibility.sh | 44 +-- t/t1300-config.sh | 16 +- t/t1305-config-include.sh | 2 +- t/t1308-config-set.sh | 6 +- t/t1400-update-ref.sh | 173 +++++----- t/t1403-show-ref.sh | 18 +- t/t1410-reflog.sh | 4 +- t/t1415-worktree-refs.sh | 4 +- t/t1430-bad-ref-name.sh | 56 ++-- t/t1450-fsck.sh | 12 +- t/t1451-fsck-buffer.sh | 6 +- t/t1460-refs-migrate.sh | 2 +- t/t1500-rev-parse.sh | 6 +- t/t1502-rev-parse-parseopt.sh | 2 +- t/t1503-rev-parse-verify.sh | 10 +- t/t1510-repo-setup.sh | 10 +- t/t1512-rev-parse-disambiguation.sh | 4 +- t/t1515-rev-parse-outside-repo.sh | 2 +- t/t1800-hook.sh | 18 +- t/t2004-checkout-cache-temp.sh | 4 +- t/t2019-checkout-ambiguous-ref.sh | 4 +- t/t2024-checkout-dwim.sh | 8 +- t/t2030-unresolve-info.sh | 6 +- t/t2060-switch.sh | 6 +- t/t2070-restore.sh | 2 +- t/t2080-parallel-checkout-basics.sh | 14 +- t/t2081-parallel-checkout-collisions.sh | 24 +- t/t2082-parallel-checkout-attributes.sh | 12 +- t/t2103-update-index-ignore-missing.sh | 6 +- t/t2200-add-update.sh | 2 +- t/t2203-add-intent.sh | 6 +- t/t2400-worktree-add.sh | 24 +- t/t2402-worktree-list.sh | 16 +- t/t2403-worktree-move.sh | 6 +- t/t2405-worktree-submodule.sh | 6 +- t/t2407-worktree-heads.sh | 26 +- t/t2500-untracked-overwriting.sh | 8 +- t/t2501-cwd-empty.sh | 4 +- t/t3001-ls-files-others-exclude.sh | 6 +- t/t3007-ls-files-recurse-submodules.sh | 6 +- t/t3200-branch.sh | 12 +- t/t3202-show-branch.sh | 10 +- t/t3203-branch-output.sh | 4 +- t/t3206-range-diff.sh | 78 ++--- t/t3207-branch-submodule.sh | 4 +- t/t3301-notes.sh | 32 +- t/t3310-notes-merge-manual-resolve.sh | 16 +- t/t3320-notes-merge-worktrees.sh | 2 +- t/t3400-rebase.sh | 16 +- t/t3402-rebase-merge.sh | 16 +- t/t3404-rebase-interactive.sh | 72 ++-- t/t3406-rebase-message.sh | 6 +- t/t3415-rebase-autosquash.sh | 10 +- t/t3416-rebase-onto-threedots.sh | 4 +- t/t3418-rebase-continue.sh | 10 +- t/t3420-rebase-autostash.sh | 24 +- t/t3422-rebase-incompatible-options.sh | 4 +- t/t3429-rebase-edit-todo.sh | 2 +- t/t3430-rebase-merges.sh | 32 +- t/t3500-cherry.sh | 4 +- t/t3501-revert-cherry-pick.sh | 6 +- t/t3504-cherry-pick-rerere.sh | 6 +- t/t3510-cherry-pick-sequence.sh | 24 +- t/t3602-rm-sparse-checkout.sh | 4 +- t/t3705-add-sparse-checkout.sh | 10 +- t/t3800-mktag.sh | 4 +- t/t3901-i18n-patch.sh | 16 +- t/t3903-stash.sh | 28 +- t/t3904-stash-patch.sh | 4 +- t/t3908-stash-in-worktree.sh | 2 +- t/t4000-diff-format.sh | 2 +- t/t4001-diff-rename.sh | 4 +- t/t4011-diff-symlink.sh | 2 +- t/t4013-diff-various.sh | 2 +- t/t4014-format-patch.sh | 344 ++++++++++---------- t/t4015-diff-whitespace.sh | 16 +- t/t4017-diff-retval.sh | 2 +- t/t4018-diff-funcname.sh | 2 +- t/t4019-diff-wserror.sh | 8 +- t/t4020-diff-external.sh | 18 +- t/t4021-format-patch-numbered.sh | 4 +- t/t4022-diff-rewrite.sh | 14 +- t/t4028-format-patch-mime-headers.sh | 6 +- t/t4031-diff-rewrite-binary.sh | 18 +- t/t4033-diff-patience.sh | 2 +- t/t4036-format-patch-signer-mime.sh | 6 +- t/t4038-diff-combined.sh | 6 +- t/t4051-diff-function-context.sh | 38 +-- t/t4053-diff-no-index.sh | 4 +- t/t4063-diff-blobs.sh | 2 +- t/t4065-diff-anchored.sh | 26 +- t/t4067-diff-partial-clone.sh | 12 +- t/t4073-diff-stat-name-width.sh | 24 +- t/t4103-apply-binary.sh | 2 +- t/t4120-apply-popt.sh | 2 +- t/t4124-apply-ws-rule.sh | 10 +- t/t4128-apply-root.sh | 2 +- t/t4140-apply-ita.sh | 4 +- t/t4141-apply-too-large.sh | 2 +- t/t4150-am.sh | 48 +-- t/t4200-rerere.sh | 6 +- t/t4201-shortlog.sh | 2 +- t/t4202-log.sh | 84 ++--- t/t4204-patch-id.sh | 2 +- t/t4205-log-pretty-formats.sh | 2 +- t/t4209-log-pickaxe.sh | 10 +- t/t4211-line-log.sh | 72 ++-- t/t4216-log-bloom.sh | 18 +- t/t4252-am-options.sh | 22 +- t/t4254-am-corrupt.sh | 6 +- t/t4258-am-quoted-cr.sh | 2 +- t/t4301-merge-tree-write-tree.sh | 18 +- t/t5000-tar-tree.sh | 10 +- t/t5004-archive-corner-cases.sh | 2 +- t/t5100-mailinfo.sh | 2 +- t/t5150-request-pull.sh | 18 +- t/t5300-pack-object.sh | 22 +- t/t5302-pack-index.sh | 6 +- t/t5304-prune.sh | 8 +- t/t5310-pack-bitmaps.sh | 14 +- t/t5317-pack-objects-filter-objects.sh | 12 +- t/t5318-commit-graph.sh | 8 +- t/t5319-multi-pack-index.sh | 16 +- t/t5324-split-commit-graph.sh | 10 +- t/t5325-reverse-index.sh | 2 +- t/t5326-multi-pack-bitmaps.sh | 28 +- t/t5328-commit-graph-64bit-time.sh | 2 +- t/t5329-pack-objects-cruft.sh | 8 +- t/t5334-incremental-multi-pack-index.sh | 2 +- t/t5335-compact-multi-pack-index.sh | 4 +- t/t5351-unpack-large-objects.sh | 2 +- t/t5402-post-merge-hook.sh | 4 +- t/t5403-post-checkout-hook.sh | 2 +- t/t5404-tracking-branches.sh | 2 +- t/t5406-remote-rejects.sh | 2 +- t/t5407-post-rewrite-hook.sh | 8 +- t/t5409-colorize-remote-messages.sh | 36 +- t/t5500-fetch-pack.sh | 38 +-- t/t5504-fetch-receive-strict.sh | 14 +- t/t5505-remote.sh | 20 +- t/t5510-fetch.sh | 10 +- t/t5512-ls-remote.sh | 8 +- t/t5514-fetch-multiple.sh | 2 +- t/t5516-fetch-push.sh | 20 +- t/t5520-pull.sh | 4 +- t/t5524-pull-msg.sh | 6 +- t/t5526-fetch-submodules.sh | 16 +- t/t5529-push-errors.sh | 4 +- t/t5530-upload-pack-error.sh | 18 +- t/t5531-deep-submodule-push.sh | 2 +- t/t5532-fetch-proxy.sh | 2 +- t/t5533-push-cas.sh | 12 +- t/t5534-push-signed.sh | 22 +- t/t5537-fetch-shallow.sh | 2 +- t/t5538-push-shallow.sh | 2 +- t/t5539-fetch-http-shallow.sh | 4 +- t/t5541-http-push-smart.sh | 32 +- t/t5544-pack-objects-hook.sh | 12 +- t/t5550-http-fetch-dumb.sh | 4 +- t/t5551-http-fetch-smart.sh | 46 +-- t/t5552-skipping-fetch-negotiator.sh | 6 +- t/t5554-noop-fetch-negotiator.sh | 4 +- t/t5557-http-get.sh | 2 +- t/t5558-clone-bundle-uri.sh | 38 +-- t/t5562-http-backend-content-length.sh | 2 +- t/t5564-http-proxy.sh | 10 +- t/t5581-http-curl-verbose.sh | 2 +- t/t5583-push-branches.sh | 8 +- t/t5601-clone.sh | 28 +- t/t5604-clone-reference.sh | 8 +- t/t5605-clone-local.sh | 2 +- t/t5606-clone-options.sh | 6 +- t/t5612-clone-refspec.sh | 2 +- t/t5616-partial-clone.sh | 60 ++-- t/t5619-clone-local-ambiguous-transport.sh | 2 +- t/t5620-backfill.sh | 12 +- t/t5700-protocol-v1.sh | 46 +-- t/t5701-git-serve.sh | 14 +- t/t5702-protocol-v2.sh | 154 ++++----- t/t5703-upload-pack-ref-in-want.sh | 22 +- t/t5705-session-id-in-capabilities.sh | 12 +- t/t5750-bundle-uri-parse.sh | 8 +- t/t5801-remote-helpers.sh | 4 +- t/t5810-proto-disable-local.sh | 2 +- t/t5813-proto-disable-ssh.sh | 4 +- t/t6000-rev-list-misc.sh | 26 +- t/t6005-rev-list-count.sh | 8 +- t/t6006-rev-list-format.sh | 4 +- t/t6009-rev-list-parent.sh | 4 +- t/t6020-bundle-misc.sh | 12 +- t/t6022-rev-list-missing.sh | 4 +- t/t6030-bisect-porcelain.sh | 150 ++++----- t/t6040-tracking-info.sh | 2 +- t/t6112-rev-list-filters-objects.sh | 24 +- t/t6115-rev-list-du.sh | 4 +- t/t6120-describe.sh | 14 +- t/t6200-fmt-merge-msg.sh | 82 ++--- t/t6402-merge-rename.sh | 4 +- t/t6403-merge-file.sh | 6 +- t/t6404-recursive-merge.sh | 2 +- t/t6406-merge-attr.sh | 20 +- t/t6417-merge-ours-theirs.sh | 30 +- t/t6418-merge-text-auto.sh | 2 +- t/t6422-merge-rename-corner-cases.sh | 8 +- t/t6423-merge-rename-directories.sh | 72 ++-- t/t6424-merge-unrelated-index-changes.sh | 6 +- t/t6427-diff3-conflict-markers.sh | 10 +- t/t6432-merge-recursive-space-options.sh | 4 +- t/t6436-merge-overwrite.sh | 6 +- t/t6437-submodule-merge.sh | 10 +- t/t6500-gc.sh | 8 +- t/t6600-test-reach.sh | 4 +- t/t7001-mv.sh | 16 +- t/t7002-mv-sparse-checkout.sh | 38 +-- t/t7003-filter-branch.sh | 16 +- t/t7004-tag.sh | 2 +- t/t7006-pager.sh | 16 +- t/t7012-skip-worktree-writing.sh | 6 +- t/t7030-verify-tag.sh | 52 +-- t/t7031-verify-tag-signed-ssh.sh | 46 +-- t/t7102-reset.sh | 2 +- t/t7110-reset-merge.sh | 40 +-- t/t7201-co.sh | 6 +- t/t7300-clean.sh | 2 +- t/t7301-clean-interactive.sh | 2 +- t/t7400-submodule-basic.sh | 32 +- t/t7402-submodule-rebase.sh | 2 +- t/t7406-submodule-update.sh | 26 +- t/t7416-submodule-dash-url.sh | 20 +- t/t7417-submodule-path-url.sh | 2 +- t/t7450-bad-git-dotfiles.sh | 18 +- t/t7501-commit-basic-functionality.sh | 16 +- t/t7502-commit-porcelain.sh | 2 +- t/t7507-commit-verbose.sh | 6 +- t/t7508-status.sh | 6 +- t/t7510-signed-commit.sh | 68 ++-- t/t7516-commit-races.sh | 4 +- t/t7519-status-fsmonitor.sh | 14 +- t/t7527-builtin-fsmonitor.sh | 82 ++--- t/t7528-signed-commit-ssh.sh | 68 ++-- t/t7600-merge.sh | 10 +- t/t7603-merge-reduce-heads.sh | 20 +- t/t7606-merge-custom.sh | 2 +- t/t7607-merge-state.sh | 4 +- t/t7610-mergetool.sh | 18 +- t/t7700-repack.sh | 14 +- t/t7703-repack-geometric.sh | 4 +- t/t7704-repack-cruft.sh | 12 +- t/t7800-difftool.sh | 26 +- t/t7810-grep.sh | 22 +- t/t7814-grep-recurse-submodules.sh | 2 +- t/t7900-maintenance.sh | 34 +- t/t8008-blame-formats.sh | 2 +- t/t8010-cat-file-filters.sh | 2 +- t/t8012-blame-colors.sh | 2 +- t/t9001-send-email.sh | 190 +++++------ t/t9003-help-autocorrect.sh | 6 +- t/t9106-git-svn-commit-diff-clobber.sh | 2 +- t/t9107-git-svn-migrate.sh | 30 +- t/t9110-git-svn-use-svm-props.sh | 20 +- t/t9111-git-svn-use-svnsync-props.sh | 18 +- t/t9114-git-svn-dcommit-merge.sh | 6 +- t/t9116-git-svn-log.sh | 8 +- t/t9117-git-svn-init-clone.sh | 12 +- t/t9119-git-svn-info.sh | 16 +- t/t9122-git-svn-author.sh | 8 +- t/t9130-git-svn-authors-file.sh | 8 +- t/t9138-git-svn-authors-prog.sh | 14 +- t/t9140-git-svn-reset.sh | 4 +- t/t9153-git-svn-rewrite-uuid.sh | 4 +- t/t9200-git-cvsexportcommit.sh | 2 +- t/t9210-scalar.sh | 34 +- t/t9211-scalar-clone.sh | 16 +- t/t9300-fast-import.sh | 10 +- t/t9350-fast-export.sh | 54 +-- t/t9351-fast-export-anonymize.sh | 36 +- t/t9400-git-cvsserver-server.sh | 4 +- t/t9501-gitweb-standalone-http-status.sh | 58 ++-- t/t9502-gitweb-standalone-parse-output.sh | 38 +-- t/t9800-git-p4-basic.sh | 10 +- t/t9801-git-p4-branch.sh | 48 +-- t/t9806-git-p4-options.sh | 10 +- t/t9807-git-p4-submit.sh | 2 +- t/t9810-git-p4-rcs.sh | 8 +- t/t9813-git-p4-preserve-users.sh | 8 +- t/t9814-git-p4-rename.sh | 8 +- t/t9827-git-p4-change-filetype.sh | 4 +- t/t9832-unshelve.sh | 6 +- t/t9833-errors.sh | 4 +- t/t9835-git-p4-metadata-encoding-python2.sh | 36 +- t/t9836-git-p4-metadata-encoding-python3.sh | 38 +-- t/t9850-shell.sh | 2 +- t/t9902-completion.sh | 26 +- 338 files changed, 2813 insertions(+), 2806 deletions(-)
t/for-each-ref-tests.sh +6 -6
@@ -523,7 +523,7 @@ test_expect_success 'Verify descending sort' ' test_expect_success 'Give help even with invalid sort atoms' ' test_expect_code 129 ${git_for_each_ref} --sort=bogus -h >actual 2>&1 && - grep "^usage: ${git_for_each_ref}" actual + test_grep "^usage: ${git_for_each_ref}" actual ' cat >expected <<\EOF
@@ -622,7 +622,7 @@ test_expect_success 'Quoting style: tcl' ' for i in "--perl --shell" "-s --python" "--python --tcl" "--tcl --perl"; do test_expect_success "more than one quoting style: $i" " test_must_fail ${git_for_each_ref} $i 2>err && - grep '^error: more than one quoting style' err + test_grep '^error: more than one quoting style' err " done
@@ -1892,7 +1892,7 @@ test_expect_success "${git_for_each_ref} --stdin: fails if extra args" ' >in && test_must_fail ${git_for_each_ref} --format="%(refname)" \ --stdin refs/heads/extra <in 2>err && - grep "unknown arguments supplied with --stdin" err + test_grep "unknown arguments supplied with --stdin" err ' test_expect_success "${git_for_each_ref} --stdin: matches" '
@@ -1955,11 +1955,11 @@ test_expect_success "${git_for_each_ref} with nested tags" ' test_expect_success 'is-base atom with non-commits' ' ${git_for_each_ref} --format="%(is-base:HEAD) %(refname)" >out 2>err && - grep "(HEAD) refs/heads/main" out && + test_grep "(HEAD) refs/heads/main" out && test_line_count = 2 err && - grep "error: object .* is a commit, not a blob" err && - grep "error: bad tag pointer to" err + test_grep "error: object .* is a commit, not a blob" err && + test_grep "error: bad tag pointer to" err ' GRADE_FORMAT="%(signature:grade)%0a%(signature:key)%0a%(signature:signer)%0a%(signature:fingerprint)%0a%(signature:primarykeyfingerprint)"
t/lib-bitmap.sh +6 -6
@@ -173,7 +173,7 @@ rev_list_tests_head () { test_expect_success "bitmap --objects handles non-commit objects ($state, $branch)" ' git rev-list --objects --use-bitmap-index $branch tagged-blob >actual && - grep $blob actual + test_grep $blob actual ' }
@@ -242,16 +242,16 @@ basic_bitmap_tests () { GIT_PROGRESS_DELAY=0 \ git pack-objects --all --stdout --progress \ </dev/null >/dev/null 2>stderr && - grep "Enumerating objects: $count, done" stderr && - grep "pack-reused $count" stderr && + test_grep "Enumerating objects: $count, done" stderr && + test_grep "pack-reused $count" stderr && # now the same but with one non-reused object git commit --allow-empty -m "an extra commit object" && GIT_PROGRESS_DELAY=0 \ git pack-objects --all --stdout --progress \ </dev/null >/dev/null 2>stderr && - grep "Enumerating objects: $((count+1)), done" stderr && - grep "pack-reused $count" stderr + test_grep "Enumerating objects: $((count+1)), done" stderr && + test_grep "pack-reused $count" stderr ' }
@@ -283,7 +283,7 @@ test_rev_exists () { then test_path_is_file $midx-$(midx_checksum $objdir).rev fi && - grep "\"category\":\"load_midx_revindex\",\"key\":\"source\",\"value\":\"$kind\"" event.trace + test_grep "\"category\":\"load_midx_revindex\",\"key\":\"source\",\"value\":\"$kind\"" event.trace ' }
t/lib-bundle-uri-protocol.sh +13 -13
@@ -63,9 +63,9 @@ test_expect_success "connect with $BUNDLE_URI_PROTOCOL:// using protocol v2: no >actual 2>err && # Server responded using protocol v2 - grep "< version 2" log && + test_grep "< version 2" log && - ! grep bundle-uri log + test_grep ! bundle-uri log ' test_expect_success "connect with $BUNDLE_URI_PROTOCOL:// using protocol v2: have bundle-uri" '
@@ -78,10 +78,10 @@ test_expect_success "connect with $BUNDLE_URI_PROTOCOL:// using protocol v2: hav >actual 2>err && # Server responded using protocol v2 - grep "< version 2" log && + test_grep "< version 2" log && # Server advertised bundle-uri capability - grep "< bundle-uri" log + test_grep "< bundle-uri" log ' test_expect_success "clone with $BUNDLE_URI_PROTOCOL:// using protocol v2: request bundle-uris" '
@@ -95,13 +95,13 @@ test_expect_success "clone with $BUNDLE_URI_PROTOCOL:// using protocol v2: reque >actual 2>err && # Server responded using protocol v2 - grep "< version 2" log && + test_grep "< version 2" log && # Server advertised bundle-uri capability - grep "< bundle-uri" log && + test_grep "< bundle-uri" log && # Client did not issue bundle-uri command - ! grep "> command=bundle-uri" log && + test_grep ! "> command=bundle-uri" log && GIT_TRACE_PACKET="$PWD/log" \ git \
@@ -111,13 +111,13 @@ test_expect_success "clone with $BUNDLE_URI_PROTOCOL:// using protocol v2: reque >actual 2>err && # Server responded using protocol v2 - grep "< version 2" log && + test_grep "< version 2" log && # Server advertised bundle-uri capability - grep "< bundle-uri" log && + test_grep "< bundle-uri" log && # Client issued bundle-uri command - grep "> command=bundle-uri" log && + test_grep "> command=bundle-uri" log && GIT_TRACE_PACKET="$PWD/log3" \ git \
@@ -128,13 +128,13 @@ test_expect_success "clone with $BUNDLE_URI_PROTOCOL:// using protocol v2: reque >actual 2>err && # Server responded using protocol v2 - grep "< version 2" log3 && + test_grep "< version 2" log3 && # Server advertised bundle-uri capability - grep "< bundle-uri" log3 && + test_grep "< bundle-uri" log3 && # Client did not issue bundle-uri command (--bundle-uri override) - ! grep "> command=bundle-uri" log3 + test_grep ! "> command=bundle-uri" log3 ' # The remaining tests will all assume transfer.bundleURI=true
t/lib-httpd.sh +1 -1
@@ -275,7 +275,7 @@ test_http_push_nonff () { ' test_expect_success 'non-fast-forward push show ref status' ' - grep "^ ! \[rejected\][ ]*$BRANCH -> $BRANCH (non-fast-forward)$" output + test_grep "^ ! \[rejected\][ ]*$BRANCH -> $BRANCH (non-fast-forward)$" output ' test_expect_success 'non-fast-forward push shows help message' '
t/pack-refs-tests.sh +1 -1
@@ -195,7 +195,7 @@ test_expect_success 'delete ref while another dangling packed ref' ' test_expect_success 'pack ref directly below refs/' ' git update-ref refs/top HEAD && git ${pack_refs} --all --prune && - grep refs/top .git/packed-refs && + test_grep refs/top .git/packed-refs && test_path_is_missing .git/refs/top '
t/show-ref-exists-tests.sh +1 -1
@@ -19,7 +19,7 @@ test_expect_success '--exists with missing reference' ' test_expect_success '--exists does not use DWIM' ' test_expect_code 2 ${git_show_ref_exists} $GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 2>err && - grep "reference does not exist" err + test_grep "reference does not exist" err ' test_expect_success '--exists with HEAD' '
t/t0000-basic.sh +8 -8
@@ -743,7 +743,7 @@ test_expect_success 'subtest: lazy prereqs do not turn off tracing' ' test_done EOF - grep "echo trace" lazy-prereq-and-tracing/err + test_grep "echo trace" lazy-prereq-and-tracing/err ' test_expect_success 'subtest: tests clean up after themselves' '
@@ -815,7 +815,7 @@ test_expect_success 'subtest: test_atexit is run' ' test_expect_success 'test_oid provides sane info by default' ' test_oid zero >actual && - grep "^00*\$" actual && + test_grep "^00*\$" actual && rawsz="$(test_oid rawsz)" && hexsz="$(test_oid hexsz)" && # +1 accounts for the trailing newline
@@ -827,7 +827,7 @@ test_expect_success 'test_oid can look up data for SHA-1' ' test_when_finished "test_detect_hash" && test_set_hash sha1 && test_oid zero >actual && - grep "^00*\$" actual && + test_grep "^00*\$" actual && rawsz="$(test_oid rawsz)" && hexsz="$(test_oid hexsz)" && test $(wc -c <actual) -eq 41 &&
@@ -839,7 +839,7 @@ test_expect_success 'test_oid can look up data for SHA-256' ' test_when_finished "test_detect_hash" && test_set_hash sha256 && test_oid zero >actual && - grep "^00*\$" actual && + test_grep "^00*\$" actual && rawsz="$(test_oid rawsz)" && hexsz="$(test_oid hexsz)" && test $(wc -c <actual) -eq 65 &&
@@ -884,11 +884,11 @@ test_expect_success 'test_bool_env' ' # test script, hence the redirection of fd 7, and aborts # with "exit 1", hence the subshell. ! ( test_bool_env envvar true ) 7>err && - grep "error: test_bool_env requires bool values" err && + test_grep "error: test_bool_env requires bool values" err && envvar=true && ! ( test_bool_env envvar invalid ) 7>err && - grep "error: test_bool_env requires bool values" err + test_grep "error: test_bool_env requires bool values" err ) '
@@ -1242,12 +1242,12 @@ test_expect_success 'test_must_fail on a failing git command with env' ' test_expect_success 'test_must_fail rejects a non-git command' ' ! test_must_fail grep ^$ notafile 2>err && - grep -F "test_must_fail: only '"'"'git'"'"' is allowed" err + test_grep -F "test_must_fail: only '"'"'git'"'"' is allowed" err ' test_expect_success 'test_must_fail rejects a non-git command with env' ' ! test_must_fail env var1=a var2=b grep ^$ notafile 2>err && - grep -F "test_must_fail: only '"'"'git'"'"' is allowed" err + test_grep -F "test_must_fail: only '"'"'git'"'"' is allowed" err ' test_done
t/t0001-init.sh +9 -9
@@ -278,9 +278,9 @@ test_expect_success POSIXPERM 'init creates a new deep directory (umask vs. shar git init --bare --shared=0660 newdir/a/b/c && test_path_is_dir newdir/a/b/c/refs && ls -ld newdir/a newdir/a/b > lsab.out && - ! grep -v "^drwxrw[sx]r-x" lsab.out && + test_grep ! -v "^drwxrw[sx]r-x" lsab.out && ls -ld newdir/a/b/c > lsc.out && - ! grep -v "^drwxrw[sx]---" lsc.out + test_grep ! -v "^drwxrw[sx]---" lsc.out ) '
@@ -619,7 +619,7 @@ test_expect_success DEFAULT_REPO_FORMAT 'extensions.refStorage is not allowed wi git init refstorage && git -C refstorage config extensions.refStorage files && test_must_fail git -C refstorage rev-parse 2>err && - grep "repo version is 0, but v1-only extension found" err + test_grep "repo version is 0, but v1-only extension found" err ' test_expect_success DEFAULT_REPO_FORMAT 'extensions.refStorage with files backend' '
@@ -637,7 +637,7 @@ test_expect_success DEFAULT_REPO_FORMAT 'extensions.refStorage with unknown back git -C refstorage config core.repositoryformatversion 1 && git -C refstorage config extensions.refStorage garbage && test_must_fail git -C refstorage rev-parse 2>err && - grep "invalid value for ${SQ}extensions.refstorage${SQ}: ${SQ}garbage${SQ}" err + test_grep "invalid value for ${SQ}extensions.refstorage${SQ}: ${SQ}garbage${SQ}" err ' test_expect_success 'init with GIT_DEFAULT_REF_FORMAT=garbage' '
@@ -848,8 +848,8 @@ test_expect_success MINGW 'redirect std handles' ' GIT_REDIRECT_STDOUT=output.txt \ GIT_REDIRECT_STDERR="2>&1" \ git rev-parse --git-dir --verify refs/invalid && - grep "^\\.git\$" output.txt && - grep "Needed a single revision" output.txt + test_grep "^\\.git\$" output.txt && + test_grep "Needed a single revision" output.txt ' test_expect_success '--initial-branch' '
@@ -862,14 +862,14 @@ test_expect_success '--initial-branch' ' git init --initial-branch=ignore initial-branch-option 2>err && test_grep "ignored --initial-branch" err && git -C initial-branch-option symbolic-ref HEAD >actual && - grep hello actual + test_grep hello actual ' test_expect_success 'overridden default initial branch name (config)' ' test_config_global init.defaultBranch nmb && GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= git init initial-branch-config && git -C initial-branch-config symbolic-ref HEAD >actual && - grep nmb actual + test_grep nmb actual ' test_expect_success 'advice on unconfigured init.defaultBranch' '
@@ -907,7 +907,7 @@ test_expect_success 'overridden default main branch name (env)' ' test_config_global init.defaultBranch nmb && GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=env git init main-branch-env && git -C main-branch-env symbolic-ref HEAD >actual && - grep env actual + test_grep env actual ' test_expect_success 'invalid default branch name' '
t/t0008-ignores.sh +4 -4
@@ -790,8 +790,8 @@ test_expect_success 'existing file and directory' ' >one && mkdir top-level-dir && git check-ignore one top-level-dir >actual && - grep one actual && - grep top-level-dir actual + test_grep one actual && + test_grep top-level-dir actual ' test_expect_success 'existing directory and file' '
@@ -800,8 +800,8 @@ test_expect_success 'existing directory and file' ' >one && mkdir top-level-dir && git check-ignore top-level-dir one >actual && - grep one actual && - grep top-level-dir actual + test_grep one actual && + test_grep top-level-dir actual ' test_expect_success 'exact prefix matching (with root)' '
t/t0009-git-dir-validation.sh +3 -3
@@ -35,7 +35,7 @@ test_expect_success PIPE 'setup: .git as a FIFO (named pipe) is rejected' ' cd parent/fifo-trap && mkfifo .git && test_must_fail git rev-parse --git-dir 2>stderr && - grep "not a regular file" stderr + test_grep "not a regular file" stderr ) '
@@ -47,7 +47,7 @@ test_expect_success SYMLINKS,PIPE 'setup: .git as a symlink to a FIFO is rejecte mkfifo target-fifo && ln -s target-fifo .git && test_must_fail git rev-parse --git-dir 2>stderr && - grep "not a regular file" stderr + test_grep "not a regular file" stderr ) '
@@ -58,7 +58,7 @@ test_expect_success 'setup: .git with garbage content is rejected' ' cd parent/garbage-trap && echo "garbage" >.git && test_must_fail git rev-parse --git-dir 2>stderr && - grep "invalid gitfile format" stderr + test_grep "invalid gitfile format" stderr ) '
t/t0012-help.sh +2 -2
@@ -131,8 +131,8 @@ test_expect_success 'git help succeeds without git.html' ' test_expect_success 'git help --user-interfaces' ' git help --user-interfaces >help.output && - grep "^ attributes " help.output && - grep "^ mailmap " help.output + test_grep "^ attributes " help.output && + test_grep "^ mailmap " help.output ' test_expect_success 'git help -c' '
t/t0013-sha1dc.sh +1 -1
@@ -16,7 +16,7 @@ fi test_expect_success 'test-sha1 detects shattered pdf' ' test_must_fail test-tool sha1 <"$TEST_DATA/shattered-1.pdf" 2>err && test_grep collision err && - grep 38762cf7f55934b34d179ae6a4c80cadccbb7f0a err + test_grep 38762cf7f55934b34d179ae6a4c80cadccbb7f0a err ' test_done
t/t0017-env-helper.sh +2 -2
@@ -88,7 +88,7 @@ test_expect_success 'test-tool env-helper reads config thanks to trace2' ' test_must_fail \ env HOME="$(pwd)/home" \ git config -l 2>err && - grep "exceeded maximum include depth" err && + test_grep "exceeded maximum include depth" err && # This validates that the assumption that we attempt to # read the configuration and fail very early in the start-up
@@ -100,7 +100,7 @@ test_expect_success 'test-tool env-helper reads config thanks to trace2' ' test-tool -C no-such-directory \ env-helper --type=bool --default=0 \ --exit-code GIT_TEST_ENV_HELPER 2>err && - grep "exceeded maximum include depth" err + test_grep "exceeded maximum include depth" err ' test_done
t/t0021-conversion.sh +9 -9
@@ -731,7 +731,7 @@ test_expect_success 'process filter should restart after unexpected write failur rm -f debug.log && git checkout --quiet --no-progress . 2>git-stderr.log && - grep "smudge write error" git-stderr.log && + test_grep "smudge write error" git-stderr.log && test_grep "error: external filter" git-stderr.log && cat >expected.log <<-EOF &&
@@ -853,7 +853,7 @@ test_expect_success 'invalid process filter must fail (and not hang!)' ' cp "$TEST_ROOT/test.o" test.r && test_must_fail git add . 2>git-stderr.log && - grep "expected git-filter-server" git-stderr.log + test_grep "expected git-filter-server" git-stderr.log ) '
@@ -970,7 +970,7 @@ test_expect_success 'missing file in delayed checkout' ' rm -rf repo-cloned && test_must_fail git clone repo repo-cloned 2>git-stderr.log && - grep "error: .missing-delay\.a. was not filtered properly" git-stderr.log + test_grep "error: .missing-delay\.a. was not filtered properly" git-stderr.log ' test_expect_success 'invalid file in delayed checkout' '
@@ -991,7 +991,7 @@ test_expect_success 'invalid file in delayed checkout' ' rm -rf repo-cloned && test_must_fail git clone repo repo-cloned 2>git-stderr.log && - grep "error: external filter .* signaled that .unfiltered. is now available although it has not been delayed earlier" git-stderr.log + test_grep "error: external filter .* signaled that .unfiltered. is now available although it has not been delayed earlier" git-stderr.log ' for mode in 'case' 'utf-8'
@@ -1032,7 +1032,7 @@ do git clone $mode-collision $mode-collision-cloned && # Make sure z was really delayed - grep "IN: smudge $dir/z .* \\[DELAYED\\]" $mode-collision-cloned/delayed.log && + test_grep "IN: smudge $dir/z .* \\[DELAYED\\]" $mode-collision-cloned/delayed.log && # Should not create $dir/z at $symlink/z test_path_is_missing $mode-collision/target-dir/z
@@ -1070,7 +1070,7 @@ test_expect_success SYMLINKS,CASE_INSENSITIVE_FS \ git commit -m super && git checkout --recurse-submodules . && - grep "IN: smudge A/B/y .* \\[DELAYED\\]" delayed.log && + test_grep "IN: smudge A/B/y .* \\[DELAYED\\]" delayed.log && test_path_is_missing target-dir/y ) '
@@ -1161,9 +1161,9 @@ test_expect_success 'delayed checkout correctly reports the number of updated en rm *.a && git checkout . 2>err && - grep "IN: smudge test-delay10.a .* \\[DELAYED\\]" delayed.log && - grep "IN: smudge test-delay11.a .* \\[DELAYED\\]" delayed.log && - grep "Updated 2 paths from the index" err + test_grep "IN: smudge test-delay10.a .* \\[DELAYED\\]" delayed.log && + test_grep "IN: smudge test-delay11.a .* \\[DELAYED\\]" delayed.log && + test_grep "Updated 2 paths from the index" err ) '
t/t0029-core-unsetenvvars.sh +2 -2
@@ -20,10 +20,10 @@ test_expect_success 'core.unsetenvvars works' ' HOBBES=Calvin && export HOBBES && git commit --allow-empty -m with 2>err && - grep Calvin err && + test_grep Calvin err && git -c core.unsetenvvars=FINDUS,HOBBES,CALVIN \ commit --allow-empty -m without 2>err && - ! grep Calvin err + test_grep ! Calvin err ' test_done
t/t0030-stripspace.sh +2 -2
@@ -407,12 +407,12 @@ test_expect_success 'strip comments with changed comment string' ' test_expect_success 'newline as commentchar is forbidden' ' test_must_fail git -c core.commentChar="$LF" stripspace -s 2>err && - grep "core.commentchar cannot contain newline" err + test_grep "core.commentchar cannot contain newline" err ' test_expect_success 'empty commentchar is forbidden' ' test_must_fail git -c core.commentchar= stripspace -s 2>err && - grep "core.commentchar must have at least one character" err + test_grep "core.commentchar must have at least one character" err ' test_expect_success '-c with single line' '
t/t0031-lockfile-pid.sh +1 -1
@@ -29,7 +29,7 @@ test_expect_success 'PID info not shown by default' ' test_must_fail git add . 2>err && # Should not crash, just show normal error without PID test_grep "Unable to create" err && - ! test_grep "is held by process" err + test_grep ! "is held by process" err ) '
t/t0040-parse-options.sh +26 -26
129 lines not on this page · raw message
t/t0041-usage.sh +1 -1
@@ -13,7 +13,7 @@ test_expect_success 'setup ' ' test_expect_success 'tag --contains <existent_tag>' ' git tag --contains "v1.0" >actual 2>actual.err && - grep "v1.0" actual && + test_grep "v1.0" actual && test_line_count = 0 actual.err '
t/t0052-simple-ipc.sh +5 -5
@@ -33,19 +33,19 @@ test_expect_success 'servers cannot share the same path' ' test_expect_success 'big response' ' test-tool simple-ipc send --token=big >actual && test_line_count -ge 10000 actual && - grep -q "big: [0]*9999\$" actual + test_grep -q "big: [0]*9999\$" actual ' test_expect_success 'chunk response' ' test-tool simple-ipc send --token=chunk >actual && test_line_count -ge 10000 actual && - grep -q "big: [0]*9999\$" actual + test_grep -q "big: [0]*9999\$" actual ' test_expect_success 'slow response' ' test-tool simple-ipc send --token=slow >actual && test_line_count -ge 100 actual && - grep -q "big: [0]*99\$" actual + test_grep -q "big: [0]*99\$" actual ' # Send an IPC with n=100,000 bytes of ballast. This should be large enough
@@ -54,7 +54,7 @@ test_expect_success 'slow response' ' # test_expect_success 'sendbytes' ' test-tool simple-ipc sendbytes --bytecount=100000 --byte=A >actual && - grep "sent:A00100000 rcvd:A00100000" actual + test_grep "sent:A00100000 rcvd:A00100000" actual ' # Start a series of <threads> client threads that each make <batchsize>
@@ -93,7 +93,7 @@ test_expect_success 'stress test threads' ' --batchsize=13 \ >actual && test_line_count = 92 actual && - grep "good 91" actual && + test_grep "good 91" actual && grep "sent:A" <actual >actual_a && cat >expect_a <<-EOF && sent:A00000019 rcvd:A00000019
t/t0061-run-command.sh +1 -1
@@ -97,7 +97,7 @@ test_expect_success POSIXPERM 'run_command reports EACCES' ' chmod -x hello.sh && test_must_fail test-tool run-command run-command ./hello.sh 2>err && - grep "fatal: cannot exec.*hello.sh" err + test_grep "fatal: cannot exec.*hello.sh" err ' test_expect_success POSIXPERM,SANITY 'unreadable directory in PATH' '
t/t0066-dir-iterator.sh +1 -1
@@ -127,7 +127,7 @@ test_expect_success SYMLINKS 'dir-iterator should not follow symlinks by default test_expect_success SYMLINKS 'dir-iterator does not resolve top-level symlinks' ' test_must_fail test-tool dir-iterator ./dir5 >out && - grep "ENOTDIR" out + test_grep "ENOTDIR" out ' test_done
t/t0068-for-each-repo.sh +8 -8
@@ -21,23 +21,23 @@ test_expect_success 'run based on configured value' ' git for-each-repo --config=run.key commit --allow-empty -m "ran" && git -C one log -1 --pretty=format:%s >message && - grep ran message && + test_grep ran message && git -C two log -1 --pretty=format:%s >message && - ! grep ran message && + test_grep ! ran message && git -C three log -1 --pretty=format:%s >message && - grep ran message && + test_grep ran message && git -C ~/four log -1 --pretty=format:%s >message && - grep ran message && + test_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 && + test_grep again message && git -C two log -1 --pretty=format:%s >message && - ! grep again message && + test_grep ! again message && git -C three log -1 --pretty=format:%s >message && - grep again message && + test_grep again message && git -C ~/four log -1 --pretty=format:%s >message && - grep again message && + test_grep again message && git -C three for-each-repo --config=run.key -- \ commit --allow-empty -m "ran from worktree" &&
t/t0070-fundamental.sh +3 -3
@@ -10,7 +10,7 @@ Verify wrappers and compatibility functions. test_expect_success 'mktemp to nonexistent directory prints filename' ' test_must_fail test-tool mktemp doesnotexist/testXXXXXX 2>err && - grep "doesnotexist/test" err + test_grep "doesnotexist/test" err ' test_expect_success POSIXPERM,SANITY 'mktemp to unwritable directory prints filename' '
@@ -18,7 +18,7 @@ test_expect_success POSIXPERM,SANITY 'mktemp to unwritable directory prints file test_when_finished "chmod +w cannotwrite" && chmod -w cannotwrite && test_must_fail test-tool mktemp cannotwrite/testXXXXXX 2>err && - grep "cannotwrite/test" err + test_grep "cannotwrite/test" err ' test_expect_success 'git_mkstemps_mode does not fail if fd 0 is not open' '
@@ -33,7 +33,7 @@ test_expect_success 'check for a bug in the regex routines' ' test_expect_success 'incomplete sideband messages are reassembled' ' test-tool pkt-line send-split-sideband >split-sideband && test-tool pkt-line receive-sideband <split-sideband 2>err && - grep "Hello, world" err + test_grep "Hello, world" err ' test_expect_success 'eof on sideband message is reported' '
t/t0081-find-pack.sh +6 -6
@@ -52,17 +52,17 @@ test_expect_success 'add more packfiles' ' # HEAD^{tree} is in 2 packfiles test-tool find-pack HEAD^{tree} >head_tree_packs && - grep "$head_commit_pack" head_tree_packs && - grep mypackname1 head_tree_packs && - ! grep mypackname2 head_tree_packs && + test_grep "$head_commit_pack" head_tree_packs && + test_grep mypackname1 head_tree_packs && + test_grep ! mypackname2 head_tree_packs && test-tool find-pack --check-count 2 HEAD^{tree} && ! test-tool find-pack --check-count 1 HEAD^{tree} && # HEAD:five.t is also in 2 packfiles test-tool find-pack HEAD:five.t >five_packs && - grep "$head_commit_pack" five_packs && - ! grep mypackname1 five_packs && - grep mypackname2 five_packs && + test_grep "$head_commit_pack" five_packs && + test_grep ! mypackname1 five_packs && + test_grep mypackname2 five_packs && test-tool find-pack -c 2 HEAD:five.t && ! test-tool find-pack --check-count=0 HEAD:five.t '
t/t0091-bugreport.sh +9 -9
@@ -40,15 +40,15 @@ test_expect_success 'sanity check "System Info" section' ' # The beginning should match "git version --build-options" verbatim, # but rather than checking bit-for-bit equality, just test some basics. - grep "git version " system && - grep "shell-path: ." system && + test_grep "git version " system && + test_grep "shell-path: ." system && # After the version, there should be some more info. # This is bound to differ from environment to environment, # so we just do some rather high-level checks. - grep "uname: ." system && - grep "compiler info: ." system && - grep "zlib." system + test_grep "uname: ." system && + test_grep "compiler info: ." system && + test_grep "zlib." system ' test_expect_success 'dies if file with same name as report already exists' '
@@ -112,7 +112,7 @@ test_expect_success UNZIP '--diagnose creates diagnostics zip archive' ' git bugreport --diagnose -o report -s test >out && zip_path=report/git-diagnostics-test.zip && - grep "Available space" out && + test_grep "Available space" out && test_path_is_file "$zip_path" && # Check zipped archive content
@@ -120,10 +120,10 @@ test_expect_success UNZIP '--diagnose creates diagnostics zip archive' ' test_file_not_empty out && "$GIT_UNZIP" -p "$zip_path" packs-local.txt >out && - grep ".git/objects" out && + test_grep ".git/objects" out && "$GIT_UNZIP" -p "$zip_path" objects-local.txt >out && - grep "^Total: [0-9][0-9]*" out && + test_grep "^Total: [0-9][0-9]*" out && # Should not include .git directory contents by default ! "$GIT_UNZIP" -l "$zip_path" | grep ".git/"
@@ -136,7 +136,7 @@ test_expect_success UNZIP '--diagnose=stats excludes .git dir contents' ' # Includes pack quantity/size info "$GIT_UNZIP" -p "$zip_path" packs-local.txt >out && - grep ".git/objects" out && + test_grep ".git/objects" out && # Does not include .git directory contents ! "$GIT_UNZIP" -l "$zip_path" | grep ".git/"
t/t0092-diagnose.sh +6 -6
@@ -8,7 +8,7 @@ test_expect_success UNZIP 'creates diagnostics zip archive' ' test_when_finished rm -rf report && git diagnose -o report -s test >out && - grep "Available space" out && + test_grep "Available space" out && zip_path=report/git-diagnostics-test.zip && test_path_is_file "$zip_path" &&
@@ -18,10 +18,10 @@ test_expect_success UNZIP 'creates diagnostics zip archive' ' test_file_not_empty out && "$GIT_UNZIP" -p "$zip_path" packs-local.txt >out && - grep ".git/objects" out && + test_grep ".git/objects" out && "$GIT_UNZIP" -p "$zip_path" objects-local.txt >out && - grep "^Total: [0-9][0-9]*" out && + test_grep "^Total: [0-9][0-9]*" out && # Should not include .git directory contents by default ! "$GIT_UNZIP" -l "$zip_path" | grep ".git/"
@@ -34,7 +34,7 @@ test_expect_success UNZIP 'counts loose objects' ' git diagnose -o test-count -s 1 >out && zip_path=test-count/git-diagnostics-1.zip && "$GIT_UNZIP" -p "$zip_path" objects-local.txt >out && - grep "^Total: [1-9][0-9]* loose objects" out + test_grep "^Total: [1-9][0-9]* loose objects" out ' test_expect_success UNZIP '--mode=stats excludes .git dir contents' '
@@ -45,7 +45,7 @@ test_expect_success UNZIP '--mode=stats excludes .git dir contents' ' # Includes pack quantity/size info zip_path=report/git-diagnostics-test.zip && "$GIT_UNZIP" -p "$zip_path" packs-local.txt >out && - grep ".git/objects" out && + test_grep ".git/objects" out && # Does not include .git directory contents ! "$GIT_UNZIP" -l "$zip_path" | grep ".git/"
@@ -59,7 +59,7 @@ test_expect_success UNZIP '--mode=all includes .git dir contents' ' # Includes pack quantity/size info zip_path=report/git-diagnostics-test.zip && "$GIT_UNZIP" -p "$zip_path" packs-local.txt >out && - grep ".git/objects" out && + test_grep ".git/objects" out && # Includes .git directory contents "$GIT_UNZIP" -l "$zip_path" | grep ".git/" &&
t/t0100-previous.sh +1 -1
@@ -50,7 +50,7 @@ test_expect_success 'merge @{-1}~1' ' git checkout main && git merge @{-1}~1 && git cat-file commit HEAD >actual && - grep "Merge branch '\''other'\''" actual + test_grep "Merge branch '\''other'\''" actual ' test_expect_success 'merge @{-100} before checking out that many branches yet' '
t/t0200-gettext-basic.sh +7 -7
@@ -16,7 +16,7 @@ test_expect_success 'sanity: $TEXTDOMAIN is git' ' ' test_expect_success 'xgettext sanity: Perl _() strings are not extracted' ' - ! grep "A Perl string xgettext will not get" "$GIT_PO_PATH"/is.po + test_grep ! "A Perl string xgettext will not get" "$GIT_PO_PATH"/is.po ' test_expect_success 'xgettext sanity: Comment extraction with --add-comments' '
@@ -26,8 +26,8 @@ test_expect_success 'xgettext sanity: Comment extraction with --add-comments' ' ' test_expect_success 'xgettext sanity: Comment extraction with --add-comments stops at statements' ' - ! grep "This is a phony" "$GIT_PO_PATH"/is.po && - ! grep "the above comment" "$GIT_PO_PATH"/is.po + test_grep ! "This is a phony" "$GIT_PO_PATH"/is.po && + test_grep ! "the above comment" "$GIT_PO_PATH"/is.po ' test_expect_success GETTEXT 'sanity: $TEXTDOMAINDIR exists without NO_GETTEXT=YesPlease' '
@@ -44,10 +44,10 @@ test_expect_success GETTEXT 'sanity: Icelandic locale was compiled' ' test_expect_success GETTEXT_LOCALE 'sanity: gettext("") metadata is OK' ' # Return value may be non-zero LANGUAGE=is LC_ALL="$is_IS_locale" gettext "" >zero-expect && - grep "Project-Id-Version: Git" zero-expect && - grep "Git Mailing List <[email protected]>" zero-expect && - grep "Content-Type: text/plain; charset=UTF-8" zero-expect && - grep "Content-Transfer-Encoding: 8bit" zero-expect + test_grep "Project-Id-Version: Git" zero-expect && + test_grep "Git Mailing List <[email protected]>" zero-expect && + test_grep "Content-Type: text/plain; charset=UTF-8" zero-expect && + test_grep "Content-Transfer-Encoding: 8bit" zero-expect ' test_expect_success GETTEXT_LOCALE 'sanity: gettext(unknown) is passed through' '
t/t0203-gettext-setlocale-sanity.sh +2 -2
@@ -12,7 +12,7 @@ test_expect_success 'git show a ISO-8859-1 commit under C locale' ' test_commit "iso-c-commit" iso-under-c && git show >out 2>err && test_must_be_empty err && - grep -q "iso-c-commit" out + test_grep -q "iso-c-commit" out ' test_expect_success GETTEXT_LOCALE 'git show a ISO-8859-1 commit under a UTF-8 locale' '
@@ -20,7 +20,7 @@ test_expect_success GETTEXT_LOCALE 'git show a ISO-8859-1 commit under a UTF-8 l test_commit "iso-utf8-commit" iso-under-utf8 && LANGUAGE=is LC_ALL="$is_IS_locale" git show >out 2>err && test_must_be_empty err && - grep -q "iso-utf8-commit" out + test_grep -q "iso-utf8-commit" out ' test_done
t/t0204-gettext-reencode-sanity.sh +4 -4
@@ -66,22 +66,22 @@ test_expect_success GETTEXT_LOCALE 'gettext: Fetching a UTF-8 msgid -> UTF-8' ' # eyes. test_expect_success GETTEXT_ISO_LOCALE 'gettext: Fetching a UTF-8 msgid -> ISO-8859-1' ' LANGUAGE=is LC_ALL="$is_IS_iso_locale" gettext "TEST: ‘single’ and “double” quotes" >actual && - grep "einfaldar" actual && - grep "$(echo tvöfaldar | iconv -f UTF-8 -t ISO8859-1)" actual + test_grep "einfaldar" actual && + test_grep "$(echo tvöfaldar | iconv -f UTF-8 -t ISO8859-1)" actual ' test_expect_success GETTEXT_LOCALE 'gettext.c: git init UTF-8 -> UTF-8' ' printf "Bjó til tóma Git lind" >expect && LANGUAGE=is LC_ALL="$is_IS_locale" git init repo >actual && test_when_finished "rm -rf repo" && - grep "^$(cat expect) " actual + test_grep "^$(cat expect) " actual ' test_expect_success GETTEXT_ISO_LOCALE 'gettext.c: git init UTF-8 -> ISO-8859-1' ' printf "Bjó til tóma Git lind" >expect && LANGUAGE=is LC_ALL="$is_IS_iso_locale" git init repo >actual && test_when_finished "rm -rf repo" && - grep "^$(iconv -f UTF-8 -t ISO8859-1 <expect) " actual + test_grep "^$(iconv -f UTF-8 -t ISO8859-1 <expect) " actual ' test_done
t/t0210-trace2-normal.sh +3 -3
@@ -333,12 +333,12 @@ test_expect_success 'unsafe URLs are redacted by default' ' GIT_TRACE2="$(pwd)/trace.normal" \ git clone https://user:[email protected]/ clone && - ! grep user:pwd trace.normal && + test_grep ! user:pwd trace.normal && GIT_TRACE2_REDACT=0 GIT_TRACE2="$(pwd)/unredacted.normal" \ git clone https://user:[email protected]/ clone2 && - grep "start .* clone https://user:[email protected]" unredacted.normal && - grep "remote.origin.url=https://user:[email protected]" unredacted.normal + test_grep "start .* clone https://user:[email protected]" unredacted.normal && + test_grep "remote.origin.url=https://user:[email protected]" unredacted.normal ' test_done
t/t0211-trace2-perf.sh +40 -40
159 lines not on this page · raw message
t/t0212-trace2-event.sh +4 -4
@@ -332,7 +332,7 @@ test_expect_success 'unsafe URLs are redacted by default in cmd_start events' ' GIT_TRACE2_EVENT="$(pwd)/trace.event" \ test-tool trace2 300redact_start git clone https://user:[email protected]/ clone2 && - ! grep user:pwd trace.event + test_grep ! user:pwd trace.event ' test_expect_success 'unsafe URLs are redacted by default in child_start events' '
@@ -341,7 +341,7 @@ test_expect_success 'unsafe URLs are redacted by default in child_start events' GIT_TRACE2_EVENT="$(pwd)/trace.event" \ test-tool trace2 301redact_child_start git clone https://user:[email protected]/ clone2 && - ! grep user:pwd trace.event + test_grep ! user:pwd trace.event ' test_expect_success 'unsafe URLs are redacted by default in exec events' '
@@ -350,7 +350,7 @@ test_expect_success 'unsafe URLs are redacted by default in exec events' ' GIT_TRACE2_EVENT="$(pwd)/trace.event" \ test-tool trace2 302redact_exec git clone https://user:[email protected]/ clone2 && - ! grep user:pwd trace.event + test_grep ! user:pwd trace.event ' test_expect_success 'unsafe URLs are redacted by default in def_param events' '
@@ -359,7 +359,7 @@ test_expect_success 'unsafe URLs are redacted by default in def_param events' ' GIT_TRACE2_EVENT="$(pwd)/trace.event" \ test-tool trace2 303redact_def_param url https://user:[email protected]/ && - ! grep user:pwd trace.event + test_grep ! user:pwd trace.event ' test_done
t/t0300-credentials.sh +2 -2
@@ -1014,7 +1014,7 @@ test_expect_success 'credential config with partial URLs' ' do git -c credential.$partial.helper=yep \ credential fill <stdin >stdout && - grep yep stdout || + test_grep yep stdout || return 1 done &&
@@ -1030,7 +1030,7 @@ test_expect_success 'credential config with partial URLs' ' do git -c credential.$partial.helper=yep \ credential fill <stdin >stdout && - ! grep yep stdout || + test_grep ! yep stdout || return 1 done &&
t/t0410-partial-clone.sh +41 -41
223 lines not on this page · raw message
t/t0450-txt-doc-vs-help.sh +1 -1
@@ -87,7 +87,7 @@ do # -h output assertions test_expect_success "$builtin -h output has no \t" ' h2s="$(help_to_synopsis "$builtin")" && - ! grep "$HT" "$h2s" + test_grep ! "$HT" "$h2s" ' test_expect_success "$builtin -h output has dashed labels" '
t/t0500-progress-display.sh +9 -9
@@ -320,8 +320,8 @@ test_expect_success 'progress generates traces' ' # t0212/parse_events.perl intentionally omits regions and data. test_region progress "Working hard" trace.event && - grep "\"key\":\"total_objects\",\"value\":\"40\"" trace.event && - grep "\"key\":\"total_bytes\",\"value\":\"409600\"" trace.event + test_grep "\"key\":\"total_objects\",\"value\":\"40\"" trace.event && + test_grep "\"key\":\"total_bytes\",\"value\":\"409600\"" trace.event ' test_expect_success 'progress generates traces: stop / start' '
@@ -344,8 +344,8 @@ test_expect_success 'progress generates traces: start without stop' ' LSAN_OPTIONS=detect_leaks=0 \ test-tool progress \ <in 2>stderr && - grep region_enter.*progress trace-start.event && - ! grep region_leave.*progress trace-start.event + test_grep region_enter.*progress trace-start.event && + test_grep ! region_leave.*progress trace-start.event ' test_expect_success 'progress generates traces: stop without start' '
@@ -355,8 +355,8 @@ test_expect_success 'progress generates traces: stop without start' ' GIT_TRACE2_EVENT="$PWD/trace-stop.event" test-tool progress \ <in 2>stderr && - ! grep region_enter.*progress trace-stop.event && - ! grep region_leave.*progress trace-stop.event + test_grep ! region_enter.*progress trace-stop.event && + test_grep ! region_leave.*progress trace-stop.event ' test_expect_success 'progress generates traces: start with active progress bar (no stops)' '
@@ -369,9 +369,9 @@ test_expect_success 'progress generates traces: start with active progress bar ( LSAN_OPTIONS=detect_leaks=0 \ test-tool progress \ <in 2>stderr && - grep region_enter.*progress.*One trace-2start.event && - grep region_enter.*progress.*Two trace-2start.event && - ! grep region_leave trace-2start.event + test_grep region_enter.*progress.*One trace-2start.event && + test_grep region_enter.*progress.*Two trace-2start.event && + test_grep ! region_leave trace-2start.event ' test_done
t/t0610-reftable-basics.sh +4 -4
@@ -776,11 +776,11 @@ test_expect_success 'reflog: can delete separate reflog entries' ' test_commit file3 && test_commit file4 && git reflog >actual && - grep file3 actual && + test_grep file3 actual && git reflog delete HEAD@{1} && git reflog >actual && - ! grep file3 actual + test_grep ! file3 actual ) '
@@ -902,8 +902,8 @@ test_expect_success 'reflog: garbage collection deletes reflog entries' ' done && git reflog refs/heads/main >actual && test_line_count = 10 actual && - grep "commit (initial): number 1" actual && - grep "commit: number 10" actual && + test_grep "commit (initial): number 1" actual && + test_grep "commit: number 10" actual && git gc && git reflog refs/heads/main >actual &&
t/t1004-read-tree-m-u-wf.sh +4 -4
@@ -142,8 +142,8 @@ test_expect_success '3-way not overwriting local changes (our side)' ' echo >>file1 "local changes" && read_tree_u_must_succeed -m -u branch-point side-a side-b && - grep "new line to be kept" file1 && - grep "local changes" file1 + test_grep "new line to be kept" file1 && + test_grep "local changes" file1 '
@@ -156,8 +156,8 @@ test_expect_success '3-way not overwriting local changes (their side)' ' echo >>file2 "local changes" && read_tree_u_must_fail -m -u branch-point side-a side-b && - ! grep "new line to be kept" file2 && - grep "local changes" file2 + test_grep ! "new line to be kept" file2 && + test_grep "local changes" file2 '
t/t1006-cat-file.sh +9 -9
@@ -696,8 +696,8 @@ test_expect_success '%(deltabase) reports packed delta bases' ' git repack -ad && git cat-file --batch-check="%(deltabase)" <blobs >actual && { - grep "$(git rev-parse HEAD:foo)" actual || - grep "$(git rev-parse HEAD:foo-plus)" actual + test_grep "$(git rev-parse HEAD:foo)" actual || + test_grep "$(git rev-parse HEAD:foo-plus)" actual } '
@@ -826,7 +826,7 @@ test_expect_success 'cat-file -t and -s on corrupt loose object' ' # Swap the two to corrupt the repository mv -f "$other_path" "$empty_path" && test_must_fail git fsck 2>err.fsck && - grep "hash-path mismatch" err.fsck && + test_grep "hash-path mismatch" err.fsck && # confirm that cat-file is reading the new swapped-in # blob...
@@ -1318,37 +1318,37 @@ test_expect_success 'cat-file --batch-all-objects --batch-check ignores replace' test_expect_success 'batch-command empty command' ' echo "" >cmd && test_expect_code 128 git cat-file --batch-command <cmd 2>err && - grep "^fatal:.*empty command in input.*" err + test_grep "^fatal:.*empty command in input.*" err ' test_expect_success 'batch-command whitespace before command' ' echo " info deadbeef" >cmd && test_expect_code 128 git cat-file --batch-command <cmd 2>err && - grep "^fatal:.*whitespace before command.*" err + test_grep "^fatal:.*whitespace before command.*" err ' test_expect_success 'batch-command unknown command' ' echo unknown_command >cmd && test_expect_code 128 git cat-file --batch-command <cmd 2>err && - grep "^fatal:.*unknown command.*" err + test_grep "^fatal:.*unknown command.*" err ' test_expect_success 'batch-command missing arguments' ' echo "info" >cmd && test_expect_code 128 git cat-file --batch-command <cmd 2>err && - grep "^fatal:.*info requires arguments.*" err + test_grep "^fatal:.*info requires arguments.*" err ' test_expect_success 'batch-command flush with arguments' ' echo "flush arg" >cmd && test_expect_code 128 git cat-file --batch-command --buffer <cmd 2>err && - grep "^fatal:.*flush takes no arguments.*" err + test_grep "^fatal:.*flush takes no arguments.*" err ' test_expect_success 'batch-command flush without --buffer' ' echo "flush" >cmd && test_expect_code 128 git cat-file --batch-command <cmd 2>err && - grep "^fatal:.*flush is only for --buffer mode.*" err + test_grep "^fatal:.*flush is only for --buffer mode.*" err ' perl_script='
t/t1007-hash-object.sh +4 -4
@@ -202,7 +202,7 @@ done test_expect_success 'too-short tree' ' echo abc >malformed-tree && test_must_fail git hash-object -t tree malformed-tree 2>err && - grep "too-short tree object" err + test_grep "too-short tree object" err ' test_expect_success PERL_TEST_HELPERS 'malformed mode in tree' '
@@ -210,7 +210,7 @@ test_expect_success PERL_TEST_HELPERS 'malformed mode in tree' ' 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 && - grep "malformed mode in tree entry" err + test_grep "malformed mode in tree entry" err ' test_expect_success PERL_TEST_HELPERS 'empty filename in tree' '
@@ -218,7 +218,7 @@ test_expect_success PERL_TEST_HELPERS 'empty filename in tree' ' 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 && - grep "empty filename in tree entry" err + test_grep "empty filename in tree entry" err ' test_expect_success PERL_TEST_HELPERS 'duplicate filename in tree' '
@@ -229,7 +229,7 @@ test_expect_success PERL_TEST_HELPERS 'duplicate filename in tree' ' 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_grep "duplicateEntries" err ' test_expect_success 'corrupt commit' '
t/t1011-read-tree-sparse-checkout.sh +5 -5
@@ -196,7 +196,7 @@ test_expect_success 'read-tree will not throw away dirty changes, non-sparse' ' echo dirty >init.t && read_tree_u_must_fail -m -u HEAD^ && test_path_is_file init.t && - grep -q dirty init.t + test_grep -q dirty init.t ' test_expect_success 'read-tree will not throw away dirty changes, sparse' '
@@ -207,7 +207,7 @@ test_expect_success 'read-tree will not throw away dirty changes, sparse' ' echo sub/added >.git/info/sparse-checkout && read_tree_u_must_fail -m -u HEAD^ && test_path_is_file init.t && - grep -q dirty init.t + test_grep -q dirty init.t ' test_expect_success 'read-tree updates worktree, dirty case' '
@@ -215,7 +215,7 @@ test_expect_success 'read-tree updates worktree, dirty case' ' git checkout -f top && echo dirty >init.t && read_tree_u_must_fail -m -u HEAD^ && - grep -q dirty init.t && + test_grep -q dirty init.t && rm init.t '
@@ -224,7 +224,7 @@ test_expect_success 'read-tree removes worktree, dirty case' ' git checkout -f top && echo dirty >added && read_tree_u_must_succeed -m -u HEAD^ && - grep -q dirty added + test_grep -q dirty added ' test_expect_success 'read-tree adds to worktree, absent case' '
@@ -240,7 +240,7 @@ test_expect_success 'read-tree adds to worktree, dirty case' ' mkdir sub && echo dirty >sub/added && read_tree_u_must_succeed -u -m HEAD^ && - grep -q dirty sub/added + test_grep -q dirty sub/added ' test_expect_success 'index removal and worktree narrowing at the same time' '
t/t1050-large.sh +3 -3
@@ -8,7 +8,7 @@ test_description='adding and checking out large blobs' test_expect_success 'core.bigFileThreshold must be non-negative' ' : >input && test_must_fail git -c core.bigFileThreshold=-1 hash-object input >out 2>err && - grep "bad numeric config value" err && + test_grep "bad numeric config value" err && test_must_be_empty out '
@@ -148,12 +148,12 @@ test_expect_success 'diff --stat' ' test_expect_success 'diff' ' git diff HEAD^ HEAD >actual && - grep "Binary files.*differ" actual + test_grep "Binary files.*differ" actual ' test_expect_success 'diff --cached' ' git diff --cached HEAD^ >actual && - grep "Binary files.*differ" actual + test_grep "Binary files.*differ" actual ' test_expect_success 'hash-object' '
t/t1091-sparse-checkout-builtin.sh +12 -12
@@ -129,7 +129,7 @@ test_expect_success 'switching to cone mode with non-cone mode patterns' ' git sparse-checkout add dir && git config --worktree core.sparseCheckoutCone true && test_must_fail git sparse-checkout add dir 2>err && - grep "existing sparse-checkout patterns do not use cone mode" err + test_grep "existing sparse-checkout patterns do not use cone mode" err ) '
@@ -803,7 +803,7 @@ test_expect_success 'cone mode clears ignored subdirectories' ' # When an untracked file is in the way, all untracked files # (even ignored files) are preserved. git -C repo sparse-checkout set folder1 2>err && - grep "contains untracked files" err && + test_grep "contains untracked files" err && test_path_is_file repo/deep/deeper2/ignored.o && test_path_is_file repo/deep/deeper2/untracked &&
@@ -882,8 +882,8 @@ test_expect_success 'malformed cone-mode patterns' ' # of using the cone-mode translation to a set of directories. git -C repo sparse-checkout list >actual 2>err && test_cmp repo/.git/info/sparse-checkout actual && - grep "warning: your sparse-checkout file may have issues: pattern .* is repeated" err && - grep "warning: disabling cone pattern matching" err + test_grep "warning: your sparse-checkout file may have issues: pattern .* is repeated" err && + test_grep "warning: disabling cone pattern matching" err ' test_expect_success 'set from subdir pays attention to prefix' '
@@ -917,34 +917,34 @@ test_expect_success 'set from subdir in non-cone mode throws an error' ' git -C repo sparse-checkout disable && test_must_fail git -C repo/deep sparse-checkout set --no-cone deeper2 ../folder1 2>error && - grep "run from the toplevel directory in non-cone mode" error + test_grep "run from the toplevel directory in non-cone mode" error ' test_expect_success 'set from subdir in non-cone mode throws an error' ' git -C repo sparse-checkout set --no-cone deep/deeper2 && test_must_fail git -C repo/deep sparse-checkout add deeper1/deepest ../folder1 2>error && - grep "run from the toplevel directory in non-cone mode" error + test_grep "run from the toplevel directory in non-cone mode" error ' test_expect_success 'by default, cone mode will error out when passed files' ' git -C repo sparse-checkout reapply --cone && test_must_fail git -C repo sparse-checkout add .gitignore 2>error && - grep ".gitignore.*is not a directory" error + test_grep ".gitignore.*is not a directory" error ' test_expect_success 'error on mistyped command line options' ' test_must_fail git -C repo sparse-checkout add --sikp-checks .gitignore 2>error && - grep "unknown option.*sikp-checks" error + test_grep "unknown option.*sikp-checks" error ' test_expect_success 'by default, non-cone mode will warn on individual files' ' git -C repo sparse-checkout reapply --no-cone && git -C repo sparse-checkout add .gitignore 2>warning && - grep "pass a leading slash before paths.*if you want a single file" warning + test_grep "pass a leading slash before paths.*if you want a single file" warning ' test_expect_success 'setup bare repo' '
@@ -1108,11 +1108,11 @@ test_expect_success 'clean' ' touch repo/folder1/extra/inside/file && test_must_fail git -C repo sparse-checkout clean 2>err && - grep "refusing to clean" err && + test_grep "refusing to clean" err && git -C repo config clean.requireForce true && test_must_fail git -C repo sparse-checkout clean 2>err && - grep "refusing to clean" err && + test_grep "refusing to clean" err && cat >expect <<-\EOF && Would remove deep/deeper2/
@@ -1255,7 +1255,7 @@ test_expect_success 'sparse-checkout operations with merge conflicts' ' test_must_fail git merge -m "will-conflict" right && test_must_fail git sparse-checkout clean -f 2>err && - grep "failed to convert index to a sparse index" err && + test_grep "failed to convert index to a sparse index" err && echo merged >folder1/even/more/dirs/file && git add --sparse folder1 &&
t/t1092-sparse-checkout-compatibility.sh +22 -22
135 lines not on this page · raw message
t/t1300-config.sh +8 -8
@@ -856,7 +856,7 @@ test_expect_success 'renaming a section with an overly-long line' ' printf "[a] g = h\\n" } >y && test_must_fail git config ${mode_prefix}rename-section -f y a xyz 2>err && - grep "refusing to work with overly long line in .y. on line 2" err + test_grep "refusing to work with overly long line in .y. on line 2" err ' cat >> .git/config << EOF
@@ -1671,9 +1671,9 @@ test_expect_success 'git --config-env=key=envvar support' ' test_expect_success 'git --config-env with missing value' ' test_must_fail env ENVVAR=value git --config-env 2>error && - grep "no config key given for --config-env" error && + test_grep "no config key given for --config-env" error && test_must_fail env ENVVAR=value git --config-env config core.name 2>error && - grep "invalid config format: config" error + test_grep "invalid config format: config" error ' test_expect_success 'git --config-env fails with invalid parameters' '
@@ -2104,7 +2104,7 @@ test_expect_success '--unset last key removes section (except if commented)' ' key = true EOF git config ${mode_unset} two.key && - ! grep two .git/config && + test_grep ! two .git/config && q_to_tab >.git/config <<-\EOF && [one]
@@ -2124,7 +2124,7 @@ test_expect_success '--unset last key removes section (except if commented)' ' Qkey = true EOF git config ${mode_unset} two.key && - grep two .git/config && + test_grep two .git/config && q_to_tab >.git/config <<-\EOF && [one]
@@ -2655,7 +2655,7 @@ test_expect_success '--type rejects unknown specifiers' ' 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_grep "bad numeric config value" error && test_must_be_empty out '
@@ -2967,12 +2967,12 @@ test_expect_success 'includeIf.hasconfig:remote.*.url forbids remote url in such # test with any Git command test_must_fail git -C hasremoteurlTest status 2>err && - grep "fatal: remote URLs cannot be configured in file directly or indirectly included by includeIf.hasconfig:remote.*.url" err + test_grep "fatal: remote URLs cannot be configured in file directly or indirectly included by includeIf.hasconfig:remote.*.url" err ' test_expect_success 'negated mode causes failure' ' test_must_fail git config --no-get 2>err && - grep "unknown option \`no-get${SQ}" err + test_grep "unknown option \`no-get${SQ}" err ' test_expect_success 'specifying multiple modes causes failure' '
t/t1305-config-include.sh +1 -1
@@ -353,7 +353,7 @@ test_expect_success 'include cycles are detected' ' git -C cycle --git-dir=. config include.path cycle && git config -f cycle/cycle include.path config && test_must_fail git -C cycle --git-dir=. config --get-all test.value 2>stderr && - grep "exceeded maximum include depth" stderr + test_grep "exceeded maximum include depth" stderr ' test_expect_success 'onbranch with unborn branch' '
t/t1308-config-set.sh +3 -3
@@ -180,7 +180,7 @@ test_expect_success 'find integer if value is non parse-able' ' test_expect_success 'non parse-able integer value during iteration' ' check_config expect_code 128 git_config_int lamb.head 2>result && - grep "fatal: bad numeric config value .* in file \.git/config" result + test_grep "fatal: bad numeric config value .* in file \.git/config" result ' test_expect_success 'find bool value for the entered key' '
@@ -302,7 +302,7 @@ test_expect_success 'proper error on directory "files"' ' echo "Error (-1) reading configuration file a-directory." >expect && mkdir a-directory && test_expect_code 2 test-tool config configset_get_value foo.bar a-directory 2>output && - grep "^warning:" output && + test_grep "^warning:" output && grep "^Error" output >actual && test_cmp expect actual '
@@ -312,7 +312,7 @@ test_expect_success POSIXPERM,SANITY 'proper error on non-accessible files' ' test_when_finished "chmod +r .git/config" && echo "Error (-1) reading configuration file .git/config." >expect && test_expect_code 2 test-tool config configset_get_value foo.bar .git/config 2>output && - grep "^warning:" output && + test_grep "^warning:" output && grep "^Error" output >actual && test_cmp expect actual '
t/t1400-update-ref.sh +88 -85
628 lines not on this page · raw message
t/t1403-show-ref.sh +9 -9
@@ -213,19 +213,19 @@ test_expect_success 'show-ref --verify with dangling ref' ' test_expect_success 'show-ref sub-modes are mutually exclusive' ' test_must_fail git show-ref --verify --exclude-existing 2>err && - grep "verify" err && - grep "exclude-existing" err && - grep "cannot be used together" err && + test_grep "verify" err && + test_grep "exclude-existing" err && + test_grep "cannot be used together" err && test_must_fail git show-ref --verify --exists 2>err && - grep "verify" err && - grep "exists" err && - grep "cannot be used together" err && + test_grep "verify" err && + test_grep "exists" err && + test_grep "cannot be used together" err && test_must_fail git show-ref --exclude-existing --exists 2>err && - grep "exclude-existing" err && - grep "exists" err && - grep "cannot be used together" err + test_grep "exclude-existing" err && + test_grep "exists" err && + test_grep "cannot be used together" err ' test_done
t/t1410-reflog.sh +2 -2
@@ -108,12 +108,12 @@ test_expect_success setup ' test_expect_success 'correct usage on sub-command -h' ' test_expect_code 129 git reflog expire -h >err && - grep "git reflog expire" err + test_grep "git reflog expire" err ' test_expect_success 'correct usage on "git reflog show -h"' ' test_expect_code 129 git reflog show -h >err && - grep -F "git reflog [show]" err + test_grep -F "git reflog [show]" err ' test_expect_success 'pass through -- to sub-command' '
t/t1415-worktree-refs.sh +2 -2
@@ -32,7 +32,7 @@ test_expect_success 'ambiguous main-worktree/HEAD' ' test_when_finished git update-ref -d refs/heads/main-worktree/HEAD && git update-ref refs/heads/main-worktree/HEAD $(git rev-parse HEAD) && git rev-parse main-worktree/HEAD 2>warn && - grep "main-worktree/HEAD.*ambiguous" warn + test_grep "main-worktree/HEAD.*ambiguous" warn ' test_expect_success 'resolve worktrees/xx/HEAD' '
@@ -45,7 +45,7 @@ test_expect_success 'ambiguous worktrees/xx/HEAD' ' git update-ref refs/heads/worktrees/wt1/HEAD $(git rev-parse HEAD) && test_when_finished git update-ref -d refs/heads/worktrees/wt1/HEAD && git rev-parse worktrees/wt1/HEAD 2>warn && - grep "worktrees/wt1/HEAD.*ambiguous" warn + test_grep "worktrees/wt1/HEAD.*ambiguous" warn ' test_expect_success 'reflog of main-worktree/HEAD' '
t/t1430-bad-ref-name.sh +28 -28
153 lines not on this page · raw message
t/t1450-fsck.sh +6 -6
@@ -68,7 +68,7 @@ test_expect_success 'object with hash mismatch' ' git update-ref refs/heads/bogus $cmt && test_must_fail git fsck 2>out && - grep "$oldoid: hash-path mismatch, found at: .*$new" out + test_grep "$oldoid: hash-path mismatch, found at: .*$new" out ) '
@@ -172,7 +172,7 @@ test_expect_success 'commit with multiple signatures is okay' ' test_when_finished "git update-ref -d refs/heads/bogus" && git fsck 2>out && cat out && - ! grep "commit $new" out + test_grep ! "commit $new" out ' test_expect_success 'email without @ is okay' '
@@ -183,7 +183,7 @@ test_expect_success 'email without @ is okay' ' git update-ref refs/heads/bogus "$new" && test_when_finished "git update-ref -d refs/heads/bogus" && git fsck 2>out && - ! grep "commit $new" out + test_grep ! "commit $new" out ' test_expect_success 'email with embedded > is not okay' '
@@ -626,7 +626,7 @@ test_expect_success 'fsck notices excessively large tree entry name' ' cd large-name && test_commit a-long-name && git -c fsck.largePathname=warn:10 fsck 2>out && - grep "warning.*large pathname" out + test_grep "warning.*large pathname" out ) '
@@ -849,7 +849,7 @@ test_expect_success 'fsck errors in packed objects' ' test_must_fail git fsck 2>out && test_grep "error in commit $one.* - bad name" out && test_grep "error in commit $two.* - bad name" out && - ! grep corrupt out + test_grep ! corrupt out ' test_expect_success 'fsck handles multiple packfiles with big blobs' '
@@ -1027,7 +1027,7 @@ test_expect_success 'bogus head does not fallback to all heads' ' test_when_finished "git rm --cached foo" && remove_object $blob && test_must_fail git fsck $ZERO_OID >out 2>&1 && - ! grep $blob out + test_grep ! $blob out ' # Corrupt the checksum on the index.
t/t1451-fsck-buffer.sh +3 -3
@@ -46,7 +46,7 @@ check () { echo "$content" } >input && test_must_fail git hash-object -t "$type" input 2>err && - grep "$fsck" err + test_grep "$fsck" err ' }
@@ -125,7 +125,7 @@ ident_checks tag tagger 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_grep badTree err ' test_expect_success 'truncated tree (missing nul)' '
@@ -135,7 +135,7 @@ test_expect_success 'truncated tree (missing nul)' ' # 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_grep badTree err ' test_done
t/t1460-refs-migrate.sh +1 -1
@@ -212,7 +212,7 @@ do test_commit -C repo initial && git -C repo refs migrate --dry-run \ --ref-format=$to_format >output && - grep "Finished dry-run migration of refs" output && + test_grep "Finished dry-run migration of refs" output && test_path_is_dir repo/.git/ref_migration.* && echo $from_format >expect && git -C repo rev-parse --show-ref-format >actual &&
t/t1500-rev-parse.sh +3 -3
@@ -204,7 +204,7 @@ test_expect_success 'rev-parse --show-object-format in repo' ' git rev-parse --show-object-format=output >actual && test_cmp expect actual && test_must_fail git rev-parse --show-object-format=squeamish-ossifrage 2>err && - grep "unknown mode for --show-object-format: squeamish-ossifrage" err + test_grep "unknown mode for --show-object-format: squeamish-ossifrage" err '
@@ -228,7 +228,7 @@ test_expect_success RUST 'rev-parse --show-object-format in repo with compat mod git rev-parse --show-object-format=compat >actual && test_cmp expect actual && test_must_fail git rev-parse --show-object-format=squeamish-ossifrage 2>err && - grep "unknown mode for --show-object-format: squeamish-ossifrage" err + test_grep "unknown mode for --show-object-format: squeamish-ossifrage" err ) && mkdir repo2 && (
@@ -254,7 +254,7 @@ test_expect_success 'rev-parse --show-ref-format with invalid storage' ' cd repo && git config extensions.refstorage broken && test_must_fail git rev-parse --show-ref-format 2>err && - grep "error: invalid value for ${SQ}extensions.refstorage${SQ}: ${SQ}broken${SQ}" err + test_grep "error: invalid value for ${SQ}extensions.refstorage${SQ}: ${SQ}broken${SQ}" err ) '
t/t1502-rev-parse-parseopt.sh +1 -1
@@ -331,7 +331,7 @@ test_expect_success 'ambiguous: --no matches both --noble and --no-noble' ' EOF test_expect_code 129 env GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=false \ git rev-parse --parseopt -- <spec 2>err --no && - grep "error: ambiguous option: no (could be --noble or --no-noble)" err + test_grep "error: ambiguous option: no (could be --noble or --no-noble)" err ' test_done
t/t1503-rev-parse-verify.sh +5 -5
@@ -62,15 +62,15 @@ test_expect_success 'works with one good rev' ' test_expect_success 'fails with any bad rev or many good revs' ' test_must_fail git rev-parse --verify 2>error && - grep "single revision" error && + test_grep "single revision" error && test_must_fail git rev-parse --verify foo 2>error && - grep "single revision" error && + test_grep "single revision" error && test_must_fail git rev-parse --verify HEAD bar 2>error && - grep "single revision" error && + test_grep "single revision" error && test_must_fail git rev-parse --verify baz HEAD 2>error && - grep "single revision" error && + test_grep "single revision" error && test_must_fail git rev-parse --verify $HASH2 HEAD 2>error && - grep "single revision" error + test_grep "single revision" error ' test_expect_success 'fails silently when using -q' '
t/t1510-repo-setup.sh +5 -5
@@ -604,7 +604,7 @@ test_expect_success '#20b/c: core.worktree and core.bare conflict' ' cd 20b/.git && test_must_fail git status >/dev/null ) 2>message && - grep "core.bare and core.worktree" message + test_grep "core.bare and core.worktree" message ' test_expect_success '#20d: core.worktree and core.bare OK when working tree not needed' '
@@ -721,8 +721,8 @@ test_expect_success '#22.2: core.worktree and core.bare conflict' ' export GIT_DIR && test_must_fail git status 2>result ) && - grep "core.bare and core.worktree" 22/.git/result && - grep "core.bare and core.worktree" 22/result + test_grep "core.bare and core.worktree" 22/.git/result && + test_grep "core.bare and core.worktree" 22/result ' # Case #23: GIT_DIR + GIT_WORK_TREE(+core.worktree) suppresses bareness.
@@ -767,7 +767,7 @@ test_expect_success '#28: core.worktree and core.bare conflict (gitfile case)' ' cd 28 && test_must_fail git status ) 2>message && - grep "core.bare and core.worktree" message + test_grep "core.bare and core.worktree" message ' # Case #29: GIT_WORK_TREE(+core.worktree) overrides core.bare (gitfile case).
@@ -791,7 +791,7 @@ test_expect_success '#30: core.worktree and core.bare conflict (gitfile version) cd 30 && test_must_fail env GIT_DIR=.git git status 2>result ) && - grep "core.bare and core.worktree" 30/result + test_grep "core.bare and core.worktree" 30/result ' # Case #31: GIT_DIR + GIT_WORK_TREE(+core.worktree) suppresses
t/t1512-rev-parse-disambiguation.sh +2 -2
@@ -378,7 +378,7 @@ test_expect_success 'ambiguous 40-hex ref' ' VAL=$(git commit-tree $TREE </dev/null) && git update-ref refs/heads/$REF $VAL && test $(git rev-parse $REF 2>err) = $REF && - grep "refname.*${REF}.*ambiguous" err + test_grep "refname.*${REF}.*ambiguous" err ' test_expect_success 'ambiguous short sha1 ref' '
@@ -387,7 +387,7 @@ test_expect_success 'ambiguous short sha1 ref' ' VAL=$(git commit-tree $TREE </dev/null) && git update-ref refs/heads/$REF $VAL && test $(git rev-parse $REF 2>err) = $VAL && - grep "refname.*${REF}.*ambiguous" err + test_grep "refname.*${REF}.*ambiguous" err ' test_expect_success 'ambiguity errors are not repeated (raw)' '
t/t1515-rev-parse-outside-repo.sh +1 -1
@@ -32,7 +32,7 @@ test_expect_success 'rev-parse --local-env-vars' ' git rev-parse --local-env-vars >actual && # we do not want to depend on the complete list here, # so just look for something plausible - grep ^GIT_DIR actual + test_grep ^GIT_DIR actual ' test_expect_success 'rev-parse --resolve-git-dir' '
t/t1800-hook.sh +9 -9
@@ -79,7 +79,7 @@ test_expect_success 'git hook usage' ' test_expect_code 129 git hook run --unknown 2>err && test_expect_code 129 git hook list && test_expect_code 129 git hook list -h && - grep "unknown option" err + test_grep "unknown option" err ' test_expect_success 'git hook list: unknown hook name is rejected' '
@@ -361,9 +361,9 @@ test_expect_success 'hook can be configured for multiple events' ' # 'ghi' should be included in both 'pre-commit' and 'test-hook' git hook list pre-commit >actual && - grep "ghi" actual && + test_grep "ghi" actual && git hook list --allow-unknown-hook-name test-hook >actual && - grep "ghi" actual + test_grep "ghi" actual ' test_expect_success 'git hook list shows hooks from the hookdir' '
@@ -569,7 +569,7 @@ test_expect_success 'git hook run a hook with a bad shebang' ' # TODO: We should emit the same (or at least a more similar) # error on MINGW (essentially Git for Windows) and all other # platforms.. See the OS-specific code in start_command() - grep -E "^(error|fatal): cannot (exec|spawn) .*bad-hooks/test-hook" err + test_grep -E "^(error|fatal): cannot (exec|spawn) .*bad-hooks/test-hook" err ' test_expect_success 'stdin to hooks' '
@@ -826,8 +826,8 @@ test_expect_success 'git hook run -j2 warns for hooks not marked parallel=true' # neither hook has parallel=true git hook run --allow-unknown-hook-name -j2 test-hook >out 2>err && - grep "hook .hook-1. is not marked as parallel=true" err && - grep "hook .hook-2. is not marked as parallel=true" err + test_grep "hook .hook-1. is not marked as parallel=true" err && + test_grep "hook .hook-2. is not marked as parallel=true" err ' test_expect_success 'hook.jobs=1 config runs hooks in series' '
@@ -1068,7 +1068,7 @@ test_expect_success 'hook.jobs=-1 resolves to online_cpus()' ' cpus=$(test-tool online-cpus) && GIT_TRACE2_EVENT="$(pwd)/trace.txt" \ git hook run --allow-unknown-hook-name test-hook >out 2>err && - grep "\"region_enter\".*\"hook\".*\"test-hook\".*\"max:$cpus\"" trace.txt + test_grep "\"region_enter\".*\"hook\".*\"test-hook\".*\"max:$cpus\"" trace.txt ' test_expect_success 'hook.<event>.jobs=-1 resolves to online_cpus()' '
@@ -1081,7 +1081,7 @@ test_expect_success 'hook.<event>.jobs=-1 resolves to online_cpus()' ' cpus=$(test-tool online-cpus) && GIT_TRACE2_EVENT="$(pwd)/trace.txt" \ git hook run --allow-unknown-hook-name test-hook >out 2>err && - grep "\"region_enter\".*\"hook\".*\"test-hook\".*\"max:$cpus\"" trace.txt + test_grep "\"region_enter\".*\"hook\".*\"test-hook\".*\"max:$cpus\"" trace.txt ' test_expect_success 'git hook run -j-1 resolves to online_cpus()' '
@@ -1092,7 +1092,7 @@ test_expect_success 'git hook run -j-1 resolves to online_cpus()' ' cpus=$(test-tool online-cpus) && GIT_TRACE2_EVENT="$(pwd)/trace.txt" \ git hook run --allow-unknown-hook-name -j-1 test-hook >out 2>err && - grep "\"region_enter\".*\"hook\".*\"test-hook\".*\"max:$cpus\"" trace.txt + test_grep "\"region_enter\".*\"hook\".*\"test-hook\".*\"max:$cpus\"" trace.txt ' test_expect_success 'hook.jobs rejects values less than -1' '
t/t2004-checkout-cache-temp.sh +2 -2
@@ -132,8 +132,8 @@ test_expect_success 'overriding --stage=all resets implied --temp' ' test_expect_success '--stage=all --no-temp is rejected' ' rm -f path* .merge_* actual && test_must_fail git checkout-index --stage=all --no-temp -- path1 2>err &&
Lines of this file are not shown. View the raw message.
t/t2081-parallel-checkout-collisions.sh +12 -12
Lines of this file are not shown. View the raw message.
t/t2082-parallel-checkout-attributes.sh +6 -6
Lines of this file are not shown. View the raw message.
t/t3206-range-diff.sh +39 -39
78 lines not on this page · raw message
t/t3404-rebase-interactive.sh +36 -36
72 lines not on this page · raw message
t/t4014-format-patch.sh +172 -172
344 lines not on this page · raw message
t/t4150-am.sh +24 -24
48 lines not on this page · raw message
t/t4202-log.sh +42 -42
84 lines not on this page · raw message
t/t4211-line-log.sh +36 -36
72 lines not on this page · raw message
t/t5334-incremental-multi-pack-index.sh +1 -1
Lines of this file are not shown. View the raw message.
t/t5551-http-fetch-smart.sh +23 -23
46 lines not on this page · raw message
t/t5616-partial-clone.sh +30 -30
60 lines not on this page · raw message
t/t5619-clone-local-ambiguous-transport.sh +1 -1
Lines of this file are not shown. View the raw message.
t/t5700-protocol-v1.sh +23 -23
46 lines not on this page · raw message
t/t5702-protocol-v2.sh +77 -77
154 lines not on this page · raw message
t/t6030-bisect-porcelain.sh +75 -75
150 lines not on this page · raw message
t/t6200-fmt-merge-msg.sh +41 -41
82 lines not on this page · raw message
t/t6423-merge-rename-directories.sh +36 -36
72 lines not on this page · raw message
t/t6424-merge-unrelated-index-changes.sh +3 -3
Lines of this file are not shown. View the raw message.
t/t6432-merge-recursive-space-options.sh +2 -2
Lines of this file are not shown. View the raw message.
t/t7030-verify-tag.sh +26 -26
52 lines not on this page · raw message
t/t7031-verify-tag-signed-ssh.sh +23 -23
46 lines not on this page · raw message
t/t7510-signed-commit.sh +34 -34
68 lines not on this page · raw message
t/t7527-builtin-fsmonitor.sh +41 -41
82 lines not on this page · raw message
t/t7528-signed-commit-ssh.sh +34 -34
68 lines not on this page · raw message
t/t9001-send-email.sh +95 -95
190 lines not on this page · raw message
t/t9350-fast-export.sh +27 -27
54 lines not on this page · raw message
t/t9501-gitweb-standalone-http-status.sh +29 -29
58 lines not on this page · raw message
t/t9502-gitweb-standalone-parse-output.sh +19 -19
Lines of this file are not shown. View the raw message.
t/t9801-git-p4-branch.sh +24 -24
48 lines not on this page · raw message
t/t9835-git-p4-metadata-encoding-python2.sh +18 -18
Lines of this file are not shown. View the raw message.
t/t9836-git-p4-metadata-encoding-python3.sh +19 -19
Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
Signature · 1 line
gitgitgadget
Part of the diff is not shown here. View the raw message.
PATCH v3 6/6 t: add greplint to detect bare grep assertions
In reply to Michael Montalbo via GitGitGadgetFrom: Michael Montalbo <[email protected]>
Without a lint guard, bare grep assertions will creep back into tests over time, defeating the previous commit's conversion.
Add greplint.pl to catch bare 'grep' used as a test assertion (where 'test_grep' should be used) and '! test_grep' (where 'test_grep !' should be used).
greplint.pl reuses the shared shell parser from lib-shell-parser.pl to tokenize test bodies. The Lexer collapses heredocs, command substitutions, and quoted strings into single tokens, so 'grep' appearing inside these contexts is not flagged. A flat walk over the token stream tracks command position and pipeline state to distinguish assertion greps from filter greps.
For double-quoted test bodies, a source-line walk counts backslash-continuation lines that the Lexer consumes without emitting into the body text, adjusting the reported line number accordingly.
Add test fixtures in greplint/ (modeled on chainlint/) covering detection of bare grep assertions, correct skipping of filters, pipelines, redirects, command substitutions, and lint-ok annotations.
Wire into the Makefile as:
- test-greplint: runs greplint.pl on $(T) $(THELPERS) $(TPERF)
- check-greplint: runs greplint.pl on fixtures, diffs against expected
- clean-greplint: removes temp dir
Add eol=lf entries in t/.gitattributes for greplint fixtures, matching chainlint, so that check-greplint passes on Windows where core.autocrlf would otherwise cause CRLF mismatches between expected and actual output.
--- t/.gitattributes | 2 + t/Makefile | 29 ++- t/greplint-cat.pl | 27 ++ t/greplint.pl | 241 ++++++++++++++++++ t/greplint/bare-grep-after-and.expect | 1 + t/greplint/bare-grep-after-and.test | 4 + t/greplint/bare-grep-after-semicolon.expect | 1 + t/greplint/bare-grep-after-semicolon.test | 4 + t/greplint/bare-grep-compound-body.expect | 3 + t/greplint/bare-grep-compound-body.test | 17 ++ t/greplint/bare-grep-count-mode.expect | 1 + t/greplint/bare-grep-count-mode.test | 3 + t/greplint/bare-grep-explicit-pattern.expect | 1 + t/greplint/bare-grep-explicit-pattern.test | 3 + t/greplint/bare-grep-flags.expect | 1 + t/greplint/bare-grep-flags.test | 3 + t/greplint/bare-grep-lint-ok.expect | 0 t/greplint/bare-grep-lint-ok.test | 4 + t/greplint/bare-grep-negated.expect | 1 + t/greplint/bare-grep-negated.test | 3 + t/greplint/bare-grep-pattern-file.expect | 1 + t/greplint/bare-grep-pattern-file.test | 3 + t/greplint/bare-grep-simple.expect | 1 + t/greplint/bare-grep-simple.test | 3 + t/greplint/bare-grep-subshell.expect | 1 + t/greplint/bare-grep-subshell.test | 5 + .../dqstring-continuation-offset.expect | 1 + t/greplint/dqstring-continuation-offset.test | 11 + t/greplint/filter-command-substitution.expect | 0 t/greplint/filter-command-substitution.test | 3 + t/greplint/filter-pipe-input.expect | 0 t/greplint/filter-pipe-input.test | 3 + t/greplint/filter-pipe-output.expect | 0 t/greplint/filter-pipe-output.test | 3 + t/greplint/filter-redirect-output.expect | 0 t/greplint/filter-redirect-output.test | 3 + t/greplint/filter-stdin-redirect.expect | 0 t/greplint/filter-stdin-redirect.test | 3 + t/greplint/grep-as-argument.expect | 0 t/greplint/grep-as-argument.test | 3 + t/greplint/grep-as-value.expect | 0 t/greplint/grep-as-value.test | 6 + t/greplint/wrong-negation.expect | 1 + t/greplint/wrong-negation.test | 3 + 44 files changed, 398 insertions(+), 5 deletions(-) create mode 100644 t/greplint-cat.pl create mode 100644 t/greplint.pl create mode 100644 t/greplint/bare-grep-after-and.expect create mode 100644 t/greplint/bare-grep-after-and.test create mode 100644 t/greplint/bare-grep-after-semicolon.expect create mode 100644 t/greplint/bare-grep-after-semicolon.test create mode 100644 t/greplint/bare-grep-compound-body.expect create mode 100644 t/greplint/bare-grep-compound-body.test create mode 100644 t/greplint/bare-grep-count-mode.expect create mode 100644 t/greplint/bare-grep-count-mode.test create mode 100644 t/greplint/bare-grep-explicit-pattern.expect create mode 100644 t/greplint/bare-grep-explicit-pattern.test create mode 100644 t/greplint/bare-grep-flags.expect create mode 100644 t/greplint/bare-grep-flags.test create mode 100644 t/greplint/bare-grep-lint-ok.expect create mode 100644 t/greplint/bare-grep-lint-ok.test create mode 100644 t/greplint/bare-grep-negated.expect create mode 100644 t/greplint/bare-grep-negated.test create mode 100644 t/greplint/bare-grep-pattern-file.expect create mode 100644 t/greplint/bare-grep-pattern-file.test create mode 100644 t/greplint/bare-grep-simple.expect create mode 100644 t/greplint/bare-grep-simple.test create mode 100644 t/greplint/bare-grep-subshell.expect create mode 100644 t/greplint/bare-grep-subshell.test create mode 100644 t/greplint/dqstring-continuation-offset.expect create mode 100644 t/greplint/dqstring-continuation-offset.test create mode 100644 t/greplint/filter-command-substitution.expect create mode 100644 t/greplint/filter-command-substitution.test create mode 100644 t/greplint/filter-pipe-input.expect create mode 100644 t/greplint/filter-pipe-input.test create mode 100644 t/greplint/filter-pipe-output.expect create mode 100644 t/greplint/filter-pipe-output.test create mode 100644 t/greplint/filter-redirect-output.expect create mode 100644 t/greplint/filter-redirect-output.test create mode 100644 t/greplint/filter-stdin-redirect.expect create mode 100644 t/greplint/filter-stdin-redirect.test create mode 100644 t/greplint/grep-as-argument.expect create mode 100644 t/greplint/grep-as-argument.test create mode 100644 t/greplint/grep-as-value.expect create mode 100644 t/greplint/grep-as-value.test create mode 100644 t/greplint/wrong-negation.expect create mode 100644 t/greplint/wrong-negation.test
t/.gitattributes +2 -0
@@ -1,5 +1,7 @@ t[0-9][0-9][0-9][0-9]/* -whitespace /chainlint/*.expect eol=lf -whitespace +/greplint/*.expect eol=lf -whitespace +/greplint/*.test eol=lf -whitespace /t0110/url-* binary /t3206/* eol=lf /t3900/*.txt eol=lf
t/Makefile +24 -5
@@ -27,9 +27,11 @@ TEST_LINT ?= test-lint ifdef TEST_OUTPUT_DIRECTORY TEST_RESULTS_DIRECTORY = $(TEST_OUTPUT_DIRECTORY)/test-results CHAINLINTTMP = $(TEST_OUTPUT_DIRECTORY)/chainlinttmp +GREPLINTTMP = $(TEST_OUTPUT_DIRECTORY)/greplinttmp else TEST_RESULTS_DIRECTORY = test-results CHAINLINTTMP = chainlinttmp +GREPLINTTMP = greplinttmp endif # Shell quote;
@@ -38,6 +40,7 @@ TEST_SHELL_PATH_SQ = $(subst ','\'',$(TEST_SHELL_PATH)) PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) TEST_RESULTS_DIRECTORY_SQ = $(subst ','\'',$(TEST_RESULTS_DIRECTORY)) CHAINLINTTMP_SQ = $(subst ','\'',$(CHAINLINTTMP)) +GREPLINTTMP_SQ = $(subst ','\'',$(GREPLINTTMP)) T = $(sort $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)) THELPERS = $(sort $(filter-out $(T),$(wildcard *.sh)))
@@ -45,6 +48,7 @@ TLIBS = $(sort $(wildcard lib-*.sh)) annotate-tests.sh TPERF = $(sort $(wildcard perf/p[0-9][0-9][0-9][0-9]-*.sh)) TINTEROP = $(sort $(wildcard interop/i[0-9][0-9][0-9][0-9]-*.sh)) CHAINLINTTESTS = $(sort $(patsubst chainlint/%.test,%,$(wildcard chainlint/*.test))) +GREPLINTTESTS = $(sort $(patsubst greplint/%.test,%,$(wildcard greplint/*.test))) CHAINLINT = '$(PERL_PATH_SQ)' chainlint.pl UNIT_TEST_SOURCES = $(wildcard unit-tests/t-*.c) UNIT_TEST_PROGRAMS = $(patsubst unit-tests/%.c,unit-tests/bin/%$(X),$(UNIT_TEST_SOURCES))
@@ -63,8 +67,8 @@ test: pre-clean check-meson $(TEST_LINT) $(CHAINLINTSUPPRESS) $(MAKE) aggregate-results-and-cleanup ifneq ($(PERL_PATH),) -test: check-chainlint -prove: check-chainlint +test: check-chainlint check-greplint +prove: check-chainlint check-greplint endif failed:
@@ -102,7 +106,7 @@ unit-tests-test-tool: pre-clean: $(RM) -r '$(TEST_RESULTS_DIRECTORY_SQ)' -clean-except-prove-cache: clean-chainlint +clean-except-prove-cache: clean-chainlint clean-greplint $(RM) -r 'trash directory'.* $(RM) -r valgrind/bin
@@ -120,6 +124,17 @@ check-chainlint: { $(CHAINLINT) --emit-all '$(CHAINLINTTMP_SQ)'/tests >'$(CHAINLINTTMP_SQ)'/actual || true; } && \ diff -u '$(CHAINLINTTMP_SQ)'/expect '$(CHAINLINTTMP_SQ)'/actual +clean-greplint: + $(RM) -r '$(GREPLINTTMP_SQ)' + +check-greplint: + @mkdir -p '$(GREPLINTTMP_SQ)' && \ + '$(PERL_PATH_SQ)' greplint-cat.pl '$(GREPLINTTMP_SQ)' $(GREPLINTTESTS) && \ + { '$(PERL_PATH_SQ)' greplint.pl \ + $(patsubst %,greplint/%.test,$(GREPLINTTESTS)) \ + >'$(GREPLINTTMP_SQ)'/actual 2>&1 || true; } && \ + diff -u '$(GREPLINTTMP_SQ)'/expect '$(GREPLINTTMP_SQ)'/actual + check-meson: @# awk acts up when trying to match single quotes, so we use \047 instead. @mkdir -p mesontmp && \
@@ -139,7 +154,7 @@ check-meson: test-lint: test-lint-duplicates test-lint-executable \ test-lint-filenames ifneq ($(PERL_PATH),) -test-lint: test-lint-shell-syntax +test-lint: test-lint-shell-syntax test-greplint else GIT_TEST_CHAIN_LINT = 0 endif
@@ -160,6 +175,9 @@ test-lint-executable: test-lint-shell-syntax: @'$(PERL_PATH_SQ)' check-non-portable-shell.pl $(T) $(THELPERS) $(TPERF) +test-greplint: + @'$(PERL_PATH_SQ)' greplint.pl $(T) $(THELPERS) $(TPERF) + test-lint-filenames: @# We do *not* pass a glob to ls-files but use grep instead, to catch @# non-ASCII characters (which are quoted within double-quotes)
@@ -185,7 +203,8 @@ perf: $(MAKE) -C perf/ all .PHONY: pre-clean $(T) aggregate-results clean valgrind perf \ - check-chainlint clean-chainlint test-chainlint $(UNIT_TESTS) + check-chainlint clean-chainlint test-chainlint \ + check-greplint clean-greplint test-greplint $(UNIT_TESTS) .PHONY: libgit-sys-test libgit-rs-test libgit-sys-test:
t/greplint-cat.pl new file +27 -0
@@ -0,0 +1,27 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +# Assemble expected output for check-greplint target. +# Usage: greplint-cat.pl <outdir> <test-name> ... +# +# For each <test-name>, reads greplint/<test-name>.expect and +# prepends "greplint/<test-name>.test:" to every non-empty line, +# matching the output format of greplint.pl. Writes combined +# expected output to <outdir>/expect. + +my $outdir = shift; +open(my $expect, '>', "$outdir/expect") + or die "unable to open $outdir/expect: $!"; + +for my $name (@ARGV) { + open(my $fh, '<', "greplint/$name.expect") + or die "unable to open greplint/$name.expect: $!"; + while (<$fh>) { + print $expect "greplint/$name.test:$_"; + } + close $fh; +} + +close $expect;
t/greplint.pl new file +241 -0
241 lines not on this page · raw message
t/greplint/bare-grep-after-and.expect new file +1 -0
@@ -0,0 +1 @@ +3: error: bare grep outside pipeline (use test_grep)
t/greplint/bare-grep-after-and.test new file +4 -0
@@ -0,0 +1,4 @@ +test_expect_success 'grep after && is flagged' ' + cmd && + grep pattern file +'
t/greplint/bare-grep-after-semicolon.expect new file +1 -0
@@ -0,0 +1 @@ +3: error: bare grep outside pipeline (use test_grep)
t/greplint/bare-grep-after-semicolon.test new file +4 -0
@@ -0,0 +1,4 @@ +test_expect_success 'grep after semicolon is flagged' ' + echo hello; + grep pattern file +'
t/greplint/bare-grep-compound-body.expect new file +3 -0
@@ -0,0 +1,3 @@ +4: error: bare grep outside pipeline (use test_grep) +8: error: bare grep outside pipeline (use test_grep) +15: error: bare grep outside pipeline (use test_grep)
t/greplint/bare-grep-compound-body.test new file +17 -0
@@ -0,0 +1,17 @@ +test_expect_success 'grep after then/do/else is flagged' ' + if true + then + grep pattern file + fi && + while true + do + grep pattern file && + break + done && + if true + then + echo yes + else + grep pattern file + fi +'
t/greplint/bare-grep-count-mode.expect new file +1 -0
@@ -0,0 +1 @@ +2: error: bare grep outside pipeline (use test_grep)
t/greplint/bare-grep-count-mode.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'grep -c is flagged (not special-cased)' ' + grep -c pattern file +'
t/greplint/bare-grep-explicit-pattern.expect new file +1 -0
@@ -0,0 +1 @@ +2: error: bare grep outside pipeline (use test_grep)
t/greplint/bare-grep-explicit-pattern.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'grep -e is flagged' ' + grep -e pattern file +'
t/greplint/bare-grep-flags.expect new file +1 -0
@@ -0,0 +1 @@ +2: error: bare grep outside pipeline (use test_grep)
t/greplint/bare-grep-flags.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'grep -E is flagged' ' + grep -E "pat+ern" file +'
t/greplint/bare-grep-lint-ok.expect new file +0 -0
t/greplint/bare-grep-lint-ok.test new file +4 -0
@@ -0,0 +1,4 @@ +test_expect_success 'grep with lint-ok annotation is not flagged' ' + grep pattern file && # lint-ok + echo done +'
t/greplint/bare-grep-negated.expect new file +1 -0
@@ -0,0 +1 @@ +2: error: bare grep outside pipeline (use test_grep)
t/greplint/bare-grep-negated.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'negated grep is flagged' ' + ! grep pattern file +'
t/greplint/bare-grep-pattern-file.expect new file +1 -0
@@ -0,0 +1 @@ +2: error: bare grep outside pipeline (use test_grep)
t/greplint/bare-grep-pattern-file.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'grep -f is flagged' ' + grep -f patterns.txt file +'
t/greplint/bare-grep-simple.expect new file +1 -0
@@ -0,0 +1 @@ +2: error: bare grep outside pipeline (use test_grep)
t/greplint/bare-grep-simple.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'bare grep is flagged' ' + grep pattern file +'
t/greplint/bare-grep-subshell.expect new file +1 -0
@@ -0,0 +1 @@ +3: error: bare grep outside pipeline (use test_grep)
t/greplint/bare-grep-subshell.test new file +5 -0
@@ -0,0 +1,5 @@ +test_expect_success 'grep in subshell is flagged' ' + ( + grep pattern file + ) +'
t/greplint/dqstring-continuation-offset.expect new file +1 -0
@@ -0,0 +1 @@ +10: error: bare grep outside pipeline (use test_grep)
t/greplint/dqstring-continuation-offset.test new file +11 -0
@@ -0,0 +1,11 @@ +# Double-quoted test bodies with backslash-continuation lines: +# the splice adjustment in check_test compensates for \<newline> +# lines that the lexer consumes without emitting into the body +# text, so the reported line number matches the source. +test_expect_success 'dqstring continuation offset' " + x=\$(echo \ + hello) && + y=\$(echo \ + world) && + grep pattern file +"
t/greplint/filter-command-substitution.expect new file +0 -0
t/greplint/filter-command-substitution.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'grep in command substitution is not flagged' ' + x=$(grep pattern file) +'
t/greplint/filter-pipe-input.expect new file +0 -0
t/greplint/filter-pipe-input.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'grep receiving pipe input is not flagged' ' + cmd | grep pattern +'
t/greplint/filter-pipe-output.expect new file +0 -0
t/greplint/filter-pipe-output.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'grep piping to another command is not flagged' ' + grep pattern file | wc -l +'
t/greplint/filter-redirect-output.expect new file +0 -0
t/greplint/filter-redirect-output.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'grep with output redirect is not flagged' ' + grep pattern file >output +'
t/greplint/filter-stdin-redirect.expect new file +0 -0
t/greplint/filter-stdin-redirect.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'grep reading from stdin redirect is not flagged' ' + grep pattern <input +'
t/greplint/grep-as-argument.expect new file +0 -0
t/greplint/grep-as-argument.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'grep as argument to another command is not flagged' ' + test_must_fail grep pattern file +'
t/greplint/grep-as-value.expect new file +0 -0
t/greplint/grep-as-value.test new file +6 -0
@@ -0,0 +1,6 @@ +test_expect_success 'grep as value in for-loop is not flagged' ' + for cmd in grep sed awk + do + echo $cmd + done +'
t/greplint/wrong-negation.expect new file +1 -0
@@ -0,0 +1 @@ +2: error: use "test_grep !" instead of "! test_grep"
t/greplint/wrong-negation.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'wrong negation of test_grep is flagged' ' + ! test_grep pattern file +'
Signature · 1 line
gitgitgadget
Re: [PATCH v3 0/6] t: add greplint.pl and convert grep to test_grep
In reply to Michael Montalbo via GitGitGadgetQuoted 32 lines · Michael Montalbo via GitGitGadget
Changes since v2:
* t3420-rebase-autostash: dropped the change to the '! grep dirty file3' line under 'rebase --quit'. As SZEDER pointed out, file3 never exists in the conflicted state, so that grep was passing only because it could not open the file. SZEDER's fix (sg/t3420-do-not-grep-in-missing-file, now in 'next') replaces the line with '
test_path_is_missingfile3', which is the right check; this series simply leaves that line to his fix.* Audited the remaining '# lint-ok' annotations for the same "grep a file that never exists with correctly running Git" gotcha, as Junio suggested. The rule the audit applies: 'grep' becomes '
test_grep' only where its exit code is the assertion; grep that produces data (a filter) or that reads a file whose presence is conditional stays a plain 'grep', becausetest_grepBUGs on a missing file.* t5537 (.git/shallow): the file is still present after the repack (the client stays shallow), so the assertion is converted to '
test_grep!' like any other; the "may not exist" note was wrong.* t1400 (.git/packed-refs): the file exists only with the files backend. Guarded the packed-refs check with a REFFILES prerequisite; the backend-agnostic 'git show-ref' check that follows still runs under every backend.
* t7450 (squatting-clone/d/a/git~2): kept as '! grep' with an improved '# lint-ok'. 'git~2' is the NTFS 8.3 short name of a planted '..git' decoy and only exists when 8.3 short-name generation is enabled. Verified on a Windows VM: with 8.3 disabled (the modern default) the short name is absent, the '! grep' correctly tolerates it, and a plain
test_grepwould BUG. So this one deliberately stays a missing-file-tolerant grep.
Quoted 2 lines
* t5326 and t5702 remain annotated: these are genuine data filters (grep produces data that is redirected/captured, not an assertion).
Great.
Quoted 4 lines
++ test_grep requires <file> to exist and will BUG otherwise.
++ When a file's presence is conditional (a backend-specific
++ file, or a path that only exists on some platforms, such as
++ an NTFS 8.3 short name), keep a plain guarded 'grep' instead.It is not quite clear if I can follow this instruction myself, without knowing what a "plain guarded 'grep'" is, unfortunately. Is it different from bog-standard grep?
Quoted 9 lines
@@ t/t1400-update-ref.sh: test_expect_success "move $m (by HEAD)" '
test_when_finished "git update-ref -d $m" &&
git update-ref -d HEAD $B &&
- ! grep "$m" .git/packed-refs &&
-+ ! grep "$m" .git/packed-refs && # lint-ok: file may not exist (reftable)
++ if test_have_prereq REFFILES
++ then
++ test_grep ! "$m" .git/packed-refs
++ fi &&The intent is shown very well in this version (admittedly, the lint-ok comment is readable but only by humans and LLMs). Here, we expect .git/packed-refs only while REFFILES prerequiste is active.
Thanks.
Re: [PATCH v3 0/6] t: add greplint.pl and convert grep to test_grep
Quoted 5 lines · Junio C Hamano
It is not quite clear if I can follow this instruction myself, without knowing what a "plain guarded 'grep'" is, unfortunately. Is it different from bog-standard grep?
I agree with you that the word "guarded" is really confusing here after reading it
again. The suggestion should just be to use "plain grep" with no mention of a guard. Will remove it.
My original intent was something along the lines of "guarded against BUG'ing on missing file", but the wording is confusing and, worse, could encourage the anti-pattern of using grep to test for file existence.
v4 cover t: add greplint.pl and convert grep to test_grep
In reply to Michael Montalbo via GitGitGadgettest_grep is a wrapper around grep for test assertions that prints the file contents on failure for easier debugging. Bare grep fails silently, making it hard to diagnose what went wrong.
This series converts existing bare grep assertions to test_grep and adds greplint.pl to prevent new ones from being introduced.
Patch 1 documents test_grep in t/README.
Patch 2 fixes three greps missing file arguments (t2402, t7507, t7700). They were reading empty stdin and passing vacuously.
Patch 3 extracts chainlint's Lexer, ShellParser, and ScriptParser into a shared module (lib-shell-parser.pl) so greplint.pl can reuse the same tokenizer. No functional change to chainlint.
Patch 4 fixes a latent line-counting bug in scan_dqstring where newlines from $() bodies inside double-quoted strings were counted twice. This does not affect chainlint (which uses byte offsets) but matters for greplint.pl's line-number reporting.
Patch 5 converts existing assertion greps to test_grep, including sourced test helpers. Greps used as data filters are left unconverted with lint-ok annotations; an assertion on a conditionally-present file is guarded on that condition (a prerequisite, or a 'test -e') and uses test_grep inside the guard.
Patch 6 adds greplint.pl with test fixtures (modeled on chainlint/) and wires it into the Makefile as test-greplint and check-greplint.
Changes since v3:
* t/README: reworded the guidance to encourage explicit file existence / pre-req checks. Instead of "keep a plain guarded 'grep'", it now says to guard the assertion on the condition that governs the file's presence (a prerequisite, or a 'test -e' on the path) and use test_grep inside the guard, with a worked example:
if test_have_prereq REFFILES
then
test_grep ! "$refname" .git/packed-refs
fi
* t7450 (squatting-clone/d/a/git~2): converted the last missing-file-tolerant '! grep' to that guarded form:
if test -f squatting-clone/d/a/git\~2
then
test_grep ! gitdir squatting-clone/d/a/git\~2
fi
'git~2' is the NTFS 8.3 short name of the planted '..git' file and exists only when 8.3 short-name generation is enabled. Use 'test -f' so the conditional presence is now explicit instead of relying on grep's tolerance for a missing file, and the assertion gains test_grep's diagnostics where git~2 does materialize. This removes the only '# lint-ok' in the series that guarded an assertion rather than a data filter.
* greplint.pl: updated the lint_ok() comment to match. A '# lint-ok' annotation now documents a single case: a grep acting as a data filter whose output is consumed by a redirect or pipe on an enclosing compound command (a subshell or brace group), which the filter heuristic cannot detect locally. The "file may not exist" rationale is gone; the two remaining annotated greps (t5326, t5702) are exactly this shape.
Note on ordering: this series leaves the t3420 '! grep dirty file3' line untouched (per the request to omit it), so it depends on sg/t3420-do-not-grep-in-missing-file, which replaces that line with 'test_path_is_missing file3' and is already in 'next'. Applied on top of that topic the series is lint-clean with no edits. On a plain 'master' that does not yet contain it, the greplint check added by the final patch will flag exactly that one line by design (the t3420 test itself still passes; only the static lint fires).
Known limitation / follow-up:
Assertions like grep pattern file >/dev/null and grep pattern <file are not converted because greplint.pl treats any redirect as a filter, so it does not flag them. The former could be converted, but test_grep prints the matching line on success just as grep does, so the >/dev/null would have to be kept or dropped as a judgment call. The latter requires turning the <file redirect into a positional file argument, since test_grep reads a named file rather than stdin. Both are left as bare grep with no annotation: unlike the genuine data-filter greps, they carry no '# lint-ok' marker, because greplint silently classifies any redirect as a filter and never flags them. A follow-up series can address these once a convention is established.
Michael Montalbo (6):
t/README: document test_grep helper
t: fix grep assertions missing file arguments
t: extract chainlint's parser into shared module
t: fix Lexer line count for $() inside double-quoted strings
t: convert grep assertions to test_grep
t: add greplint to detect bare grep assertions
t/.gitattributes | 2 + t/Makefile | 29 +- t/README | 34 ++ t/chainlint.pl | 529 +---------------- t/for-each-ref-tests.sh | 12 +- t/greplint-cat.pl | 27 + t/greplint.pl | 258 +++++++++ t/greplint/bare-grep-after-and.expect | 1 + t/greplint/bare-grep-after-and.test | 4 + t/greplint/bare-grep-after-semicolon.expect | 1 + t/greplint/bare-grep-after-semicolon.test | 4 + t/greplint/bare-grep-compound-body.expect | 3 + t/greplint/bare-grep-compound-body.test | 17 + t/greplint/bare-grep-count-mode.expect | 1 + t/greplint/bare-grep-count-mode.test | 3 + t/greplint/bare-grep-explicit-pattern.expect | 1 + t/greplint/bare-grep-explicit-pattern.test | 3 + t/greplint/bare-grep-flags.expect | 1 + t/greplint/bare-grep-flags.test | 3 + t/greplint/bare-grep-lint-ok.expect | 0 t/greplint/bare-grep-lint-ok.test | 4 + t/greplint/bare-grep-negated.expect | 1 + t/greplint/bare-grep-negated.test | 3 + t/greplint/bare-grep-pattern-file.expect | 1 + t/greplint/bare-grep-pattern-file.test | 3 + t/greplint/bare-grep-simple.expect | 1 + t/greplint/bare-grep-simple.test | 3 + t/greplint/bare-grep-subshell.expect | 1 + t/greplint/bare-grep-subshell.test | 5 + .../dqstring-continuation-offset.expect | 1 + t/greplint/dqstring-continuation-offset.test | 11 + t/greplint/filter-command-substitution.expect | 0 t/greplint/filter-command-substitution.test | 3 + t/greplint/filter-pipe-input.expect | 0 t/greplint/filter-pipe-input.test | 3 + t/greplint/filter-pipe-output.expect | 0 t/greplint/filter-pipe-output.test | 3 + t/greplint/filter-redirect-output.expect | 0 t/greplint/filter-redirect-output.test | 3 + t/greplint/filter-stdin-redirect.expect | 0 t/greplint/filter-stdin-redirect.test | 3 + t/greplint/grep-as-argument.expect | 0 t/greplint/grep-as-argument.test | 3 + t/greplint/grep-as-value.expect | 0 t/greplint/grep-as-value.test | 6 + t/greplint/wrong-negation.expect | 1 + t/greplint/wrong-negation.test | 3 + t/lib-bitmap.sh | 12 +- t/lib-bundle-uri-protocol.sh | 26 +- t/lib-httpd.sh | 2 +- t/lib-shell-parser.pl | 534 ++++++++++++++++++ t/pack-refs-tests.sh | 2 +- t/show-ref-exists-tests.sh | 2 +- t/t0000-basic.sh | 16 +- t/t0001-init.sh | 18 +- t/t0008-ignores.sh | 8 +- t/t0009-git-dir-validation.sh | 6 +- t/t0012-help.sh | 4 +- t/t0013-sha1dc.sh | 2 +- t/t0017-env-helper.sh | 4 +- t/t0021-conversion.sh | 18 +- t/t0029-core-unsetenvvars.sh | 4 +- t/t0030-stripspace.sh | 4 +- t/t0031-lockfile-pid.sh | 2 +- t/t0040-parse-options.sh | 52 +- t/t0041-usage.sh | 2 +- t/t0052-simple-ipc.sh | 10 +- t/t0061-run-command.sh | 2 +- t/t0066-dir-iterator.sh | 2 +- t/t0068-for-each-repo.sh | 16 +- t/t0070-fundamental.sh | 6 +- t/t0081-find-pack.sh | 12 +- t/t0091-bugreport.sh | 18 +- t/t0092-diagnose.sh | 12 +- t/t0100-previous.sh | 2 +- t/t0200-gettext-basic.sh | 14 +- t/t0203-gettext-setlocale-sanity.sh | 4 +- t/t0204-gettext-reencode-sanity.sh | 8 +- t/t0210-trace2-normal.sh | 6 +- t/t0211-trace2-perf.sh | 80 +-- t/t0212-trace2-event.sh | 8 +- t/t0300-credentials.sh | 4 +- t/t0410-partial-clone.sh | 82 +-- t/t0450-txt-doc-vs-help.sh | 2 +- t/t0500-progress-display.sh | 18 +- t/t0610-reftable-basics.sh | 8 +- t/t1004-read-tree-m-u-wf.sh | 8 +- t/t1006-cat-file.sh | 18 +- t/t1007-hash-object.sh | 8 +- t/t1011-read-tree-sparse-checkout.sh | 10 +- t/t1050-large.sh | 6 +- t/t1091-sparse-checkout-builtin.sh | 24 +- t/t1092-sparse-checkout-compatibility.sh | 44 +- t/t1300-config.sh | 16 +- t/t1305-config-include.sh | 2 +- t/t1308-config-set.sh | 6 +- t/t1400-update-ref.sh | 173 +++--- t/t1403-show-ref.sh | 18 +- t/t1410-reflog.sh | 4 +- t/t1415-worktree-refs.sh | 4 +- t/t1430-bad-ref-name.sh | 56 +- t/t1450-fsck.sh | 12 +- t/t1451-fsck-buffer.sh | 6 +- t/t1460-refs-migrate.sh | 2 +- t/t1500-rev-parse.sh | 6 +- t/t1502-rev-parse-parseopt.sh | 2 +- t/t1503-rev-parse-verify.sh | 10 +- t/t1510-repo-setup.sh | 10 +- t/t1512-rev-parse-disambiguation.sh | 4 +- t/t1515-rev-parse-outside-repo.sh | 2 +- t/t1800-hook.sh | 18 +- t/t2004-checkout-cache-temp.sh | 4 +- t/t2019-checkout-ambiguous-ref.sh | 4 +- t/t2024-checkout-dwim.sh | 8 +- t/t2030-unresolve-info.sh | 6 +- t/t2060-switch.sh | 6 +- t/t2070-restore.sh | 2 +- t/t2080-parallel-checkout-basics.sh | 14 +- t/t2081-parallel-checkout-collisions.sh | 24 +- t/t2082-parallel-checkout-attributes.sh | 12 +- t/t2103-update-index-ignore-missing.sh | 6 +- t/t2200-add-update.sh | 2 +- t/t2203-add-intent.sh | 6 +- t/t2400-worktree-add.sh | 24 +- t/t2402-worktree-list.sh | 16 +- t/t2403-worktree-move.sh | 6 +- t/t2405-worktree-submodule.sh | 6 +- t/t2407-worktree-heads.sh | 26 +- t/t2500-untracked-overwriting.sh | 8 +- t/t2501-cwd-empty.sh | 4 +- t/t3001-ls-files-others-exclude.sh | 6 +- t/t3007-ls-files-recurse-submodules.sh | 6 +- t/t3200-branch.sh | 12 +- t/t3202-show-branch.sh | 10 +- t/t3203-branch-output.sh | 4 +- t/t3206-range-diff.sh | 78 +-- t/t3207-branch-submodule.sh | 4 +- t/t3301-notes.sh | 32 +- t/t3310-notes-merge-manual-resolve.sh | 16 +- t/t3320-notes-merge-worktrees.sh | 2 +- t/t3400-rebase.sh | 16 +- t/t3402-rebase-merge.sh | 16 +- t/t3404-rebase-interactive.sh | 72 +-- t/t3406-rebase-message.sh | 6 +- t/t3415-rebase-autosquash.sh | 10 +- t/t3416-rebase-onto-threedots.sh | 4 +- t/t3418-rebase-continue.sh | 10 +- t/t3420-rebase-autostash.sh | 24 +- t/t3422-rebase-incompatible-options.sh | 4 +- t/t3429-rebase-edit-todo.sh | 2 +- t/t3430-rebase-merges.sh | 32 +- t/t3500-cherry.sh | 4 +- t/t3501-revert-cherry-pick.sh | 6 +- t/t3504-cherry-pick-rerere.sh | 6 +- t/t3510-cherry-pick-sequence.sh | 24 +- t/t3602-rm-sparse-checkout.sh | 4 +- t/t3705-add-sparse-checkout.sh | 10 +- t/t3800-mktag.sh | 4 +- t/t3901-i18n-patch.sh | 16 +- t/t3903-stash.sh | 28 +- t/t3904-stash-patch.sh | 4 +- t/t3908-stash-in-worktree.sh | 2 +- t/t4000-diff-format.sh | 2 +- t/t4001-diff-rename.sh | 4 +- t/t4011-diff-symlink.sh | 2 +- t/t4013-diff-various.sh | 2 +- t/t4014-format-patch.sh | 344 +++++------ t/t4015-diff-whitespace.sh | 16 +- t/t4017-diff-retval.sh | 2 +- t/t4018-diff-funcname.sh | 2 +- t/t4019-diff-wserror.sh | 8 +- t/t4020-diff-external.sh | 18 +- t/t4021-format-patch-numbered.sh | 4 +- t/t4022-diff-rewrite.sh | 14 +- t/t4028-format-patch-mime-headers.sh | 6 +- t/t4031-diff-rewrite-binary.sh | 18 +- t/t4033-diff-patience.sh | 2 +- t/t4036-format-patch-signer-mime.sh | 6 +- t/t4038-diff-combined.sh | 6 +- t/t4051-diff-function-context.sh | 38 +- t/t4053-diff-no-index.sh | 4 +- t/t4063-diff-blobs.sh | 2 +- t/t4065-diff-anchored.sh | 26 +- t/t4067-diff-partial-clone.sh | 12 +- t/t4073-diff-stat-name-width.sh | 24 +- t/t4103-apply-binary.sh | 2 +- t/t4120-apply-popt.sh | 2 +- t/t4124-apply-ws-rule.sh | 10 +- t/t4128-apply-root.sh | 2 +- t/t4140-apply-ita.sh | 4 +- t/t4141-apply-too-large.sh | 2 +- t/t4150-am.sh | 48 +- t/t4200-rerere.sh | 6 +- t/t4201-shortlog.sh | 2 +- t/t4202-log.sh | 84 +-- t/t4204-patch-id.sh | 2 +- t/t4205-log-pretty-formats.sh | 2 +- t/t4209-log-pickaxe.sh | 10 +- t/t4211-line-log.sh | 72 +-- t/t4216-log-bloom.sh | 18 +- t/t4252-am-options.sh | 22 +- t/t4254-am-corrupt.sh | 6 +- t/t4258-am-quoted-cr.sh | 2 +- t/t4301-merge-tree-write-tree.sh | 18 +- t/t5000-tar-tree.sh | 10 +- t/t5004-archive-corner-cases.sh | 2 +- t/t5100-mailinfo.sh | 2 +- t/t5150-request-pull.sh | 18 +- t/t5300-pack-object.sh | 22 +- t/t5302-pack-index.sh | 6 +- t/t5304-prune.sh | 8 +- t/t5310-pack-bitmaps.sh | 14 +- t/t5317-pack-objects-filter-objects.sh | 12 +- t/t5318-commit-graph.sh | 8 +- t/t5319-multi-pack-index.sh | 16 +- t/t5324-split-commit-graph.sh | 10 +- t/t5325-reverse-index.sh | 2 +- t/t5326-multi-pack-bitmaps.sh | 28 +- t/t5328-commit-graph-64bit-time.sh | 2 +- t/t5329-pack-objects-cruft.sh | 8 +- t/t5334-incremental-multi-pack-index.sh | 2 +- t/t5335-compact-multi-pack-index.sh | 4 +- t/t5351-unpack-large-objects.sh | 2 +- t/t5402-post-merge-hook.sh | 4 +- t/t5403-post-checkout-hook.sh | 2 +- t/t5404-tracking-branches.sh | 2 +- t/t5406-remote-rejects.sh | 2 +- t/t5407-post-rewrite-hook.sh | 8 +- t/t5409-colorize-remote-messages.sh | 36 +- t/t5500-fetch-pack.sh | 38 +- t/t5504-fetch-receive-strict.sh | 14 +- t/t5505-remote.sh | 20 +- t/t5510-fetch.sh | 10 +- t/t5512-ls-remote.sh | 8 +- t/t5514-fetch-multiple.sh | 2 +- t/t5516-fetch-push.sh | 20 +- t/t5520-pull.sh | 4 +- t/t5524-pull-msg.sh | 6 +- t/t5526-fetch-submodules.sh | 16 +- t/t5529-push-errors.sh | 4 +- t/t5530-upload-pack-error.sh | 18 +- t/t5531-deep-submodule-push.sh | 2 +- t/t5532-fetch-proxy.sh | 2 +- t/t5533-push-cas.sh | 12 +- t/t5534-push-signed.sh | 22 +- t/t5537-fetch-shallow.sh | 2 +- t/t5538-push-shallow.sh | 2 +- t/t5539-fetch-http-shallow.sh | 4 +- t/t5541-http-push-smart.sh | 32 +- t/t5544-pack-objects-hook.sh | 12 +- t/t5550-http-fetch-dumb.sh | 4 +- t/t5551-http-fetch-smart.sh | 46 +- t/t5552-skipping-fetch-negotiator.sh | 6 +- t/t5554-noop-fetch-negotiator.sh | 4 +- t/t5557-http-get.sh | 2 +- t/t5558-clone-bundle-uri.sh | 38 +- t/t5562-http-backend-content-length.sh | 2 +- t/t5564-http-proxy.sh | 10 +- t/t5581-http-curl-verbose.sh | 2 +- t/t5583-push-branches.sh | 8 +- t/t5601-clone.sh | 28 +- t/t5604-clone-reference.sh | 8 +- t/t5605-clone-local.sh | 2 +- t/t5606-clone-options.sh | 6 +- t/t5612-clone-refspec.sh | 2 +- t/t5616-partial-clone.sh | 60 +- t/t5619-clone-local-ambiguous-transport.sh | 2 +- t/t5620-backfill.sh | 12 +- t/t5700-protocol-v1.sh | 46 +- t/t5701-git-serve.sh | 14 +- t/t5702-protocol-v2.sh | 154 ++--- t/t5703-upload-pack-ref-in-want.sh | 22 +- t/t5705-session-id-in-capabilities.sh | 12 +- t/t5750-bundle-uri-parse.sh | 8 +- t/t5801-remote-helpers.sh | 4 +- t/t5810-proto-disable-local.sh | 2 +- t/t5813-proto-disable-ssh.sh | 4 +- t/t6000-rev-list-misc.sh | 26 +- t/t6005-rev-list-count.sh | 8 +- t/t6006-rev-list-format.sh | 4 +- t/t6009-rev-list-parent.sh | 4 +- t/t6020-bundle-misc.sh | 12 +- t/t6022-rev-list-missing.sh | 4 +- t/t6030-bisect-porcelain.sh | 150 ++--- t/t6040-tracking-info.sh | 2 +- t/t6112-rev-list-filters-objects.sh | 24 +- t/t6115-rev-list-du.sh | 4 +- t/t6120-describe.sh | 14 +- t/t6200-fmt-merge-msg.sh | 82 +-- t/t6402-merge-rename.sh | 4 +- t/t6403-merge-file.sh | 6 +- t/t6404-recursive-merge.sh | 2 +- t/t6406-merge-attr.sh | 20 +- t/t6417-merge-ours-theirs.sh | 30 +- t/t6418-merge-text-auto.sh | 2 +- t/t6422-merge-rename-corner-cases.sh | 8 +- t/t6423-merge-rename-directories.sh | 72 +-- t/t6424-merge-unrelated-index-changes.sh | 6 +- t/t6427-diff3-conflict-markers.sh | 10 +- t/t6432-merge-recursive-space-options.sh | 4 +- t/t6436-merge-overwrite.sh | 6 +- t/t6437-submodule-merge.sh | 10 +- t/t6500-gc.sh | 8 +- t/t6600-test-reach.sh | 4 +- t/t7001-mv.sh | 16 +- t/t7002-mv-sparse-checkout.sh | 38 +- t/t7003-filter-branch.sh | 16 +- t/t7004-tag.sh | 2 +- t/t7006-pager.sh | 16 +- t/t7012-skip-worktree-writing.sh | 6 +- t/t7030-verify-tag.sh | 52 +- t/t7031-verify-tag-signed-ssh.sh | 46 +- t/t7102-reset.sh | 2 +- t/t7110-reset-merge.sh | 40 +- t/t7201-co.sh | 6 +- t/t7300-clean.sh | 2 +- t/t7301-clean-interactive.sh | 2 +- t/t7400-submodule-basic.sh | 32 +- t/t7402-submodule-rebase.sh | 2 +- t/t7406-submodule-update.sh | 26 +- t/t7416-submodule-dash-url.sh | 20 +- t/t7417-submodule-path-url.sh | 2 +- t/t7450-bad-git-dotfiles.sh | 20 +- t/t7501-commit-basic-functionality.sh | 16 +- t/t7502-commit-porcelain.sh | 2 +- t/t7507-commit-verbose.sh | 6 +- t/t7508-status.sh | 6 +- t/t7510-signed-commit.sh | 68 +-- t/t7516-commit-races.sh | 4 +- t/t7519-status-fsmonitor.sh | 14 +- t/t7527-builtin-fsmonitor.sh | 82 +-- t/t7528-signed-commit-ssh.sh | 68 +-- t/t7600-merge.sh | 10 +- t/t7603-merge-reduce-heads.sh | 20 +- t/t7606-merge-custom.sh | 2 +- t/t7607-merge-state.sh | 4 +- t/t7610-mergetool.sh | 18 +- t/t7700-repack.sh | 14 +- t/t7703-repack-geometric.sh | 4 +- t/t7704-repack-cruft.sh | 12 +- t/t7800-difftool.sh | 26 +- t/t7810-grep.sh | 22 +- t/t7814-grep-recurse-submodules.sh | 2 +- t/t7900-maintenance.sh | 34 +- t/t8008-blame-formats.sh | 2 +- t/t8010-cat-file-filters.sh | 2 +- t/t8012-blame-colors.sh | 2 +- t/t9001-send-email.sh | 190 +++---- t/t9003-help-autocorrect.sh | 6 +- t/t9106-git-svn-commit-diff-clobber.sh | 2 +- t/t9107-git-svn-migrate.sh | 30 +- t/t9110-git-svn-use-svm-props.sh | 20 +- t/t9111-git-svn-use-svnsync-props.sh | 18 +- t/t9114-git-svn-dcommit-merge.sh | 6 +- t/t9116-git-svn-log.sh | 8 +- t/t9117-git-svn-init-clone.sh | 12 +- t/t9119-git-svn-info.sh | 16 +- t/t9122-git-svn-author.sh | 8 +- t/t9130-git-svn-authors-file.sh | 8 +- t/t9138-git-svn-authors-prog.sh | 14 +- t/t9140-git-svn-reset.sh | 4 +- t/t9153-git-svn-rewrite-uuid.sh | 4 +- t/t9200-git-cvsexportcommit.sh | 2 +- t/t9210-scalar.sh | 34 +- t/t9211-scalar-clone.sh | 16 +- t/t9300-fast-import.sh | 10 +- t/t9350-fast-export.sh | 54 +- t/t9351-fast-export-anonymize.sh | 36 +- t/t9400-git-cvsserver-server.sh | 4 +- t/t9501-gitweb-standalone-http-status.sh | 58 +- t/t9502-gitweb-standalone-parse-output.sh | 38 +- t/t9800-git-p4-basic.sh | 10 +- t/t9801-git-p4-branch.sh | 48 +- t/t9806-git-p4-options.sh | 10 +- t/t9807-git-p4-submit.sh | 2 +- t/t9810-git-p4-rcs.sh | 8 +- t/t9813-git-p4-preserve-users.sh | 8 +- t/t9814-git-p4-rename.sh | 8 +- t/t9827-git-p4-change-filetype.sh | 4 +- t/t9832-unshelve.sh | 6 +- t/t9833-errors.sh | 4 +- t/t9835-git-p4-metadata-encoding-python2.sh | 36 +- t/t9836-git-p4-metadata-encoding-python3.sh | 38 +- t/t9850-shell.sh | 2 +- t/t9902-completion.sh | 26 +- 385 files changed, 3810 insertions(+), 3328 deletions(-) create mode 100644 t/greplint-cat.pl create mode 100644 t/greplint.pl create mode 100644 t/greplint/bare-grep-after-and.expect create mode 100644 t/greplint/bare-grep-after-and.test create mode 100644 t/greplint/bare-grep-after-semicolon.expect create mode 100644 t/greplint/bare-grep-after-semicolon.test create mode 100644 t/greplint/bare-grep-compound-body.expect create mode 100644 t/greplint/bare-grep-compound-body.test create mode 100644 t/greplint/bare-grep-count-mode.expect create mode 100644 t/greplint/bare-grep-count-mode.test create mode 100644 t/greplint/bare-grep-explicit-pattern.expect create mode 100644 t/greplint/bare-grep-explicit-pattern.test create mode 100644 t/greplint/bare-grep-flags.expect create mode 100644 t/greplint/bare-grep-flags.test create mode 100644 t/greplint/bare-grep-lint-ok.expect create mode 100644 t/greplint/bare-grep-lint-ok.test create mode 100644 t/greplint/bare-grep-negated.expect create mode 100644 t/greplint/bare-grep-negated.test create mode 100644 t/greplint/bare-grep-pattern-file.expect create mode 100644 t/greplint/bare-grep-pattern-file.test create mode 100644 t/greplint/bare-grep-simple.expect create mode 100644 t/greplint/bare-grep-simple.test create mode 100644 t/greplint/bare-grep-subshell.expect create mode 100644 t/greplint/bare-grep-subshell.test create mode 100644 t/greplint/dqstring-continuation-offset.expect create mode 100644 t/greplint/dqstring-continuation-offset.test create mode 100644 t/greplint/filter-command-substitution.expect create mode 100644 t/greplint/filter-command-substitution.test create mode 100644 t/greplint/filter-pipe-input.expect create mode 100644 t/greplint/filter-pipe-input.test create mode 100644 t/greplint/filter-pipe-output.expect create mode 100644 t/greplint/filter-pipe-output.test create mode 100644 t/greplint/filter-redirect-output.expect create mode 100644 t/greplint/filter-redirect-output.test create mode 100644 t/greplint/filter-stdin-redirect.expect create mode 100644 t/greplint/filter-stdin-redirect.test create mode 100644 t/greplint/grep-as-argument.expect create mode 100644 t/greplint/grep-as-argument.test create mode 100644 t/greplint/grep-as-value.expect create mode 100644 t/greplint/grep-as-value.test create mode 100644 t/greplint/wrong-negation.expect create mode 100644 t/greplint/wrong-negation.test create mode 100644 t/lib-shell-parser.pl
base-commit: e9019fcafe0040228b8631c30f97ae1adb61bcdc
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2135%2Fmmontalbo%2Fmm%2Ftest-grep-docs-v4
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2135/mmontalbo/mm/test-grep-docs-v4
Pull-Request: https://github.com/gitgitgadget/git/pull/2135
Range-diff vs v3:
1: ec6b478c4c ! 1: 44d5db91bc t/README: document test_grep helper
@@ t/README: see test-lib-functions.sh for the full list and their options.
+ 'grep' is the right choice because the exit code is not the
+ assertion itself.
+
-+ test_grep requires <file> to exist and will BUG otherwise.
-+ When a file's presence is conditional (a backend-specific
-+ file, or a path that only exists on some platforms, such as
-+ an NTFS 8.3 short name), keep a plain guarded 'grep' instead.
++ test_grep requires <file> to exist and will BUG otherwise, so
++ use it only where the file is guaranteed to exist at that point.
++ When a file's presence is conditional (a backend-specific file,
++ or a path that only exists on some platforms, such as an NTFS
++ 8.3 short name), guard the assertion on that condition (a
++ prerequisite, or a 'test -e' on the path) and use test_grep
++ inside the guard:
++
++ if test_have_prereq REFFILES
++ then
++ test_grep ! "$refname" .git/packed-refs
++ fi
+
- test_path_is_file <path>
test_path_is_dir <path>
2: 7a837b77cd = 2: 44ba6d1f1a t: fix grep assertions missing file arguments 3: 5894ca1724 = 3: 8f3ebe6426 t: extract chainlint's parser into shared module 4: 416c95fee5 = 4: 5689d2074a t: fix Lexer line count for $() inside double-quoted strings 5: 7518445733 ! 5: 53fedba4d4 t: convert grep assertions to test_grep
@@ Commit message
exists only with the files backend, so its check is guarded with a REFFILES prerequisite; the backend-agnostic 'git show-ref' check that follows still runs under every backend. In t7450 'git~2' is
- the NTFS 8.3 short name of a decoy '..git' file and only exists
- when 8.3 short-name generation is enabled; that '! grep' tolerates
- the missing file on purpose, so it is left as-is with a
- "# lint-ok" annotation rather than converted (a plain test_grep
- would BUG when the short name is absent).
+ the NTFS 8.3 short name of a '..git' file and only exists
+ when 8.3 short-name generation is enabled, so its check is guarded
+ with a 'test -f' on the path and uses test_grep inside the guard,
+ the same shape as t1400 (a plain test_grep would BUG when the
+ short name is absent).
The conversion was generated using a grep-assertion linter (greplint.pl, added in the following commit) to identify bare
@@ Commit message
# test_must_fail git show-ref --verify -q $m
#
# t7450: git~2 is an NTFS 8.3 short name that exists only when
- # short-name generation is enabled, so this stays a missing-file-
- # tolerant '! grep'; add a comment plus "# lint-ok" so the linter
- # skips it.
+ # short-name generation is enabled, so guard the check on its
+ # presence with 'test -f' and note in a comment why the path can
+ # be absent (a plain test_grep would BUG when it is):
+ #
+ # - ! grep gitdir squatting-clone/d/a/git~2
+ # + if test -f squatting-clone/d/a/git~2
+ # + then
+ # + test_grep ! gitdir squatting-clone/d/a/git~2
+ # + fi
# Step 2: reorder pre-existing '! test_grep' to 'test_grep !' # (must come before steps 3-4 so greplint does not see them)
@@ t/t7450-bad-git-dotfiles.sh: test_expect_success WINDOWS 'prevent git~1 squattin
clone --recurse-submodules squatting squatting-clone 2>err &&
test_grep -e "directory not empty" -e "not an empty directory" err &&
- ! grep gitdir squatting-clone/d/a/git~2
-+ # git~2 is the 8.3 short name of the ..git decoy, present
-+ # only when 8.3 name generation is on; a missing git~2 is
-+ # fine because the "directory not empty" check above is the
-+ # real assertion.
-+ ! grep gitdir squatting-clone/d/a/git~2 # lint-ok: 8.3 short name git~2 may not exist
++ # git~2 is an 8.3 short name, present only when 8.3 name
++ # generation is enabled. The "directory not empty" check
++ # above is the primary assertion.
++ if test -f squatting-clone/d/a/git~2
++ then
++ test_grep ! gitdir squatting-clone/d/a/git~2
++ fi
fi
'
6: 3b12a959fd ! 6: 5cda64fc26 t: add greplint to detect bare grep assertions
@@ t/greplint.pl (new)
+ return 1;
+}
+
-+# Some bare greps are intentional (e.g. file may not exist, -+# data filter). A '# lint-ok' annotation on the source line -+# suppresses the warning.
++# lint_ok() reports whether a bare grep carries a trailing ++# '# lint-ok' comment telling this linter to skip it.
++#
++# In practice this is needed for just one case: a grep acting ++# as a data filter whose output is consumed by a redirect or ++# pipe on an enclosing compound command (such as a subshell or ++# brace group) rather than by grep's own pipeline, e.g.
++#
++# ( grep ... && # lint-ok
++# sed ... ) >out
++#
++# { grep ... || : # lint-ok
++# } >out
++#
++# is_filter() only scans grep's own pipeline: it stops at the ++# separator before the compound command closes and never sees ++# the outer redirect, so it would flag such a grep as an ++# assertion. A grep that really is an assertion is better ++# written as test_grep (or a guarded test_grep when the file's ++# presence is conditional) than annotated with lint-ok.
+sub lint_ok {
+ my ($raw_lines, $ln) = @_;
+ if ($ln < 1 || $ln > @$raw_lines) {
Signature · 1 line
gitgitgadget
PATCH v4 1/6 t/README: document test_grep helper
From: Michael Montalbo <[email protected]>
test_grep is a wrapper around grep for test assertions that prints the file contents on failure for easier debugging. It also accepts '!' as its first argument for negation, which preserves the diagnostic output that '! test_grep' would suppress.
Despite being widely used (and the preferred replacement for bare grep in assertions), test_grep has no entry in t/README alongside the other documented helpers like test_cmp and test_line_count. Add one.
--- t/README | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+)
t/README +34 -0
@@ -1039,6 +1039,40 @@ see test-lib-functions.sh for the full list and their options. Check whether a file has the length it is expected to. + - test_grep [!] [<grep-options>] <pattern> <file> + + Check whether <file> contains a line matching <pattern>, or + with '!' that no line matches. Use this instead of bare + 'grep <pattern> <file>' in test assertions. On failure, + test_grep prints the contents of <file> for easier debugging, + whereas a bare 'grep' would fail silently. + + For negation, pass '!' as the first argument: + + test_grep ! "^diff --git" actual + + Do not negate by writing '! test_grep', as that suppresses the + diagnostic output. + + test_grep should only be used as a test assertion. When grep + is used as a data filter (e.g. 'grep -v "^index" actual >filtered') + or inside a command substitution (e.g. '$(grep -c ...)'), plain + 'grep' is the right choice because the exit code is not the + assertion itself. + + test_grep requires <file> to exist and will BUG otherwise, so + use it only where the file is guaranteed to exist at that point. + When a file's presence is conditional (a backend-specific file, + or a path that only exists on some platforms, such as an NTFS + 8.3 short name), guard the assertion on that condition (a + prerequisite, or a 'test -e' on the path) and use test_grep + inside the guard: + + if test_have_prereq REFFILES + then + test_grep ! "$refname" .git/packed-refs + fi + - test_path_is_file <path> test_path_is_dir <path> test_path_is_missing <path>
Signature · 1 line
gitgitgadget
PATCH v4 2/6 t: fix grep assertions missing file arguments
In reply to Michael Montalbo via GitGitGadgetFrom: Michael Montalbo <[email protected]>
Three grep assertions were missing their file arguments, causing them to read from empty stdin instead of the intended file:
- t2402: '! grep ...' should read from 'out', matching the grep on the preceding line.
- t7507: the closing quote is in the wrong place, making the entire 'diff --git actual' a single pattern with no file argument instead of pattern 'diff --git' and file 'actual'.
- t7700: '! grep ...' should read from 'packlist', matching the redirect on the preceding line.
Without file arguments these greps always succeed (empty stdin matches nothing), so the assertions were not actually checking anything. All three tests pass with the corrected file arguments, confirming the intended behavior is sound.
--- t/t2402-worktree-list.sh | 2 +- t/t7507-commit-verbose.sh | 2 +- t/t7700-repack.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-)
t/t2402-worktree-list.sh +1 -1
@@ -144,7 +144,7 @@ test_expect_success '"list" all worktrees with prunable annotation' ' rm -rf prunable && git worktree list >out && grep "/prunable *[0-9a-f].* prunable$" out && - ! grep "/unprunable *[0-9a-f].* prunable$" + ! grep "/unprunable *[0-9a-f].* prunable$" out ' test_expect_success '"list" all worktrees --porcelain with prunable' '
t/t7507-commit-verbose.sh +1 -1
@@ -163,7 +163,7 @@ done test_expect_success "status ignores commit.verbose=true" ' git -c commit.verbose=true status >actual && - ! grep "^diff --git actual" + ! grep "^diff --git" actual ' test_done
t/t7700-repack.sh +1 -1
@@ -194,7 +194,7 @@ test_expect_success 'local packed unreachable obs that exist in alternate ODB ar rm -f .git/objects/pack/* && mv pack-* .git/objects/pack/ && git verify-pack -v -- .git/objects/pack/*.idx >packlist && - ! grep "^$coid " && + ! grep "^$coid " packlist && echo >.git/objects/info/alternates && test_must_fail git show $coid '
Signature · 1 line
gitgitgadget
PATCH v4 3/6 t: extract chainlint's parser into shared module
In reply to Michael Montalbo via GitGitGadgetFrom: Michael Montalbo <[email protected]>
Move chainlint.pl's Lexer, ShellParser, and ScriptParser into a shared module (lib-shell-parser.pl) so other lint tools can reuse the same shell parsing infrastructure. A subsequent commit adds greplint.pl, which needs the same tokenizer to correctly identify command boundaries.
ScriptParser's check_test() becomes a no-op in the shared module. chainlint.pl defines ChainlintParser (extending ScriptParser) with the &&-chain check_test() implementation.
No functional change: chainlint produces the same output and check-chainlint self-tests pass.
--- t/chainlint.pl | 529 +---------------------------------------- t/lib-shell-parser.pl | 531 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 543 insertions(+), 517 deletions(-) create mode 100644 t/lib-shell-parser.pl
t/chainlint.pl +12 -517
@@ -23,458 +23,9 @@ my $jobs = -1; my $show_stats; my $emit_all; -# Lexer tokenizes POSIX shell scripts. It is roughly modeled after section 2.3 -# "Token Recognition" of POSIX chapter 2 "Shell Command Language". Although -# similar to lexical analyzers for other languages, this one differs in a few -# substantial ways due to quirks of the shell command language. -# -# For instance, in many languages, newline is just whitespace like space or -# TAB, but in shell a newline is a command separator, thus a distinct lexical -# token. A newline is significant and returned as a distinct token even at the -# end of a shell comment. -# -# In other languages, `1+2` would typically be scanned as three tokens -# (`1`, `+`, and `2`), but in shell it is a single token. However, the similar -# `1 + 2`, which embeds whitespace, is scanned as three token in shell, as well. -# In shell, several characters with special meaning lose that meaning when not -# surrounded by whitespace. For instance, the negation operator `!` is special -# when standing alone surrounded by whitespace; whereas in `foo!uucp` it is -# just a plain character in the longer token "foo!uucp". In many other -# languages, `"string"/foo:'string'` might be scanned as five tokens ("string", -# `/`, `foo`, `:`, and 'string'), but in shell, it is just a single token. -# -# The lexical analyzer for the shell command language is also somewhat unusual -# in that it recursively invokes the parser to handle the body of `$(...)` -# expressions which can contain arbitrary shell code. Such expressions may be -# encountered both inside and outside of double-quoted strings. -# -# The lexical analyzer is responsible for consuming shell here-doc bodies which -# extend from the line following a `<<TAG` operator until a line consisting -# solely of `TAG`. Here-doc consumption begins when a newline is encountered. -# It is legal for multiple here-doc `<<TAG` operators to be present on a single -# line, in which case their bodies must be present one following the next, and -# are consumed in the (left-to-right) order the `<<TAG` operators appear on the -# line. A special complication is that the bodies of all here-docs must be -# consumed when the newline is encountered even if the parse context depth has -# changed. For instance, in `cat <<A && x=$(cat <<B &&\n`, bodies of here-docs -# "A" and "B" must be consumed even though "A" was introduced outside the -# recursive parse context in which "B" was introduced and in which the newline -# is encountered. -package Lexer; - -sub new { - my ($class, $parser, $s) = @_; - bless { - parser => $parser, - buff => $s, - lineno => 1, - heretags => [] - } => $class; -} - -sub scan_heredoc_tag { - my $self = shift @_; - ${$self->{buff}} =~ /\G(-?)/gc; - my $indented = $1; - my $token = $self->scan_token(); - return "<<$indented" unless $token; - my $tag = $token->[0]; - $tag =~ s/['"\\]//g; - $$token[0] = $indented ? "\t$tag" : "$tag"; - push(@{$self->{heretags}}, $token); - return "<<$indented$tag"; -} - -sub scan_op { - my ($self, $c) = @_; - my $b = $self->{buff}; - return $c unless $$b =~ /\G(.)/sgc; - my $cc = $c . $1; - return scan_heredoc_tag($self) if $cc eq '<<'; - return $cc if $cc =~ /^(?:&&|\|\||>>|;;|<&|>&|<>|>\|)$/; - pos($$b)--; - return $c; -} - -sub scan_sqstring { - my $self = shift @_; - ${$self->{buff}} =~ /\G([^']*'|.*\z)/sgc; - my $s = $1; - $self->{lineno} += () = $s =~ /\n/sg; - return "'" . $s; -} - -sub scan_dqstring { - my $self = shift @_; - my $b = $self->{buff}; - my $s = '"'; - while (1) { - # slurp up non-special characters - $s .= $1 if $$b =~ /\G([^"\$\\]+)/gc; - # handle special characters - last unless $$b =~ /\G(.)/sgc; - my $c = $1; - $s .= '"', last if $c eq '"'; - $s .= '$' . $self->scan_dollar(), next if $c eq '$'; - if ($c eq '\\') { - $s .= '\\', last unless $$b =~ /\G(.)/sgc; - $c = $1; - $self->{lineno}++, next if $c eq "\n"; # line splice - # backslash escapes only $, `, ", \ in dq-string - $s .= '\\' unless $c =~ /^[\$`"\\]$/; - $s .= $c; - next; - } - die("internal error scanning dq-string '$c'\n"); - } - $self->{lineno} += () = $s =~ /\n/sg; - return $s; -} - -sub scan_balanced { - my ($self, $c1, $c2) = @_; - my $b = $self->{buff}; - my $depth = 1; - my $s = $c1; - while ($$b =~ /\G([^\Q$c1$c2\E]*(?:[\Q$c1$c2\E]|\z))/gc) { - $s .= $1; - $depth++, next if $s =~ /\Q$c1\E$/; - $depth--; - last if $depth == 0; - } - $self->{lineno} += () = $s =~ /\n/sg; - return $s; -} - -sub scan_subst { - my $self = shift @_; - my @tokens = $self->{parser}->parse(qr/^\)$/); - $self->{parser}->next_token(); # closing ")" - return @tokens; -} - -sub scan_dollar { - my $self = shift @_; - my $b = $self->{buff}; - return $self->scan_balanced('(', ')') 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. - return ''; -} - -sub swallow_heredocs { - my $self = shift @_; - my $b = $self->{buff}; - my $tags = $self->{heretags}; - while (my $tag = shift @$tags) { - my $start = pos($$b); - my $indent = $$tag[0] =~ s/^\t// ? '\\s*' : ''; - $$b =~ /(?:\G|\n)$indent\Q$$tag[0]\E(?:\n|\z)/gc; - if (pos($$b) > $start) { - my $body = substr($$b, $start, pos($$b) - $start); - $self->{parser}->{heredocs}->{$$tag[0]} = { - content => substr($body, 0, length($body) - length($&)), - start_line => $self->{lineno}, - }; - $self->{lineno} += () = $body =~ /\n/sg; - next; - } - push(@{$self->{parser}->{problems}}, ['HEREDOC', $tag]); - $$b =~ /(?:\G|\n).*\z/gc; # consume rest of input - my $body = substr($$b, $start, pos($$b) - $start); - $self->{lineno} += () = $body =~ /\n/sg; - last; - } -} - -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) - $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; - 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->{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; - $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, $start, pos($$b), $startln, $self->{lineno}] : undef; -} - -# ShellParser parses POSIX shell scripts (with minor extensions for Bash). It -# is a recursive descent parser very roughly modeled after section 2.10 "Shell -# Grammar" of POSIX chapter 2 "Shell Command Language". -package ShellParser; - -sub new { - my ($class, $s) = @_; - my $self = bless { - buff => [], - stop => [], - output => [], - heredocs => {}, - insubshell => 0, - } => $class; - $self->{lexer} = Lexer->new($self, $s); - return $self; -} - -sub next_token { - my $self = shift @_; - return pop(@{$self->{buff}}) if @{$self->{buff}}; - return $self->{lexer}->scan_token(); -} - -sub untoken { - my $self = shift @_; - push(@{$self->{buff}}, @_); -} - -sub peek { - my $self = shift @_; - my $token = $self->next_token(); - return undef unless defined($token); - $self->untoken($token); - return $token; -} - -sub stop_at { - my ($self, $token) = @_; - return 1 unless defined($token); - my $stop = ${$self->{stop}}[-1] if @{$self->{stop}}; - return defined($stop) && $token->[0] =~ $stop; -} - -sub expect { - my ($self, $expect) = @_; - my $token = $self->next_token(); - 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 (); -} - -sub optional_newlines { - my $self = shift @_; - my @tokens; - while (my $token = $self->peek()) { - last unless $token->[0] eq "\n"; - push(@tokens, $self->next_token()); - } - return @tokens; -} - -sub parse_group { - my $self = shift @_; - return ($self->parse(qr/^}$/), - $self->expect('}')); -} - -sub parse_subshell { - my $self = shift @_; - $self->{insubshell}++; - my @tokens = ($self->parse(qr/^\)$/), - $self->expect(')')); - $self->{insubshell}--; - return @tokens; -} - -sub parse_case_pattern { - my $self = shift @_; - my @tokens; - while (defined(my $token = $self->next_token())) { - push(@tokens, $token); - last if $token->[0] eq ')'; - } - return @tokens; -} - -sub parse_case { - my $self = shift @_; - my @tokens; - push(@tokens, - $self->next_token(), # subject - $self->optional_newlines(), - $self->expect('in'), - $self->optional_newlines()); - while (1) { - my $token = $self->peek(); - 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->[0] ne 'esac'; - push(@tokens, - $self->expect(';;'), - $self->optional_newlines()); - } - push(@tokens, $self->expect('esac')); - return @tokens; -} - -sub parse_for { - my $self = shift @_; - my @tokens; - push(@tokens, - $self->next_token(), # variable - $self->optional_newlines()); - my $token = $self->peek(); - if (defined($token) && $token->[0] eq 'in') { - push(@tokens, - $self->expect('in'), - $self->optional_newlines()); - } - push(@tokens, - $self->parse(qr/^do$/), # items - $self->expect('do'), - $self->optional_newlines(), - $self->parse_loop_body(), - $self->expect('done')); - return @tokens; -} - -sub parse_if { - my $self = shift @_; - my @tokens; - while (1) { - push(@tokens, - $self->parse(qr/^then$/), # if/elif condition - $self->expect('then'), - $self->optional_newlines(), - $self->parse(qr/^(?:elif|else|fi)$/)); # if/elif body - my $token = $self->peek(); - last unless defined($token) && $token->[0] eq 'elif'; - push(@tokens, $self->expect('elif')); - } - my $token = $self->peek(); - if (defined($token) && $token->[0] eq 'else') { - push(@tokens, - $self->expect('else'), - $self->optional_newlines(), - $self->parse(qr/^fi$/)); # else body - } - push(@tokens, $self->expect('fi')); - return @tokens; -} - -sub parse_loop_body { - my $self = shift @_; - return $self->parse(qr/^done$/); -} - -sub parse_loop { - my $self = shift @_; - return ($self->parse(qr/^do$/), # condition - $self->expect('do'), - $self->optional_newlines(), - $self->parse_loop_body(), - $self->expect('done')); -} - -sub parse_func { - my $self = shift @_; - return ($self->expect('('), - $self->expect(')'), - $self->optional_newlines(), - $self->parse_cmd()); # body -} - -sub parse_bash_array_assignment { - my $self = shift @_; - my @tokens = $self->expect('('); - while (defined(my $token = $self->next_token())) { - push(@tokens, $token); - last if $token->[0] eq ')'; - } - return @tokens; -} - -my %compound = ( - '{' => \&parse_group, - '(' => \&parse_subshell, - 'case' => \&parse_case, - 'for' => \&parse_for, - 'if' => \&parse_if, - 'until' => \&parse_loop, - 'while' => \&parse_loop); - -sub parse_cmd { - my $self = shift @_; - my $cmd = $self->next_token(); - return () unless defined($cmd); - return $cmd if $cmd->[0] eq "\n"; - - my $token; - my @tokens = $cmd; - if ($cmd->[0] eq '!') { - push(@tokens, $self->parse_cmd()); - return @tokens; - } elsif (my $f = $compound{$cmd->[0]}) { - push(@tokens, $self->$f()); - } elsif (defined($token = $self->peek()) && $token->[0] eq '(') { - if ($cmd->[0] !~ /\w=$/) { - push(@tokens, $self->parse_func()); - return @tokens; - } - 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->[0] =~ /^(?:[;&\n|]|&&|\|\|)$/; - } - push(@tokens, $self->next_token()) if $tokens[-1]->[0] ne "\n" && defined($token = $self->peek()) && $token->[0] eq "\n"; - return @tokens; -} - -sub accumulate { - my ($self, $tokens, $cmd) = @_; - push(@$tokens, @$cmd); -} - -sub parse { - my ($self, $stop) = @_; - push(@{$self->{stop}}, $stop); - goto DONE if $self->stop_at($self->peek()); - my @tokens; - while (my @cmd = $self->parse_cmd()) { - $self->accumulate(\@tokens, \@cmd); - last if $self->stop_at($self->peek()); - } -DONE: - pop(@{$self->{stop}}); - return @tokens; -} +use File::Basename; +do(dirname($0) . "/lib-shell-parser.pl") + or die "$0: failed to load lib-shell-parser.pl: $@$!\n"; # TestParser is a subclass of ShellParser which, beyond parsing shell script # code, is also imbued with semantic knowledge of test construction, and checks
@@ -482,9 +33,10 @@ DONE: # the tests themselves or in behaviors being exercised by the tests. As such, # TestParser is only called upon to parse test bodies, not the top-level # scripts in which the tests are defined. + package TestParser; -use base 'ShellParser'; +our @ISA = ('ShellParser'); sub new { my $class = shift @_;
@@ -578,51 +130,10 @@ DONE: $self->SUPER::accumulate($tokens, $cmd); } -# ScriptParser is a subclass of ShellParser which identifies individual test -# definitions within test scripts, and passes each test body through TestParser -# to identify possible problems. ShellParser detects test definitions not only -# at the top-level of test scripts but also within compound commands such as -# loops and function definitions. -package ScriptParser; - -use base 'ShellParser'; - -sub new { - my $class = shift @_; - my $self = $class->SUPER::new(@_); - $self->{ntests} = 0; - $self->{nerrs} = 0; - return $self; -} +# ChainlintParser extends ScriptParser with &&-chain checking +package ChainlintParser; -# extract the raw content of a token, which may be a single string or a -# 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 @_ : $_)->[0]; - # simple case: 'sqstring' or "dqstring" - return $token if $token =~ s/^'([^']*)'$/$1/; - return $token if $token =~ s/^"([^"]*)"$/$1/; - - # composite case - my ($s, $q, $escaped); - while (1) { - # slurp up non-special characters - $s .= $1 if $token =~ /\G([^\\'"]*)/gc; - # handle special characters - last unless $token =~ /\G(.)/sgc; - my $c = $1; - $q = undef, next if defined($q) && $c eq $q; - $q = $c, next if !defined($q) && $c =~ /^['"]$/; - if ($c eq '\\') { - last unless $token =~ /\G(.)/sgc; - $c = $1; - $s .= '\\' if $c eq "\n"; # preserve line splice - } - $s .= $c; - } - return $s -} +our @ISA = ('ScriptParser'); sub format_problem { local $_ = shift;
@@ -635,10 +146,10 @@ sub format_problem { sub check_test { my $self = shift @_; - my $title = unwrap(shift @_); + my $title = ScriptParser::unwrap(shift @_); my $body = shift @_; my $lineno = $body->[3]; - $body = unwrap($body); + $body = ScriptParser::unwrap($body); if ($body eq '-') { my $herebody = shift @_; $body = $herebody->{content};
@@ -673,24 +184,8 @@ sub check_test { push(@{$self->{output}}, "$c->{blue}# chainlint: $title$c->{reset}\n$checked"); } -sub parse_cmd { - my $self = shift @_; - my @tokens = $self->SUPER::parse_cmd(); - return @tokens unless @tokens && $tokens[0]->[0] =~ /^test_expect_(?:success|failure)$/; - my $n = $#tokens; - $n-- while $n >= 0 && $tokens[$n]->[0] =~ /^(?:[;&\n|]|&&|\|\|)$/; - my $herebody; - if ($n >= 2 && $tokens[$n-1]->[0] eq '-' && $tokens[$n]->[0] =~ /^<<-?(.+)$/) { - $herebody = $self->{heredocs}->{$1}; - $n--; - } - $self->check_test($tokens[1], $tokens[2], $herebody) if $n == 2; # title body - $self->check_test($tokens[2], $tokens[3], $herebody) if $n > 2; # prereq title body - return @tokens; -} - # main contains high-level functionality for processing command-line switches, -# feeding input test scripts to ScriptParser, and reporting results. +# feeding input test scripts to ChainlintParser, and reporting results. package main; my $getnow = sub { return time(); };
@@ -803,7 +298,7 @@ sub check_script { } my $s = do { local $/; <$fh> }; close($fh); - my $parser = ScriptParser->new(\$s); + my $parser = ChainlintParser->new(\$s); 1 while $parser->parse_cmd(); if (@{$parser->{output}}) { my $c = fd_colors(1);
t/lib-shell-parser.pl new file +531 -0
531 lines not on this page · raw message
Signature · 1 line
gitgitgadget
PATCH v4 4/6 t: fix Lexer line count for $() inside double-quoted strings
In reply to Michael Montalbo via GitGitGadgetFrom: Michael Montalbo <[email protected]>
scan_dqstring's post-loop newline counter re-counts newlines that were already counted during recursive parsing of $() bodies. This happens because scan_dollar returns text containing newlines (from multi-line command substitutions), and the catch-all counter at the end of scan_dqstring counts all of them again.
Fix this by counting newlines inline as non-special characters are consumed, and removing the post-loop catch-all. Each newline is now counted exactly once: literal newlines at the inline match, line splices at the backslash handler, and $() newlines by scan_token during the recursive parse.
This is a latent bug: any consumer that relies on token line numbers rather than byte offsets would get incorrect results for tokens following a multi-line $() inside a double-quoted string. chainlint is not affected because it annotates the original body text using byte offsets, not token line numbers.
--- t/lib-shell-parser.pl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
t/lib-shell-parser.pl +6 -3
@@ -93,8 +93,12 @@ sub scan_dqstring { my $b = $self->{buff}; my $s = '"'; while (1) { - # slurp up non-special characters - $s .= $1 if $$b =~ /\G([^"\$\\]+)/gc; + # Slurp non-special characters; count newlines here because + # newlines inside $() are already counted by the recursive parse. + if ($$b =~ /\G([^"\$\\]+)/gc) { + $s .= $1; + $self->{lineno} += $1 =~ tr/\n//; + } # handle special characters last unless $$b =~ /\G(.)/sgc; my $c = $1;
@@ -111,7 +115,6 @@ sub scan_dqstring { } die("internal error scanning dq-string '$c'\n"); } - $self->{lineno} += () = $s =~ /\n/sg; return $s; }
Signature · 1 line
gitgitgadget
PATCH v4 5/6 t: convert grep assertions to test_grep
In reply to Michael Montalbo via GitGitGadgetFrom: Michael Montalbo <[email protected]>
Replace bare grep with test_grep in test assertions across the suite, including sourced test helpers (lib-*.sh, *-tests.sh). test_grep prints the contents of the file being searched on failure, making debugging easier than a bare grep which fails silently.
Only assertion-style greps are converted: grep used as a filter in pipelines, command substitutions, conditionals, or with redirected I/O is left as-is with a "# lint-ok" annotation. Existing '! test_grep' calls are rewritten to 'test_grep !' so that the diagnostic output is preserved on failure.
test_grep requires the file it reads to exist, so '! grep' assertions that inspect a file whose presence is conditional need care. In t5537 the '.git/shallow' file is still present after the repack (the client remains shallow), so the assertion is converted like any other. In t1400 the '.git/packed-refs' file exists only with the files backend, so its check is guarded with a REFFILES prerequisite; the backend-agnostic 'git show-ref' check that follows still runs under every backend. In t7450 'git~2' is the NTFS 8.3 short name of a '..git' file and only exists when 8.3 short-name generation is enabled, so its check is guarded with a 'test -f' on the path and uses test_grep inside the guard, the same shape as t1400 (a plain test_grep would BUG when the short name is absent).
The conversion was generated using a grep-assertion linter (greplint.pl, added in the following commit) to identify bare grep calls at command position. To reproduce, from the t/ directory:
# Step 1: annotate the two data-filter greps (grep produces # data, not a verdict) so the linter skips them.
sed -i '/grep -vf before commits\.raw/s/$/ # lint-ok: data filter/' \
t5326-multi-pack-bitmaps.sh
sed -i '/grep -E "^\[0-9a-f\].*|| :/s/$/ # lint-ok: data filter/' \
t5702-protocol-v2.sh
# Step 1b: two '! grep' assertions need more than a mechanical # conversion; handle them by hand before the linter-driven steps # below so it leaves them alone.
#
# t1400: '.git/packed-refs' is absent under reftable, so guard the # check with REFFILES (a plain test_grep would BUG on the missing # file):
#
# git update-ref -d HEAD $B &&
# - ! grep "$m" .git/packed-refs &&
# + if test_have_prereq REFFILES
# + then
# + test_grep ! "$m" .git/packed-refs
# + fi &&
# test_must_fail git show-ref --verify -q $m
#
# t7450: git~2 is an NTFS 8.3 short name that exists only when # short-name generation is enabled, so guard the check on its # presence with 'test -f' and note in a comment why the path can # be absent (a plain test_grep would BUG when it is):
#
# - ! grep gitdir squatting-clone/d/a/git~2
# + if test -f squatting-clone/d/a/git~2
# + then
# + test_grep ! gitdir squatting-clone/d/a/git~2
# + fi
# Step 2: reorder pre-existing '! test_grep' to 'test_grep !' # (must come before steps 3-4 so greplint does not see them) sed -i 's/! test_grep/test_grep !/' t0031-lockfile-pid.sh sed -i 's/! test_grep/test_grep !/' t5300-pack-object.sh sed -i 's/! test_grep/test_grep !/' t5319-multi-pack-index.sh
# Step 3: convert '! grep' -> 'test_grep !'
perl greplint.pl *.sh 2>&1 | cut -d: -f1,2 |
while IFS=: read f l; do
sed -i "${l}s/! *grep/test_grep !/" "$f"
done
# Step 4: convert remaining 'grep' -> 'test_grep' perl greplint.pl *.sh 2>&1 | cut -d: -f1,2 | while IFS=: read f l; do
sed -i "${l}s/grep/test_grep/" "$f"
done
To verify, run: make -C t test-greplint
--- t/for-each-ref-tests.sh | 12 +- t/lib-bitmap.sh | 12 +- t/lib-bundle-uri-protocol.sh | 26 +- t/lib-httpd.sh | 2 +- t/pack-refs-tests.sh | 2 +- t/show-ref-exists-tests.sh | 2 +- t/t0000-basic.sh | 16 +- t/t0001-init.sh | 18 +- t/t0008-ignores.sh | 8 +- t/t0009-git-dir-validation.sh | 6 +- t/t0012-help.sh | 4 +- t/t0013-sha1dc.sh | 2 +- t/t0017-env-helper.sh | 4 +- t/t0021-conversion.sh | 18 +- t/t0029-core-unsetenvvars.sh | 4 +- t/t0030-stripspace.sh | 4 +- t/t0031-lockfile-pid.sh | 2 +- t/t0040-parse-options.sh | 52 +-- t/t0041-usage.sh | 2 +- t/t0052-simple-ipc.sh | 10 +- t/t0061-run-command.sh | 2 +- t/t0066-dir-iterator.sh | 2 +- t/t0068-for-each-repo.sh | 16 +- t/t0070-fundamental.sh | 6 +- t/t0081-find-pack.sh | 12 +- t/t0091-bugreport.sh | 18 +- t/t0092-diagnose.sh | 12 +- t/t0100-previous.sh | 2 +- t/t0200-gettext-basic.sh | 14 +- t/t0203-gettext-setlocale-sanity.sh | 4 +- t/t0204-gettext-reencode-sanity.sh | 8 +- t/t0210-trace2-normal.sh | 6 +- t/t0211-trace2-perf.sh | 80 ++--- t/t0212-trace2-event.sh | 8 +- t/t0300-credentials.sh | 4 +- t/t0410-partial-clone.sh | 82 ++--- t/t0450-txt-doc-vs-help.sh | 2 +- t/t0500-progress-display.sh | 18 +- t/t0610-reftable-basics.sh | 8 +- t/t1004-read-tree-m-u-wf.sh | 8 +- t/t1006-cat-file.sh | 18 +- t/t1007-hash-object.sh | 8 +- t/t1011-read-tree-sparse-checkout.sh | 10 +- t/t1050-large.sh | 6 +- t/t1091-sparse-checkout-builtin.sh | 24 +- t/t1092-sparse-checkout-compatibility.sh | 44 +-- t/t1300-config.sh | 16 +- t/t1305-config-include.sh | 2 +- t/t1308-config-set.sh | 6 +- t/t1400-update-ref.sh | 173 +++++----- t/t1403-show-ref.sh | 18 +- t/t1410-reflog.sh | 4 +- t/t1415-worktree-refs.sh | 4 +- t/t1430-bad-ref-name.sh | 56 ++-- t/t1450-fsck.sh | 12 +- t/t1451-fsck-buffer.sh | 6 +- t/t1460-refs-migrate.sh | 2 +- t/t1500-rev-parse.sh | 6 +- t/t1502-rev-parse-parseopt.sh | 2 +- t/t1503-rev-parse-verify.sh | 10 +- t/t1510-repo-setup.sh | 10 +- t/t1512-rev-parse-disambiguation.sh | 4 +- t/t1515-rev-parse-outside-repo.sh | 2 +- t/t1800-hook.sh | 18 +- t/t2004-checkout-cache-temp.sh | 4 +- t/t2019-checkout-ambiguous-ref.sh | 4 +- t/t2024-checkout-dwim.sh | 8 +- t/t2030-unresolve-info.sh | 6 +- t/t2060-switch.sh | 6 +- t/t2070-restore.sh | 2 +- t/t2080-parallel-checkout-basics.sh | 14 +- t/t2081-parallel-checkout-collisions.sh | 24 +- t/t2082-parallel-checkout-attributes.sh | 12 +- t/t2103-update-index-ignore-missing.sh | 6 +- t/t2200-add-update.sh | 2 +- t/t2203-add-intent.sh | 6 +- t/t2400-worktree-add.sh | 24 +- t/t2402-worktree-list.sh | 16 +- t/t2403-worktree-move.sh | 6 +- t/t2405-worktree-submodule.sh | 6 +- t/t2407-worktree-heads.sh | 26 +- t/t2500-untracked-overwriting.sh | 8 +- t/t2501-cwd-empty.sh | 4 +- t/t3001-ls-files-others-exclude.sh | 6 +- t/t3007-ls-files-recurse-submodules.sh | 6 +- t/t3200-branch.sh | 12 +- t/t3202-show-branch.sh | 10 +- t/t3203-branch-output.sh | 4 +- t/t3206-range-diff.sh | 78 ++--- t/t3207-branch-submodule.sh | 4 +- t/t3301-notes.sh | 32 +- t/t3310-notes-merge-manual-resolve.sh | 16 +- t/t3320-notes-merge-worktrees.sh | 2 +- t/t3400-rebase.sh | 16 +- t/t3402-rebase-merge.sh | 16 +- t/t3404-rebase-interactive.sh | 72 ++-- t/t3406-rebase-message.sh | 6 +- t/t3415-rebase-autosquash.sh | 10 +- t/t3416-rebase-onto-threedots.sh | 4 +- t/t3418-rebase-continue.sh | 10 +- t/t3420-rebase-autostash.sh | 24 +- t/t3422-rebase-incompatible-options.sh | 4 +- t/t3429-rebase-edit-todo.sh | 2 +- t/t3430-rebase-merges.sh | 32 +- t/t3500-cherry.sh | 4 +- t/t3501-revert-cherry-pick.sh | 6 +- t/t3504-cherry-pick-rerere.sh | 6 +- t/t3510-cherry-pick-sequence.sh | 24 +- t/t3602-rm-sparse-checkout.sh | 4 +- t/t3705-add-sparse-checkout.sh | 10 +- t/t3800-mktag.sh | 4 +- t/t3901-i18n-patch.sh | 16 +- t/t3903-stash.sh | 28 +- t/t3904-stash-patch.sh | 4 +- t/t3908-stash-in-worktree.sh | 2 +- t/t4000-diff-format.sh | 2 +- t/t4001-diff-rename.sh | 4 +- t/t4011-diff-symlink.sh | 2 +- t/t4013-diff-various.sh | 2 +- t/t4014-format-patch.sh | 344 ++++++++++---------- t/t4015-diff-whitespace.sh | 16 +- t/t4017-diff-retval.sh | 2 +- t/t4018-diff-funcname.sh | 2 +- t/t4019-diff-wserror.sh | 8 +- t/t4020-diff-external.sh | 18 +- t/t4021-format-patch-numbered.sh | 4 +- t/t4022-diff-rewrite.sh | 14 +- t/t4028-format-patch-mime-headers.sh | 6 +- t/t4031-diff-rewrite-binary.sh | 18 +- t/t4033-diff-patience.sh | 2 +- t/t4036-format-patch-signer-mime.sh | 6 +- t/t4038-diff-combined.sh | 6 +- t/t4051-diff-function-context.sh | 38 +-- t/t4053-diff-no-index.sh | 4 +- t/t4063-diff-blobs.sh | 2 +- t/t4065-diff-anchored.sh | 26 +- t/t4067-diff-partial-clone.sh | 12 +- t/t4073-diff-stat-name-width.sh | 24 +- t/t4103-apply-binary.sh | 2 +- t/t4120-apply-popt.sh | 2 +- t/t4124-apply-ws-rule.sh | 10 +- t/t4128-apply-root.sh | 2 +- t/t4140-apply-ita.sh | 4 +- t/t4141-apply-too-large.sh | 2 +- t/t4150-am.sh | 48 +-- t/t4200-rerere.sh | 6 +- t/t4201-shortlog.sh | 2 +- t/t4202-log.sh | 84 ++--- t/t4204-patch-id.sh | 2 +- t/t4205-log-pretty-formats.sh | 2 +- t/t4209-log-pickaxe.sh | 10 +- t/t4211-line-log.sh | 72 ++-- t/t4216-log-bloom.sh | 18 +- t/t4252-am-options.sh | 22 +- t/t4254-am-corrupt.sh | 6 +- t/t4258-am-quoted-cr.sh | 2 +- t/t4301-merge-tree-write-tree.sh | 18 +- t/t5000-tar-tree.sh | 10 +- t/t5004-archive-corner-cases.sh | 2 +- t/t5100-mailinfo.sh | 2 +- t/t5150-request-pull.sh | 18 +- t/t5300-pack-object.sh | 22 +- t/t5302-pack-index.sh | 6 +- t/t5304-prune.sh | 8 +- t/t5310-pack-bitmaps.sh | 14 +- t/t5317-pack-objects-filter-objects.sh | 12 +- t/t5318-commit-graph.sh | 8 +- t/t5319-multi-pack-index.sh | 16 +- t/t5324-split-commit-graph.sh | 10 +- t/t5325-reverse-index.sh | 2 +- t/t5326-multi-pack-bitmaps.sh | 28 +- t/t5328-commit-graph-64bit-time.sh | 2 +- t/t5329-pack-objects-cruft.sh | 8 +- t/t5334-incremental-multi-pack-index.sh | 2 +- t/t5335-compact-multi-pack-index.sh | 4 +- t/t5351-unpack-large-objects.sh | 2 +- t/t5402-post-merge-hook.sh | 4 +- t/t5403-post-checkout-hook.sh | 2 +- t/t5404-tracking-branches.sh | 2 +- t/t5406-remote-rejects.sh | 2 +- t/t5407-post-rewrite-hook.sh | 8 +- t/t5409-colorize-remote-messages.sh | 36 +- t/t5500-fetch-pack.sh | 38 +-- t/t5504-fetch-receive-strict.sh | 14 +- t/t5505-remote.sh | 20 +- t/t5510-fetch.sh | 10 +- t/t5512-ls-remote.sh | 8 +- t/t5514-fetch-multiple.sh | 2 +- t/t5516-fetch-push.sh | 20 +- t/t5520-pull.sh | 4 +- t/t5524-pull-msg.sh | 6 +- t/t5526-fetch-submodules.sh | 16 +- t/t5529-push-errors.sh | 4 +- t/t5530-upload-pack-error.sh | 18 +- t/t5531-deep-submodule-push.sh | 2 +- t/t5532-fetch-proxy.sh | 2 +- t/t5533-push-cas.sh | 12 +- t/t5534-push-signed.sh | 22 +- t/t5537-fetch-shallow.sh | 2 +- t/t5538-push-shallow.sh | 2 +- t/t5539-fetch-http-shallow.sh | 4 +- t/t5541-http-push-smart.sh | 32 +- t/t5544-pack-objects-hook.sh | 12 +- t/t5550-http-fetch-dumb.sh | 4 +- t/t5551-http-fetch-smart.sh | 46 +-- t/t5552-skipping-fetch-negotiator.sh | 6 +- t/t5554-noop-fetch-negotiator.sh | 4 +- t/t5557-http-get.sh | 2 +- t/t5558-clone-bundle-uri.sh | 38 +-- t/t5562-http-backend-content-length.sh | 2 +- t/t5564-http-proxy.sh | 10 +- t/t5581-http-curl-verbose.sh | 2 +- t/t5583-push-branches.sh | 8 +- t/t5601-clone.sh | 28 +- t/t5604-clone-reference.sh | 8 +- t/t5605-clone-local.sh | 2 +- t/t5606-clone-options.sh | 6 +- t/t5612-clone-refspec.sh | 2 +- t/t5616-partial-clone.sh | 60 ++-- t/t5619-clone-local-ambiguous-transport.sh | 2 +- t/t5620-backfill.sh | 12 +- t/t5700-protocol-v1.sh | 46 +-- t/t5701-git-serve.sh | 14 +- t/t5702-protocol-v2.sh | 154 ++++----- t/t5703-upload-pack-ref-in-want.sh | 22 +- t/t5705-session-id-in-capabilities.sh | 12 +- t/t5750-bundle-uri-parse.sh | 8 +- t/t5801-remote-helpers.sh | 4 +- t/t5810-proto-disable-local.sh | 2 +- t/t5813-proto-disable-ssh.sh | 4 +- t/t6000-rev-list-misc.sh | 26 +- t/t6005-rev-list-count.sh | 8 +- t/t6006-rev-list-format.sh | 4 +- t/t6009-rev-list-parent.sh | 4 +- t/t6020-bundle-misc.sh | 12 +- t/t6022-rev-list-missing.sh | 4 +- t/t6030-bisect-porcelain.sh | 150 ++++----- t/t6040-tracking-info.sh | 2 +- t/t6112-rev-list-filters-objects.sh | 24 +- t/t6115-rev-list-du.sh | 4 +- t/t6120-describe.sh | 14 +- t/t6200-fmt-merge-msg.sh | 82 ++--- t/t6402-merge-rename.sh | 4 +- t/t6403-merge-file.sh | 6 +- t/t6404-recursive-merge.sh | 2 +- t/t6406-merge-attr.sh | 20 +- t/t6417-merge-ours-theirs.sh | 30 +- t/t6418-merge-text-auto.sh | 2 +- t/t6422-merge-rename-corner-cases.sh | 8 +- t/t6423-merge-rename-directories.sh | 72 ++-- t/t6424-merge-unrelated-index-changes.sh | 6 +- t/t6427-diff3-conflict-markers.sh | 10 +- t/t6432-merge-recursive-space-options.sh | 4 +- t/t6436-merge-overwrite.sh | 6 +- t/t6437-submodule-merge.sh | 10 +- t/t6500-gc.sh | 8 +- t/t6600-test-reach.sh | 4 +- t/t7001-mv.sh | 16 +- t/t7002-mv-sparse-checkout.sh | 38 +-- t/t7003-filter-branch.sh | 16 +- t/t7004-tag.sh | 2 +- t/t7006-pager.sh | 16 +- t/t7012-skip-worktree-writing.sh | 6 +- t/t7030-verify-tag.sh | 52 +-- t/t7031-verify-tag-signed-ssh.sh | 46 +-- t/t7102-reset.sh | 2 +- t/t7110-reset-merge.sh | 40 +-- t/t7201-co.sh | 6 +- t/t7300-clean.sh | 2 +- t/t7301-clean-interactive.sh | 2 +- t/t7400-submodule-basic.sh | 32 +- t/t7402-submodule-rebase.sh | 2 +- t/t7406-submodule-update.sh | 26 +- t/t7416-submodule-dash-url.sh | 20 +- t/t7417-submodule-path-url.sh | 2 +- t/t7450-bad-git-dotfiles.sh | 20 +- t/t7501-commit-basic-functionality.sh | 16 +- t/t7502-commit-porcelain.sh | 2 +- t/t7507-commit-verbose.sh | 6 +- t/t7508-status.sh | 6 +- t/t7510-signed-commit.sh | 68 ++-- t/t7516-commit-races.sh | 4 +- t/t7519-status-fsmonitor.sh | 14 +- t/t7527-builtin-fsmonitor.sh | 82 ++--- t/t7528-signed-commit-ssh.sh | 68 ++-- t/t7600-merge.sh | 10 +- t/t7603-merge-reduce-heads.sh | 20 +- t/t7606-merge-custom.sh | 2 +- t/t7607-merge-state.sh | 4 +- t/t7610-mergetool.sh | 18 +- t/t7700-repack.sh | 14 +- t/t7703-repack-geometric.sh | 4 +- t/t7704-repack-cruft.sh | 12 +- t/t7800-difftool.sh | 26 +- t/t7810-grep.sh | 22 +- t/t7814-grep-recurse-submodules.sh | 2 +- t/t7900-maintenance.sh | 34 +- t/t8008-blame-formats.sh | 2 +- t/t8010-cat-file-filters.sh | 2 +- t/t8012-blame-colors.sh | 2 +- t/t9001-send-email.sh | 190 +++++------ t/t9003-help-autocorrect.sh | 6 +- t/t9106-git-svn-commit-diff-clobber.sh | 2 +- t/t9107-git-svn-migrate.sh | 30 +- t/t9110-git-svn-use-svm-props.sh | 20 +- t/t9111-git-svn-use-svnsync-props.sh | 18 +- t/t9114-git-svn-dcommit-merge.sh | 6 +- t/t9116-git-svn-log.sh | 8 +- t/t9117-git-svn-init-clone.sh | 12 +- t/t9119-git-svn-info.sh | 16 +- t/t9122-git-svn-author.sh | 8 +- t/t9130-git-svn-authors-file.sh | 8 +- t/t9138-git-svn-authors-prog.sh | 14 +- t/t9140-git-svn-reset.sh | 4 +- t/t9153-git-svn-rewrite-uuid.sh | 4 +- t/t9200-git-cvsexportcommit.sh | 2 +- t/t9210-scalar.sh | 34 +- t/t9211-scalar-clone.sh | 16 +- t/t9300-fast-import.sh | 10 +- t/t9350-fast-export.sh | 54 +-- t/t9351-fast-export-anonymize.sh | 36 +- t/t9400-git-cvsserver-server.sh | 4 +- t/t9501-gitweb-standalone-http-status.sh | 58 ++-- t/t9502-gitweb-standalone-parse-output.sh | 38 +-- t/t9800-git-p4-basic.sh | 10 +- t/t9801-git-p4-branch.sh | 48 +-- t/t9806-git-p4-options.sh | 10 +- t/t9807-git-p4-submit.sh | 2 +- t/t9810-git-p4-rcs.sh | 8 +- t/t9813-git-p4-preserve-users.sh | 8 +- t/t9814-git-p4-rename.sh | 8 +- t/t9827-git-p4-change-filetype.sh | 4 +- t/t9832-unshelve.sh | 6 +- t/t9833-errors.sh | 4 +- t/t9835-git-p4-metadata-encoding-python2.sh | 36 +- t/t9836-git-p4-metadata-encoding-python3.sh | 38 +-- t/t9850-shell.sh | 2 +- t/t9902-completion.sh | 26 +- 338 files changed, 2815 insertions(+), 2806 deletions(-)
t/for-each-ref-tests.sh +6 -6
@@ -523,7 +523,7 @@ test_expect_success 'Verify descending sort' ' test_expect_success 'Give help even with invalid sort atoms' ' test_expect_code 129 ${git_for_each_ref} --sort=bogus -h >actual 2>&1 && - grep "^usage: ${git_for_each_ref}" actual + test_grep "^usage: ${git_for_each_ref}" actual ' cat >expected <<\EOF
@@ -622,7 +622,7 @@ test_expect_success 'Quoting style: tcl' ' for i in "--perl --shell" "-s --python" "--python --tcl" "--tcl --perl"; do test_expect_success "more than one quoting style: $i" " test_must_fail ${git_for_each_ref} $i 2>err && - grep '^error: more than one quoting style' err + test_grep '^error: more than one quoting style' err " done
@@ -1892,7 +1892,7 @@ test_expect_success "${git_for_each_ref} --stdin: fails if extra args" ' >in && test_must_fail ${git_for_each_ref} --format="%(refname)" \ --stdin refs/heads/extra <in 2>err && - grep "unknown arguments supplied with --stdin" err + test_grep "unknown arguments supplied with --stdin" err ' test_expect_success "${git_for_each_ref} --stdin: matches" '
@@ -1955,11 +1955,11 @@ test_expect_success "${git_for_each_ref} with nested tags" ' test_expect_success 'is-base atom with non-commits' ' ${git_for_each_ref} --format="%(is-base:HEAD) %(refname)" >out 2>err && - grep "(HEAD) refs/heads/main" out && + test_grep "(HEAD) refs/heads/main" out && test_line_count = 2 err && - grep "error: object .* is a commit, not a blob" err && - grep "error: bad tag pointer to" err + test_grep "error: object .* is a commit, not a blob" err && + test_grep "error: bad tag pointer to" err ' GRADE_FORMAT="%(signature:grade)%0a%(signature:key)%0a%(signature:signer)%0a%(signature:fingerprint)%0a%(signature:primarykeyfingerprint)"
t/lib-bitmap.sh +6 -6
@@ -173,7 +173,7 @@ rev_list_tests_head () { test_expect_success "bitmap --objects handles non-commit objects ($state, $branch)" ' git rev-list --objects --use-bitmap-index $branch tagged-blob >actual && - grep $blob actual + test_grep $blob actual ' }
@@ -242,16 +242,16 @@ basic_bitmap_tests () { GIT_PROGRESS_DELAY=0 \ git pack-objects --all --stdout --progress \ </dev/null >/dev/null 2>stderr && - grep "Enumerating objects: $count, done" stderr && - grep "pack-reused $count" stderr && + test_grep "Enumerating objects: $count, done" stderr && + test_grep "pack-reused $count" stderr && # now the same but with one non-reused object git commit --allow-empty -m "an extra commit object" && GIT_PROGRESS_DELAY=0 \ git pack-objects --all --stdout --progress \ </dev/null >/dev/null 2>stderr && - grep "Enumerating objects: $((count+1)), done" stderr && - grep "pack-reused $count" stderr + test_grep "Enumerating objects: $((count+1)), done" stderr && + test_grep "pack-reused $count" stderr ' }
@@ -283,7 +283,7 @@ test_rev_exists () { then test_path_is_file $midx-$(midx_checksum $objdir).rev fi && - grep "\"category\":\"load_midx_revindex\",\"key\":\"source\",\"value\":\"$kind\"" event.trace + test_grep "\"category\":\"load_midx_revindex\",\"key\":\"source\",\"value\":\"$kind\"" event.trace ' }
t/lib-bundle-uri-protocol.sh +13 -13
@@ -63,9 +63,9 @@ test_expect_success "connect with $BUNDLE_URI_PROTOCOL:// using protocol v2: no >actual 2>err && # Server responded using protocol v2 - grep "< version 2" log && + test_grep "< version 2" log && - ! grep bundle-uri log + test_grep ! bundle-uri log ' test_expect_success "connect with $BUNDLE_URI_PROTOCOL:// using protocol v2: have bundle-uri" '
@@ -78,10 +78,10 @@ test_expect_success "connect with $BUNDLE_URI_PROTOCOL:// using protocol v2: hav >actual 2>err && # Server responded using protocol v2 - grep "< version 2" log && + test_grep "< version 2" log && # Server advertised bundle-uri capability - grep "< bundle-uri" log + test_grep "< bundle-uri" log ' test_expect_success "clone with $BUNDLE_URI_PROTOCOL:// using protocol v2: request bundle-uris" '
@@ -95,13 +95,13 @@ test_expect_success "clone with $BUNDLE_URI_PROTOCOL:// using protocol v2: reque >actual 2>err && # Server responded using protocol v2 - grep "< version 2" log && + test_grep "< version 2" log && # Server advertised bundle-uri capability - grep "< bundle-uri" log && + test_grep "< bundle-uri" log && # Client did not issue bundle-uri command - ! grep "> command=bundle-uri" log && + test_grep ! "> command=bundle-uri" log && GIT_TRACE_PACKET="$PWD/log" \ git \
@@ -111,13 +111,13 @@ test_expect_success "clone with $BUNDLE_URI_PROTOCOL:// using protocol v2: reque >actual 2>err && # Server responded using protocol v2 - grep "< version 2" log && + test_grep "< version 2" log && # Server advertised bundle-uri capability - grep "< bundle-uri" log && + test_grep "< bundle-uri" log && # Client issued bundle-uri command - grep "> command=bundle-uri" log && + test_grep "> command=bundle-uri" log && GIT_TRACE_PACKET="$PWD/log3" \ git \
@@ -128,13 +128,13 @@ test_expect_success "clone with $BUNDLE_URI_PROTOCOL:// using protocol v2: reque >actual 2>err && # Server responded using protocol v2 - grep "< version 2" log3 && + test_grep "< version 2" log3 && # Server advertised bundle-uri capability - grep "< bundle-uri" log3 && + test_grep "< bundle-uri" log3 && # Client did not issue bundle-uri command (--bundle-uri override) - ! grep "> command=bundle-uri" log3 + test_grep ! "> command=bundle-uri" log3 ' # The remaining tests will all assume transfer.bundleURI=true
t/lib-httpd.sh +1 -1
@@ -275,7 +275,7 @@ test_http_push_nonff () { ' test_expect_success 'non-fast-forward push show ref status' ' - grep "^ ! \[rejected\][ ]*$BRANCH -> $BRANCH (non-fast-forward)$" output + test_grep "^ ! \[rejected\][ ]*$BRANCH -> $BRANCH (non-fast-forward)$" output ' test_expect_success 'non-fast-forward push shows help message' '
t/pack-refs-tests.sh +1 -1
@@ -195,7 +195,7 @@ test_expect_success 'delete ref while another dangling packed ref' ' test_expect_success 'pack ref directly below refs/' ' git update-ref refs/top HEAD && git ${pack_refs} --all --prune && - grep refs/top .git/packed-refs && + test_grep refs/top .git/packed-refs && test_path_is_missing .git/refs/top '
t/show-ref-exists-tests.sh +1 -1
@@ -19,7 +19,7 @@ test_expect_success '--exists with missing reference' ' test_expect_success '--exists does not use DWIM' ' test_expect_code 2 ${git_show_ref_exists} $GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 2>err && - grep "reference does not exist" err + test_grep "reference does not exist" err ' test_expect_success '--exists with HEAD' '
t/t0000-basic.sh +8 -8
@@ -743,7 +743,7 @@ test_expect_success 'subtest: lazy prereqs do not turn off tracing' ' test_done EOF - grep "echo trace" lazy-prereq-and-tracing/err + test_grep "echo trace" lazy-prereq-and-tracing/err ' test_expect_success 'subtest: tests clean up after themselves' '
@@ -815,7 +815,7 @@ test_expect_success 'subtest: test_atexit is run' ' test_expect_success 'test_oid provides sane info by default' ' test_oid zero >actual && - grep "^00*\$" actual && + test_grep "^00*\$" actual && rawsz="$(test_oid rawsz)" && hexsz="$(test_oid hexsz)" && # +1 accounts for the trailing newline
@@ -827,7 +827,7 @@ test_expect_success 'test_oid can look up data for SHA-1' ' test_when_finished "test_detect_hash" && test_set_hash sha1 && test_oid zero >actual && - grep "^00*\$" actual && + test_grep "^00*\$" actual && rawsz="$(test_oid rawsz)" && hexsz="$(test_oid hexsz)" && test $(wc -c <actual) -eq 41 &&
@@ -839,7 +839,7 @@ test_expect_success 'test_oid can look up data for SHA-256' ' test_when_finished "test_detect_hash" && test_set_hash sha256 && test_oid zero >actual && - grep "^00*\$" actual && + test_grep "^00*\$" actual && rawsz="$(test_oid rawsz)" && hexsz="$(test_oid hexsz)" && test $(wc -c <actual) -eq 65 &&
@@ -884,11 +884,11 @@ test_expect_success 'test_bool_env' ' # test script, hence the redirection of fd 7, and aborts # with "exit 1", hence the subshell. ! ( test_bool_env envvar true ) 7>err && - grep "error: test_bool_env requires bool values" err && + test_grep "error: test_bool_env requires bool values" err && envvar=true && ! ( test_bool_env envvar invalid ) 7>err && - grep "error: test_bool_env requires bool values" err + test_grep "error: test_bool_env requires bool values" err ) '
@@ -1242,12 +1242,12 @@ test_expect_success 'test_must_fail on a failing git command with env' ' test_expect_success 'test_must_fail rejects a non-git command' ' ! test_must_fail grep ^$ notafile 2>err && - grep -F "test_must_fail: only '"'"'git'"'"' is allowed" err + test_grep -F "test_must_fail: only '"'"'git'"'"' is allowed" err ' test_expect_success 'test_must_fail rejects a non-git command with env' ' ! test_must_fail env var1=a var2=b grep ^$ notafile 2>err && - grep -F "test_must_fail: only '"'"'git'"'"' is allowed" err + test_grep -F "test_must_fail: only '"'"'git'"'"' is allowed" err ' test_done
t/t0001-init.sh +9 -9
@@ -278,9 +278,9 @@ test_expect_success POSIXPERM 'init creates a new deep directory (umask vs. shar git init --bare --shared=0660 newdir/a/b/c && test_path_is_dir newdir/a/b/c/refs && ls -ld newdir/a newdir/a/b > lsab.out && - ! grep -v "^drwxrw[sx]r-x" lsab.out && + test_grep ! -v "^drwxrw[sx]r-x" lsab.out && ls -ld newdir/a/b/c > lsc.out && - ! grep -v "^drwxrw[sx]---" lsc.out + test_grep ! -v "^drwxrw[sx]---" lsc.out ) '
@@ -619,7 +619,7 @@ test_expect_success DEFAULT_REPO_FORMAT 'extensions.refStorage is not allowed wi git init refstorage && git -C refstorage config extensions.refStorage files && test_must_fail git -C refstorage rev-parse 2>err && - grep "repo version is 0, but v1-only extension found" err + test_grep "repo version is 0, but v1-only extension found" err ' test_expect_success DEFAULT_REPO_FORMAT 'extensions.refStorage with files backend' '
@@ -637,7 +637,7 @@ test_expect_success DEFAULT_REPO_FORMAT 'extensions.refStorage with unknown back git -C refstorage config core.repositoryformatversion 1 && git -C refstorage config extensions.refStorage garbage && test_must_fail git -C refstorage rev-parse 2>err && - grep "invalid value for ${SQ}extensions.refstorage${SQ}: ${SQ}garbage${SQ}" err + test_grep "invalid value for ${SQ}extensions.refstorage${SQ}: ${SQ}garbage${SQ}" err ' test_expect_success 'init with GIT_DEFAULT_REF_FORMAT=garbage' '
@@ -848,8 +848,8 @@ test_expect_success MINGW 'redirect std handles' ' GIT_REDIRECT_STDOUT=output.txt \ GIT_REDIRECT_STDERR="2>&1" \ git rev-parse --git-dir --verify refs/invalid && - grep "^\\.git\$" output.txt && - grep "Needed a single revision" output.txt + test_grep "^\\.git\$" output.txt && + test_grep "Needed a single revision" output.txt ' test_expect_success '--initial-branch' '
@@ -862,14 +862,14 @@ test_expect_success '--initial-branch' ' git init --initial-branch=ignore initial-branch-option 2>err && test_grep "ignored --initial-branch" err && git -C initial-branch-option symbolic-ref HEAD >actual && - grep hello actual + test_grep hello actual ' test_expect_success 'overridden default initial branch name (config)' ' test_config_global init.defaultBranch nmb && GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= git init initial-branch-config && git -C initial-branch-config symbolic-ref HEAD >actual && - grep nmb actual + test_grep nmb actual ' test_expect_success 'advice on unconfigured init.defaultBranch' '
@@ -907,7 +907,7 @@ test_expect_success 'overridden default main branch name (env)' ' test_config_global init.defaultBranch nmb && GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=env git init main-branch-env && git -C main-branch-env symbolic-ref HEAD >actual && - grep env actual + test_grep env actual ' test_expect_success 'invalid default branch name' '
t/t0008-ignores.sh +4 -4
@@ -790,8 +790,8 @@ test_expect_success 'existing file and directory' ' >one && mkdir top-level-dir && git check-ignore one top-level-dir >actual && - grep one actual && - grep top-level-dir actual + test_grep one actual && + test_grep top-level-dir actual ' test_expect_success 'existing directory and file' '
@@ -800,8 +800,8 @@ test_expect_success 'existing directory and file' ' >one && mkdir top-level-dir && git check-ignore top-level-dir one >actual && - grep one actual && - grep top-level-dir actual + test_grep one actual && + test_grep top-level-dir actual ' test_expect_success 'exact prefix matching (with root)' '
t/t0009-git-dir-validation.sh +3 -3
@@ -35,7 +35,7 @@ test_expect_success PIPE 'setup: .git as a FIFO (named pipe) is rejected' ' cd parent/fifo-trap && mkfifo .git && test_must_fail git rev-parse --git-dir 2>stderr && - grep "not a regular file" stderr + test_grep "not a regular file" stderr ) '
@@ -47,7 +47,7 @@ test_expect_success SYMLINKS,PIPE 'setup: .git as a symlink to a FIFO is rejecte mkfifo target-fifo && ln -s target-fifo .git && test_must_fail git rev-parse --git-dir 2>stderr && - grep "not a regular file" stderr + test_grep "not a regular file" stderr ) '
@@ -58,7 +58,7 @@ test_expect_success 'setup: .git with garbage content is rejected' ' cd parent/garbage-trap && echo "garbage" >.git && test_must_fail git rev-parse --git-dir 2>stderr && - grep "invalid gitfile format" stderr + test_grep "invalid gitfile format" stderr ) '
t/t0012-help.sh +2 -2
@@ -131,8 +131,8 @@ test_expect_success 'git help succeeds without git.html' ' test_expect_success 'git help --user-interfaces' ' git help --user-interfaces >help.output && - grep "^ attributes " help.output && - grep "^ mailmap " help.output + test_grep "^ attributes " help.output && + test_grep "^ mailmap " help.output ' test_expect_success 'git help -c' '
t/t0013-sha1dc.sh +1 -1
@@ -16,7 +16,7 @@ fi test_expect_success 'test-sha1 detects shattered pdf' ' test_must_fail test-tool sha1 <"$TEST_DATA/shattered-1.pdf" 2>err && test_grep collision err && - grep 38762cf7f55934b34d179ae6a4c80cadccbb7f0a err + test_grep 38762cf7f55934b34d179ae6a4c80cadccbb7f0a err ' test_done
t/t0017-env-helper.sh +2 -2
@@ -88,7 +88,7 @@ test_expect_success 'test-tool env-helper reads config thanks to trace2' ' test_must_fail \ env HOME="$(pwd)/home" \ git config -l 2>err && - grep "exceeded maximum include depth" err && + test_grep "exceeded maximum include depth" err && # This validates that the assumption that we attempt to # read the configuration and fail very early in the start-up
@@ -100,7 +100,7 @@ test_expect_success 'test-tool env-helper reads config thanks to trace2' ' test-tool -C no-such-directory \ env-helper --type=bool --default=0 \ --exit-code GIT_TEST_ENV_HELPER 2>err && - grep "exceeded maximum include depth" err + test_grep "exceeded maximum include depth" err ' test_done
t/t0021-conversion.sh +9 -9
@@ -731,7 +731,7 @@ test_expect_success 'process filter should restart after unexpected write failur rm -f debug.log && git checkout --quiet --no-progress . 2>git-stderr.log && - grep "smudge write error" git-stderr.log && + test_grep "smudge write error" git-stderr.log && test_grep "error: external filter" git-stderr.log && cat >expected.log <<-EOF &&
@@ -853,7 +853,7 @@ test_expect_success 'invalid process filter must fail (and not hang!)' ' cp "$TEST_ROOT/test.o" test.r && test_must_fail git add . 2>git-stderr.log && - grep "expected git-filter-server" git-stderr.log + test_grep "expected git-filter-server" git-stderr.log ) '
@@ -970,7 +970,7 @@ test_expect_success 'missing file in delayed checkout' ' rm -rf repo-cloned && test_must_fail git clone repo repo-cloned 2>git-stderr.log && - grep "error: .missing-delay\.a. was not filtered properly" git-stderr.log + test_grep "error: .missing-delay\.a. was not filtered properly" git-stderr.log ' test_expect_success 'invalid file in delayed checkout' '
@@ -991,7 +991,7 @@ test_expect_success 'invalid file in delayed checkout' ' rm -rf repo-cloned && test_must_fail git clone repo repo-cloned 2>git-stderr.log && - grep "error: external filter .* signaled that .unfiltered. is now available although it has not been delayed earlier" git-stderr.log + test_grep "error: external filter .* signaled that .unfiltered. is now available although it has not been delayed earlier" git-stderr.log ' for mode in 'case' 'utf-8'
@@ -1032,7 +1032,7 @@ do git clone $mode-collision $mode-collision-cloned && # Make sure z was really delayed - grep "IN: smudge $dir/z .* \\[DELAYED\\]" $mode-collision-cloned/delayed.log && + test_grep "IN: smudge $dir/z .* \\[DELAYED\\]" $mode-collision-cloned/delayed.log && # Should not create $dir/z at $symlink/z test_path_is_missing $mode-collision/target-dir/z
@@ -1070,7 +1070,7 @@ test_expect_success SYMLINKS,CASE_INSENSITIVE_FS \ git commit -m super && git checkout --recurse-submodules . && - grep "IN: smudge A/B/y .* \\[DELAYED\\]" delayed.log && + test_grep "IN: smudge A/B/y .* \\[DELAYED\\]" delayed.log && test_path_is_missing target-dir/y ) '
@@ -1161,9 +1161,9 @@ test_expect_success 'delayed checkout correctly reports the number of updated en rm *.a && git checkout . 2>err && - grep "IN: smudge test-delay10.a .* \\[DELAYED\\]" delayed.log && - grep "IN: smudge test-delay11.a .* \\[DELAYED\\]" delayed.log && - grep "Updated 2 paths from the index" err + test_grep "IN: smudge test-delay10.a .* \\[DELAYED\\]" delayed.log && + test_grep "IN: smudge test-delay11.a .* \\[DELAYED\\]" delayed.log && + test_grep "Updated 2 paths from the index" err ) '
t/t0029-core-unsetenvvars.sh +2 -2
@@ -20,10 +20,10 @@ test_expect_success 'core.unsetenvvars works' ' HOBBES=Calvin && export HOBBES && git commit --allow-empty -m with 2>err && - grep Calvin err && + test_grep Calvin err && git -c core.unsetenvvars=FINDUS,HOBBES,CALVIN \ commit --allow-empty -m without 2>err && - ! grep Calvin err + test_grep ! Calvin err ' test_done
t/t0030-stripspace.sh +2 -2
@@ -407,12 +407,12 @@ test_expect_success 'strip comments with changed comment string' ' test_expect_success 'newline as commentchar is forbidden' ' test_must_fail git -c core.commentChar="$LF" stripspace -s 2>err && - grep "core.commentchar cannot contain newline" err + test_grep "core.commentchar cannot contain newline" err ' test_expect_success 'empty commentchar is forbidden' ' test_must_fail git -c core.commentchar= stripspace -s 2>err && - grep "core.commentchar must have at least one character" err + test_grep "core.commentchar must have at least one character" err ' test_expect_success '-c with single line' '
t/t0031-lockfile-pid.sh +1 -1
@@ -29,7 +29,7 @@ test_expect_success 'PID info not shown by default' ' test_must_fail git add . 2>err && # Should not crash, just show normal error without PID test_grep "Unable to create" err && - ! test_grep "is held by process" err + test_grep ! "is held by process" err ) '
t/t0040-parse-options.sh +26 -26
129 lines not on this page · raw message
t/t0041-usage.sh +1 -1
@@ -13,7 +13,7 @@ test_expect_success 'setup ' ' test_expect_success 'tag --contains <existent_tag>' ' git tag --contains "v1.0" >actual 2>actual.err && - grep "v1.0" actual && + test_grep "v1.0" actual && test_line_count = 0 actual.err '
t/t0052-simple-ipc.sh +5 -5
@@ -33,19 +33,19 @@ test_expect_success 'servers cannot share the same path' ' test_expect_success 'big response' ' test-tool simple-ipc send --token=big >actual && test_line_count -ge 10000 actual && - grep -q "big: [0]*9999\$" actual + test_grep -q "big: [0]*9999\$" actual ' test_expect_success 'chunk response' ' test-tool simple-ipc send --token=chunk >actual && test_line_count -ge 10000 actual && - grep -q "big: [0]*9999\$" actual + test_grep -q "big: [0]*9999\$" actual ' test_expect_success 'slow response' ' test-tool simple-ipc send --token=slow >actual && test_line_count -ge 100 actual && - grep -q "big: [0]*99\$" actual + test_grep -q "big: [0]*99\$" actual ' # Send an IPC with n=100,000 bytes of ballast. This should be large enough
@@ -54,7 +54,7 @@ test_expect_success 'slow response' ' # test_expect_success 'sendbytes' ' test-tool simple-ipc sendbytes --bytecount=100000 --byte=A >actual && - grep "sent:A00100000 rcvd:A00100000" actual + test_grep "sent:A00100000 rcvd:A00100000" actual ' # Start a series of <threads> client threads that each make <batchsize>
@@ -93,7 +93,7 @@ test_expect_success 'stress test threads' ' --batchsize=13 \ >actual && test_line_count = 92 actual && - grep "good 91" actual && + test_grep "good 91" actual && grep "sent:A" <actual >actual_a && cat >expect_a <<-EOF && sent:A00000019 rcvd:A00000019
t/t0061-run-command.sh +1 -1
@@ -97,7 +97,7 @@ test_expect_success POSIXPERM 'run_command reports EACCES' ' chmod -x hello.sh && test_must_fail test-tool run-command run-command ./hello.sh 2>err && - grep "fatal: cannot exec.*hello.sh" err + test_grep "fatal: cannot exec.*hello.sh" err ' test_expect_success POSIXPERM,SANITY 'unreadable directory in PATH' '
t/t0066-dir-iterator.sh +1 -1
@@ -127,7 +127,7 @@ test_expect_success SYMLINKS 'dir-iterator should not follow symlinks by default test_expect_success SYMLINKS 'dir-iterator does not resolve top-level symlinks' ' test_must_fail test-tool dir-iterator ./dir5 >out && - grep "ENOTDIR" out + test_grep "ENOTDIR" out ' test_done
t/t0068-for-each-repo.sh +8 -8
@@ -21,23 +21,23 @@ test_expect_success 'run based on configured value' ' git for-each-repo --config=run.key commit --allow-empty -m "ran" && git -C one log -1 --pretty=format:%s >message && - grep ran message && + test_grep ran message && git -C two log -1 --pretty=format:%s >message && - ! grep ran message && + test_grep ! ran message && git -C three log -1 --pretty=format:%s >message && - grep ran message && + test_grep ran message && git -C ~/four log -1 --pretty=format:%s >message && - grep ran message && + test_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 && + test_grep again message && git -C two log -1 --pretty=format:%s >message && - ! grep again message && + test_grep ! again message && git -C three log -1 --pretty=format:%s >message && - grep again message && + test_grep again message && git -C ~/four log -1 --pretty=format:%s >message && - grep again message && + test_grep again message && git -C three for-each-repo --config=run.key -- \ commit --allow-empty -m "ran from worktree" &&
t/t0070-fundamental.sh +3 -3
@@ -10,7 +10,7 @@ Verify wrappers and compatibility functions. test_expect_success 'mktemp to nonexistent directory prints filename' ' test_must_fail test-tool mktemp doesnotexist/testXXXXXX 2>err && - grep "doesnotexist/test" err + test_grep "doesnotexist/test" err ' test_expect_success POSIXPERM,SANITY 'mktemp to unwritable directory prints filename' '
@@ -18,7 +18,7 @@ test_expect_success POSIXPERM,SANITY 'mktemp to unwritable directory prints file test_when_finished "chmod +w cannotwrite" && chmod -w cannotwrite && test_must_fail test-tool mktemp cannotwrite/testXXXXXX 2>err && - grep "cannotwrite/test" err + test_grep "cannotwrite/test" err ' test_expect_success 'git_mkstemps_mode does not fail if fd 0 is not open' '
@@ -33,7 +33,7 @@ test_expect_success 'check for a bug in the regex routines' ' test_expect_success 'incomplete sideband messages are reassembled' ' test-tool pkt-line send-split-sideband >split-sideband && test-tool pkt-line receive-sideband <split-sideband 2>err && - grep "Hello, world" err + test_grep "Hello, world" err ' test_expect_success 'eof on sideband message is reported' '
t/t0081-find-pack.sh +6 -6
@@ -52,17 +52,17 @@ test_expect_success 'add more packfiles' ' # HEAD^{tree} is in 2 packfiles test-tool find-pack HEAD^{tree} >head_tree_packs && - grep "$head_commit_pack" head_tree_packs && - grep mypackname1 head_tree_packs && - ! grep mypackname2 head_tree_packs && + test_grep "$head_commit_pack" head_tree_packs && + test_grep mypackname1 head_tree_packs && + test_grep ! mypackname2 head_tree_packs && test-tool find-pack --check-count 2 HEAD^{tree} && ! test-tool find-pack --check-count 1 HEAD^{tree} && # HEAD:five.t is also in 2 packfiles test-tool find-pack HEAD:five.t >five_packs && - grep "$head_commit_pack" five_packs && - ! grep mypackname1 five_packs && - grep mypackname2 five_packs && + test_grep "$head_commit_pack" five_packs && + test_grep ! mypackname1 five_packs && + test_grep mypackname2 five_packs && test-tool find-pack -c 2 HEAD:five.t && ! test-tool find-pack --check-count=0 HEAD:five.t '
t/t0091-bugreport.sh +9 -9
@@ -40,15 +40,15 @@ test_expect_success 'sanity check "System Info" section' ' # The beginning should match "git version --build-options" verbatim, # but rather than checking bit-for-bit equality, just test some basics. - grep "git version " system && - grep "shell-path: ." system && + test_grep "git version " system && + test_grep "shell-path: ." system && # After the version, there should be some more info. # This is bound to differ from environment to environment, # so we just do some rather high-level checks. - grep "uname: ." system && - grep "compiler info: ." system && - grep "zlib." system + test_grep "uname: ." system && + test_grep "compiler info: ." system && + test_grep "zlib." system ' test_expect_success 'dies if file with same name as report already exists' '
@@ -112,7 +112,7 @@ test_expect_success UNZIP '--diagnose creates diagnostics zip archive' ' git bugreport --diagnose -o report -s test >out && zip_path=report/git-diagnostics-test.zip && - grep "Available space" out && + test_grep "Available space" out && test_path_is_file "$zip_path" && # Check zipped archive content
@@ -120,10 +120,10 @@ test_expect_success UNZIP '--diagnose creates diagnostics zip archive' ' test_file_not_empty out && "$GIT_UNZIP" -p "$zip_path" packs-local.txt >out && - grep ".git/objects" out && + test_grep ".git/objects" out && "$GIT_UNZIP" -p "$zip_path" objects-local.txt >out && - grep "^Total: [0-9][0-9]*" out && + test_grep "^Total: [0-9][0-9]*" out && # Should not include .git directory contents by default ! "$GIT_UNZIP" -l "$zip_path" | grep ".git/"
@@ -136,7 +136,7 @@ test_expect_success UNZIP '--diagnose=stats excludes .git dir contents' ' # Includes pack quantity/size info "$GIT_UNZIP" -p "$zip_path" packs-local.txt >out && - grep ".git/objects" out && + test_grep ".git/objects" out && # Does not include .git directory contents ! "$GIT_UNZIP" -l "$zip_path" | grep ".git/"
t/t0092-diagnose.sh +6 -6
@@ -8,7 +8,7 @@ test_expect_success UNZIP 'creates diagnostics zip archive' ' test_when_finished rm -rf report && git diagnose -o report -s test >out && - grep "Available space" out && + test_grep "Available space" out && zip_path=report/git-diagnostics-test.zip && test_path_is_file "$zip_path" &&
@@ -18,10 +18,10 @@ test_expect_success UNZIP 'creates diagnostics zip archive' ' test_file_not_empty out && "$GIT_UNZIP" -p "$zip_path" packs-local.txt >out && - grep ".git/objects" out && + test_grep ".git/objects" out && "$GIT_UNZIP" -p "$zip_path" objects-local.txt >out && - grep "^Total: [0-9][0-9]*" out && + test_grep "^Total: [0-9][0-9]*" out && # Should not include .git directory contents by default ! "$GIT_UNZIP" -l "$zip_path" | grep ".git/"
@@ -34,7 +34,7 @@ test_expect_success UNZIP 'counts loose objects' ' git diagnose -o test-count -s 1 >out && zip_path=test-count/git-diagnostics-1.zip && "$GIT_UNZIP" -p "$zip_path" objects-local.txt >out && - grep "^Total: [1-9][0-9]* loose objects" out + test_grep "^Total: [1-9][0-9]* loose objects" out ' test_expect_success UNZIP '--mode=stats excludes .git dir contents' '
@@ -45,7 +45,7 @@ test_expect_success UNZIP '--mode=stats excludes .git dir contents' ' # Includes pack quantity/size info zip_path=report/git-diagnostics-test.zip && "$GIT_UNZIP" -p "$zip_path" packs-local.txt >out && - grep ".git/objects" out && + test_grep ".git/objects" out && # Does not include .git directory contents ! "$GIT_UNZIP" -l "$zip_path" | grep ".git/"
@@ -59,7 +59,7 @@ test_expect_success UNZIP '--mode=all includes .git dir contents' ' # Includes pack quantity/size info zip_path=report/git-diagnostics-test.zip && "$GIT_UNZIP" -p "$zip_path" packs-local.txt >out && - grep ".git/objects" out && + test_grep ".git/objects" out && # Includes .git directory contents "$GIT_UNZIP" -l "$zip_path" | grep ".git/" &&
t/t0100-previous.sh +1 -1
@@ -50,7 +50,7 @@ test_expect_success 'merge @{-1}~1' ' git checkout main && git merge @{-1}~1 && git cat-file commit HEAD >actual && - grep "Merge branch '\''other'\''" actual + test_grep "Merge branch '\''other'\''" actual ' test_expect_success 'merge @{-100} before checking out that many branches yet' '
t/t0200-gettext-basic.sh +7 -7
@@ -16,7 +16,7 @@ test_expect_success 'sanity: $TEXTDOMAIN is git' ' ' test_expect_success 'xgettext sanity: Perl _() strings are not extracted' ' - ! grep "A Perl string xgettext will not get" "$GIT_PO_PATH"/is.po + test_grep ! "A Perl string xgettext will not get" "$GIT_PO_PATH"/is.po ' test_expect_success 'xgettext sanity: Comment extraction with --add-comments' '
@@ -26,8 +26,8 @@ test_expect_success 'xgettext sanity: Comment extraction with --add-comments' ' ' test_expect_success 'xgettext sanity: Comment extraction with --add-comments stops at statements' ' - ! grep "This is a phony" "$GIT_PO_PATH"/is.po && - ! grep "the above comment" "$GIT_PO_PATH"/is.po + test_grep ! "This is a phony" "$GIT_PO_PATH"/is.po && + test_grep ! "the above comment" "$GIT_PO_PATH"/is.po ' test_expect_success GETTEXT 'sanity: $TEXTDOMAINDIR exists without NO_GETTEXT=YesPlease' '
@@ -44,10 +44,10 @@ test_expect_success GETTEXT 'sanity: Icelandic locale was compiled' ' test_expect_success GETTEXT_LOCALE 'sanity: gettext("") metadata is OK' ' # Return value may be non-zero LANGUAGE=is LC_ALL="$is_IS_locale" gettext "" >zero-expect && - grep "Project-Id-Version: Git" zero-expect && - grep "Git Mailing List <[email protected]>" zero-expect && - grep "Content-Type: text/plain; charset=UTF-8" zero-expect && - grep "Content-Transfer-Encoding: 8bit" zero-expect + test_grep "Project-Id-Version: Git" zero-expect && + test_grep "Git Mailing List <[email protected]>" zero-expect && + test_grep "Content-Type: text/plain; charset=UTF-8" zero-expect && + test_grep "Content-Transfer-Encoding: 8bit" zero-expect ' test_expect_success GETTEXT_LOCALE 'sanity: gettext(unknown) is passed through' '
t/t0203-gettext-setlocale-sanity.sh +2 -2
@@ -12,7 +12,7 @@ test_expect_success 'git show a ISO-8859-1 commit under C locale' ' test_commit "iso-c-commit" iso-under-c && git show >out 2>err && test_must_be_empty err && - grep -q "iso-c-commit" out + test_grep -q "iso-c-commit" out ' test_expect_success GETTEXT_LOCALE 'git show a ISO-8859-1 commit under a UTF-8 locale' '
@@ -20,7 +20,7 @@ test_expect_success GETTEXT_LOCALE 'git show a ISO-8859-1 commit under a UTF-8 l test_commit "iso-utf8-commit" iso-under-utf8 && LANGUAGE=is LC_ALL="$is_IS_locale" git show >out 2>err && test_must_be_empty err && - grep -q "iso-utf8-commit" out + test_grep -q "iso-utf8-commit" out ' test_done
t/t0204-gettext-reencode-sanity.sh +4 -4
@@ -66,22 +66,22 @@ test_expect_success GETTEXT_LOCALE 'gettext: Fetching a UTF-8 msgid -> UTF-8' ' # eyes. test_expect_success GETTEXT_ISO_LOCALE 'gettext: Fetching a UTF-8 msgid -> ISO-8859-1' ' LANGUAGE=is LC_ALL="$is_IS_iso_locale" gettext "TEST: ‘single’ and “double” quotes" >actual && - grep "einfaldar" actual && - grep "$(echo tvöfaldar | iconv -f UTF-8 -t ISO8859-1)" actual + test_grep "einfaldar" actual && + test_grep "$(echo tvöfaldar | iconv -f UTF-8 -t ISO8859-1)" actual ' test_expect_success GETTEXT_LOCALE 'gettext.c: git init UTF-8 -> UTF-8' ' printf "Bjó til tóma Git lind" >expect && LANGUAGE=is LC_ALL="$is_IS_locale" git init repo >actual && test_when_finished "rm -rf repo" && - grep "^$(cat expect) " actual + test_grep "^$(cat expect) " actual ' test_expect_success GETTEXT_ISO_LOCALE 'gettext.c: git init UTF-8 -> ISO-8859-1' ' printf "Bjó til tóma Git lind" >expect && LANGUAGE=is LC_ALL="$is_IS_iso_locale" git init repo >actual && test_when_finished "rm -rf repo" && - grep "^$(iconv -f UTF-8 -t ISO8859-1 <expect) " actual + test_grep "^$(iconv -f UTF-8 -t ISO8859-1 <expect) " actual ' test_done
t/t0210-trace2-normal.sh +3 -3
@@ -333,12 +333,12 @@ test_expect_success 'unsafe URLs are redacted by default' ' GIT_TRACE2="$(pwd)/trace.normal" \ git clone https://user:[email protected]/ clone && - ! grep user:pwd trace.normal && + test_grep ! user:pwd trace.normal && GIT_TRACE2_REDACT=0 GIT_TRACE2="$(pwd)/unredacted.normal" \ git clone https://user:[email protected]/ clone2 && - grep "start .* clone https://user:[email protected]" unredacted.normal && - grep "remote.origin.url=https://user:[email protected]" unredacted.normal + test_grep "start .* clone https://user:[email protected]" unredacted.normal && + test_grep "remote.origin.url=https://user:[email protected]" unredacted.normal ' test_done
t/t0211-trace2-perf.sh +40 -40
159 lines not on this page · raw message
t/t0212-trace2-event.sh +4 -4
@@ -332,7 +332,7 @@ test_expect_success 'unsafe URLs are redacted by default in cmd_start events' ' GIT_TRACE2_EVENT="$(pwd)/trace.event" \ test-tool trace2 300redact_start git clone https://user:[email protected]/ clone2 && - ! grep user:pwd trace.event + test_grep ! user:pwd trace.event ' test_expect_success 'unsafe URLs are redacted by default in child_start events' '
@@ -341,7 +341,7 @@ test_expect_success 'unsafe URLs are redacted by default in child_start events' GIT_TRACE2_EVENT="$(pwd)/trace.event" \ test-tool trace2 301redact_child_start git clone https://user:[email protected]/ clone2 && - ! grep user:pwd trace.event + test_grep ! user:pwd trace.event ' test_expect_success 'unsafe URLs are redacted by default in exec events' '
@@ -350,7 +350,7 @@ test_expect_success 'unsafe URLs are redacted by default in exec events' ' GIT_TRACE2_EVENT="$(pwd)/trace.event" \ test-tool trace2 302redact_exec git clone https://user:[email protected]/ clone2 && - ! grep user:pwd trace.event + test_grep ! user:pwd trace.event ' test_expect_success 'unsafe URLs are redacted by default in def_param events' '
@@ -359,7 +359,7 @@ test_expect_success 'unsafe URLs are redacted by default in def_param events' ' GIT_TRACE2_EVENT="$(pwd)/trace.event" \ test-tool trace2 303redact_def_param url https://user:[email protected]/ && - ! grep user:pwd trace.event + test_grep ! user:pwd trace.event ' test_done
t/t0300-credentials.sh +2 -2
@@ -1014,7 +1014,7 @@ test_expect_success 'credential config with partial URLs' ' do git -c credential.$partial.helper=yep \ credential fill <stdin >stdout && - grep yep stdout || + test_grep yep stdout || return 1 done &&
@@ -1030,7 +1030,7 @@ test_expect_success 'credential config with partial URLs' ' do git -c credential.$partial.helper=yep \ credential fill <stdin >stdout && - ! grep yep stdout || + test_grep ! yep stdout || return 1 done &&
t/t0410-partial-clone.sh +41 -41
223 lines not on this page · raw message
t/t0450-txt-doc-vs-help.sh +1 -1
@@ -87,7 +87,7 @@ do # -h output assertions test_expect_success "$builtin -h output has no \t" ' h2s="$(help_to_synopsis "$builtin")" && - ! grep "$HT" "$h2s" + test_grep ! "$HT" "$h2s" ' test_expect_success "$builtin -h output has dashed labels" '
t/t0500-progress-display.sh +9 -9
@@ -320,8 +320,8 @@ test_expect_success 'progress generates traces' ' # t0212/parse_events.perl intentionally omits regions and data. test_region progress "Working hard" trace.event && - grep "\"key\":\"total_objects\",\"value\":\"40\"" trace.event && - grep "\"key\":\"total_bytes\",\"value\":\"409600\"" trace.event + test_grep "\"key\":\"total_objects\",\"value\":\"40\"" trace.event && + test_grep "\"key\":\"total_bytes\",\"value\":\"409600\"" trace.event ' test_expect_success 'progress generates traces: stop / start' '
@@ -344,8 +344,8 @@ test_expect_success 'progress generates traces: start without stop' ' LSAN_OPTIONS=detect_leaks=0 \ test-tool progress \ <in 2>stderr && - grep region_enter.*progress trace-start.event && - ! grep region_leave.*progress trace-start.event + test_grep region_enter.*progress trace-start.event && + test_grep ! region_leave.*progress trace-start.event ' test_expect_success 'progress generates traces: stop without start' '
@@ -355,8 +355,8 @@ test_expect_success 'progress generates traces: stop without start' ' GIT_TRACE2_EVENT="$PWD/trace-stop.event" test-tool progress \ <in 2>stderr && - ! grep region_enter.*progress trace-stop.event && - ! grep region_leave.*progress trace-stop.event + test_grep ! region_enter.*progress trace-stop.event && + test_grep ! region_leave.*progress trace-stop.event ' test_expect_success 'progress generates traces: start with active progress bar (no stops)' '
@@ -369,9 +369,9 @@ test_expect_success 'progress generates traces: start with active progress bar ( LSAN_OPTIONS=detect_leaks=0 \ test-tool progress \ <in 2>stderr && - grep region_enter.*progress.*One trace-2start.event && - grep region_enter.*progress.*Two trace-2start.event && - ! grep region_leave trace-2start.event + test_grep region_enter.*progress.*One trace-2start.event && + test_grep region_enter.*progress.*Two trace-2start.event && + test_grep ! region_leave trace-2start.event ' test_done
t/t0610-reftable-basics.sh +4 -4
@@ -776,11 +776,11 @@ test_expect_success 'reflog: can delete separate reflog entries' ' test_commit file3 && test_commit file4 && git reflog >actual && - grep file3 actual && + test_grep file3 actual && git reflog delete HEAD@{1} && git reflog >actual && - ! grep file3 actual + test_grep ! file3 actual ) '
@@ -902,8 +902,8 @@ test_expect_success 'reflog: garbage collection deletes reflog entries' ' done && git reflog refs/heads/main >actual && test_line_count = 10 actual && - grep "commit (initial): number 1" actual && - grep "commit: number 10" actual && + test_grep "commit (initial): number 1" actual && + test_grep "commit: number 10" actual && git gc && git reflog refs/heads/main >actual &&
t/t1004-read-tree-m-u-wf.sh +4 -4
@@ -142,8 +142,8 @@ test_expect_success '3-way not overwriting local changes (our side)' ' echo >>file1 "local changes" && read_tree_u_must_succeed -m -u branch-point side-a side-b && - grep "new line to be kept" file1 && - grep "local changes" file1 + test_grep "new line to be kept" file1 && + test_grep "local changes" file1 '
@@ -156,8 +156,8 @@ test_expect_success '3-way not overwriting local changes (their side)' ' echo >>file2 "local changes" && read_tree_u_must_fail -m -u branch-point side-a side-b && - ! grep "new line to be kept" file2 && - grep "local changes" file2 + test_grep ! "new line to be kept" file2 && + test_grep "local changes" file2 '
t/t1006-cat-file.sh +9 -9
@@ -696,8 +696,8 @@ test_expect_success '%(deltabase) reports packed delta bases' ' git repack -ad && git cat-file --batch-check="%(deltabase)" <blobs >actual && { - grep "$(git rev-parse HEAD:foo)" actual || - grep "$(git rev-parse HEAD:foo-plus)" actual + test_grep "$(git rev-parse HEAD:foo)" actual || + test_grep "$(git rev-parse HEAD:foo-plus)" actual } '
@@ -826,7 +826,7 @@ test_expect_success 'cat-file -t and -s on corrupt loose object' ' # Swap the two to corrupt the repository mv -f "$other_path" "$empty_path" && test_must_fail git fsck 2>err.fsck && - grep "hash-path mismatch" err.fsck && + test_grep "hash-path mismatch" err.fsck && # confirm that cat-file is reading the new swapped-in # blob...
@@ -1318,37 +1318,37 @@ test_expect_success 'cat-file --batch-all-objects --batch-check ignores replace' test_expect_success 'batch-command empty command' ' echo "" >cmd && test_expect_code 128 git cat-file --batch-command <cmd 2>err && - grep "^fatal:.*empty command in input.*" err + test_grep "^fatal:.*empty command in input.*" err ' test_expect_success 'batch-command whitespace before command' ' echo " info deadbeef" >cmd && test_expect_code 128 git cat-file --batch-command <cmd 2>err && - grep "^fatal:.*whitespace before command.*" err + test_grep "^fatal:.*whitespace before command.*" err ' test_expect_success 'batch-command unknown command' ' echo unknown_command >cmd && test_expect_code 128 git cat-file --batch-command <cmd 2>err && - grep "^fatal:.*unknown command.*" err + test_grep "^fatal:.*unknown command.*" err ' test_expect_success 'batch-command missing arguments' ' echo "info" >cmd && test_expect_code 128 git cat-file --batch-command <cmd 2>err && - grep "^fatal:.*info requires arguments.*" err + test_grep "^fatal:.*info requires arguments.*" err ' test_expect_success 'batch-command flush with arguments' ' echo "flush arg" >cmd && test_expect_code 128 git cat-file --batch-command --buffer <cmd 2>err && - grep "^fatal:.*flush takes no arguments.*" err + test_grep "^fatal:.*flush takes no arguments.*" err ' test_expect_success 'batch-command flush without --buffer' ' echo "flush" >cmd && test_expect_code 128 git cat-file --batch-command <cmd 2>err && - grep "^fatal:.*flush is only for --buffer mode.*" err + test_grep "^fatal:.*flush is only for --buffer mode.*" err ' perl_script='
t/t1007-hash-object.sh +4 -4
@@ -202,7 +202,7 @@ done test_expect_success 'too-short tree' ' echo abc >malformed-tree && test_must_fail git hash-object -t tree malformed-tree 2>err && - grep "too-short tree object" err + test_grep "too-short tree object" err ' test_expect_success PERL_TEST_HELPERS 'malformed mode in tree' '
@@ -210,7 +210,7 @@ test_expect_success PERL_TEST_HELPERS 'malformed mode in tree' ' 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 && - grep "malformed mode in tree entry" err + test_grep "malformed mode in tree entry" err ' test_expect_success PERL_TEST_HELPERS 'empty filename in tree' '
@@ -218,7 +218,7 @@ test_expect_success PERL_TEST_HELPERS 'empty filename in tree' ' 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 && - grep "empty filename in tree entry" err + test_grep "empty filename in tree entry" err ' test_expect_success PERL_TEST_HELPERS 'duplicate filename in tree' '
@@ -229,7 +229,7 @@ test_expect_success PERL_TEST_HELPERS 'duplicate filename in tree' ' 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_grep "duplicateEntries" err ' test_expect_success 'corrupt commit' '
t/t1011-read-tree-sparse-checkout.sh +5 -5
@@ -196,7 +196,7 @@ test_expect_success 'read-tree will not throw away dirty changes, non-sparse' ' echo dirty >init.t && read_tree_u_must_fail -m -u HEAD^ && test_path_is_file init.t && - grep -q dirty init.t + test_grep -q dirty init.t ' test_expect_success 'read-tree will not throw away dirty changes, sparse' '
@@ -207,7 +207,7 @@ test_expect_success 'read-tree will not throw away dirty changes, sparse' ' echo sub/added >.git/info/sparse-checkout && read_tree_u_must_fail -m -u HEAD^ && test_path_is_file init.t && - grep -q dirty init.t + test_grep -q dirty init.t ' test_expect_success 'read-tree updates worktree, dirty case' '
@@ -215,7 +215,7 @@ test_expect_success 'read-tree updates worktree, dirty case' ' git checkout -f top && echo dirty >init.t && read_tree_u_must_fail -m -u HEAD^ && - grep -q dirty init.t && + test_grep -q dirty init.t && rm init.t '
@@ -224,7 +224,7 @@ test_expect_success 'read-tree removes worktree, dirty case' ' git checkout -f top && echo dirty >added && read_tree_u_must_succeed -m -u HEAD^ && - grep -q dirty added + test_grep -q dirty added ' test_expect_success 'read-tree adds to worktree, absent case' '
@@ -240,7 +240,7 @@ test_expect_success 'read-tree adds to worktree, dirty case' ' mkdir sub && echo dirty >sub/added && read_tree_u_must_succeed -u -m HEAD^ && - grep -q dirty sub/added + test_grep -q dirty sub/added ' test_expect_success 'index removal and worktree narrowing at the same time' '
t/t1050-large.sh +3 -3
@@ -8,7 +8,7 @@ test_description='adding and checking out large blobs' test_expect_success 'core.bigFileThreshold must be non-negative' ' : >input && test_must_fail git -c core.bigFileThreshold=-1 hash-object input >out 2>err && - grep "bad numeric config value" err && + test_grep "bad numeric config value" err && test_must_be_empty out '
@@ -148,12 +148,12 @@ test_expect_success 'diff --stat' ' test_expect_success 'diff' ' git diff HEAD^ HEAD >actual && - grep "Binary files.*differ" actual + test_grep "Binary files.*differ" actual ' test_expect_success 'diff --cached' ' git diff --cached HEAD^ >actual && - grep "Binary files.*differ" actual + test_grep "Binary files.*differ" actual ' test_expect_success 'hash-object' '
t/t1091-sparse-checkout-builtin.sh +12 -12
@@ -129,7 +129,7 @@ test_expect_success 'switching to cone mode with non-cone mode patterns' ' git sparse-checkout add dir && git config --worktree core.sparseCheckoutCone true && test_must_fail git sparse-checkout add dir 2>err && - grep "existing sparse-checkout patterns do not use cone mode" err + test_grep "existing sparse-checkout patterns do not use cone mode" err ) '
@@ -803,7 +803,7 @@ test_expect_success 'cone mode clears ignored subdirectories' ' # When an untracked file is in the way, all untracked files # (even ignored files) are preserved. git -C repo sparse-checkout set folder1 2>err && - grep "contains untracked files" err && + test_grep "contains untracked files" err && test_path_is_file repo/deep/deeper2/ignored.o && test_path_is_file repo/deep/deeper2/untracked &&
@@ -882,8 +882,8 @@ test_expect_success 'malformed cone-mode patterns' ' # of using the cone-mode translation to a set of directories. git -C repo sparse-checkout list >actual 2>err && test_cmp repo/.git/info/sparse-checkout actual && - grep "warning: your sparse-checkout file may have issues: pattern .* is repeated" err && - grep "warning: disabling cone pattern matching" err + test_grep "warning: your sparse-checkout file may have issues: pattern .* is repeated" err && + test_grep "warning: disabling cone pattern matching" err ' test_expect_success 'set from subdir pays attention to prefix' '
@@ -917,34 +917,34 @@ test_expect_success 'set from subdir in non-cone mode throws an error' ' git -C repo sparse-checkout disable && test_must_fail git -C repo/deep sparse-checkout set --no-cone deeper2 ../folder1 2>error && - grep "run from the toplevel directory in non-cone mode" error + test_grep "run from the toplevel directory in non-cone mode" error ' test_expect_success 'set from subdir in non-cone mode throws an error' ' git -C repo sparse-checkout set --no-cone deep/deeper2 && test_must_fail git -C repo/deep sparse-checkout add deeper1/deepest ../folder1 2>error && - grep "run from the toplevel directory in non-cone mode" error + test_grep "run from the toplevel directory in non-cone mode" error ' test_expect_success 'by default, cone mode will error out when passed files' ' git -C repo sparse-checkout reapply --cone && test_must_fail git -C repo sparse-checkout add .gitignore 2>error && - grep ".gitignore.*is not a directory" error + test_grep ".gitignore.*is not a directory" error ' test_expect_success 'error on mistyped command line options' ' test_must_fail git -C repo sparse-checkout add --sikp-checks .gitignore 2>error && - grep "unknown option.*sikp-checks" error + test_grep "unknown option.*sikp-checks" error ' test_expect_success 'by default, non-cone mode will warn on individual files' ' git -C repo sparse-checkout reapply --no-cone && git -C repo sparse-checkout add .gitignore 2>warning && - grep "pass a leading slash before paths.*if you want a single file" warning + test_grep "pass a leading slash before paths.*if you want a single file" warning ' test_expect_success 'setup bare repo' '
@@ -1108,11 +1108,11 @@ test_expect_success 'clean' ' touch repo/folder1/extra/inside/file && test_must_fail git -C repo sparse-checkout clean 2>err && - grep "refusing to clean" err && + test_grep "refusing to clean" err && git -C repo config clean.requireForce true && test_must_fail git -C repo sparse-checkout clean 2>err && - grep "refusing to clean" err && + test_grep "refusing to clean" err && cat >expect <<-\EOF && Would remove deep/deeper2/
@@ -1255,7 +1255,7 @@ test_expect_success 'sparse-checkout operations with merge conflicts' ' test_must_fail git merge -m "will-conflict" right && test_must_fail git sparse-checkout clean -f 2>err && - grep "failed to convert index to a sparse index" err && + test_grep "failed to convert index to a sparse index" err && echo merged >folder1/even/more/dirs/file && git add --sparse folder1 &&
t/t1092-sparse-checkout-compatibility.sh +22 -22
135 lines not on this page · raw message
t/t1300-config.sh +8 -8
@@ -856,7 +856,7 @@ test_expect_success 'renaming a section with an overly-long line' ' printf "[a] g = h\\n" } >y && test_must_fail git config ${mode_prefix}rename-section -f y a xyz 2>err && - grep "refusing to work with overly long line in .y. on line 2" err + test_grep "refusing to work with overly long line in .y. on line 2" err ' cat >> .git/config << EOF
@@ -1671,9 +1671,9 @@ test_expect_success 'git --config-env=key=envvar support' ' test_expect_success 'git --config-env with missing value' ' test_must_fail env ENVVAR=value git --config-env 2>error && - grep "no config key given for --config-env" error && + test_grep "no config key given for --config-env" error && test_must_fail env ENVVAR=value git --config-env config core.name 2>error && - grep "invalid config format: config" error + test_grep "invalid config format: config" error ' test_expect_success 'git --config-env fails with invalid parameters' '
@@ -2104,7 +2104,7 @@ test_expect_success '--unset last key removes section (except if commented)' ' key = true EOF git config ${mode_unset} two.key && - ! grep two .git/config && + test_grep ! two .git/config && q_to_tab >.git/config <<-\EOF && [one]
@@ -2124,7 +2124,7 @@ test_expect_success '--unset last key removes section (except if commented)' ' Qkey = true EOF git config ${mode_unset} two.key && - grep two .git/config && + test_grep two .git/config && q_to_tab >.git/config <<-\EOF && [one]
@@ -2655,7 +2655,7 @@ test_expect_success '--type rejects unknown specifiers' ' 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_grep "bad numeric config value" error && test_must_be_empty out '
@@ -2967,12 +2967,12 @@ test_expect_success 'includeIf.hasconfig:remote.*.url forbids remote url in such # test with any Git command test_must_fail git -C hasremoteurlTest status 2>err && - grep "fatal: remote URLs cannot be configured in file directly or indirectly included by includeIf.hasconfig:remote.*.url" err + test_grep "fatal: remote URLs cannot be configured in file directly or indirectly included by includeIf.hasconfig:remote.*.url" err ' test_expect_success 'negated mode causes failure' ' test_must_fail git config --no-get 2>err && - grep "unknown option \`no-get${SQ}" err + test_grep "unknown option \`no-get${SQ}" err ' test_expect_success 'specifying multiple modes causes failure' '
t/t1305-config-include.sh +1 -1
@@ -353,7 +353,7 @@ test_expect_success 'include cycles are detected' ' git -C cycle --git-dir=. config include.path cycle && git config -f cycle/cycle include.path config && test_must_fail git -C cycle --git-dir=. config --get-all test.value 2>stderr && - grep "exceeded maximum include depth" stderr + test_grep "exceeded maximum include depth" stderr ' test_expect_success 'onbranch with unborn branch' '
t/t1308-config-set.sh +3 -3
@@ -180,7 +180,7 @@ test_expect_success 'find integer if value is non parse-able' ' test_expect_success 'non parse-able integer value during iteration' ' check_config expect_code 128 git_config_int lamb.head 2>result && - grep "fatal: bad numeric config value .* in file \.git/config" result + test_grep "fatal: bad numeric config value .* in file \.git/config" result ' test_expect_success 'find bool value for the entered key' '
@@ -302,7 +302,7 @@ test_expect_success 'proper error on directory "files"' ' echo "Error (-1) reading configuration file a-directory." >expect && mkdir a-directory && test_expect_code 2 test-tool config configset_get_value foo.bar a-directory 2>output && - grep "^warning:" output && + test_grep "^warning:" output && grep "^Error" output >actual && test_cmp expect actual '
@@ -312,7 +312,7 @@ test_expect_success POSIXPERM,SANITY 'proper error on non-accessible files' ' test_when_finished "chmod +r .git/config" && echo "Error (-1) reading configuration file .git/config." >expect && test_expect_code 2 test-tool config configset_get_value foo.bar .git/config 2>output && - grep "^warning:" output && + test_grep "^warning:" output && grep "^Error" output >actual && test_cmp expect actual '
t/t1400-update-ref.sh +88 -85
628 lines not on this page · raw message
t/t1403-show-ref.sh +9 -9
@@ -213,19 +213,19 @@ test_expect_success 'show-ref --verify with dangling ref' ' test_expect_success 'show-ref sub-modes are mutually exclusive' ' test_must_fail git show-ref --verify --exclude-existing 2>err && - grep "verify" err && - grep "exclude-existing" err && - grep "cannot be used together" err && + test_grep "verify" err && + test_grep "exclude-existing" err && + test_grep "cannot be used together" err && test_must_fail git show-ref --verify --exists 2>err && - grep "verify" err && - grep "exists" err && - grep "cannot be used together" err && + test_grep "verify" err && + test_grep "exists" err && + test_grep "cannot be used together" err && test_must_fail git show-ref --exclude-existing --exists 2>err && - grep "exclude-existing" err && - grep "exists" err && - grep "cannot be used together" err + test_grep "exclude-existing" err && + test_grep "exists" err && + test_grep "cannot be used together" err ' test_done
t/t1410-reflog.sh +2 -2
@@ -108,12 +108,12 @@ test_expect_success setup ' test_expect_success 'correct usage on sub-command -h' ' test_expect_code 129 git reflog expire -h >err && - grep "git reflog expire" err + test_grep "git reflog expire" err ' test_expect_success 'correct usage on "git reflog show -h"' ' test_expect_code 129 git reflog show -h >err && - grep -F "git reflog [show]" err + test_grep -F "git reflog [show]" err ' test_expect_success 'pass through -- to sub-command' '
t/t1415-worktree-refs.sh +2 -2
@@ -32,7 +32,7 @@ test_expect_success 'ambiguous main-worktree/HEAD' ' test_when_finished git update-ref -d refs/heads/main-worktree/HEAD && git update-ref refs/heads/main-worktree/HEAD $(git rev-parse HEAD) && git rev-parse main-worktree/HEAD 2>warn && - grep "main-worktree/HEAD.*ambiguous" warn + test_grep "main-worktree/HEAD.*ambiguous" warn ' test_expect_success 'resolve worktrees/xx/HEAD' '
@@ -45,7 +45,7 @@ test_expect_success 'ambiguous worktrees/xx/HEAD' ' git update-ref refs/heads/worktrees/wt1/HEAD $(git rev-parse HEAD) && test_when_finished git update-ref -d refs/heads/worktrees/wt1/HEAD && git rev-parse worktrees/wt1/HEAD 2>warn && - grep "worktrees/wt1/HEAD.*ambiguous" warn + test_grep "worktrees/wt1/HEAD.*ambiguous" warn ' test_expect_success 'reflog of main-worktree/HEAD' '
t/t1430-bad-ref-name.sh +28 -28
153 lines not on this page · raw message
t/t1450-fsck.sh +6 -6
@@ -68,7 +68,7 @@ test_expect_success 'object with hash mismatch' ' git update-ref refs/heads/bogus $cmt && test_must_fail git fsck 2>out && - grep "$oldoid: hash-path mismatch, found at: .*$new" out + test_grep "$oldoid: hash-path mismatch, found at: .*$new" out ) '
@@ -172,7 +172,7 @@ test_expect_success 'commit with multiple signatures is okay' ' test_when_finished "git update-ref -d refs/heads/bogus" && git fsck 2>out && cat out && - ! grep "commit $new" out + test_grep ! "commit $new" out ' test_expect_success 'email without @ is okay' '
@@ -183,7 +183,7 @@ test_expect_success 'email without @ is okay' ' git update-ref refs/heads/bogus "$new" && test_when_finished "git update-ref -d refs/heads/bogus" && git fsck 2>out && - ! grep "commit $new" out + test_grep ! "commit $new" out ' test_expect_success 'email with embedded > is not okay' '
@@ -626,7 +626,7 @@ test_expect_success 'fsck notices excessively large tree entry name' ' cd large-name && test_commit a-long-name && git -c fsck.largePathname=warn:10 fsck 2>out && - grep "warning.*large pathname" out + test_grep "warning.*large pathname" out ) '
@@ -849,7 +849,7 @@ test_expect_success 'fsck errors in packed objects' ' test_must_fail git fsck 2>out && test_grep "error in commit $one.* - bad name" out && test_grep "error in commit $two.* - bad name" out && - ! grep corrupt out + test_grep ! corrupt out ' test_expect_success 'fsck handles multiple packfiles with big blobs' '
@@ -1027,7 +1027,7 @@ test_expect_success 'bogus head does not fallback to all heads' ' test_when_finished "git rm --cached foo" && remove_object $blob && test_must_fail git fsck $ZERO_OID >out 2>&1 && - ! grep $blob out + test_grep ! $blob out ' # Corrupt the checksum on the index.
t/t1451-fsck-buffer.sh +3 -3
@@ -46,7 +46,7 @@ check () { echo "$content" } >input && test_must_fail git hash-object -t "$type" input 2>err && - grep "$fsck" err + test_grep "$fsck" err ' }
@@ -125,7 +125,7 @@ ident_checks tag tagger 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_grep badTree err ' test_expect_success 'truncated tree (missing nul)' '
@@ -135,7 +135,7 @@ test_expect_success 'truncated tree (missing nul)' ' # 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_grep badTree err ' test_done
t/t1460-refs-migrate.sh +1 -1
@@ -212,7 +212,7 @@ do test_commit -C repo initial && git -C repo refs migrate --dry-run \ --ref-format=$to_format >output && - grep "Finished dry-run migration of refs" output && + test_grep "Finished dry-run migration of refs" output && test_path_is_dir repo/.git/ref_migration.* && echo $from_format >expect && git -C repo rev-parse --show-ref-format >actual &&
t/t1500-rev-parse.sh +3 -3
@@ -204,7 +204,7 @@ test_expect_success 'rev-parse --show-object-format in repo' ' git rev-parse --show-object-format=output >actual && test_cmp expect actual && test_must_fail git rev-parse --show-object-format=squeamish-ossifrage 2>err && - grep "unknown mode for --show-object-format: squeamish-ossifrage" err + test_grep "unknown mode for --show-object-format: squeamish-ossifrage" err '
@@ -228,7 +228,7 @@ test_expect_success RUST 'rev-parse --show-object-format in repo with compat mod git rev-parse --show-object-format=compat >actual && test_cmp expect actual && test_must_fail git rev-parse --show-object-format=squeamish-ossifrage 2>err && - grep "unknown mode for --show-object-format: squeamish-ossifrage" err + test_grep "unknown mode for --show-object-format: squeamish-ossifrage" err ) && mkdir repo2 && (
@@ -254,7 +254,7 @@ test_expect_success 'rev-parse --show-ref-format with invalid storage' ' cd repo && git config extensions.refstorage broken && test_must_fail git rev-parse --show-ref-format 2>err && - grep "error: invalid value for ${SQ}extensions.refstorage${SQ}: ${SQ}broken${SQ}" err + test_grep "error: invalid value for ${SQ}extensions.refstorage${SQ}: ${SQ}broken${SQ}" err ) '
t/t1502-rev-parse-parseopt.sh +1 -1
@@ -331,7 +331,7 @@ test_expect_success 'ambiguous: --no matches both --noble and --no-noble' ' EOF test_expect_code 129 env GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=false \ git rev-parse --parseopt -- <spec 2>err --no && - grep "error: ambiguous option: no (could be --noble or --no-noble)" err + test_grep "error: ambiguous option: no (could be --noble or --no-noble)" err ' test_done
t/t1503-rev-parse-verify.sh +5 -5
@@ -62,15 +62,15 @@ test_expect_success 'works with one good rev' ' test_expect_success 'fails with any bad rev or many good revs' ' test_must_fail git rev-parse --verify 2>error && - grep "single revision" error && + test_grep "single revision" error && test_must_fail git rev-parse --verify foo 2>error && - grep "single revision" error && + test_grep "single revision" error && test_must_fail git rev-parse --verify HEAD bar 2>error && - grep "single revision" error && + test_grep "single revision" error && test_must_fail git rev-parse --verify baz HEAD 2>error && - grep "single revision" error && + test_grep "single revision" error && test_must_fail git rev-parse --verify $HASH2 HEAD 2>error && - grep "single revision" error + test_grep "single revision" error ' test_expect_success 'fails silently when using -q' '
t/t1510-repo-setup.sh +5 -5
@@ -604,7 +604,7 @@ test_expect_success '#20b/c: core.worktree and core.bare conflict' ' cd 20b/.git && test_must_fail git status >/dev/null ) 2>message && - grep "core.bare and core.worktree" message + test_grep "core.bare and core.worktree" message ' test_expect_success '#20d: core.worktree and core.bare OK when working tree not needed' '
@@ -721,8 +721,8 @@ test_expect_success '#22.2: core.worktree and core.bare conflict' ' export GIT_DIR && test_must_fail git status 2>result ) && - grep "core.bare and core.worktree" 22/.git/result && - grep "core.bare and core.worktree" 22/result + test_grep "core.bare and core.worktree" 22/.git/result && + test_grep "core.bare and core.worktree" 22/result ' # Case #23: GIT_DIR + GIT_WORK_TREE(+core.worktree) suppresses bareness.
@@ -767,7 +767,7 @@ test_expect_success '#28: core.worktree and core.bare conflict (gitfile case)' ' cd 28 && test_must_fail git status ) 2>message && - grep "core.bare and core.worktree" message + test_grep "core.bare and core.worktree" message ' # Case #29: GIT_WORK_TREE(+core.worktree) overrides core.bare (gitfile case).
@@ -791,7 +791,7 @@ test_expect_success '#30: core.worktree and core.bare conflict (gitfile version) cd 30 && test_must_fail env GIT_DIR=.git git status 2>result ) && - grep "core.bare and core.worktree" 30/result + test_grep "core.bare and core.worktree" 30/result ' # Case #31: GIT_DIR + GIT_WORK_TREE(+core.worktree) suppresses
t/t1512-rev-parse-disambiguation.sh +2 -2
@@ -378,7 +378,7 @@ test_expect_success 'ambiguous 40-hex ref' ' VAL=$(git commit-tree $TREE </dev/null) && git update-ref refs/heads/$REF $VAL && test $(git rev-parse $REF 2>err) = $REF && - grep "refname.*${REF}.*ambiguous" err + test_grep "refname.*${REF}.*ambiguous" err ' test_expect_success 'ambiguous short sha1 ref' '
@@ -387,7 +387,7 @@ test_expect_success 'ambiguous short sha1 ref' ' VAL=$(git commit-tree $TREE </dev/null) && git update-ref refs/heads/$REF $VAL && test $(git rev-parse $REF 2>err) = $VAL && - grep "refname.*${REF}.*ambiguous" err + test_grep "refname.*${REF}.*ambiguous" err ' test_expect_success 'ambiguity errors are not repeated (raw)' '
t/t1515-rev-parse-outside-repo.sh +1 -1
@@ -32,7 +32,7 @@ test_expect_success 'rev-parse --local-env-vars' ' git rev-parse --local-env-vars >actual && # we do not want to depend on the complete list here, # so just look for something plausible - grep ^GIT_DIR actual + test_grep ^GIT_DIR actual ' test_expect_success 'rev-parse --resolve-git-dir' '
t/t1800-hook.sh +9 -9
@@ -79,7 +79,7 @@ test_expect_success 'git hook usage' ' test_expect_code 129 git hook run --unknown 2>err && test_expect_code 129 git hook list && test_expect_code 129 git hook list -h && - grep "unknown option" err + test_grep "unknown option" err ' test_expect_success 'git hook list: unknown hook name is rejected' '
@@ -361,9 +361,9 @@ test_expect_success 'hook can be configured for multiple events' ' # 'ghi' should be included in both 'pre-commit' and 'test-hook' git hook list pre-commit >actual && - grep "ghi" actual && + test_grep "ghi" actual && git hook list --allow-unknown-hook-name test-hook >actual && - grep "ghi" actual + test_grep "ghi" actual ' test_expect_success 'git hook list shows hooks from the hookdir' '
@@ -569,7 +569,7 @@ test_expect_success 'git hook run a hook with a bad shebang' ' # TODO: We should emit the same (or at least a more similar) # error on MINGW (essentially Git for Windows) and all other # platforms.. See the OS-specific code in start_command() - grep -E "^(error|fatal): cannot (exec|spawn) .*bad-hooks/test-hook" err + test_grep -E "^(error|fatal): cannot (exec|spawn) .*bad-hooks/test-hook" err ' test_expect_success 'stdin to hooks' '
@@ -826,8 +826,8 @@ test_expect_success 'git hook run -j2 warns for hooks not marked parallel=true' # neither hook has parallel=true git hook run --allow-unknown-hook-name -j2 test-hook >out 2>err && - grep "hook .hook-1. is not marked as parallel=true" err && - grep "hook .hook-2. is not marked as parallel=true" err + test_grep "hook .hook-1. is not marked as parallel=true" err && + test_grep "hook .hook-2. is not marked as parallel=true" err ' test_expect_success 'hook.jobs=1 config runs hooks in series' '
@@ -1068,7 +1068,7 @@ test_expect_success 'hook.jobs=-1 resolves to online_cpus()' ' cpus=$(test-tool online-cpus) && GIT_TRACE2_EVENT="$(pwd)/trace.txt" \ git hook run --allow-unknown-hook-name test-hook >out 2>err && - grep "\"region_enter\".*\"hook\".*\"test-hook\".*\"max:$cpus\"" trace.txt + test_grep "\"region_enter\".*\"hook\".*\"test-hook\".*\"max:$cpus\"" trace.txt ' test_expect_success 'hook.<event>.jobs=-1 resolves to online_cpus()' '
@@ -1081,7 +1081,7 @@ test_expect_success 'hook.<event>.jobs=-1 resolves to online_cpus()' ' cpus=$(test-tool online-cpus) && GIT_TRACE2_EVENT="$(pwd)/trace.txt" \ git hook run --allow-unknown-hook-name test-hook >out 2>err && - grep "\"region_enter\".*\"hook\".*\"test-hook\".*\"max:$cpus\"" trace.txt + test_grep "\"region_enter\".*\"hook\".*\"test-hook\".*\"max:$cpus\"" trace.txt ' test_expect_success 'git hook run -j-1 resolves to online_cpus()' '
@@ -1092,7 +1092,7 @@ test_expect_success 'git hook run -j-1 resolves to online_cpus()' ' cpus=$(test-tool online-cpus) && GIT_TRACE2_EVENT="$(pwd)/trace.txt" \ git hook run --allow-unknown-hook-name -j-1 test-hook >out 2>err && - grep "\"region_enter\".*\"hook\".*\"test-hook\".*\"max:$cpus\"" trace.txt + test_grep "\"region_enter\".*\"hook\".*\"test-hook\".*\"max:$cpus\"" trace.txt ' test_expect_success 'hook.jobs rejects values less than -1' '
t/t2004-checkout-cache-temp.sh +2 -2
@@ -132,8 +132,8 @@ test_expect_success 'overriding --stage=all resets implied --temp' ' test_expect_success '--stage=all --no-temp is rejected' ' rm -f path* .merge_* actual && test_must_fail git checkout-index --stage=all --no-temp -- path1 2>err &&
Lines of this file are not shown. View the raw message.
t/t2081-parallel-checkout-collisions.sh +12 -12
Lines of this file are not shown. View the raw message.
t/t2082-parallel-checkout-attributes.sh +6 -6
Lines of this file are not shown. View the raw message.
t/t3206-range-diff.sh +39 -39
78 lines not on this page · raw message
t/t3404-rebase-interactive.sh +36 -36
72 lines not on this page · raw message
t/t4014-format-patch.sh +172 -172
344 lines not on this page · raw message
t/t4150-am.sh +24 -24
48 lines not on this page · raw message
t/t4202-log.sh +42 -42
84 lines not on this page · raw message
t/t4211-line-log.sh +36 -36
72 lines not on this page · raw message
t/t5334-incremental-multi-pack-index.sh +1 -1
Lines of this file are not shown. View the raw message.
t/t5551-http-fetch-smart.sh +23 -23
46 lines not on this page · raw message
t/t5616-partial-clone.sh +30 -30
60 lines not on this page · raw message
t/t5619-clone-local-ambiguous-transport.sh +1 -1
Lines of this file are not shown. View the raw message.
t/t5700-protocol-v1.sh +23 -23
46 lines not on this page · raw message
t/t5702-protocol-v2.sh +77 -77
154 lines not on this page · raw message
t/t6030-bisect-porcelain.sh +75 -75
150 lines not on this page · raw message
t/t6200-fmt-merge-msg.sh +41 -41
82 lines not on this page · raw message
t/t6423-merge-rename-directories.sh +36 -36
72 lines not on this page · raw message
t/t6424-merge-unrelated-index-changes.sh +3 -3
Lines of this file are not shown. View the raw message.
t/t6432-merge-recursive-space-options.sh +2 -2
Lines of this file are not shown. View the raw message.
t/t7030-verify-tag.sh +26 -26
52 lines not on this page · raw message
t/t7031-verify-tag-signed-ssh.sh +23 -23
46 lines not on this page · raw message
t/t7510-signed-commit.sh +34 -34
68 lines not on this page · raw message
t/t7527-builtin-fsmonitor.sh +41 -41
82 lines not on this page · raw message
t/t7528-signed-commit-ssh.sh +34 -34
68 lines not on this page · raw message
t/t9001-send-email.sh +95 -95
190 lines not on this page · raw message
t/t9350-fast-export.sh +27 -27
54 lines not on this page · raw message
t/t9501-gitweb-standalone-http-status.sh +29 -29
58 lines not on this page · raw message
t/t9502-gitweb-standalone-parse-output.sh +19 -19
Lines of this file are not shown. View the raw message.
t/t9801-git-p4-branch.sh +24 -24
48 lines not on this page · raw message
t/t9835-git-p4-metadata-encoding-python2.sh +18 -18
Lines of this file are not shown. View the raw message.
t/t9836-git-p4-metadata-encoding-python3.sh +19 -19
Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
Signature · 1 line
gitgitgadget
Part of the diff is not shown here. View the raw message.
PATCH v4 6/6 t: add greplint to detect bare grep assertions
In reply to Michael Montalbo via GitGitGadgetFrom: Michael Montalbo <[email protected]>
Without a lint guard, bare grep assertions will creep back into tests over time, defeating the previous commit's conversion.
Add greplint.pl to catch bare 'grep' used as a test assertion (where 'test_grep' should be used) and '! test_grep' (where 'test_grep !' should be used).
greplint.pl reuses the shared shell parser from lib-shell-parser.pl to tokenize test bodies. The Lexer collapses heredocs, command substitutions, and quoted strings into single tokens, so 'grep' appearing inside these contexts is not flagged. A flat walk over the token stream tracks command position and pipeline state to distinguish assertion greps from filter greps.
For double-quoted test bodies, a source-line walk counts backslash-continuation lines that the Lexer consumes without emitting into the body text, adjusting the reported line number accordingly.
Add test fixtures in greplint/ (modeled on chainlint/) covering detection of bare grep assertions, correct skipping of filters, pipelines, redirects, command substitutions, and lint-ok annotations.
Wire into the Makefile as:
- test-greplint: runs greplint.pl on $(T) $(THELPERS) $(TPERF)
- check-greplint: runs greplint.pl on fixtures, diffs against expected
- clean-greplint: removes temp dir
Add eol=lf entries in t/.gitattributes for greplint fixtures, matching chainlint, so that check-greplint passes on Windows where core.autocrlf would otherwise cause CRLF mismatches between expected and actual output.
--- t/.gitattributes | 2 + t/Makefile | 29 +- t/greplint-cat.pl | 27 ++ t/greplint.pl | 258 ++++++++++++++++++ t/greplint/bare-grep-after-and.expect | 1 + t/greplint/bare-grep-after-and.test | 4 + t/greplint/bare-grep-after-semicolon.expect | 1 + t/greplint/bare-grep-after-semicolon.test | 4 + t/greplint/bare-grep-compound-body.expect | 3 + t/greplint/bare-grep-compound-body.test | 17 ++ t/greplint/bare-grep-count-mode.expect | 1 + t/greplint/bare-grep-count-mode.test | 3 + t/greplint/bare-grep-explicit-pattern.expect | 1 + t/greplint/bare-grep-explicit-pattern.test | 3 + t/greplint/bare-grep-flags.expect | 1 + t/greplint/bare-grep-flags.test | 3 + t/greplint/bare-grep-lint-ok.expect | 0 t/greplint/bare-grep-lint-ok.test | 4 + t/greplint/bare-grep-negated.expect | 1 + t/greplint/bare-grep-negated.test | 3 + t/greplint/bare-grep-pattern-file.expect | 1 + t/greplint/bare-grep-pattern-file.test | 3 + t/greplint/bare-grep-simple.expect | 1 + t/greplint/bare-grep-simple.test | 3 + t/greplint/bare-grep-subshell.expect | 1 + t/greplint/bare-grep-subshell.test | 5 + .../dqstring-continuation-offset.expect | 1 + t/greplint/dqstring-continuation-offset.test | 11 + t/greplint/filter-command-substitution.expect | 0 t/greplint/filter-command-substitution.test | 3 + t/greplint/filter-pipe-input.expect | 0 t/greplint/filter-pipe-input.test | 3 + t/greplint/filter-pipe-output.expect | 0 t/greplint/filter-pipe-output.test | 3 + t/greplint/filter-redirect-output.expect | 0 t/greplint/filter-redirect-output.test | 3 + t/greplint/filter-stdin-redirect.expect | 0 t/greplint/filter-stdin-redirect.test | 3 + t/greplint/grep-as-argument.expect | 0 t/greplint/grep-as-argument.test | 3 + t/greplint/grep-as-value.expect | 0 t/greplint/grep-as-value.test | 6 + t/greplint/wrong-negation.expect | 1 + t/greplint/wrong-negation.test | 3 + 44 files changed, 415 insertions(+), 5 deletions(-) create mode 100644 t/greplint-cat.pl create mode 100644 t/greplint.pl create mode 100644 t/greplint/bare-grep-after-and.expect create mode 100644 t/greplint/bare-grep-after-and.test create mode 100644 t/greplint/bare-grep-after-semicolon.expect create mode 100644 t/greplint/bare-grep-after-semicolon.test create mode 100644 t/greplint/bare-grep-compound-body.expect create mode 100644 t/greplint/bare-grep-compound-body.test create mode 100644 t/greplint/bare-grep-count-mode.expect create mode 100644 t/greplint/bare-grep-count-mode.test create mode 100644 t/greplint/bare-grep-explicit-pattern.expect create mode 100644 t/greplint/bare-grep-explicit-pattern.test create mode 100644 t/greplint/bare-grep-flags.expect create mode 100644 t/greplint/bare-grep-flags.test create mode 100644 t/greplint/bare-grep-lint-ok.expect create mode 100644 t/greplint/bare-grep-lint-ok.test create mode 100644 t/greplint/bare-grep-negated.expect create mode 100644 t/greplint/bare-grep-negated.test create mode 100644 t/greplint/bare-grep-pattern-file.expect create mode 100644 t/greplint/bare-grep-pattern-file.test create mode 100644 t/greplint/bare-grep-simple.expect create mode 100644 t/greplint/bare-grep-simple.test create mode 100644 t/greplint/bare-grep-subshell.expect create mode 100644 t/greplint/bare-grep-subshell.test create mode 100644 t/greplint/dqstring-continuation-offset.expect create mode 100644 t/greplint/dqstring-continuation-offset.test create mode 100644 t/greplint/filter-command-substitution.expect create mode 100644 t/greplint/filter-command-substitution.test create mode 100644 t/greplint/filter-pipe-input.expect create mode 100644 t/greplint/filter-pipe-input.test create mode 100644 t/greplint/filter-pipe-output.expect create mode 100644 t/greplint/filter-pipe-output.test create mode 100644 t/greplint/filter-redirect-output.expect create mode 100644 t/greplint/filter-redirect-output.test create mode 100644 t/greplint/filter-stdin-redirect.expect create mode 100644 t/greplint/filter-stdin-redirect.test create mode 100644 t/greplint/grep-as-argument.expect create mode 100644 t/greplint/grep-as-argument.test create mode 100644 t/greplint/grep-as-value.expect create mode 100644 t/greplint/grep-as-value.test create mode 100644 t/greplint/wrong-negation.expect create mode 100644 t/greplint/wrong-negation.test
t/.gitattributes +2 -0
@@ -1,5 +1,7 @@ t[0-9][0-9][0-9][0-9]/* -whitespace /chainlint/*.expect eol=lf -whitespace +/greplint/*.expect eol=lf -whitespace +/greplint/*.test eol=lf -whitespace /t0110/url-* binary /t3206/* eol=lf /t3900/*.txt eol=lf
t/Makefile +24 -5
@@ -27,9 +27,11 @@ TEST_LINT ?= test-lint ifdef TEST_OUTPUT_DIRECTORY TEST_RESULTS_DIRECTORY = $(TEST_OUTPUT_DIRECTORY)/test-results CHAINLINTTMP = $(TEST_OUTPUT_DIRECTORY)/chainlinttmp +GREPLINTTMP = $(TEST_OUTPUT_DIRECTORY)/greplinttmp else TEST_RESULTS_DIRECTORY = test-results CHAINLINTTMP = chainlinttmp +GREPLINTTMP = greplinttmp endif # Shell quote;
@@ -38,6 +40,7 @@ TEST_SHELL_PATH_SQ = $(subst ','\'',$(TEST_SHELL_PATH)) PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) TEST_RESULTS_DIRECTORY_SQ = $(subst ','\'',$(TEST_RESULTS_DIRECTORY)) CHAINLINTTMP_SQ = $(subst ','\'',$(CHAINLINTTMP)) +GREPLINTTMP_SQ = $(subst ','\'',$(GREPLINTTMP)) T = $(sort $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)) THELPERS = $(sort $(filter-out $(T),$(wildcard *.sh)))
@@ -45,6 +48,7 @@ TLIBS = $(sort $(wildcard lib-*.sh)) annotate-tests.sh TPERF = $(sort $(wildcard perf/p[0-9][0-9][0-9][0-9]-*.sh)) TINTEROP = $(sort $(wildcard interop/i[0-9][0-9][0-9][0-9]-*.sh)) CHAINLINTTESTS = $(sort $(patsubst chainlint/%.test,%,$(wildcard chainlint/*.test))) +GREPLINTTESTS = $(sort $(patsubst greplint/%.test,%,$(wildcard greplint/*.test))) CHAINLINT = '$(PERL_PATH_SQ)' chainlint.pl UNIT_TEST_SOURCES = $(wildcard unit-tests/t-*.c) UNIT_TEST_PROGRAMS = $(patsubst unit-tests/%.c,unit-tests/bin/%$(X),$(UNIT_TEST_SOURCES))
@@ -63,8 +67,8 @@ test: pre-clean check-meson $(TEST_LINT) $(CHAINLINTSUPPRESS) $(MAKE) aggregate-results-and-cleanup ifneq ($(PERL_PATH),) -test: check-chainlint -prove: check-chainlint +test: check-chainlint check-greplint +prove: check-chainlint check-greplint endif failed:
@@ -102,7 +106,7 @@ unit-tests-test-tool: pre-clean: $(RM) -r '$(TEST_RESULTS_DIRECTORY_SQ)' -clean-except-prove-cache: clean-chainlint +clean-except-prove-cache: clean-chainlint clean-greplint $(RM) -r 'trash directory'.* $(RM) -r valgrind/bin
@@ -120,6 +124,17 @@ check-chainlint: { $(CHAINLINT) --emit-all '$(CHAINLINTTMP_SQ)'/tests >'$(CHAINLINTTMP_SQ)'/actual || true; } && \ diff -u '$(CHAINLINTTMP_SQ)'/expect '$(CHAINLINTTMP_SQ)'/actual +clean-greplint: + $(RM) -r '$(GREPLINTTMP_SQ)' + +check-greplint: + @mkdir -p '$(GREPLINTTMP_SQ)' && \ + '$(PERL_PATH_SQ)' greplint-cat.pl '$(GREPLINTTMP_SQ)' $(GREPLINTTESTS) && \ + { '$(PERL_PATH_SQ)' greplint.pl \ + $(patsubst %,greplint/%.test,$(GREPLINTTESTS)) \ + >'$(GREPLINTTMP_SQ)'/actual 2>&1 || true; } && \ + diff -u '$(GREPLINTTMP_SQ)'/expect '$(GREPLINTTMP_SQ)'/actual + check-meson: @# awk acts up when trying to match single quotes, so we use \047 instead. @mkdir -p mesontmp && \
@@ -139,7 +154,7 @@ check-meson: test-lint: test-lint-duplicates test-lint-executable \ test-lint-filenames ifneq ($(PERL_PATH),) -test-lint: test-lint-shell-syntax +test-lint: test-lint-shell-syntax test-greplint else GIT_TEST_CHAIN_LINT = 0 endif
@@ -160,6 +175,9 @@ test-lint-executable: test-lint-shell-syntax: @'$(PERL_PATH_SQ)' check-non-portable-shell.pl $(T) $(THELPERS) $(TPERF) +test-greplint: + @'$(PERL_PATH_SQ)' greplint.pl $(T) $(THELPERS) $(TPERF) + test-lint-filenames: @# We do *not* pass a glob to ls-files but use grep instead, to catch @# non-ASCII characters (which are quoted within double-quotes)
@@ -185,7 +203,8 @@ perf: $(MAKE) -C perf/ all .PHONY: pre-clean $(T) aggregate-results clean valgrind perf \ - check-chainlint clean-chainlint test-chainlint $(UNIT_TESTS) + check-chainlint clean-chainlint test-chainlint \ + check-greplint clean-greplint test-greplint $(UNIT_TESTS) .PHONY: libgit-sys-test libgit-rs-test libgit-sys-test:
t/greplint-cat.pl new file +27 -0
@@ -0,0 +1,27 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +# Assemble expected output for check-greplint target. +# Usage: greplint-cat.pl <outdir> <test-name> ... +# +# For each <test-name>, reads greplint/<test-name>.expect and +# prepends "greplint/<test-name>.test:" to every non-empty line, +# matching the output format of greplint.pl. Writes combined +# expected output to <outdir>/expect. + +my $outdir = shift; +open(my $expect, '>', "$outdir/expect") + or die "unable to open $outdir/expect: $!"; + +for my $name (@ARGV) { + open(my $fh, '<', "greplint/$name.expect") + or die "unable to open greplint/$name.expect: $!"; + while (<$fh>) { + print $expect "greplint/$name.test:$_"; + } + close $fh; +} + +close $expect;
t/greplint.pl new file +258 -0
258 lines not on this page · raw message
t/greplint/bare-grep-after-and.expect new file +1 -0
@@ -0,0 +1 @@ +3: error: bare grep outside pipeline (use test_grep)
t/greplint/bare-grep-after-and.test new file +4 -0
@@ -0,0 +1,4 @@ +test_expect_success 'grep after && is flagged' ' + cmd && + grep pattern file +'
t/greplint/bare-grep-after-semicolon.expect new file +1 -0
@@ -0,0 +1 @@ +3: error: bare grep outside pipeline (use test_grep)
t/greplint/bare-grep-after-semicolon.test new file +4 -0
@@ -0,0 +1,4 @@ +test_expect_success 'grep after semicolon is flagged' ' + echo hello; + grep pattern file +'
t/greplint/bare-grep-compound-body.expect new file +3 -0
@@ -0,0 +1,3 @@ +4: error: bare grep outside pipeline (use test_grep) +8: error: bare grep outside pipeline (use test_grep) +15: error: bare grep outside pipeline (use test_grep)
t/greplint/bare-grep-compound-body.test new file +17 -0
@@ -0,0 +1,17 @@ +test_expect_success 'grep after then/do/else is flagged' ' + if true + then + grep pattern file + fi && + while true + do + grep pattern file && + break + done && + if true + then + echo yes + else + grep pattern file + fi +'
t/greplint/bare-grep-count-mode.expect new file +1 -0
@@ -0,0 +1 @@ +2: error: bare grep outside pipeline (use test_grep)
t/greplint/bare-grep-count-mode.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'grep -c is flagged (not special-cased)' ' + grep -c pattern file +'
t/greplint/bare-grep-explicit-pattern.expect new file +1 -0
@@ -0,0 +1 @@ +2: error: bare grep outside pipeline (use test_grep)
t/greplint/bare-grep-explicit-pattern.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'grep -e is flagged' ' + grep -e pattern file +'
t/greplint/bare-grep-flags.expect new file +1 -0
@@ -0,0 +1 @@ +2: error: bare grep outside pipeline (use test_grep)
t/greplint/bare-grep-flags.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'grep -E is flagged' ' + grep -E "pat+ern" file +'
t/greplint/bare-grep-lint-ok.expect new file +0 -0
t/greplint/bare-grep-lint-ok.test new file +4 -0
@@ -0,0 +1,4 @@ +test_expect_success 'grep with lint-ok annotation is not flagged' ' + grep pattern file && # lint-ok + echo done +'
t/greplint/bare-grep-negated.expect new file +1 -0
@@ -0,0 +1 @@ +2: error: bare grep outside pipeline (use test_grep)
t/greplint/bare-grep-negated.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'negated grep is flagged' ' + ! grep pattern file +'
t/greplint/bare-grep-pattern-file.expect new file +1 -0
@@ -0,0 +1 @@ +2: error: bare grep outside pipeline (use test_grep)
t/greplint/bare-grep-pattern-file.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'grep -f is flagged' ' + grep -f patterns.txt file +'
t/greplint/bare-grep-simple.expect new file +1 -0
@@ -0,0 +1 @@ +2: error: bare grep outside pipeline (use test_grep)
t/greplint/bare-grep-simple.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'bare grep is flagged' ' + grep pattern file +'
t/greplint/bare-grep-subshell.expect new file +1 -0
@@ -0,0 +1 @@ +3: error: bare grep outside pipeline (use test_grep)
t/greplint/bare-grep-subshell.test new file +5 -0
@@ -0,0 +1,5 @@ +test_expect_success 'grep in subshell is flagged' ' + ( + grep pattern file + ) +'
t/greplint/dqstring-continuation-offset.expect new file +1 -0
@@ -0,0 +1 @@ +10: error: bare grep outside pipeline (use test_grep)
t/greplint/dqstring-continuation-offset.test new file +11 -0
@@ -0,0 +1,11 @@ +# Double-quoted test bodies with backslash-continuation lines: +# the splice adjustment in check_test compensates for \<newline> +# lines that the lexer consumes without emitting into the body +# text, so the reported line number matches the source. +test_expect_success 'dqstring continuation offset' " + x=\$(echo \ + hello) && + y=\$(echo \ + world) && + grep pattern file +"
t/greplint/filter-command-substitution.expect new file +0 -0
t/greplint/filter-command-substitution.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'grep in command substitution is not flagged' ' + x=$(grep pattern file) +'
t/greplint/filter-pipe-input.expect new file +0 -0
t/greplint/filter-pipe-input.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'grep receiving pipe input is not flagged' ' + cmd | grep pattern +'
t/greplint/filter-pipe-output.expect new file +0 -0
t/greplint/filter-pipe-output.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'grep piping to another command is not flagged' ' + grep pattern file | wc -l +'
t/greplint/filter-redirect-output.expect new file +0 -0
t/greplint/filter-redirect-output.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'grep with output redirect is not flagged' ' + grep pattern file >output +'
t/greplint/filter-stdin-redirect.expect new file +0 -0
t/greplint/filter-stdin-redirect.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'grep reading from stdin redirect is not flagged' ' + grep pattern <input +'
t/greplint/grep-as-argument.expect new file +0 -0
t/greplint/grep-as-argument.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'grep as argument to another command is not flagged' ' + test_must_fail grep pattern file +'
t/greplint/grep-as-value.expect new file +0 -0
t/greplint/grep-as-value.test new file +6 -0
@@ -0,0 +1,6 @@ +test_expect_success 'grep as value in for-loop is not flagged' ' + for cmd in grep sed awk + do + echo $cmd + done +'
t/greplint/wrong-negation.expect new file +1 -0
@@ -0,0 +1 @@ +2: error: use "test_grep !" instead of "! test_grep"
t/greplint/wrong-negation.test new file +3 -0
@@ -0,0 +1,3 @@ +test_expect_success 'wrong negation of test_grep is flagged' ' + ! test_grep pattern file +'
Signature · 1 line
gitgitgadget