diff --git a/src/Environment.php b/src/Environment.php index 5b50f0249..bbd99b727 100644 --- a/src/Environment.php +++ b/src/Environment.php @@ -808,17 +808,14 @@ class Environment return array_merge($this->extensionSet->getGlobals(), $this->globals); } + /** + * @deprecated since Twig 3.13 + */ public function mergeGlobals(array $context): array { - // we don't use array_merge as the context being generally - // bigger than globals, this code is faster. - foreach ($this->getGlobals() as $key => $value) { - if (!\array_key_exists($key, $context)) { - $context[$key] = $value; - } - } + trigger_deprecation('twig/twig', '3.13', 'The "%s" method is deprecated.', __METHOD__); - return $context; + return $context + $this->getGlobals(); } /** diff --git a/src/ExtensionSet.php b/src/ExtensionSet.php index 679076750..deec0da70 100644 --- a/src/ExtensionSet.php +++ b/src/ExtensionSet.php @@ -357,12 +357,7 @@ final class ExtensionSet continue; } - $extGlobals = $extension->getGlobals(); - if (!\is_array($extGlobals)) { - throw new \UnexpectedValueException(\sprintf('"%s::getGlobals()" must return an array of globals.', $extension::class)); - } - - $globals = array_merge($globals, $extGlobals); + $globals = array_merge($globals, $extension->getGlobals()); } if ($this->initialized) { diff --git a/src/Node/BlockNode.php b/src/Node/BlockNode.php index d5d87bc0a..36c47752b 100644 --- a/src/Node/BlockNode.php +++ b/src/Node/BlockNode.php @@ -31,7 +31,7 @@ class BlockNode extends Node $compiler ->addDebugInfo($this) ->write("/**\n") - ->write(" * @return iterable\n") + ->write(" * @return iterable\n") ->write(" */\n") ->write(\sprintf("public function block_%s(array \$context, array \$blocks = []): iterable\n", $this->getAttribute('name')), "{\n") ->indent() diff --git a/src/Node/MacroNode.php b/src/Node/MacroNode.php index ca08500da..7c9d64b4c 100644 --- a/src/Node/MacroNode.php +++ b/src/Node/MacroNode.php @@ -66,7 +66,7 @@ class MacroNode extends Node ->write("{\n") ->indent() ->write("\$macros = \$this->macros;\n") - ->write("\$context = \$this->env->mergeGlobals([\n") + ->write("\$context = [\n") ->indent() ; @@ -79,7 +79,7 @@ class MacroNode extends Node ; } - $node = new CaptureNode($this->getNode('body'), $this->getNode('body')->lineno, $this->getNode('body')->tag); + $node = new CaptureNode($this->getNode('body'), $this->getNode('body')->lineno); $compiler ->write('') @@ -87,7 +87,7 @@ class MacroNode extends Node ->raw(' => ') ->raw("\$__varargs__,\n") ->outdent() - ->write("]);\n\n") + ->write("] + \$this->env->getGlobals();\n\n") ->write("\$blocks = [];\n\n") ->write('return ') ->subcompile($node) diff --git a/src/Node/WithNode.php b/src/Node/WithNode.php index f9104948b..487e2800b 100644 --- a/src/Node/WithNode.php +++ b/src/Node/WithNode.php @@ -61,7 +61,7 @@ class WithNode extends Node $compiler->write("\$context = [];\n"); } - $compiler->write(\sprintf("\$context = \$this->env->mergeGlobals(array_merge(\$context, \$%s));\n", $varsName)); + $compiler->write(\sprintf("\$context = \$%s + \$context + \$this->env->getGlobals();\n", $varsName)); } $compiler diff --git a/src/Template.php b/src/Template.php index 25b74b5cb..80ef58671 100644 --- a/src/Template.php +++ b/src/Template.php @@ -68,7 +68,7 @@ abstract class Template * @param array $context An array of parameters to pass to the template * @param array $blocks An array of blocks to pass to the template * - * @return iterable + * @return iterable */ abstract protected function doDisplay(array $context, array $blocks = []): iterable; @@ -331,11 +331,11 @@ abstract class Template } /** - * @return iterable + * @return iterable */ public function yield(array $context, array $blocks = []): iterable { - $context = $this->env->mergeGlobals($context); + $context += $this->env->getGlobals(); $blocks = array_merge($this->blocks, $blocks); try { @@ -361,7 +361,7 @@ abstract class Template } /** - * @return iterable + * @return iterable */ public function yieldBlock($name, array $context, array $blocks = [], $useBlocks = true, ?self $templateContext = null): iterable { @@ -421,7 +421,7 @@ abstract class Template * @param array $context The context * @param array $blocks The current set of blocks * - * @return iterable + * @return iterable */ public function yieldParentBlock($name, array $context, array $blocks = []): iterable { diff --git a/src/TemplateWrapper.php b/src/TemplateWrapper.php index c31f50161..135c59188 100644 --- a/src/TemplateWrapper.php +++ b/src/TemplateWrapper.php @@ -57,12 +57,12 @@ final class TemplateWrapper public function renderBlock(string $name, array $context = []): string { - return $this->template->renderBlock($name, $this->env->mergeGlobals($context)); + return $this->template->renderBlock($name, $context + $this->env->getGlobals()); } public function displayBlock(string $name, array $context = []) { - $context = $this->env->mergeGlobals($context); + $context += $this->env->getGlobals(); foreach ($this->template->yieldBlock($name, $context) as $data) { echo $data; } diff --git a/src/TokenParser/TypesTokenParser.php b/src/TokenParser/TypesTokenParser.php index b579fd0c0..2172ed263 100644 --- a/src/TokenParser/TypesTokenParser.php +++ b/src/TokenParser/TypesTokenParser.php @@ -62,14 +62,14 @@ final class TypesTokenParser extends AbstractTokenParser $first = false; $nameToken = $stream->expect(Token::NAME_TYPE); - $isOptional = $stream->nextIf(Token::PUNCTUATION_TYPE, '?') !== null; + $isOptional = null !== $stream->nextIf(Token::PUNCTUATION_TYPE, '?'); $stream->expect(Token::PUNCTUATION_TYPE, ':', 'A type name must be followed by a colon (:)'); $valueToken = $stream->expect(Token::STRING_TYPE); $types[$nameToken->getValue()] = [ - 'type' => $valueToken->getValue(), + 'type' => $valueToken->getValue(), 'optional' => $isOptional, ]; } diff --git a/src/Util/ReflectionCallable.php b/src/Util/ReflectionCallable.php index 4214abcbb..5fd5d1ba7 100644 --- a/src/Util/ReflectionCallable.php +++ b/src/Util/ReflectionCallable.php @@ -25,7 +25,7 @@ final class ReflectionCallable private string $name; public function __construct( - private TwigCallableInterface $twigCallable, + TwigCallableInterface $twigCallable, ) { $callable = $twigCallable->getCallable(); if (\is_string($callable) && false !== $pos = strpos($callable, '::')) { diff --git a/tests/Cache/FilesystemTest.php b/tests/Cache/FilesystemTest.php index 5396ada83..d66d20b69 100644 --- a/tests/Cache/FilesystemTest.php +++ b/tests/Cache/FilesystemTest.php @@ -81,9 +81,6 @@ class FilesystemTest extends TestCase public function testWriteFailMkdir() { - $this->expectException(\RuntimeException::class); - $this->expectExceptionMessage('Unable to create the cache directory'); - if (\defined('PHP_WINDOWS_VERSION_BUILD')) { $this->markTestSkipped('Read-only directories not possible on Windows.'); } @@ -97,14 +94,14 @@ class FilesystemTest extends TestCase @mkdir($this->directory, 0555, true); $this->assertDirectoryExists($this->directory); + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage('Unable to create the cache directory'); + $this->cache->write($key, $content); } public function testWriteFailDirWritable() { - $this->expectException(\RuntimeException::class); - $this->expectExceptionMessage('Unable to write in the cache directory'); - if (\defined('PHP_WINDOWS_VERSION_BUILD')) { $this->markTestSkipped('Read-only directories not possible on Windows.'); } @@ -120,14 +117,14 @@ class FilesystemTest extends TestCase @mkdir($this->directory.'/cache', 0555); $this->assertDirectoryExists($this->directory.'/cache'); + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage('Unable to write in the cache directory'); + $this->cache->write($key, $content); } public function testWriteFailWriteFile() { - $this->expectException(\RuntimeException::class); - $this->expectExceptionMessage('Failed to write cache file'); - $key = $this->directory.'/cache/cachefile.php'; $content = $this->generateSource(); @@ -137,6 +134,9 @@ class FilesystemTest extends TestCase @mkdir($key, 0777, true); $this->assertDirectoryExists($key); + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage('Failed to write cache file'); + $this->cache->write($key, $content); } diff --git a/tests/CustomExtensionTest.php b/tests/CustomExtensionTest.php index e50bb9ca2..a38fe7531 100644 --- a/tests/CustomExtensionTest.php +++ b/tests/CustomExtensionTest.php @@ -22,11 +22,12 @@ class CustomExtensionTest extends TestCase #[DataProvider('provideInvalidExtensions')] public function testGetInvalidOperators(ExtensionInterface $extension, $expectedExceptionMessage) { + $env = new Environment(new ArrayLoader()); + $env->addExtension($extension); + $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage($expectedExceptionMessage); - $env = new Environment(new ArrayLoader()); - $env->addExtension($extension); $env->getUnaryOperators(); } diff --git a/tests/EnvironmentTest.php b/tests/EnvironmentTest.php index 91c5aa32c..b9b5d8e47 100644 --- a/tests/EnvironmentTest.php +++ b/tests/EnvironmentTest.php @@ -47,7 +47,7 @@ class EnvironmentTest extends TestCase $this->assertEquals(Environment::MINOR_VERSION, $exploded[1]); $this->assertEquals(Environment::RELEASE_VERSION, $exploded[2]); - $this->assertEquals(Environment::VERSION_ID, \sprintf('%s0%s0%s', $exploded[0], $exploded[1], $exploded[2])); + $this->assertEquals(Environment::VERSION_ID, Environment::MAJOR_VERSION * 10000 + Environment::MINOR_VERSION * 100 + Environment::RELEASE_VERSION); } public function testAutoescapeOption() @@ -177,7 +177,7 @@ class EnvironmentTest extends TestCase // force compilation $twig = new Environment($loader = new ArrayLoader(['index' => '{{ foo }}']), $options); - $twig->addExtension($extension = new class extends AbstractExtension { + $twig->addExtension($extension = new class() extends AbstractExtension { public bool $throw = false; public function getFilters(): array @@ -334,12 +334,12 @@ class EnvironmentTest extends TestCase public function testOverrideExtension() { + $twig = new Environment(new ArrayLoader()); + $twig->addExtension(new EnvironmentTest_Extension()); + $this->expectException(\LogicException::class); $this->expectExceptionMessage('Unable to register extension "Twig\Tests\EnvironmentTest_Extension" as it is already registered.'); - $twig = new Environment(new ArrayLoader()); - - $twig->addExtension(new EnvironmentTest_Extension()); $twig->addExtension(new EnvironmentTest_Extension()); } @@ -372,11 +372,12 @@ class EnvironmentTest extends TestCase public function testFailLoadTemplate() { + $template = 'testFailLoadTemplate.twig'; + $twig = new Environment(new ArrayLoader([$template => false])); + $this->expectException(RuntimeError::class); $this->expectExceptionMessage('Failed to load Twig template "testFailLoadTemplate.twig", index "112233": cache might be corrupted in "testFailLoadTemplate.twig".'); - $template = 'testFailLoadTemplate.twig'; - $twig = new Environment(new ArrayLoader([$template => false])); $twig->loadTemplate($twig->getTemplateClass($template), $template, 112233); } diff --git a/tests/ExpressionParserTest.php b/tests/ExpressionParserTest.php index 84592bb4e..8adffce9b 100644 --- a/tests/ExpressionParserTest.php +++ b/tests/ExpressionParserTest.php @@ -32,10 +32,10 @@ class ExpressionParserTest extends TestCase #[DataProvider('getFailingTestsForAssignment')] public function testCanOnlyAssignToNames($template) { - $this->expectException(SyntaxError::class); - $env = new Environment(new ArrayLoader(), ['cache' => false, 'autoescape' => false]); $parser = new Parser($env); + + $this->expectException(SyntaxError::class); $parser->parse($env->tokenize(new Source($template, 'index'))); } @@ -71,10 +71,10 @@ class ExpressionParserTest extends TestCase #[DataProvider('getFailingTestsForSequence')] public function testSequenceSyntaxError($template) { - $this->expectException(SyntaxError::class); - $env = new Environment(new ArrayLoader(), ['cache' => false, 'autoescape' => false]); $parser = new Parser($env); + + $this->expectException(SyntaxError::class); $parser->parse($env->tokenize(new Source($template, 'index'))); } @@ -197,12 +197,11 @@ class ExpressionParserTest extends TestCase public function testStringExpressionDoesNotConcatenateTwoConsecutiveStrings() { - $this->expectException(SyntaxError::class); - $env = new Environment(new ArrayLoader(), ['cache' => false, 'autoescape' => false, 'optimizations' => 0]); $stream = $env->tokenize(new Source('{{ "a" "b" }}', 'index')); $parser = new Parser($env); + $this->expectException(SyntaxError::class); $parser->parse($stream); } @@ -263,44 +262,42 @@ class ExpressionParserTest extends TestCase public function testAttributeCallDoesNotSupportNamedArguments() { - $this->expectException(SyntaxError::class); - $env = new Environment(new ArrayLoader(), ['cache' => false, 'autoescape' => false]); $parser = new Parser($env); + $this->expectException(SyntaxError::class); $parser->parse($env->tokenize(new Source('{{ foo.bar(name="Foo") }}', 'index'))); } public function testMacroCallDoesNotSupportNamedArguments() { - $this->expectException(SyntaxError::class); - $env = new Environment(new ArrayLoader(), ['cache' => false, 'autoescape' => false]); $parser = new Parser($env); + $this->expectException(SyntaxError::class); $parser->parse($env->tokenize(new Source('{% from _self import foo %}{% macro foo() %}{% endmacro %}{{ foo(name="Foo") }}', 'index'))); } public function testMacroDefinitionDoesNotSupportNonNameVariableName() { - $this->expectException(SyntaxError::class); - $this->expectExceptionMessage('An argument must be a name. Unexpected token "string" of value "a" ("name" expected) in "index" at line 1.'); - $env = new Environment(new ArrayLoader(), ['cache' => false, 'autoescape' => false]); $parser = new Parser($env); + $this->expectException(SyntaxError::class); + $this->expectExceptionMessage('An argument must be a name. Unexpected token "string" of value "a" ("name" expected) in "index" at line 1.'); + $parser->parse($env->tokenize(new Source('{% macro foo("a") %}{% endmacro %}', 'index'))); } #[DataProvider('getMacroDefinitionDoesNotSupportNonConstantDefaultValues')] public function testMacroDefinitionDoesNotSupportNonConstantDefaultValues($template) { - $this->expectException(SyntaxError::class); - $this->expectExceptionMessage('A default value for an argument must be a constant (a boolean, a string, a number, a sequence, or a mapping) in "index" at line 1'); - $env = new Environment(new ArrayLoader(), ['cache' => false, 'autoescape' => false]); $parser = new Parser($env); + $this->expectException(SyntaxError::class); + $this->expectExceptionMessage('A default value for an argument must be a constant (a boolean, a string, a number, a sequence, or a mapping) in "index" at line 1'); + $parser->parse($env->tokenize(new Source($template, 'index'))); } @@ -340,67 +337,68 @@ class ExpressionParserTest extends TestCase public function testUnknownFunction() { - $this->expectException(SyntaxError::class); - $this->expectExceptionMessage('Unknown "cycl" function. Did you mean "cycle" in "index" at line 1?'); - $env = new Environment(new ArrayLoader(), ['cache' => false, 'autoescape' => false]); $parser = new Parser($env); + $this->expectException(SyntaxError::class); + $this->expectExceptionMessage('Unknown "cycl" function. Did you mean "cycle" in "index" at line 1?'); + $parser->parse($env->tokenize(new Source('{{ cycl() }}', 'index'))); } public function testUnknownFunctionWithoutSuggestions() { - $this->expectException(SyntaxError::class); - $this->expectExceptionMessage('Unknown "foobar" function in "index" at line 1.'); - $env = new Environment(new ArrayLoader(), ['cache' => false, 'autoescape' => false]); $parser = new Parser($env); + $this->expectException(SyntaxError::class); + $this->expectExceptionMessage('Unknown "foobar" function in "index" at line 1.'); + $parser->parse($env->tokenize(new Source('{{ foobar() }}', 'index'))); } public function testUnknownFilter() { - $this->expectException(SyntaxError::class); - $this->expectExceptionMessage('Unknown "lowe" filter. Did you mean "lower" in "index" at line 1?'); - $env = new Environment(new ArrayLoader(), ['cache' => false, 'autoescape' => false]); $parser = new Parser($env); + $this->expectException(SyntaxError::class); + $this->expectExceptionMessage('Unknown "lowe" filter. Did you mean "lower" in "index" at line 1?'); + $parser->parse($env->tokenize(new Source('{{ 1|lowe }}', 'index'))); } public function testUnknownFilterWithoutSuggestions() { - $this->expectException(SyntaxError::class); - $this->expectExceptionMessage('Unknown "foobar" filter in "index" at line 1.'); - $env = new Environment(new ArrayLoader(), ['cache' => false, 'autoescape' => false]); $parser = new Parser($env); + $this->expectException(SyntaxError::class); + $this->expectExceptionMessage('Unknown "foobar" filter in "index" at line 1.'); + $parser->parse($env->tokenize(new Source('{{ 1|foobar }}', 'index'))); } public function testUnknownTest() { - $this->expectException(SyntaxError::class); - $this->expectExceptionMessage('Unknown "nul" test. Did you mean "null" in "index" at line 1'); - $env = new Environment(new ArrayLoader(), ['cache' => false, 'autoescape' => false]); $parser = new Parser($env); $stream = $env->tokenize(new Source('{{ 1 is nul }}', 'index')); + + $this->expectException(SyntaxError::class); + $this->expectExceptionMessage('Unknown "nul" test. Did you mean "null" in "index" at line 1'); + $parser->parse($stream); } public function testUnknownTestWithoutSuggestions() { - $this->expectException(SyntaxError::class); - $this->expectExceptionMessage('Unknown "foobar" test in "index" at line 1.'); - $env = new Environment(new ArrayLoader(), ['cache' => false, 'autoescape' => false]); $parser = new Parser($env); + $this->expectException(SyntaxError::class); + $this->expectExceptionMessage('Unknown "foobar" test in "index" at line 1.'); + $parser->parse($env->tokenize(new Source('{{ 1 is foobar }}', 'index'))); } diff --git a/tests/Extension/CoreTest.php b/tests/Extension/CoreTest.php index 808b71d88..5f936872c 100644 --- a/tests/Extension/CoreTest.php +++ b/tests/Extension/CoreTest.php @@ -50,7 +50,8 @@ class CoreTest extends TestCase { return [ 'empty' => [[]], - 'non-countable' => [new class extends \ArrayObject{}], + 'non-countable' => [new class() extends \ArrayObject { + }], ]; } diff --git a/tests/Extension/SandboxTest.php b/tests/Extension/SandboxTest.php index 551ddad4c..ae945cb87 100644 --- a/tests/Extension/SandboxTest.php +++ b/tests/Extension/SandboxTest.php @@ -69,10 +69,11 @@ class SandboxTest extends TestCase #[DataProvider('getSandboxedForCoreTagsTests')] public function testSandboxForCoreTags(string $tag, string $template) { - $this->expectException(SecurityError::class); - $this->expectExceptionMessageMatches(sprintf('/Tag "%s" is not allowed in "index \(string template .+?\)" at line 1/', $tag)); - $twig = $this->getEnvironment(true, [], self::$templates, []); + + $this->expectException(SecurityError::class); + $this->expectExceptionMessageMatches(\sprintf('/Tag "%s" is not allowed in "index \(string template .+?\)" at line 1/', $tag)); + $twig->createTemplate($template, 'index')->render([]); } @@ -94,16 +95,18 @@ class SandboxTest extends TestCase yield ['macro', '{% macro foo() %}{% endmacro %}']; yield ['sandbox', '{% sandbox %}{% endsandbox %}']; yield ['set', '{% set foo = 1 %}']; + yield ['extends', '{% extends "1_empty" %}']; yield ['use', '{% use "1_empty" %}']; yield ['with', '{% with foo %}{% endwith %}']; } public function testSandboxWithInheritance() { + $twig = $this->getEnvironment(true, [], self::$templates, ['extends', 'block']); + $this->expectException(SecurityError::class); $this->expectExceptionMessage('Filter "json_encode" is not allowed in "1_child" at line 3.'); - $twig = $this->getEnvironment(true, [], self::$templates, ['extends', 'block']); $twig->load('1_child')->render([]); } @@ -413,14 +416,14 @@ EOF public function testSandboxWithNoClosureFilter() { - $this->expectException(RuntimeError::class); - $this->expectExceptionMessage('The callable passed to the "filter" filter must be a Closure in sandbox mode in "index" at line 1.'); - $twig = $this->getEnvironment(true, ['autoescape' => 'html'], ['index' => <<expectException(RuntimeError::class); + $this->expectExceptionMessage('The callable passed to the "filter" filter must be a Closure in sandbox mode in "index" at line 1.'); + $twig->load('index')->render([]); } diff --git a/tests/LexerTest.php b/tests/LexerTest.php index ead83e2af..465ce2f22 100644 --- a/tests/LexerTest.php +++ b/tests/LexerTest.php @@ -290,12 +290,12 @@ class LexerTest extends TestCase public function testStringWithUnterminatedInterpolation() { + $template = '{{ "bar #{x" }}'; + $lexer = new Lexer(new Environment(new ArrayLoader())); + $this->expectException(SyntaxError::class); $this->expectExceptionMessage('Unclosed """'); - $template = '{{ "bar #{x" }}'; - - $lexer = new Lexer(new Environment(new ArrayLoader())); $lexer->tokenize(new Source($template, 'index')); } @@ -359,9 +359,6 @@ class LexerTest extends TestCase public function testUnterminatedVariable() { - $this->expectException(SyntaxError::class); - $this->expectExceptionMessage('Unclosed "variable" in "index" at line 3'); - $template = ' {{ @@ -372,14 +369,14 @@ bar '; $lexer = new Lexer(new Environment(new ArrayLoader())); + + $this->expectException(SyntaxError::class); + $this->expectExceptionMessage('Unclosed "variable" in "index" at line 3'); $lexer->tokenize(new Source($template, 'index')); } public function testUnterminatedBlock() { - $this->expectException(SyntaxError::class); - $this->expectExceptionMessage('Unclosed "block" in "index" at line 3'); - $template = ' {% @@ -390,6 +387,10 @@ bar '; $lexer = new Lexer(new Environment(new ArrayLoader())); + + $this->expectException(SyntaxError::class); + $this->expectExceptionMessage('Unclosed "block" in "index" at line 3'); + $lexer->tokenize(new Source($template, 'index')); } diff --git a/tests/Loader/ArrayTest.php b/tests/Loader/ArrayTest.php index 543fe9ff6..478adf931 100644 --- a/tests/Loader/ArrayTest.php +++ b/tests/Loader/ArrayTest.php @@ -19,10 +19,9 @@ class ArrayTest extends TestCase { public function testGetSourceContextWhenTemplateDoesNotExist() { - $this->expectException(LoaderError::class); - $loader = new ArrayLoader(); + $this->expectException(LoaderError::class); $loader->getSourceContext('foo'); } @@ -57,10 +56,9 @@ class ArrayTest extends TestCase public function testGetCacheKeyWhenTemplateDoesNotExist() { - $this->expectException(LoaderError::class); - $loader = new ArrayLoader(); + $this->expectException(LoaderError::class); $loader->getCacheKey('foo'); } @@ -80,10 +78,9 @@ class ArrayTest extends TestCase public function testIsFreshWhenTemplateDoesNotExist() { - $this->expectException(LoaderError::class); - $loader = new ArrayLoader(); + $this->expectException(LoaderError::class); $loader->isFresh('foo', time()); } } diff --git a/tests/Loader/ChainTest.php b/tests/Loader/ChainTest.php index 52d6d4c72..16ccb9473 100644 --- a/tests/Loader/ChainTest.php +++ b/tests/Loader/ChainTest.php @@ -43,10 +43,9 @@ class ChainTest extends TestCase public function testGetSourceContextWhenTemplateDoesNotExist() { - $this->expectException(LoaderError::class); - $loader = new ChainLoader([]); + $this->expectException(LoaderError::class); $loader->getSourceContext('foo'); } @@ -63,10 +62,9 @@ class ChainTest extends TestCase public function testGetCacheKeyWhenTemplateDoesNotExist() { - $this->expectException(LoaderError::class); - $loader = new ChainLoader([]); + $this->expectException(LoaderError::class); $loader->getCacheKey('foo'); } diff --git a/tests/Node/BlockTest.php b/tests/Node/BlockTest.php index 13447ae7d..66e7ac52f 100644 --- a/tests/Node/BlockTest.php +++ b/tests/Node/BlockTest.php @@ -35,7 +35,7 @@ class BlockTest extends NodeTestCase $tests[] = [new BlockNode('foo', new TextNode('foo', 1), 1), << + * @return iterable */ public function block_foo(array \$context, array \$blocks = []): iterable { diff --git a/tests/Node/Expression/FilterTest.php b/tests/Node/Expression/FilterTest.php index 747af6f4c..3c667b5be 100644 --- a/tests/Node/Expression/FilterTest.php +++ b/tests/Node/Expression/FilterTest.php @@ -126,29 +126,31 @@ class FilterTest extends NodeTestCase public function testCompileWithWrongNamedArgumentName() { - $this->expectException(SyntaxError::class); - $this->expectExceptionMessage('Unknown argument "foobar" for filter "date(format, timezone)" at line 1.'); - $date = new ConstantExpression(0, 1); $node = $this->createFilter($this->getEnvironment(), $date, 'date', [ 'foobar' => new ConstantExpression('America/Chicago', 1), ]); $compiler = $this->getCompiler(); + + $this->expectException(SyntaxError::class); + $this->expectExceptionMessage('Unknown argument "foobar" for filter "date(format, timezone)" at line 1.'); + $compiler->compile($node); } public function testCompileWithMissingNamedArgument() { - $this->expectException(SyntaxError::class); - $this->expectExceptionMessage('Value for argument "from" is required for filter "replace" at line 1.'); - $value = new ConstantExpression(0, 1); $node = $this->createFilter($this->getEnvironment(), $value, 'replace', [ 'to' => new ConstantExpression('foo', 1), ]); $compiler = $this->getCompiler(); + + $this->expectException(SyntaxError::class); + $this->expectExceptionMessage('Value for argument "from" is required for filter "replace" at line 1.'); + $compiler->compile($node); } @@ -173,7 +175,7 @@ class FilterTest extends NodeTestCase private static function createExtension(): AbstractExtension { - return new class extends AbstractExtension { + return new class() extends AbstractExtension { public function getFilters(): array { return [ diff --git a/tests/Node/MacroTest.php b/tests/Node/MacroTest.php index abda32418..33c548f4d 100644 --- a/tests/Node/MacroTest.php +++ b/tests/Node/MacroTest.php @@ -49,11 +49,11 @@ class MacroTest extends NodeTestCase public function macro_foo(\$__foo__ = null, \$__bar__ = "Foo", ...\$__varargs__) { \$macros = \$this->macros; - \$context = \$this->env->mergeGlobals([ + \$context = [ "foo" => \$__foo__, "bar" => \$__bar__, "varargs" => \$__varargs__, - ]); + ] + \$this->env->getGlobals(); \$blocks = []; @@ -71,11 +71,11 @@ EOF public function macro_foo(\$__foo__ = null, \$__bar__ = "Foo", ...\$__varargs__) { \$macros = \$this->macros; - \$context = \$this->env->mergeGlobals([ + \$context = [ "foo" => \$__foo__, "bar" => \$__bar__, "varargs" => \$__varargs__, - ]); + ] + \$this->env->getGlobals(); \$blocks = []; diff --git a/tests/ParserTest.php b/tests/ParserTest.php index af74ba7c2..7fc98e58e 100644 --- a/tests/ParserTest.php +++ b/tests/ParserTest.php @@ -30,9 +30,6 @@ class ParserTest extends TestCase { public function testUnknownTag() { - $this->expectException(SyntaxError::class); - $this->expectExceptionMessage('Unknown "foo" tag. Did you mean "for" at line 1?'); - $stream = new TokenStream([ new Token(Token::BLOCK_START_TYPE, '', 1), new Token(Token::NAME_TYPE, 'foo', 1), @@ -40,14 +37,15 @@ class ParserTest extends TestCase new Token(Token::EOF_TYPE, '', 1), ]); $parser = new Parser(new Environment(new ArrayLoader())); + + $this->expectException(SyntaxError::class); + $this->expectExceptionMessage('Unknown "foo" tag. Did you mean "for" at line 1?'); + $parser->parse($stream); } public function testUnknownTagWithoutSuggestions() { - $this->expectException(SyntaxError::class); - $this->expectExceptionMessage('Unknown "foobar" tag at line 1.'); - $stream = new TokenStream([ new Token(Token::BLOCK_START_TYPE, '', 1), new Token(Token::NAME_TYPE, 'foobar', 1), @@ -55,6 +53,10 @@ class ParserTest extends TestCase new Token(Token::EOF_TYPE, '', 1), ]); $parser = new Parser(new Environment(new ArrayLoader())); + + $this->expectException(SyntaxError::class); + $this->expectExceptionMessage('Unknown "foobar" tag at line 1.'); + $parser->parse($stream); } @@ -87,11 +89,11 @@ class ParserTest extends TestCase #[DataProvider('getFilterBodyNodesDataThrowsException')] public function testFilterBodyNodesThrowsException($input) { - $this->expectException(SyntaxError::class); - $parser = $this->getParser(); $m = new \ReflectionMethod($parser, 'filterBodyNodes'); + + $this->expectException(SyntaxError::class); $m->invoke($parser, $input); } @@ -186,7 +188,7 @@ EOF $this->assertNull($argumentNodes->getNode('po')->getAttribute('value')); $this->assertFalse($argumentNodes->getNode('lo')->hasAttribute('is_implicit')); - $this->assertSame(true, $argumentNodes->getNode('lo')->getAttribute('value')); + $this->assertTrue($argumentNodes->getNode('lo')->getAttribute('value')); } protected function getParser() diff --git a/tests/TemplateTest.php b/tests/TemplateTest.php index 541acebe5..48e1f4478 100644 --- a/tests/TemplateTest.php +++ b/tests/TemplateTest.php @@ -28,10 +28,10 @@ class TemplateTest extends TestCase { public function testDisplayBlocksAcceptTemplateOnlyAsBlocks() { - $this->expectException(\LogicException::class); - $twig = new Environment(new ArrayLoader()); $template = new TemplateForTest($twig); + + $this->expectException(\LogicException::class); $template->renderBlock('foo', [], ['foo' => [new \stdClass(), 'foo']]); } @@ -138,21 +138,22 @@ class TemplateTest extends TestCase public function testRenderBlockWithUndefinedBlock() { + $twig = new Environment(new ArrayLoader()); + $template = new TemplateForTest($twig, 'index.twig'); + $this->expectException(RuntimeError::class); $this->expectExceptionMessage('Block "unknown" on template "index.twig" does not exist in "index.twig".'); - $twig = new Environment(new ArrayLoader()); - $template = new TemplateForTest($twig, 'index.twig'); $template->renderBlock('unknown', []); } public function testRenderBlockWithUndefinedParentBlock() { - $this->expectException(RuntimeError::class); - $this->expectExceptionMessage('Block "foo" should not call parent() in "index.twig" as the block does not exist in the parent template "parent.twig"'); - $twig = new Environment(new ArrayLoader()); $template = new TemplateForTest($twig, 'parent.twig'); + + $this->expectException(RuntimeError::class); + $this->expectExceptionMessage('Block "foo" should not call parent() in "index.twig" as the block does not exist in the parent template "parent.twig"'); $template->renderBlock('foo', [], ['foo' => [new TemplateForTest($twig, 'index.twig'), 'block_foo']], false); } @@ -418,12 +419,12 @@ class TemplateForTest extends Template return $this->name; } - public function getDebugInfo() : array + public function getDebugInfo(): array { return []; } - public function getSourceContext() : Source + public function getSourceContext(): Source { return new Source('', $this->getTemplateName()); } diff --git a/tests/TokenParser/TypesTokenParserTest.php b/tests/TokenParser/TypesTokenParserTest.php index 42a27f810..f477e7715 100644 --- a/tests/TokenParser/TypesTokenParserTest.php +++ b/tests/TokenParser/TypesTokenParserTest.php @@ -15,7 +15,7 @@ class TypesTokenParserTest extends TestCase public function testMappingParsing(string $template, array $expected): void { $env = new Environment(new ArrayLoader(), ['cache' => false, 'autoescape' => false]); - $stream = $env->tokenize($source = new Source($template, '')); + $stream = $env->tokenize(new Source($template, '')); $parser = new Parser($env); $typesNode = $parser->parse($stream)->getNode('body')->getNode('0'); @@ -36,7 +36,7 @@ class TypesTokenParserTest extends TestCase [ '{% types {foo: "bar"} %}', [ - 'foo' => ['type' => 'bar', 'optional' => false] + 'foo' => ['type' => 'bar', 'optional' => false], ], ], @@ -44,7 +44,7 @@ class TypesTokenParserTest extends TestCase [ '{% types {foo: "bar",} %}', [ - 'foo' => ['type' => 'bar', 'optional' => false] + 'foo' => ['type' => 'bar', 'optional' => false], ], ], @@ -52,7 +52,7 @@ class TypesTokenParserTest extends TestCase [ '{% types {foo?: "bar"} %}', [ - 'foo' => ['type' => 'bar', 'optional' => true] + 'foo' => ['type' => 'bar', 'optional' => true], ], ], @@ -62,7 +62,7 @@ class TypesTokenParserTest extends TestCase [ 'foo' => ['type' => 'foo', 'optional' => false], 'bar' => ['type' => 'foo', 'optional' => true], - 'baz' => ['type' => 'baz', 'optional' => false] + 'baz' => ['type' => 'baz', 'optional' => false], ], ], ]; diff --git a/tests/TokenStreamTest.php b/tests/TokenStreamTest.php index e8cb474b3..8f86ac87a 100644 --- a/tests/TokenStreamTest.php +++ b/tests/TokenStreamTest.php @@ -48,12 +48,13 @@ class TokenStreamTest extends TestCase public function testEndOfTemplateNext() { - $this->expectException(SyntaxError::class); - $this->expectExceptionMessage('Unexpected end of template'); - $stream = new TokenStream([ new Token(Token::BLOCK_START_TYPE, 1, 1), ]); + + $this->expectException(SyntaxError::class); + $this->expectExceptionMessage('Unexpected end of template'); + while (!$stream->isEOF()) { $stream->next(); } @@ -61,12 +62,13 @@ class TokenStreamTest extends TestCase public function testEndOfTemplateLook() { - $this->expectException(SyntaxError::class); - $this->expectExceptionMessage('Unexpected end of template'); - $stream = new TokenStream([ new Token(Token::BLOCK_START_TYPE, 1, 1), ]); + + $this->expectException(SyntaxError::class); + $this->expectExceptionMessage('Unexpected end of template'); + while (!$stream->isEOF()) { $stream->look(); $stream->next();