1<?php 2 3/* 4 * This file is part of Twig. 5 * 6 * (c) Fabien Potencier 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12use Twig\Environment; 13use Twig\Error\Error; 14use Twig\Error\RuntimeError; 15use Twig\Loader\ArrayLoader; 16use Twig\Loader\FilesystemLoader; 17use Twig\Source; 18 19class Twig_Tests_ErrorTest extends \PHPUnit\Framework\TestCase 20{ 21 public function testErrorWithObjectFilename() 22 { 23 $error = new Error('foo'); 24 $error->setSourceContext(new Source('', new \SplFileInfo(__FILE__))); 25 26 $this->assertContains('test'.DIRECTORY_SEPARATOR.'Twig'.DIRECTORY_SEPARATOR.'Tests'.DIRECTORY_SEPARATOR.'ErrorTest.php', $error->getMessage()); 27 } 28 29 public function testErrorWithArrayFilename() 30 { 31 $error = new Error('foo'); 32 $error->setSourceContext(new Source('', ['foo' => 'bar'])); 33 34 $this->assertEquals('foo in {"foo":"bar"}', $error->getMessage()); 35 } 36 37 public function testTwigExceptionGuessWithMissingVarAndArrayLoader() 38 { 39 $loader = new ArrayLoader([ 40 'base.html' => '{% block content %}{% endblock %}', 41 'index.html' => <<<EOHTML 42{% extends 'base.html' %} 43{% block content %} 44 {{ foo.bar }} 45{% endblock %} 46{% block foo %} 47 {{ foo.bar }} 48{% endblock %} 49EOHTML 50 ]); 51 $twig = new Environment($loader, ['strict_variables' => true, 'debug' => true, 'cache' => false]); 52 53 $template = $twig->load('index.html'); 54 try { 55 $template->render([]); 56 57 $this->fail(); 58 } catch (RuntimeError $e) { 59 $this->assertEquals('Variable "foo" does not exist in "index.html" at line 3.', $e->getMessage()); 60 $this->assertEquals(3, $e->getTemplateLine()); 61 $this->assertEquals('index.html', $e->getSourceContext()->getName()); 62 } 63 } 64 65 public function testTwigExceptionGuessWithExceptionAndArrayLoader() 66 { 67 $loader = new ArrayLoader([ 68 'base.html' => '{% block content %}{% endblock %}', 69 'index.html' => <<<EOHTML 70{% extends 'base.html' %} 71{% block content %} 72 {{ foo.bar }} 73{% endblock %} 74{% block foo %} 75 {{ foo.bar }} 76{% endblock %} 77EOHTML 78 ]); 79 $twig = new Environment($loader, ['strict_variables' => true, 'debug' => true, 'cache' => false]); 80 81 $template = $twig->load('index.html'); 82 try { 83 $template->render(['foo' => new Twig_Tests_ErrorTest_Foo()]); 84 85 $this->fail(); 86 } catch (RuntimeError $e) { 87 $this->assertEquals('An exception has been thrown during the rendering of a template ("Runtime error...") in "index.html" at line 3.', $e->getMessage()); 88 $this->assertEquals(3, $e->getTemplateLine()); 89 $this->assertEquals('index.html', $e->getSourceContext()->getName()); 90 } 91 } 92 93 public function testTwigExceptionGuessWithMissingVarAndFilesystemLoader() 94 { 95 $loader = new FilesystemLoader(__DIR__.'/Fixtures/errors'); 96 $twig = new Environment($loader, ['strict_variables' => true, 'debug' => true, 'cache' => false]); 97 98 $template = $twig->load('index.html'); 99 try { 100 $template->render([]); 101 102 $this->fail(); 103 } catch (RuntimeError $e) { 104 $this->assertEquals('Variable "foo" does not exist.', $e->getMessage()); 105 $this->assertEquals(3, $e->getTemplateLine()); 106 $this->assertEquals('index.html', $e->getSourceContext()->getName()); 107 $this->assertEquals(3, $e->getLine()); 108 $this->assertEquals(strtr(__DIR__.'/Fixtures/errors/index.html', '/', DIRECTORY_SEPARATOR), $e->getFile()); 109 } 110 } 111 112 public function testTwigExceptionGuessWithExceptionAndFilesystemLoader() 113 { 114 $loader = new FilesystemLoader(__DIR__.'/Fixtures/errors'); 115 $twig = new Environment($loader, ['strict_variables' => true, 'debug' => true, 'cache' => false]); 116 117 $template = $twig->load('index.html'); 118 try { 119 $template->render(['foo' => new Twig_Tests_ErrorTest_Foo()]); 120 121 $this->fail(); 122 } catch (RuntimeError $e) { 123 $this->assertEquals('An exception has been thrown during the rendering of a template ("Runtime error...").', $e->getMessage()); 124 $this->assertEquals(3, $e->getTemplateLine()); 125 $this->assertEquals('index.html', $e->getSourceContext()->getName()); 126 $this->assertEquals(3, $e->getLine()); 127 $this->assertEquals(strtr(__DIR__.'/Fixtures/errors/index.html', '/', DIRECTORY_SEPARATOR), $e->getFile()); 128 } 129 } 130 131 /** 132 * @dataProvider getErroredTemplates 133 */ 134 public function testTwigExceptionAddsFileAndLine($templates, $name, $line) 135 { 136 $loader = new ArrayLoader($templates); 137 $twig = new Environment($loader, ['strict_variables' => true, 'debug' => true, 'cache' => false]); 138 139 $template = $twig->load('index'); 140 141 try { 142 $template->render([]); 143 144 $this->fail(); 145 } catch (RuntimeError $e) { 146 $this->assertEquals(sprintf('Variable "foo" does not exist in "%s" at line %d.', $name, $line), $e->getMessage()); 147 $this->assertEquals($line, $e->getTemplateLine()); 148 $this->assertEquals($name, $e->getSourceContext()->getName()); 149 } 150 151 try { 152 $template->render(['foo' => new Twig_Tests_ErrorTest_Foo()]); 153 154 $this->fail(); 155 } catch (RuntimeError $e) { 156 $this->assertEquals(sprintf('An exception has been thrown during the rendering of a template ("Runtime error...") in "%s" at line %d.', $name, $line), $e->getMessage()); 157 $this->assertEquals($line, $e->getTemplateLine()); 158 $this->assertEquals($name, $e->getSourceContext()->getName()); 159 } 160 } 161 162 public function getErroredTemplates() 163 { 164 return [ 165 // error occurs in a template 166 [ 167 [ 168 'index' => "\n\n{{ foo.bar }}\n\n\n{{ 'foo' }}", 169 ], 170 'index', 3, 171 ], 172 173 // error occurs in an included template 174 [ 175 [ 176 'index' => "{% include 'partial' %}", 177 'partial' => '{{ foo.bar }}', 178 ], 179 'partial', 1, 180 ], 181 182 // error occurs in a parent block when called via parent() 183 [ 184 [ 185 'index' => "{% extends 'base' %} 186 {% block content %} 187 {{ parent() }} 188 {% endblock %}", 189 'base' => '{% block content %}{{ foo.bar }}{% endblock %}', 190 ], 191 'base', 1, 192 ], 193 194 // error occurs in a block from the child 195 [ 196 [ 197 'index' => "{% extends 'base' %} 198 {% block content %} 199 {{ foo.bar }} 200 {% endblock %} 201 {% block foo %} 202 {{ foo.bar }} 203 {% endblock %}", 204 'base' => '{% block content %}{% endblock %}', 205 ], 206 'index', 3, 207 ], 208 ]; 209 } 210} 211 212class Twig_Tests_ErrorTest_Foo 213{ 214 public function bar() 215 { 216 throw new \Exception('Runtime error...'); 217 } 218} 219