Project

General

Profile

1 2 Manuela
<?php
2
3
/*
4
 * This file is part of Twig.
5
 *
6
 * (c) 2010 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
12
/**
13
 * Integration test helper.
14
 *
15
 * @author Fabien Potencier <fabien@symfony.com>
16
 * @author Karma Dordrak <drak@zikula.org>
17
 */
18
abstract class Twig_Test_IntegrationTestCase extends PHPUnit_Framework_TestCase
19
{
20
    /**
21
     * @return string
22
     */
23
    abstract protected function getFixturesDir();
24
25
    /**
26
     * @return Twig_ExtensionInterface[]
27
     */
28
    protected function getExtensions()
29
    {
30
        return array();
31
    }
32
33
    /**
34
     * @return Twig_SimpleFilter[]
35
     */
36
    protected function getTwigFilters()
37
    {
38
        return array();
39
    }
40
41
    /**
42
     * @return Twig_SimpleFunction[]
43
     */
44
    protected function getTwigFunctions()
45
    {
46
        return array();
47
    }
48
49
    /**
50
     * @return Twig_SimpleTest[]
51
     */
52
    protected function getTwigTests()
53
    {
54
        return array();
55
    }
56
57
    /**
58
     * @dataProvider getTests
59
     */
60
    public function testIntegration($file, $message, $condition, $templates, $exception, $outputs)
61
    {
62
        $this->doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs);
63
    }
64
65
    /**
66
     * @dataProvider getLegacyTests
67
     * @group legacy
68
     */
69
    public function testLegacyIntegration($file, $message, $condition, $templates, $exception, $outputs)
70
    {
71
        $this->doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs);
72
    }
73
74
    public function getTests($name, $legacyTests = false)
75
    {
76
        $fixturesDir = realpath($this->getFixturesDir());
77
        $tests = array();
78
79
        foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($fixturesDir), RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
80
            if (!preg_match('/\.test$/', $file)) {
81
                continue;
82
            }
83
84
            if ($legacyTests xor false !== strpos($file->getRealpath(), '.legacy.test')) {
85
                continue;
86
            }
87
88
            $test = file_get_contents($file->getRealpath());
89
90
            if (preg_match('/--TEST--\s*(.*?)\s*(?:--CONDITION--\s*(.*))?\s*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)\s*(?:--DATA--\s*(.*))?\s*--EXCEPTION--\s*(.*)/sx', $test, $match)) {
91
                $message = $match[1];
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)) {
97
                $message = $match[1];
98
                $condition = $match[2];
99
                $templates = self::parseTemplates($match[3]);
100
                $exception = false;
101
                preg_match_all('/--DATA--(.*?)(?:--CONFIG--(.*?))?--EXPECT--(.*?)(?=\-\-DATA\-\-|$)/s', $test, $outputs, PREG_SET_ORDER);
102
            } else {
103
                throw new InvalidArgumentException(sprintf('Test "%s" is not valid.', str_replace($fixturesDir.'/', '', $file)));
104
            }
105
106
            $tests[] = array(str_replace($fixturesDir.'/', '', $file), $message, $condition, $templates, $exception, $outputs);
107
        }
108
109
        if ($legacyTests && empty($tests)) {
110
            // add a dummy test to avoid a PHPUnit message
111
            return array(array('not', '-', '', array(), '', array()));
112
        }
113
114
        return $tests;
115
    }
116
117
    public function getLegacyTests()
118
    {
119
        return $this->getTests('testLegacyIntegration', true);
120
    }
121
122
    protected function doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs)
123
    {
124
        if ($condition) {
125
            eval('$ret = '.$condition.';');
126
            if (!$ret) {
127
                $this->markTestSkipped($condition);
128
            }
129
        }
130
131
        $loader = new Twig_Loader_Array($templates);
132
133
        foreach ($outputs as $i => $match) {
134
            $config = array_merge(array(
135
                'cache' => false,
136
                'strict_variables' => true,
137
            ), $match[2] ? eval($match[2].';') : array());
138
            $twig = new Twig_Environment($loader, $config);
139
            $twig->addGlobal('global', 'global');
140
            foreach ($this->getExtensions() as $extension) {
141
                $twig->addExtension($extension);
142
            }
143
144
            foreach ($this->getTwigFilters() as $filter) {
145
                $twig->addFilter($filter);
146
            }
147
148
            foreach ($this->getTwigTests() as $test) {
149
                $twig->addTest($test);
150
            }
151
152
            foreach ($this->getTwigFunctions() as $function) {
153
                $twig->addFunction($function);
154
            }
155
156
            // avoid using the same PHP class name for different cases
157
            // only for PHP 5.2+
158
            if (PHP_VERSION_ID >= 50300) {
159
                $p = new ReflectionProperty($twig, 'templateClassPrefix');
160
                $p->setAccessible(true);
161
                $p->setValue($twig, '__TwigTemplate_'.hash('sha256', uniqid(mt_rand(), true), false).'_');
162
            }
163
164
            try {
165
                $template = $twig->loadTemplate('index.twig');
166
            } catch (Exception $e) {
167
                if (false !== $exception) {
168
                    $message = $e->getMessage();
169
                    $this->assertSame(trim($exception), trim(sprintf('%s: %s', get_class($e), $message)));
170
                    $this->assertSame('.', substr($message, strlen($message) - 1), $message, 'Exception message must end with a dot.');
171
172
                    return;
173
                }
174
175
                if ($e instanceof Twig_Error_Syntax) {
176
                    $e->setTemplateFile($file);
177
178
                    throw $e;
179
                }
180
181
                throw new Twig_Error(sprintf('%s: %s', get_class($e), $e->getMessage()), -1, $file, $e);
182
            }
183
184
            try {
185
                $output = trim($template->render(eval($match[1].';')), "\n ");
186
            } catch (Exception $e) {
187
                if (false !== $exception) {
188
                    $this->assertSame(trim($exception), trim(sprintf('%s: %s', get_class($e), $e->getMessage())));
189
190
                    return;
191
                }
192
193
                if ($e instanceof Twig_Error_Syntax) {
194
                    $e->setTemplateFile($file);
195
                } else {
196
                    $e = new Twig_Error(sprintf('%s: %s', get_class($e), $e->getMessage()), -1, $file, $e);
197
                }
198
199
                $output = trim(sprintf('%s: %s', get_class($e), $e->getMessage()));
200
            }
201
202
            if (false !== $exception) {
203
                list($class) = explode(':', $exception);
204
                $this->assertThat(null, new PHPUnit_Framework_Constraint_Exception($class));
205
            }
206
207
            $expected = trim($match[3], "\n ");
208
209
            if ($expected !== $output) {
210
                printf("Compiled templates that failed on case %d:\n", $i + 1);
211
212
                foreach (array_keys($templates) as $name) {
213
                    echo "Template: $name\n";
214
                    $source = $loader->getSource($name);
215
                    echo $twig->compile($twig->parse($twig->tokenize($source, $name)));
216
                }
217
            }
218
            $this->assertEquals($expected, $output, $message.' (in '.$file.')');
219
        }
220
    }
221
222
    protected static function parseTemplates($test)
223
    {
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];
228
        }
229
230
        return $templates;
231
    }
232
}