Skip to content

Commit 2b61c8d

Browse files
sunshinecogitster
authored andcommitted
tests: diagnose unclosed here-doc in chainlint.pl
An unclosed here-doc in a test is a problem, because it silently gobbles up any remaining commands. Since 99a64e4 (tests: lint for run-away here-doc, 2017-03-22) we detect this by piggy-backing on the internal chainlint checker in test-lib.sh. However, it would be nice to detect it in chainlint.pl, for a few reasons: - the output from chainlint.pl is much nicer; it can show the exact spot of the error, rather than a vague "somewhere in this test you broke the &&-chain or had a bad here-doc" message. - the implementation in test-lib.sh runs for each test snippet. And since it requires a subshell, the extra cost is small but not zero. If chainlint.pl can reliably find the problem, we can optimize the test-lib.sh code. The chainlint.pl code never intended to find here-doc problems. But since it has to parse them anyway (to avoid reporting problems inside here-docs), most of what we need is already there. We can detect the problem when we fail to find the missing end-tag in swallow_heredocs(). The extra change in scan_heredoc_tag() stores the location of the start of the here-doc, which lets us mark it as the source of the error in the output (see the new tests for examples). [jk: added commit message and tests] Signed-off-by: Eric Sunshine <[email protected]> Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 1686de5 commit 2b61c8d

File tree

5 files changed

+34
-3
lines changed

5 files changed

+34
-3
lines changed

t/chainlint.pl

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ sub scan_heredoc_tag {
8080
return "<<$indented" unless $token;
8181
my $tag = $token->[0];
8282
$tag =~ s/['"\\]//g;
83-
push(@{$self->{heretags}}, $indented ? "\t$tag" : "$tag");
83+
$$token[0] = $indented ? "\t$tag" : "$tag";
84+
push(@{$self->{heretags}}, $token);
8485
return "<<$indented$tag";
8586
}
8687

@@ -169,10 +170,18 @@ sub swallow_heredocs {
169170
my $tags = $self->{heretags};
170171
while (my $tag = shift @$tags) {
171172
my $start = pos($$b);
172-
my $indent = $tag =~ s/^\t// ? '\\s*' : '';
173-
$$b =~ /(?:\G|\n)$indent\Q$tag\E(?:\n|\z)/gc;
173+
my $indent = $$tag[0] =~ s/^\t// ? '\\s*' : '';
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+
}
180+
push(@{$self->{parser}->{problems}}, ['UNCLOSED-HEREDOC', $tag]);
181+
$$b =~ /(?:\G|\n).*\z/gc; # consume rest of input
174182
my $body = substr($$b, $start, pos($$b) - $start);
175183
$self->{lineno} += () = $body =~ /\n/sg;
184+
last;
176185
}
177186
}
178187

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
command_which_is_run &&
2+
cat >expect <<-\EOF ?!UNCLOSED-HEREDOC?! &&
3+
we forget to end the here-doc
4+
command_which_is_gobbled
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
command_which_is_run &&
2+
cat >expect <<-\EOF &&
3+
we forget to end the here-doc
4+
command_which_is_gobbled

t/chainlint/unclosed-here-doc.expect

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
command_which_is_run &&
2+
cat >expect <<\EOF ?!UNCLOSED-HEREDOC?! &&
3+
we try to end the here-doc below,
4+
but the indentation throws us off
5+
since the operator is not "<<-".
6+
EOF
7+
command_which_is_gobbled

t/chainlint/unclosed-here-doc.test

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
command_which_is_run &&
2+
cat >expect <<\EOF &&
3+
we try to end the here-doc below,
4+
but the indentation throws us off
5+
since the operator is not "<<-".
6+
EOF
7+
command_which_is_gobbled

0 commit comments

Comments
 (0)