|
12 | 12 | */
|
13 | 13 |
|
14 | 14 | use PHPUnit\Framework\TestCase;
|
| 15 | +use Twig\Attribute\YieldReady; |
| 16 | +use Twig\Compiler; |
15 | 17 | use Twig\Environment;
|
16 | 18 | use Twig\Error\Error;
|
17 | 19 | use Twig\Error\RuntimeError;
|
18 | 20 | use Twig\Error\SyntaxError;
|
19 | 21 | use Twig\Loader\ArrayLoader;
|
20 | 22 | use Twig\Loader\FilesystemLoader;
|
| 23 | +use Twig\Loader\LoaderInterface; |
| 24 | +use Twig\Node\Node; |
21 | 25 | use Twig\Source;
|
| 26 | +use Twig\Token; |
| 27 | +use Twig\TokenParser\AbstractTokenParser; |
22 | 28 |
|
23 | 29 | class ErrorTest extends TestCase
|
24 | 30 | {
|
@@ -253,6 +259,101 @@ public function testTwigExceptionUpdateFileAndLineTogether()
|
253 | 259 | }
|
254 | 260 | }
|
255 | 261 |
|
| 262 | + /** |
| 263 | + * @dataProvider getErrorWithoutLineAndContextData |
| 264 | + */ |
| 265 | + public function testErrorWithoutLineAndContext(LoaderInterface $loader, bool $debug, bool $addDebugInfo, bool $exceptionWithLineAndContext) |
| 266 | + { |
| 267 | + $twig = new Environment($loader, ['debug' => $debug, 'cache' => false]); |
| 268 | + $twig->removeCache('no_line_and_context_exception.twig'); |
| 269 | + $twig->removeCache('no_line_and_context_exception_include.twig'); |
| 270 | + $twig->addTokenParser(new class($addDebugInfo, $exceptionWithLineAndContext) extends AbstractTokenParser { |
| 271 | + public function __construct(private bool $addDebugInfo, private bool $exceptionWithLineAndContext) |
| 272 | + { |
| 273 | + } |
| 274 | + |
| 275 | + public function parse(Token $token) |
| 276 | + { |
| 277 | + $stream = $this->parser->getStream(); |
| 278 | + $stream->expect(Token::BLOCK_END_TYPE); |
| 279 | + $lineno = $stream->getCurrent()->getLine(); |
| 280 | + |
| 281 | + return new #[YieldReady]class($lineno, $this->addDebugInfo, $this->exceptionWithLineAndContext) extends Node |
| 282 | + { |
| 283 | + public function __construct(int $lineno,private bool $addDebugInfo, private bool $exceptionWithLineAndContext) |
| 284 | + { |
| 285 | + parent::__construct([], [], $lineno); |
| 286 | + } |
| 287 | + |
| 288 | + public function compile(Compiler $compiler): void |
| 289 | + { |
| 290 | + if ($this->addDebugInfo) { |
| 291 | + $compiler->addDebugInfo($this); |
| 292 | + } |
| 293 | + if ($this->exceptionWithLineAndContext) { |
| 294 | + $compiler |
| 295 | + ->write('throw new \Twig\Error\RuntimeError("Runtime error.", ') |
| 296 | + ->repr($this->lineno)->raw(", \$this->getSourceContext()") |
| 297 | + ->raw(');') |
| 298 | + ; |
| 299 | + } else { |
| 300 | + $compiler->write('throw new \Twig\Error\RuntimeError("Runtime error.");'); |
| 301 | + } |
| 302 | + } |
| 303 | + }; |
| 304 | + } |
| 305 | + |
| 306 | + public function getTag() |
| 307 | + { |
| 308 | + return 'foo'; |
| 309 | + } |
| 310 | + }); |
| 311 | + |
| 312 | + try { |
| 313 | + $twig->render('no_line_and_context_exception.twig'); |
| 314 | + $this->fail(); |
| 315 | + } catch (RuntimeError $e) { |
| 316 | + $line = $addDebugInfo || $exceptionWithLineAndContext ? 5 : 1; |
| 317 | + |
| 318 | + $this->assertSame(\sprintf('Runtime error in "no_line_and_context_exception_include.twig" at line %d.', $line), $e->getMessage()); |
| 319 | + $this->assertSame($line, $e->getTemplateLine()); |
| 320 | + |
| 321 | + if ($loader instanceof FilesystemLoader) { |
| 322 | + $this->assertStringContainsString(\sprintf('errors/no_line_and_context_exception_include.twig', $line), $e->getFile()); |
| 323 | + $this->assertSame($line, $e->getLine()); |
| 324 | + } else { |
| 325 | + $this->assertStringContainsString('Environment.php', $e->getFile()); |
| 326 | + $this->assertNotSame($line, $e->getLine()); |
| 327 | + } |
| 328 | + } |
| 329 | + } |
| 330 | + |
| 331 | + public static function getErrorWithoutLineAndContextData(): iterable |
| 332 | + { |
| 333 | + $fileLoaders = [ |
| 334 | + new ArrayLoader([ |
| 335 | + 'no_line_and_context_exception.twig' => "\n\n{{ include('no_line_and_context_exception_include.twig') }}", |
| 336 | + 'no_line_and_context_exception_include.twig' => "\n\n\n\n{% foo %}", |
| 337 | + ]), |
| 338 | + new FilesystemLoader(__DIR__.'/Fixtures/errors'), |
| 339 | + ]; |
| 340 | + |
| 341 | + foreach ($fileLoaders as $loader) { |
| 342 | + foreach ([false, true] as $exceptionWithLineAndContext) { |
| 343 | + foreach ([false, true] as $addDebugInfo) { |
| 344 | + foreach ([false, true] as $debug) { |
| 345 | + $name = ($loader instanceof FilesystemLoader ? 'filesystem' : 'array') |
| 346 | + .($debug ? '_with_debug' : '_without_debug') |
| 347 | + .($addDebugInfo ? '_with_debug_info' : '_without_debug_info') |
| 348 | + .($exceptionWithLineAndContext ? '_with_context' : '_without_context') |
| 349 | + ; |
| 350 | + yield $name => [$loader, $debug, $addDebugInfo, $exceptionWithLineAndContext, $name]; |
| 351 | + } |
| 352 | + } |
| 353 | + } |
| 354 | + } |
| 355 | + } |
| 356 | + |
256 | 357 | public static function getErroredTemplates()
|
257 | 358 | {
|
258 | 359 | return [
|
|
0 commit comments