Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lib/Template/Directive.pm
Original file line number Diff line number Diff line change
Expand Up @@ -574,12 +574,12 @@ sub while {

# WHILE
do {
my \$_tt_failsafe = $WHILE_MAX;
my \$_tt_failsafe = \$Template::Directive::WHILE_MAX;
$label:
while (($expr) && --\$_tt_failsafe >= 0) {
$block
}
die "WHILE loop terminated (> $WHILE_MAX iterations)\\n"
die "WHILE loop terminated (> " . \$Template::Directive::WHILE_MAX . " iterations)\\n"
if \$_tt_failsafe < 0;
};
EOF
Expand Down
75 changes: 75 additions & 0 deletions t/while_max_runtime.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#============================================================= -*-perl-*-
#
# t/while_max_runtime.t
#
# Test that WHILE_MAX is read at runtime, not baked at compile-time
#
#========================================================================

use strict;
use warnings;
use lib qw( ./lib ../lib );
use Template;
use Template::Directive;
use File::Temp qw(tempdir);
use Test::More tests => 6;

# Set a low initial WHILE_MAX
$Template::Directive::WHILE_MAX = 10;

my $tt = Template->new();
my $output;

my $tmpl = '[% TRY; WHILE 1; "."; END; CATCH; error.info; END %]';

# Process with WHILE_MAX = 10
$tt->process(\$tmpl, {}, \$output) || die $tt->error;
like($output, qr/^\.{10}WHILE loop terminated/,
'WHILE stops at 10 iterations when WHILE_MAX is 10');

# Change WHILE_MAX to 20 at runtime — same template engine, no recompilation
$Template::Directive::WHILE_MAX = 20;
$output = '';
$tt->process(\$tmpl, {}, \$output) || die $tt->error;
like($output, qr/^\.{20}WHILE loop terminated/,
'WHILE stops at 20 iterations after changing WHILE_MAX at runtime');

# Verify the error message also uses the runtime value
like($output, qr/> 20 iterations/,
'error message reflects runtime WHILE_MAX value');

# Change back to verify it works in both directions
$Template::Directive::WHILE_MAX = 5;
$output = '';
$tt->process(\$tmpl, {}, \$output) || die $tt->error;
like($output, qr/^\.{5}WHILE loop terminated.*> 5 iterations/,
'WHILE stops at 5 iterations after lowering WHILE_MAX');

# Test with compiled-to-disk templates: WHILE_MAX should be read
# from the package variable at execution time, not from the compiled file
my $srcdir = tempdir(CLEANUP => 1);
my $compdir = tempdir(CLEANUP => 1);

# Write a template file
open my $fh, '>', "$srcdir/loop.tt" or die "Can't write: $!";
print $fh '[% TRY; WHILE 1; "."; END; CATCH; error.info; END %]';
close $fh;

# Compile with WHILE_MAX = 15
$Template::Directive::WHILE_MAX = 15;
my $tt_comp = Template->new({
INCLUDE_PATH => $srcdir,
COMPILE_DIR => $compdir,
COMPILE_EXT => '.ttc',
});
$output = '';
$tt_comp->process('loop.tt', {}, \$output) || die $tt_comp->error;
like($output, qr/^\.{15}WHILE loop terminated.*> 15 iterations/,
'compiled template respects WHILE_MAX = 15');

# Change WHILE_MAX and re-process the same compiled template
$Template::Directive::WHILE_MAX = 8;
$output = '';
$tt_comp->process('loop.tt', {}, \$output) || die $tt_comp->error;
like($output, qr/^\.{8}WHILE loop terminated.*> 8 iterations/,
'compiled-to-disk template picks up WHILE_MAX = 8 at runtime');