mirror of
https://github.com/twigphp/Twig.git
synced 2026-08-17 13:53:35 +00:00
Skip the string cast in PrintNode when the expression is already a string and add tests
This commit is contained in:
@@ -73,7 +73,7 @@ class ForTest extends NodeTestCase
|
||||
\$context['_parent'] = \$context;
|
||||
\$context['_seq'] = CoreExtension::ensureTraversable($itemsGetter);
|
||||
foreach (\$context['_seq'] as \$context["key"] => \$context["item"]) {
|
||||
yield $fooGetter;
|
||||
yield (string) $fooGetter;
|
||||
}
|
||||
\$_parent = \$context['_parent'];
|
||||
unset(\$context['_seq'], \$context['key'], \$context['item'], \$context['_parent']);
|
||||
@@ -107,7 +107,7 @@ if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_
|
||||
\$context['loop']['last'] = 1 === \$length;
|
||||
}
|
||||
foreach (\$context['_seq'] as \$context["k"] => \$context["v"]) {
|
||||
yield $fooGetter;
|
||||
yield (string) $fooGetter;
|
||||
++\$context['loop']['index0'];
|
||||
++\$context['loop']['index'];
|
||||
\$context['loop']['first'] = false;
|
||||
@@ -149,7 +149,7 @@ if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_
|
||||
\$context['loop']['last'] = 1 === \$length;
|
||||
}
|
||||
foreach (\$context['_seq'] as \$context["k"] => \$context["v"]) {
|
||||
yield $fooGetter;
|
||||
yield (string) $fooGetter;
|
||||
++\$context['loop']['index0'];
|
||||
++\$context['loop']['index'];
|
||||
\$context['loop']['first'] = false;
|
||||
@@ -192,7 +192,7 @@ if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_
|
||||
\$context['loop']['last'] = 1 === \$length;
|
||||
}
|
||||
foreach (\$context['_seq'] as \$context["k"] => \$context["v"]) {
|
||||
yield $fooGetter;
|
||||
yield (string) $fooGetter;
|
||||
\$context['_iterated'] = true;
|
||||
++\$context['loop']['index0'];
|
||||
++\$context['loop']['index'];
|
||||
@@ -206,7 +206,7 @@ foreach (\$context['_seq'] as \$context["k"] => \$context["v"]) {
|
||||
// line 5
|
||||
if (!\$context['_iterated']) {
|
||||
// line 6
|
||||
yield $fooGetter;
|
||||
yield (string) $fooGetter;
|
||||
}
|
||||
\$_parent = \$context['_parent'];
|
||||
unset(\$context['_seq'], \$context['k'], \$context['v'], \$context['_parent'], \$context['_iterated'], \$context['loop']);
|
||||
|
||||
@@ -63,7 +63,7 @@ class IfTest extends NodeTestCase
|
||||
$tests[] = [$node, <<<EOF
|
||||
// line 1
|
||||
if (true) {
|
||||
yield $fooGetter;
|
||||
yield (string) $fooGetter;
|
||||
}
|
||||
EOF
|
||||
];
|
||||
@@ -80,9 +80,9 @@ EOF
|
||||
$tests[] = [$node, <<<EOF
|
||||
// line 1
|
||||
if (true) {
|
||||
yield $fooGetter;
|
||||
yield (string) $fooGetter;
|
||||
} elseif (false) {
|
||||
yield $barGetter;
|
||||
yield (string) $barGetter;
|
||||
}
|
||||
EOF
|
||||
];
|
||||
@@ -97,9 +97,9 @@ EOF
|
||||
$tests[] = [$node, <<<EOF
|
||||
// line 1
|
||||
if (true) {
|
||||
yield $fooGetter;
|
||||
yield (string) $fooGetter;
|
||||
} else {
|
||||
yield $barGetter;
|
||||
yield (string) $barGetter;
|
||||
}
|
||||
EOF
|
||||
];
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace Twig\Tests\Node;
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Twig\Node\Expression\Binary\ConcatBinary;
|
||||
use Twig\Node\Expression\ConstantExpression;
|
||||
use Twig\Node\Expression\GetAttrExpression;
|
||||
use Twig\Node\Expression\Variable\ContextVariable;
|
||||
@@ -40,8 +41,20 @@ class PrintTest extends NodeTestCase
|
||||
public static function provideTests(): iterable
|
||||
{
|
||||
$tests = [];
|
||||
|
||||
// a string literal is known to be a string, so the cast is skipped
|
||||
$tests[] = [new PrintNode(new ConstantExpression('foo', 1), 1), "// line 1\nyield \"foo\";"];
|
||||
|
||||
// a non-string expression is cast to make the conversion happen here for a useful stack trace
|
||||
$tests[] = [new PrintNode(new ContextVariable('foo', 1), 1), "// line 1\nyield (string) (\$context[\"foo\"] ?? null);"];
|
||||
|
||||
// a non-string constant is cast as well
|
||||
$tests[] = [new PrintNode(new ConstantExpression(42, 1), 1), "// line 1\nyield (string) 42;"];
|
||||
|
||||
// a concatenation always returns a string, so the cast is skipped
|
||||
$concat = new ConcatBinary(new ContextVariable('foo', 1), new ContextVariable('bar', 1), 1);
|
||||
$tests[] = [new PrintNode($concat, 1), "// line 1\nyield ((\$context[\"foo\"] ?? null) . (\$context[\"bar\"] ?? null));"];
|
||||
|
||||
$expr = new ContextVariable('foo', 1);
|
||||
$attr = new ConstantExpression('bar', 1);
|
||||
$node = new GetAttrExpression($expr, $attr, null, Template::METHOD_CALL, 1);
|
||||
|
||||
@@ -376,6 +376,35 @@ class TemplateTest extends TestCase
|
||||
$this->assertNull(CoreExtension::getAttribute($twig, $template->getSourceContext(), $object, 'foo'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideNonStringPrintValues
|
||||
*/
|
||||
public function testPrintingANonStringReportsTheErrorAtThePrintLocation($value, string $expectedMessage)
|
||||
{
|
||||
$twig = new Environment(new ArrayLoader(['index' => "foo\n{{ value }}\nbar"]));
|
||||
|
||||
set_error_handler(static function (int $type, string $msg, string $file, int $line): bool {
|
||||
throw new \ErrorException($msg, 0, $type, $file, $line);
|
||||
}, \E_WARNING);
|
||||
|
||||
try {
|
||||
$twig->render('index', ['value' => $value]);
|
||||
$this->fail('Printing a non-string value should fail.');
|
||||
} catch (RuntimeError $e) {
|
||||
$this->assertSame('index', $e->getSourceContext()->getName());
|
||||
$this->assertSame(2, $e->getTemplateLine());
|
||||
$this->assertSame($expectedMessage, $e->getPrevious()->getMessage());
|
||||
} finally {
|
||||
restore_error_handler();
|
||||
}
|
||||
}
|
||||
|
||||
public static function provideNonStringPrintValues(): iterable
|
||||
{
|
||||
yield 'array' => [['a', 'b'], 'Array to string conversion'];
|
||||
yield 'non-Stringable object' => [new \stdClass(), 'Object of class stdClass could not be converted to string'];
|
||||
}
|
||||
|
||||
public static function getGetAttributeTests()
|
||||
{
|
||||
$array = [
|
||||
|
||||
Reference in New Issue
Block a user