3 require_once('src/lightncandy.php');
4 require_once('tests/helpers_for_test.php');
6 $tmpdir = sys_get_temp_dir();
7 $errlog_fn = tempnam($tmpdir, 'terr_');
9 function start_catch_error_log() {
11 date_default_timezone_set('GMT');
12 if (file_exists($errlog_fn)) {
15 return ini_set('error_log', $errlog_fn);
18 function stop_catch_error_log() {
20 ini_restore('error_log');
21 if (!file_exists($errlog_fn)) {
24 return array_map(function ($l) {
26 preg_match('/GMT\] (.+)/', $l, $m);
27 return isset($m[1]) ? $m[1] : $l;
31 class errorTest extends PHPUnit_Framework_TestCase
33 public function testException()
35 $this->setExpectedException('Exception', 'Bad token {{{foo}} ! Do you mean {{foo}} or {{{foo}}}?');
36 $php = LightnCandy::compile('{{{foo}}', Array('flags' => LightnCandy::FLAG_ERROR_EXCEPTION));
39 public function testErrorLog()
41 start_catch_error_log();
42 $php = LightnCandy::compile('{{{foo}}', Array('flags' => LightnCandy::FLAG_ERROR_LOG));
43 $e = stop_catch_error_log();
45 $this->assertEquals(Array('Bad token {{{foo}} ! Do you mean {{foo}} or {{{foo}}}?'), $e);
47 $this->markTestIncomplete('skip HHVM');
52 * @dataProvider renderErrorProvider
54 public function testRenderingException($test)
56 $this->setExpectedException('Exception', $test['expected']);
57 $php = LightnCandy::compile($test['template'], $test['options']);
58 $renderer = LightnCandy::prepare($php);
59 $renderer(null, LCRun3::DEBUG_ERROR_EXCEPTION);
63 * @dataProvider renderErrorProvider
65 public function testRenderingErrorLog($test)
67 start_catch_error_log();
68 $php = LightnCandy::compile($test['template'], $test['options']);
69 $renderer = LightnCandy::prepare($php);
70 $renderer(null, LCRun3::DEBUG_ERROR_LOG);
71 $e = stop_catch_error_log();
73 $this->assertEquals(Array($test['expected']), $e);
75 $this->markTestIncomplete('skip HHVM');
79 public function renderErrorProvider()
83 'template' => '{{{foo}}}',
84 'expected' => 'LCRun3: [foo] is not exist',
87 'template' => '{{foo}}',
90 'foo' => function () {
95 'expected' => 'LCRun3: call custom helper \'foo\' error: Division by zero',
99 return array_map(function($i) {
100 if (!isset($i['options'])) {
101 $i['options'] = Array('flags' => LightnCandy::FLAG_RENDER_DEBUG);
103 if (!isset($i['options']['flags'])) {
104 $i['options']['flags'] = LightnCandy::FLAG_RENDER_DEBUG;
111 * @dataProvider errorProvider
113 public function testErrors($test)
117 $php = LightnCandy::compile($test['template'], $test['options']);
118 $context = LightnCandy::getContext();
120 // This case should be compiled without error
121 if (!isset($test['expected'])) {
125 $this->assertEquals($test['expected'], $context['error'], "Code: $php");
128 public function errorProvider()
132 'template' => '{{testerr1}}}',
133 'expected' => 'Bad token {{testerr1}}} ! Do you mean {{testerr1}} or {{{testerr1}}}?',
136 'template' => '{{{testerr2}}',
137 'expected' => 'Bad token {{{testerr2}} ! Do you mean {{testerr2}} or {{{testerr2}}}?',
140 'template' => '{{{#testerr3}}}',
141 'expected' => 'Bad token {{{#testerr3}}} ! Do you mean {{#testerr3}} ?',
144 'template' => '{{{!testerr4}}}',
145 'expected' => 'Bad token {{{!testerr4}}} ! Do you mean {{!testerr4}} ?',
148 'template' => '{{{^testerr5}}}',
149 'expected' => 'Bad token {{{^testerr5}}} ! Do you mean {{^testerr5}} ?',
152 'template' => '{{{/testerr6}}}',
153 'expected' => 'Bad token {{{/testerr6}}} ! Do you mean {{/testerr6}} ?',
156 'template' => '{{win[ner.test1}}',
157 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
158 'expected' => 'Wrong variable naming in {{win[ner.test1}}',
161 'template' => '{{win]ner.test2}}',
162 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
163 'expected' => 'Wrong variable naming as \'win]ner.test2\' in {{win]ner.test2}} !',
166 'template' => '{{wi[n]ner.test3}}',
167 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
168 'expected' => 'Wrong variable naming as \'wi[n]ner.test3\' in {{wi[n]ner.test3}} !',
171 'template' => '{{winner].[test4]}}',
172 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
173 'expected' => 'Wrong variable naming as \'winner].[test4]\' in {{winner].[test4]}} !',
176 'template' => '{{winner[.test5]}}',
177 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
178 'expected' => 'Wrong variable naming as \'winner[.test5]\' in {{winner[.test5]}} !',
181 'template' => '{{winner.[.test6]}}',
182 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
185 'template' => '{{winner.[#te.st7]}}',
186 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
189 'template' => '{{test8}}',
190 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
193 'template' => '{{test9]}}',
194 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
195 'expected' => 'Wrong variable naming as \'test9]\' in {{test9]}} !',
198 'template' => '{{testA[}}',
199 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
200 'expected' => 'Wrong variable naming in {{testA[}}',
203 'template' => '{{[testB}}',
204 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
205 'expected' => 'Wrong variable naming in {{[testB}}',
208 'template' => '{{]testC}}',
209 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
210 'expected' => 'Wrong variable naming as \']testC\' in {{]testC}} !',
213 'template' => '{{[testD]}}',
214 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
217 'template' => '{{te]stE}}',
218 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
219 'expected' => 'Wrong variable naming as \'te]stE\' in {{te]stE}} !',
222 'template' => '{{tee[stF}}',
223 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
224 'expected' => 'Wrong variable naming in {{tee[stF}}',
227 'template' => '{{te.e[stG}}',
228 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
229 'expected' => 'Wrong variable naming in {{te.e[stG}}',
232 'template' => '{{te.e]stH}}',
233 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
234 'expected' => 'Wrong variable naming as \'te.e]stH\' in {{te.e]stH}} !',
237 'template' => '{{te.e[st.endI}}',
238 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
239 'expected' => 'Wrong variable naming in {{te.e[st.endI}}',
242 'template' => '{{te.e]st.endJ}}',
243 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
244 'expected' => 'Wrong variable naming as \'te.e]st.endJ\' in {{te.e]st.endJ}} !',
247 'template' => '{{te.[est].endK}}',
248 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
251 'template' => '{{te.t[est].endL}}',
252 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
253 'expected' => 'Wrong variable naming as \'te.t[est].endL\' in {{te.t[est].endL}} !',
256 'template' => '{{te.t[est]o.endM}}',
257 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
258 'expected' => 'Wrong variable naming as \'te.t[est]o.endM\' in {{te.t[est]o.endM}} !',
261 'template' => '{{te.[est]o.endN}}',
262 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
263 'expected' => 'Wrong variable naming as \'te.[est]o.endN\' in {{te.[est]o.endN}} !',
266 'template' => '{{te.[e.st].endO}}',
267 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
270 'template' => '{{te.[e.s[t].endP}}',
271 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
274 'template' => '{{te.[e[s.t].endQ}}',
275 'options' => Array('flags' => LightnCandy::FLAG_ADVARNAME),
278 'template' => '{{helper}}',
279 'options' => Array('helpers' => Array(
280 'helper' => Array('bad input'),
282 'expected' => 'I found an array in helpers with key as helper, please fix it.',
285 'template' => '<ul>{{#each item}}<li>{{name}}</li>',
286 'expected' => 'Unclosed token {{#each item}} !!',
289 'template' => 'issue63: {{test_join}} Test! {{this}} {{/test_join}}',
290 'expected' => 'Unexpect token: {{/test_join}} !',
293 'template' => '{{#if a}}TEST{{/with}}',
294 'options' => Array('flags' => LightnCandy::FLAG_WITH),
295 'expected' => 'Unexpect token: {{/with}} !',
298 'template' => '{{#foo}}error{{/bar}}',
299 'expected' => 'Unexpect token {{/bar}} ! Previous token {{#[foo]}} is not closed',
302 'template' => '{{../foo}}',
303 'expected' => 'Do not support {{../var}}, you should do compile with LightnCandy::FLAG_PARENT flag',
306 'template' => '{{..}}',
307 'expected' => 'Do not support {{../var}}, you should do compile with LightnCandy::FLAG_PARENT flag',
310 'template' => '{{test_join [a]=b}}',
312 'flags' => LightnCandy::FLAG_NAMEDARG,
313 'helpers' => Array('test_join')
315 'expected' => "Wrong argument name as '[a]' in {{test_join [a]=b}} ! You should fix your template or compile with LightnCandy::FLAG_ADVARNAME flag.",
318 'template' => '{{a=b}}',
319 'options' => Array('flags' => LightnCandy::FLAG_NAMEDARG),
320 'expected' => 'Do not support name=value in {{a=b}}, you should use it after a custom helper.',
323 'template' => '{{test a=b}}',
324 'options' => Array('flags' => LightnCandy::FLAG_NAMEDARG),
325 'expected' => 'Do not support name=value in {{test a=b}}, maybe you missing the custom helper?',
328 'template' => '{{#test a=b}}YA~{{/test}}',
329 'options' => Array('flags' => LightnCandy::FLAG_NAMEDARG),
330 'expected' => 'Do not support name=value in {{#test a=b}}, maybe you missing the block custom helper?',
333 'template' => '{{#foo}}1{{^}}2{{/foo}}',
334 'expected' => 'Do not support {{^}}, you should do compile with LightnCandy::FLAG_ELSE flag',
337 'template' => '{{#with a}OK!{{/with}}',
338 'options' => Array('flags' => LightnCandy::FLAG_WITH),
339 'expected' => 'Unclosed token {{#with a}OK!{{/with}} !!',
342 'template' => '{{#each a}OK!{{/each}}',
343 'expected' => 'Unclosed token {{#each a}OK!{{/each}} !!',
346 'template' => '{{#with items}}OK!{{/with}}',
347 'options' => Array('flags' => LightnCandy::FLAG_WITH),
350 'template' => '{{#with}}OK!{{/with}}',
351 'options' => Array('flags' => LightnCandy::FLAG_WITH),
352 'expected' => 'No argument after {{#with}} !',
355 'template' => '{{>not_found}}',
356 'expected' => "Can not find partial file for 'not_found', you should set correct basedir and fileext in options",
359 'template' => '{{>tests/test1 foo}}',
360 'options' => Array('basedir' => '.'),
361 'expected' => 'Do not support {{>tests/test1 [foo]}}, you should do compile with LightnCandy::FLAG_RUNTIMEPARTIAL flag',
364 'template' => '{{#with foo}}ABC{{/with}}',
365 'expected' => 'Do not support {{#with var}}, you should do compile with LightnCandy::FLAG_WITH flag',
368 'template' => '{{abc}}',
369 'options' => Array('helpers' => Array('abc')),
370 'expected' => 'Can not find custom helper function defination abc() !',
373 'template' => '{{=~= =~=}}',
374 'expected' => "Can not set delimiter contains '=' , you try to set delimiter as '~=' and '=~'.",
377 'template' => '{{>recursive}}',
378 'options' => Array('basedir' => 'tests', 'flags' => LightnCandy::FLAG_WITH),
380 'I found recursive partial includes as the path: recursive -> recursive! You should fix your template or compile with LightnCandy::FLAG_RUNTIMEPARTIAL flag.',
381 "Skip rendering partial 'recursive' again due to recursive detected",
385 'template' => '{{test_join (foo bar)}}',
387 'flags' => LightnCandy::FLAG_ADVARNAME,
388 'helpers' => Array('test_join'),
390 'expected' => "Can not find custom helper function defination foo() !",
393 'template' => '{{1 + 2}}',
395 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
396 'helpers' => Array('test_join'),
398 'expected' => "Wrong variable naming as '+' in {{1 + 2}} ! You should wrap ! \" # % & ' * + , ; < = > { | } ~ into [ ]",
401 'template' => '{{> (foo) bar}}',
403 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
407 "Can not find custom helper function defination foo() !",
408 "You use dynamic partial name as '(foo)', this only works with option FLAG_RUNTIMEPARTIAL enabled",
412 'template' => '{{{{#foo}}}',
414 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
417 'Bad token {{{{#foo}}} ! Do you mean {{{{#foo}}}} ?',
418 'Wrong raw block begin with {{{{#foo}}} ! Remove "#" to fix this issue.',
419 'Unclosed token {{{{foo}}}} !!',
423 'template' => '{{{{foo}}}} {{ {{{{/bar}}}}',
425 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
428 'Unclosed token {{{{foo}}}} !!',
432 'template' => '{{{{foo}}}} {{ {{{{#foo}}}}',
434 'flags' => LightnCandy::FLAG_HANDLEBARSJS,
437 'Unclosed token {{{{foo}}}} !!',
442 return array_map(function($i) {
443 if (!isset($i['options'])) {
444 $i['options'] = Array('flags' => 0);
446 if (!isset($i['options']['flags'])) {
447 $i['options']['flags'] = 0;
449 if (isset($i['expected']) && !is_array($i['expected'])) {
450 $i['expected'] = Array($i['expected']);