4 * This file is part of Twig.
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
13 * Integration test helper.
15 * @author Fabien Potencier <fabien@symfony.com>
16 * @author Karma Dordrak <drak@zikula.org>
18 abstract class Twig_Test_IntegrationTestCase extends PHPUnit_Framework_TestCase
23 abstract protected function getFixturesDir();
26 * @return Twig_ExtensionInterface[]
28 protected function getExtensions()
34 * @return Twig_SimpleFilter[]
36 protected function getTwigFilters()
42 * @return Twig_SimpleFunction[]
44 protected function getTwigFunctions()
50 * @return Twig_SimpleTest[]
52 protected function getTwigTests()
58 * @dataProvider getTests
60 public function testIntegration($file, $message, $condition, $templates, $exception, $outputs)
62 $this->doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs);
66 * @dataProvider getLegacyTests
69 public function testLegacyIntegration($file, $message, $condition, $templates, $exception, $outputs)
71 $this->doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs);
74 public function getTests($name, $legacyTests = false)
76 $fixturesDir = realpath($this->getFixturesDir());
79 foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($fixturesDir), RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
80 if (!preg_match('/\.test$/', $file)) {
84 if ($legacyTests xor false !== strpos($file->getRealpath(), '.legacy.test')) {
88 $test = file_get_contents($file->getRealpath());
90 if (preg_match('/--TEST--\s*(.*?)\s*(?:--CONDITION--\s*(.*))?\s*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)\s*(?:--DATA--\s*(.*))?\s*--EXCEPTION--\s*(.*)/sx', $test, $match)) {
92 $condition = $match[2];
93 $templates = self::parseTemplates($match[3]);
94 $exception = $match[5];
95 $outputs = array(array(null, $match[4], null, ''));
96 } elseif (preg_match('/--TEST--\s*(.*?)\s*(?:--CONDITION--\s*(.*))?\s*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)--DATA--.*?--EXPECT--.*/s', $test, $match)) {
98 $condition = $match[2];
99 $templates = self::parseTemplates($match[3]);
101 preg_match_all('/--DATA--(.*?)(?:--CONFIG--(.*?))?--EXPECT--(.*?)(?=\-\-DATA\-\-|$)/s', $test, $outputs, PREG_SET_ORDER);
103 throw new InvalidArgumentException(sprintf('Test "%s" is not valid.', str_replace($fixturesDir.'/', '', $file)));
106 $tests[] = array(str_replace($fixturesDir.'/', '', $file), $message, $condition, $templates, $exception, $outputs);
109 if ($legacyTests && empty($tests)) {
110 // add a dummy test to avoid a PHPUnit message
111 return array(array('not', '-', '', array(), '', array()));
117 public function getLegacyTests()
119 return $this->getTests('testLegacyIntegration', true);
122 protected function doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs)
125 $this->markTestSkipped('no legacy tests to run');
129 eval('$ret = '.$condition.';');
131 $this->markTestSkipped($condition);
135 $loader = new Twig_Loader_Array($templates);
137 foreach ($outputs as $i => $match) {
138 $config = array_merge(array(
140 'strict_variables' => true,
141 ), $match[2] ? eval($match[2].';') : array());
142 $twig = new Twig_Environment($loader, $config);
143 $twig->addGlobal('global', 'global');
144 foreach ($this->getExtensions() as $extension) {
145 $twig->addExtension($extension);
148 foreach ($this->getTwigFilters() as $filter) {
149 $twig->addFilter($filter);
152 foreach ($this->getTwigTests() as $test) {
153 $twig->addTest($test);
156 foreach ($this->getTwigFunctions() as $function) {
157 $twig->addFunction($function);
160 // avoid using the same PHP class name for different cases
162 if (PHP_VERSION_ID >= 50300) {
163 $p = new ReflectionProperty($twig, 'templateClassPrefix');
164 $p->setAccessible(true);
165 $p->setValue($twig, '__TwigTemplate_'.hash('sha256', uniqid(mt_rand(), true), false).'_');
169 $template = $twig->loadTemplate('index.twig');
170 } catch (Exception $e) {
171 if (false !== $exception) {
172 $message = $e->getMessage();
173 $this->assertSame(trim($exception), trim(sprintf('%s: %s', get_class($e), $message)));
174 $last = substr($message, strlen($message) - 1);
175 $this->assertTrue('.' === $last || '?' === $last, $message, 'Exception message must end with a dot or a question mark.');
180 throw new Twig_Error(sprintf('%s: %s', get_class($e), $e->getMessage()), -1, $file, $e);
184 $output = trim($template->render(eval($match[1].';')), "\n ");
185 } catch (Exception $e) {
186 if (false !== $exception) {
187 $this->assertSame(trim($exception), trim(sprintf('%s: %s', get_class($e), $e->getMessage())));
192 $e = new Twig_Error(sprintf('%s: %s', get_class($e), $e->getMessage()), -1, $file, $e);
194 $output = trim(sprintf('%s: %s', get_class($e), $e->getMessage()));
197 if (false !== $exception) {
198 list($class) = explode(':', $exception);
199 $this->assertThat(null, new PHPUnit_Framework_Constraint_Exception($class));
202 $expected = trim($match[3], "\n ");
204 if ($expected !== $output) {
205 printf("Compiled templates that failed on case %d:\n", $i + 1);
207 foreach (array_keys($templates) as $name) {
208 echo "Template: $name\n";
209 $loader = $twig->getLoader();
210 if (!$loader instanceof Twig_SourceContextLoaderInterface) {
211 $source = new Twig_Source($loader->getSource($name), $name);
213 $source = $loader->getSourceContext($name);
215 echo $twig->compile($twig->parse($twig->tokenize($source)));
218 $this->assertEquals($expected, $output, $message.' (in '.$file.')');
222 protected static function parseTemplates($test)
224 $templates = array();
225 preg_match_all('/--TEMPLATE(?:\((.*?)\))?--(.*?)(?=\-\-TEMPLATE|$)/s', $test, $matches, PREG_SET_ORDER);
226 foreach ($matches as $match) {
227 $templates[($match[1] ? $match[1] : 'index.twig')] = $match[2];