Git fork

chainlint.pl: recognize test bodies defined via heredoc

In order to check tests for semantic problems, chainlint.pl scans test
scripts, looking for tests defined as:

test_expect_success [prereq] title '
body
'

where `body` is a single string which is then treated as a standalone
chunk of code and "linted" to detect semantic issues. (The same happens
for `test_expect_failure` definitions.)

The introduction of test definitions in which the test body is instead
presented via a heredoc rather than as a single string creates a blind
spot in the linting process since such invocations are not recognized by
chainlint.pl.

Prepare for this new style by also recognizing tests defined as:

test_expect_success [prereq] title - <<\EOT
body
EOT

A minor complication is that chainlint.pl has never considered heredoc
bodies significant since it doesn't scan them for semantic problems,
thus it has always simply thrown them away. However, with the new
`test_expect_success` calling sequence, heredoc bodies become
meaningful, thus need to be captured.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>

authored by

Eric Sunshine and committed by
Junio C Hamano
a4a5f282 03763e68

+22 -5
+22 -5
t/chainlint.pl
··· 174 $$b =~ /(?:\G|\n)$indent\Q$$tag[0]\E(?:\n|\z)/gc; 175 if (pos($$b) > $start) { 176 my $body = substr($$b, $start, pos($$b) - $start); 177 $self->{lineno} += () = $body =~ /\n/sg; 178 next; 179 } ··· 232 my $self = bless { 233 buff => [], 234 stop => [], 235 - output => [] 236 } => $class; 237 $self->{lexer} = Lexer->new($self, $s); 238 return $self; ··· 616 617 sub check_test { 618 my $self = shift @_; 619 - my ($title, $body) = map(unwrap, @_); 620 $self->{ntests}++; 621 my $parser = TestParser->new(\$body); 622 my @tokens = $parser->parse(); 623 my $problems = $parser->{problems}; 624 return unless $emit_all || @$problems; 625 my $c = main::fd_colors(1); 626 - my $lineno = $_[1]->[3]; 627 my $start = 0; 628 my $checked = ''; 629 for (sort {$a->[1]->[2] <=> $b->[1]->[2]} @$problems) { ··· 649 return @tokens unless @tokens && $tokens[0]->[0] =~ /^test_expect_(?:success|failure)$/; 650 my $n = $#tokens; 651 $n-- while $n >= 0 && $tokens[$n]->[0] =~ /^(?:[;&\n|]|&&|\|\|)$/; 652 - $self->check_test($tokens[1], $tokens[2]) if $n == 2; # title body 653 - $self->check_test($tokens[2], $tokens[3]) if $n > 2; # prereq title body 654 return @tokens; 655 } 656
··· 174 $$b =~ /(?:\G|\n)$indent\Q$$tag[0]\E(?:\n|\z)/gc; 175 if (pos($$b) > $start) { 176 my $body = substr($$b, $start, pos($$b) - $start); 177 + $self->{parser}->{heredocs}->{$$tag[0]} = { 178 + content => substr($body, 0, length($body) - length($&)), 179 + start_line => $self->{lineno}, 180 + }; 181 $self->{lineno} += () = $body =~ /\n/sg; 182 next; 183 } ··· 236 my $self = bless { 237 buff => [], 238 stop => [], 239 + output => [], 240 + heredocs => {}, 241 } => $class; 242 $self->{lexer} = Lexer->new($self, $s); 243 return $self; ··· 621 622 sub check_test { 623 my $self = shift @_; 624 + my $title = unwrap(shift @_); 625 + my $body = shift @_; 626 + my $lineno = $body->[3]; 627 + $body = unwrap($body); 628 + if ($body eq '-') { 629 + my $herebody = shift @_; 630 + $body = $herebody->{content}; 631 + $lineno = $herebody->{start_line}; 632 + } 633 $self->{ntests}++; 634 my $parser = TestParser->new(\$body); 635 my @tokens = $parser->parse(); 636 my $problems = $parser->{problems}; 637 return unless $emit_all || @$problems; 638 my $c = main::fd_colors(1); 639 my $start = 0; 640 my $checked = ''; 641 for (sort {$a->[1]->[2] <=> $b->[1]->[2]} @$problems) { ··· 661 return @tokens unless @tokens && $tokens[0]->[0] =~ /^test_expect_(?:success|failure)$/; 662 my $n = $#tokens; 663 $n-- while $n >= 0 && $tokens[$n]->[0] =~ /^(?:[;&\n|]|&&|\|\|)$/; 664 + my $herebody; 665 + if ($n >= 2 && $tokens[$n-1]->[0] eq '-' && $tokens[$n]->[0] =~ /^<<-?(.+)$/) { 666 + $herebody = $self->{heredocs}->{$1}; 667 + $n--; 668 + } 669 + $self->check_test($tokens[1], $tokens[2], $herebody) if $n == 2; # title body 670 + $self->check_test($tokens[2], $tokens[3], $herebody) if $n > 2; # prereq title body 671 return @tokens; 672 } 673