aboutsummaryrefslogtreecommitdiffstats
path: root/tests/template
diff options
context:
space:
mode:
authorNils Adermann <naderman@naderman.de>2010-03-10 16:24:19 +0100
committerNils Adermann <naderman@naderman.de>2010-03-10 16:24:19 +0100
commit60bd1edcb5e5992e6e693d0f68db47e678f7d54a (patch)
treedffc10407f0ef6a85d034415d7e30407ccf3f21a /tests/template
parentd9567f121b11d3f5b068b85e7c862c27fc495005 (diff)
downloadforums-60bd1edcb5e5992e6e693d0f68db47e678f7d54a.tar
forums-60bd1edcb5e5992e6e693d0f68db47e678f7d54a.tar.gz
forums-60bd1edcb5e5992e6e693d0f68db47e678f7d54a.tar.bz2
forums-60bd1edcb5e5992e6e693d0f68db47e678f7d54a.tar.xz
forums-60bd1edcb5e5992e6e693d0f68db47e678f7d54a.zip
[develop-olympus] Backported 3.1 unit tests to 3.0.
Start adding unit tests for bugs you fix! Tests for anything are welcome really. We have to work on these a lot.
Diffstat (limited to 'tests/template')
-rw-r--r--tests/template/all_tests.php40
-rw-r--r--tests/template/template.php671
-rw-r--r--tests/template/templates/_dummy_include.php3
-rw-r--r--tests/template/templates/basic.html20
-rw-r--r--tests/template/templates/define.html8
-rw-r--r--tests/template/templates/expressions.html86
-rw-r--r--tests/template/templates/if.html11
-rw-r--r--tests/template/templates/include.html1
-rw-r--r--tests/template/templates/includephp.html1
-rw-r--r--tests/template/templates/lang.html3
-rw-r--r--tests/template/templates/loop.html21
-rw-r--r--tests/template/templates/loop_advanced.html19
-rw-r--r--tests/template/templates/loop_nested.html8
-rw-r--r--tests/template/templates/loop_vars.html21
-rw-r--r--tests/template/templates/php.html1
-rw-r--r--tests/template/templates/variable.html1
16 files changed, 915 insertions, 0 deletions
diff --git a/tests/template/all_tests.php b/tests/template/all_tests.php
new file mode 100644
index 0000000000..ea258c1680
--- /dev/null
+++ b/tests/template/all_tests.php
@@ -0,0 +1,40 @@
+<?php
+/**
+*
+* @package testing
+* @copyright (c) 2008 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License
+*
+*/
+
+if (!defined('PHPUnit_MAIN_METHOD'))
+{
+ define('PHPUnit_MAIN_METHOD', 'phpbb_template_all_tests::main');
+}
+
+require_once 'test_framework/framework.php';
+require_once 'PHPUnit/TextUI/TestRunner.php';
+
+require_once 'template/template.php';
+
+class phpbb_template_all_tests
+{
+ public static function main()
+ {
+ PHPUnit_TextUI_TestRunner::run(self::suite());
+ }
+
+ public static function suite()
+ {
+ $suite = new PHPUnit_Framework_TestSuite('phpBB Template Engine');
+
+ $suite->addTestSuite('phpbb_template_template_test');
+
+ return $suite;
+ }
+}
+
+if (PHPUnit_MAIN_METHOD == 'phpbb_template_all_tests::main')
+{
+ phpbb_template_all_tests::main();
+}
diff --git a/tests/template/template.php b/tests/template/template.php
new file mode 100644
index 0000000000..df12f92046
--- /dev/null
+++ b/tests/template/template.php
@@ -0,0 +1,671 @@
+<?php
+/**
+*
+* @package testing
+* @copyright (c) 2008 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License
+*
+*/
+
+require_once 'test_framework/framework.php';
+
+require_once '../phpBB/includes/template.php';
+
+class phpbb_template_template_test extends phpbb_test_case
+{
+ private $template;
+ private $template_path;
+
+ // Keep the contents of the cache for debugging?
+ const PRESERVE_CACHE = true;
+
+ private function display($handle)
+ {
+ // allow the templates to throw notices
+ $error_level = error_reporting();
+ error_reporting($error_level & ~E_NOTICE);
+
+ ob_start();
+ $this->assertTrue($this->template->display($handle, false));
+
+ // reset error level
+ error_reporting($error_level);
+
+ return self::trim_template_result(ob_get_clean());
+ }
+
+ private static function trim_template_result($result)
+ {
+ return str_replace("\n\n", "\n", implode("\n", array_map('trim', explode("\n", trim($result)))));
+ }
+
+ private function setup_engine()
+ {
+ $this->template_path = dirname(__FILE__) . '/templates';
+ $this->template = new template();
+ $this->template->set_custom_template($this->template_path, 'tests');
+ }
+
+ protected function setUp()
+ {
+ // Test the engine can be used
+ $this->setup_engine();
+
+ if (!is_writable(dirname($this->template->cachepath)))
+ {
+ $this->markTestSkipped("Template cache directory is not writable.");
+ }
+
+ foreach (glob($this->template->cachepath . '*') as $file)
+ {
+ unlink($file);
+ }
+
+ $GLOBALS['config'] = array(
+ 'load_tplcompile' => true,
+ 'tpl_allow_php' => false,
+ );
+ }
+
+ protected function tearDown()
+ {
+ if (is_object($this->template))
+ {
+ foreach (glob($this->template->cachepath . '*') as $file)
+ {
+ unlink($file);
+ }
+ }
+ }
+
+ /**
+ * @todo put test data into templates/xyz.test
+ */
+ public static function template_data()
+ {
+ return array(
+ /*
+ array(
+ '', // File
+ array(), // vars
+ array(), // block vars
+ array(), // destroy
+ '', // Expected result
+ ),
+ */
+ array(
+ 'basic.html',
+ array(),
+ array(),
+ array(),
+ "pass\npass\n<!-- DUMMY var -->",
+ ),
+ array(
+ 'variable.html',
+ array('VARIABLE' => 'value'),
+ array(),
+ array(),
+ 'value',
+ ),
+ array(
+ 'if.html',
+ array(),
+ array(),
+ array(),
+ '0',
+ ),
+ array(
+ 'if.html',
+ array('S_VALUE' => true),
+ array(),
+ array(),
+ "1\n0",
+ ),
+ array(
+ 'if.html',
+ array('S_VALUE' => true, 'S_OTHER_VALUE' => true),
+ array(),
+ array(),
+ '1',
+ ),
+ array(
+ 'if.html',
+ array('S_VALUE' => false, 'S_OTHER_VALUE' => true),
+ array(),
+ array(),
+ '2',
+ ),
+ array(
+ 'loop.html',
+ array(),
+ array(),
+ array(),
+ "noloop\nnoloop",
+ ),
+ array(
+ 'loop.html',
+ array(),
+ array('loop' => array(array())),
+ array(),
+ "loop\nloop",
+ ),
+ array(
+ 'loop.html',
+ array(),
+ array('loop' => array(array(), array()), 'loop.block' => array(array())),
+ array(),
+ "loop\nloop\nloop\nloop",
+ ),
+ array(
+ 'loop.html',
+ array(),
+ array('loop' => array(array(), array()), 'loop.block' => array(array()), 'block' => array(array(), array())),
+ array(),
+ "loop\nloop\nloop\nloop\nloop#0-block#0\nloop#0-block#1\nloop#1-block#0\nloop#1-block#1",
+ ),
+ array(
+ 'loop_vars.html',
+ array(),
+ array('loop' => array(array('VARIABLE' => 'x'))),
+ array(),
+ "first\n0\nx\nset\nlast",
+ ),/* no nested top level loops
+ array(
+ 'loop_vars.html',
+ array(),
+ array('loop' => array(array('VARIABLE' => 'x'), array('VARIABLE' => 'y'))),
+ array(),
+ "first\n0\n0\n2\nx\nset\n1\n1\n2\ny\nset\nlast",
+ ),
+ array(
+ 'loop_vars.html',
+ array(),
+ array('loop' => array(array('VARIABLE' => 'x'), array('VARIABLE' => 'y')), 'loop.inner' => array(array(), array())),
+ array(),
+ "first\n0\n0\n2\nx\nset\n1\n1\n2\ny\nset\nlast\n0\n\n1\nlast inner\ninner loop",
+ ),*/
+ array(
+ 'loop_advanced.html',
+ array(),
+ array('loop' => array(array(), array(), array(), array(), array(), array(), array())),
+ array(),
+ "101234561\nx\n101234561\nx\n101234561\nx\n1234561\nx\n1\nx\n101\nx\n234\nx\n10\nx\n561\nx\n561",
+ ),
+ array(
+ 'define.html',
+ array(),
+ array('loop' => array(array(), array(), array(), array(), array(), array(), array()), 'test' => array(array()), 'test.deep' => array(array()), 'test.deep.defines' => array(array())),
+ array(),
+ "xyz\nabc",
+ ),
+ array(
+ 'expressions.html',
+ array(),
+ array(),
+ array(),
+ trim(str_repeat("pass", 39)),
+ ),
+ array(
+ 'php.html',
+ array(),
+ array(),
+ array(),
+ '',
+ ),
+ array(
+ 'include.html',
+ array('VARIABLE' => 'value'),
+ array(),
+ array(),
+ 'value',
+ ),
+ array(
+ 'loop_vars.html',
+ array(),
+ array('loop' => array(array('VARIABLE' => 'x'), array('VARIABLE' => 'y')), 'loop.inner' => array(array(), array())),
+ array('loop'),
+ '',
+ ),/* no top level nested loops
+ array(
+ 'loop_vars.html',
+ array(),
+ array('loop' => array(array('VARIABLE' => 'x'), array('VARIABLE' => 'y')), 'loop.inner' => array(array(), array())),
+ array('loop.inner'),
+ "first\n0\n0\n2\nx\nset\n1\n1\n2\ny\nset\nlast",
+ ),*/
+ array(
+ 'lang.html',
+ array(),
+ array(),
+ array(),
+ "{ VARIABLE }\n{ VARIABLE }",
+ ),
+ array(
+ 'lang.html',
+ array('L_VARIABLE' => "Value'"),
+ array(),
+ array(),
+ "Value'\nValue\'",
+ ),
+ array(
+ 'lang.html',
+ array('LA_VARIABLE' => "Value'"),
+ array(),
+ array(),
+ "{ VARIABLE }\nValue'",
+ ),
+ );
+ }
+
+ public function test_missing_file()
+ {
+ $filename = 'file_not_found.html';
+
+ $this->template->set_filenames(array('test' => $filename));
+ $this->assertFileNotExists($this->template_path . '/' . $filename, 'Testing missing file, file cannot exist');
+
+ $expecting = sprintf('template->_tpl_load_file(): File %s does not exist or is empty', realpath($this->template_path) . '/' . $filename);
+ $this->setExpectedTriggerError(E_USER_ERROR, $expecting);
+
+ $this->display('test');
+ }
+
+ public function test_empty_file()
+ {
+ $expecting = 'template->set_filenames: Empty filename specified for test';
+
+ $this->setExpectedTriggerError(E_USER_ERROR, $expecting);
+ $this->template->set_filenames(array('test' => ''));
+ }
+
+ public function test_invalid_handle()
+ {
+ $expecting = 'template->_tpl_load(): No file specified for handle test';
+ $this->setExpectedTriggerError(E_USER_ERROR, $expecting);
+
+ $this->display('test');
+ }
+
+ private function run_template($file, array $vars, array $block_vars, array $destroy, $expected, $cache_file)
+ {
+ $this->template->set_filenames(array('test' => $file));
+ $this->template->assign_vars($vars);
+
+ foreach ($block_vars as $block => $loops)
+ {
+ foreach ($loops as $_vars)
+ {
+ $this->template->assign_block_vars($block, $_vars);
+ }
+ }
+
+ foreach ($destroy as $block)
+ {
+ $this->template->destroy_block_vars($block);
+ }
+
+ try
+ {
+ $this->assertEquals($expected, $this->display('test'), "Testing $file");
+ $this->assertFileExists($cache_file);
+ }
+ catch (ErrorException $e)
+ {
+ if (file_exists($cache_file))
+ {
+ copy($cache_file, str_replace('ctpl_', 'tests_ctpl_', $cache_file));
+ }
+
+ throw $e;
+ }
+
+ // For debugging
+ if (self::PRESERVE_CACHE)
+ {
+ copy($cache_file, str_replace('ctpl_', 'tests_ctpl_', $cache_file));
+ }
+ }
+
+ /**
+ * @dataProvider template_data
+ */
+ public function test_template($file, array $vars, array $block_vars, array $destroy, $expected)
+ {
+ global $phpEx;
+ $cache_file = $this->template->cachepath . str_replace('/', '.', $file) . '.' . $phpEx;
+
+ $this->assertFileNotExists($cache_file);
+
+ $this->run_template($file, $vars, $block_vars, $destroy, $expected, $cache_file);
+
+ // Reset the engine state
+ $this->setup_engine();
+
+ $this->run_template($file, $vars, $block_vars, $destroy, $expected, $cache_file);
+ }
+
+ /**
+ * @dataProvider template_data
+ */
+ public function test_assign_display($file, array $vars, array $block_vars, array $destroy, $expected)
+ {
+ $this->template->set_filenames(array(
+ 'test' => $file,
+ 'container' => 'variable.html',
+ ));
+ $this->template->assign_vars($vars);
+
+ foreach ($block_vars as $block => $loops)
+ {
+ foreach ($loops as $_vars)
+ {
+ $this->template->assign_block_vars($block, $_vars);
+ }
+ }
+
+ foreach ($destroy as $block)
+ {
+ $this->template->destroy_block_vars($block);
+ }
+
+ $this->assertEquals($expected, self::trim_template_result($this->template->assign_display('test')), "Testing assign_display($file)");
+
+ $this->template->assign_display('test', 'VARIABLE', false);
+ $this->assertEquals($expected, $this->display('container'), "Testing assign_display($file)");
+ }
+
+ public function test_php()
+ {
+ global $phpEx;
+
+ $GLOBALS['config']['tpl_allow_php'] = true;
+
+ $cache_file = $this->template->cachepath . 'php.html.' . $phpEx;
+
+ $this->assertFileNotExists($cache_file);
+
+ $this->run_template('php.html', array(), array(), array(), 'test', $cache_file);
+
+ $GLOBALS['config']['tpl_allow_php'] = false;
+ }
+
+ public function test_includephp()
+ {
+ $this->markTestIncomplete('Include PHP test file paths are broken');
+
+ $GLOBALS['config']['tpl_allow_php'] = true;
+
+ $cache_file = $this->template->cachepath . 'includephp.html.' . PHP_EXT;
+
+ $cwd = getcwd();
+ chdir(dirname(__FILE__) . '/templates');
+
+ $this->run_template('includephp.html', array(), array(), array(), 'testing included php', $cache_file);
+
+ $this->template->set_filenames(array('test' => 'includephp.html'));
+ $this->assertEquals('testing included php', $this->display('test'), "Testing $file");
+
+ chdir($cwd);
+
+ $GLOBALS['config']['tpl_allow_php'] = false;
+ }
+
+ public static function alter_block_array_data()
+ {
+ return array(
+ array(
+ 'outer',
+ array('VARIABLE' => 'before'),
+ false,
+ 'insert',
+ <<<EOT
+outer - 0/4 - before
+outer - 1/4
+middle - 0/2
+middle - 1/2
+outer - 2/4
+middle - 0/3
+middle - 1/3
+middle - 2/3
+outer - 3/4
+middle - 0/2
+middle - 1/2
+EOT
+,
+ 'Test inserting before on top level block',
+ ),
+ array(
+ 'outer',
+ array('VARIABLE' => 'after'),
+ true,
+ 'insert',
+ <<<EOT
+outer - 0/4
+middle - 0/2
+middle - 1/2
+outer - 1/4
+middle - 0/3
+middle - 1/3
+middle - 2/3
+outer - 2/4
+middle - 0/2
+middle - 1/2
+outer - 3/4 - after
+EOT
+,
+ 'Test inserting after on top level block',
+ ),
+ array(
+ 'outer',
+ array('VARIABLE' => 'pos #1'),
+ 1,
+ 'insert',
+ <<<EOT
+outer - 0/4
+middle - 0/2
+middle - 1/2
+outer - 1/4 - pos #1
+outer - 2/4
+middle - 0/3
+middle - 1/3
+middle - 2/3
+outer - 3/4
+middle - 0/2
+middle - 1/2
+EOT
+,
+ 'Test inserting at 1 on top level block',
+ ),
+ array(
+ 'outer',
+ array('VARIABLE' => 'pos #1'),
+ 0,
+ 'change',
+ <<<EOT
+outer - 0/3 - pos #1
+middle - 0/2
+middle - 1/2
+outer - 1/3
+middle - 0/3
+middle - 1/3
+middle - 2/3
+outer - 2/3
+middle - 0/2
+middle - 1/2
+EOT
+,
+ 'Test inserting at 1 on top level block',
+ ),
+ array(
+ 'outer[0].middle',
+ array('VARIABLE' => 'before'),
+ false,
+ 'insert',
+ <<<EOT
+outer - 0/3
+middle - 0/3 - before
+middle - 1/3
+middle - 2/3
+outer - 1/3
+middle - 0/3
+middle - 1/3
+middle - 2/3
+outer - 2/3
+middle - 0/2
+middle - 1/2
+EOT
+,
+ 'Test inserting before on nested block',
+ ),
+ array(
+ 'outer[0].middle',
+ array('VARIABLE' => 'after'),
+ true,
+ 'insert',
+ <<<EOT
+outer - 0/3
+middle - 0/3
+middle - 1/3
+middle - 2/3 - after
+outer - 1/3
+middle - 0/3
+middle - 1/3
+middle - 2/3
+outer - 2/3
+middle - 0/2
+middle - 1/2
+EOT
+,
+ 'Test inserting after on nested block',
+ ),
+ array(
+ 'outer[0].middle',
+ array('VARIABLE' => 'pos #1'),
+ 1,
+ 'insert',
+ <<<EOT
+outer - 0/3
+middle - 0/3
+middle - 1/3 - pos #1
+middle - 2/3
+outer - 1/3
+middle - 0/3
+middle - 1/3
+middle - 2/3
+outer - 2/3
+middle - 0/2
+middle - 1/2
+EOT
+,
+ 'Test inserting at pos 1 on nested block',
+ ),
+ array(
+ 'outer[1].middle',
+ array('VARIABLE' => 'before'),
+ false,
+ 'insert',
+ <<<EOT
+outer - 0/3
+middle - 0/2
+middle - 1/2
+outer - 1/3
+middle - 0/4 - before
+middle - 1/4
+middle - 2/4
+middle - 3/4
+outer - 2/3
+middle - 0/2
+middle - 1/2
+EOT
+,
+ 'Test inserting before on nested block (pos 1)',
+ ),
+ array(
+ 'outer[].middle',
+ array('VARIABLE' => 'before'),
+ false,
+ 'insert',
+ <<<EOT
+outer - 0/3
+middle - 0/2
+middle - 1/2
+outer - 1/3
+middle - 0/3
+middle - 1/3
+middle - 2/3
+outer - 2/3
+middle - 0/3 - before
+middle - 1/3
+middle - 2/3
+EOT
+,
+ 'Test inserting before on nested block (end)',
+ ),
+ array(
+ 'outer.middle',
+ array('VARIABLE' => 'before'),
+ false,
+ 'insert',
+ <<<EOT
+outer - 0/3
+middle - 0/2
+middle - 1/2
+outer - 1/3
+middle - 0/3
+middle - 1/3
+middle - 2/3
+outer - 2/3
+middle - 0/3 - before
+middle - 1/3
+middle - 2/3
+EOT
+,
+ 'Test inserting before on nested block (end)',
+ ),
+ );
+ }
+
+/*
+ <<<EOT
+outer - 0/3
+middle - 0/2
+middle - 1/2
+outer - 1/3
+middle - 0/3
+middle - 1/3
+middle - 2/3
+outer - 2/3
+middle - 0/2
+middle - 1/2
+EOT
+,
+*/
+
+ /**
+ * @dataProvider alter_block_array_data
+ */
+ public function test_alter_block_array($alter_block, array $vararray, $key, $mode, $expect, $description)
+ {
+ $this->markTestIncomplete('Alter Block Test is broken');
+
+ $this->template->set_filenames(array('test' => 'loop_nested.html'));
+
+ // @todo Change this
+ $this->template->assign_block_vars('outer', array());
+ $this->template->assign_block_vars('outer.middle', array());
+ $this->template->assign_block_vars('outer.middle', array());
+ $this->template->assign_block_vars('outer', array());
+ $this->template->assign_block_vars('outer.middle', array());
+ $this->template->assign_block_vars('outer.middle', array());
+ $this->template->assign_block_vars('outer.middle', array());
+ $this->template->assign_block_vars('outer', array());
+ $this->template->assign_block_vars('outer.middle', array());
+ $this->template->assign_block_vars('outer.middle', array());
+
+ $this->assertEquals("outer - 0/3\nmiddle - 0/2\nmiddle - 1/2\nouter - 1/3\nmiddle - 0/3\nmiddle - 1/3\nmiddle - 2/3\nouter - 2/3\nmiddle - 0/2\nmiddle - 1/2", $this->display('test'), 'Ensuring template is built correctly before modification');
+
+ $this->template->alter_block_array($alter_block, $vararray, $key, $mode);
+ $this->assertEquals($expect, $this->display('test'), $description);
+ }
+}
+
diff --git a/tests/template/templates/_dummy_include.php b/tests/template/templates/_dummy_include.php
new file mode 100644
index 0000000000..1de5dddf59
--- /dev/null
+++ b/tests/template/templates/_dummy_include.php
@@ -0,0 +1,3 @@
+<?php
+
+echo "testing included php";
diff --git a/tests/template/templates/basic.html b/tests/template/templates/basic.html
new file mode 100644
index 0000000000..c1dd690260
--- /dev/null
+++ b/tests/template/templates/basic.html
@@ -0,0 +1,20 @@
+<!-- IF S_FALSE -->
+fail
+<!-- ENDIF -->
+<!-- IF S_TRUE -->
+pass
+<!-- ENDIF -->
+<!-- IF S_FALSE -->
+fail
+<!-- ELSEIF S_FALSE and not S_TRUE -->
+fail
+<!-- ELSE -->
+pass
+<!-- ENDIF -->
+<!-- BEGIN empty -->
+fail
+<!-- BEGINELSE -->
+pass
+<!-- END empty -->
+
+<!-- DUMMY var -->
diff --git a/tests/template/templates/define.html b/tests/template/templates/define.html
new file mode 100644
index 0000000000..82237d21a3
--- /dev/null
+++ b/tests/template/templates/define.html
@@ -0,0 +1,8 @@
+<!-- DEFINE $VALUE = 'xyz' -->
+{$VALUE}
+<!-- DEFINE $VALUE = 'abc' -->
+{$VALUE}
+<!-- UNDEFINE $VALUE -->
+{$VALUE}
+<!-- DEFINE $VALUE -->
+
diff --git a/tests/template/templates/expressions.html b/tests/template/templates/expressions.html
new file mode 100644
index 0000000000..c40d967dab
--- /dev/null
+++ b/tests/template/templates/expressions.html
@@ -0,0 +1,86 @@
+<!-- IF 10 is even -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+<!-- IF 9 is even -->fail<!-- ELSE -->pass<!-- ENDIF -->
+
+<!-- IF not 390 is even -->fail<!-- ELSE -->pass<!-- ENDIF -->
+
+<!-- IF 9 is odd -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+<!-- IF 32 is odd -->fail<!-- ELSE -->pass<!-- ENDIF -->
+
+<!-- IF 32 is div by 16 -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+<!-- IF 10 is not even -->fail<!-- ELSE -->pass<!-- ENDIF -->
+
+<!-- IF 24 == 24 -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+<!-- IF 24 eq 24 -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+<!-- IF ((((((24 == 24)))))) -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+
+<!-- IF 24 != 20 -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+<!-- IF 24 <> 20 -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+<!-- IF 24 ne 20 -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+<!-- IF 24 neq 20 -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+
+<!-- IF 10 lt 20 -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+<!-- IF 10 < 20 -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+
+<!-- IF 10 le 20 -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+<!-- IF 10 lte 20 -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+<!-- IF 10 <= 20 -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+<!-- IF 20 le 20 -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+<!-- IF 20 lte 20 -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+<!-- IF 20 <= 20 -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+
+<!-- IF 9 gt 1 -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+<!-- IF 9 > 1 -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+
+<!-- IF 9 >= 1 -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+<!-- IF 9 gte 1 -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+<!-- IF 9 ge 1 -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+<!-- IF 9 >= 9 -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+<!-- IF 9 gte 9 -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+<!-- IF 9 ge 9 -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+
+<!-- IF true && (10 > 4) -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+<!-- IF true and (10 > 4) -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+
+<!-- IF false || true -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+<!-- IF false or true -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+
+<!-- IF !false -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+<!-- IF not false -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+<!-- IF not not not false -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+
+<!-- IF 6 % 4 == 2 -->pass<!-- ELSE -->fail<!-- ENDIF -->
+
+<!-- IF 24 mod 12 == 0 -->pass<!-- ELSE -->fail<!-- ENDIF -->
diff --git a/tests/template/templates/if.html b/tests/template/templates/if.html
new file mode 100644
index 0000000000..c502e52f51
--- /dev/null
+++ b/tests/template/templates/if.html
@@ -0,0 +1,11 @@
+<!-- IF S_VALUE -->
+1
+<!-- ELSEIF S_OTHER_VALUE -->
+2
+<!-- ELSE -->
+0
+<!-- ENDIF -->
+
+<!-- IF (S_VALUE > S_OTHER_VALUE) -->
+0
+<!-- ENDIF -->
diff --git a/tests/template/templates/include.html b/tests/template/templates/include.html
new file mode 100644
index 0000000000..730d713d65
--- /dev/null
+++ b/tests/template/templates/include.html
@@ -0,0 +1 @@
+<!-- INCLUDE variable.html -->
diff --git a/tests/template/templates/includephp.html b/tests/template/templates/includephp.html
new file mode 100644
index 0000000000..3e13fa33fa
--- /dev/null
+++ b/tests/template/templates/includephp.html
@@ -0,0 +1 @@
+<!-- INCLUDEPHP ../templates/_dummy_include.php -->
diff --git a/tests/template/templates/lang.html b/tests/template/templates/lang.html
new file mode 100644
index 0000000000..2b5ea1cafe
--- /dev/null
+++ b/tests/template/templates/lang.html
@@ -0,0 +1,3 @@
+{L_VARIABLE}
+
+{LA_VARIABLE}
diff --git a/tests/template/templates/loop.html b/tests/template/templates/loop.html
new file mode 100644
index 0000000000..de1a10004d
--- /dev/null
+++ b/tests/template/templates/loop.html
@@ -0,0 +1,21 @@
+<!-- BEGIN loop -->
+loop
+<!-- BEGINELSE -->
+noloop
+<!-- END loop -->
+
+<!-- IF .loop -->
+loop
+<!-- ELSE -->
+noloop
+<!-- ENDIF -->
+
+<!-- IF .loop == 2 -->
+loop
+<!-- ENDIF -->
+
+<!-- BEGIN loop -->
+<!-- BEGIN !block -->
+loop#{loop.S_ROW_COUNT}-block#{block.S_ROW_COUNT}
+<!-- END !block -->
+<!-- END loop -->
diff --git a/tests/template/templates/loop_advanced.html b/tests/template/templates/loop_advanced.html
new file mode 100644
index 0000000000..c75fe55f03
--- /dev/null
+++ b/tests/template/templates/loop_advanced.html
@@ -0,0 +1,19 @@
+<!-- BEGIN loop -->{loop.S_FIRST_ROW}{loop.S_ROW_COUNT}{loop.S_LAST_ROW}<!-- END loop -->
+x
+<!-- BEGIN loop(0) -->{loop.S_FIRST_ROW}{loop.S_ROW_COUNT}{loop.S_LAST_ROW}<!-- END loop -->
+x
+<!-- BEGIN loop(0,-1) -->{loop.S_FIRST_ROW}{loop.S_ROW_COUNT}{loop.S_LAST_ROW}<!-- END loop -->
+x
+<!-- BEGIN loop(1) -->{loop.S_FIRST_ROW}{loop.S_ROW_COUNT}{loop.S_LAST_ROW}<!-- END loop -->
+x
+<!-- BEGIN loop(1,1) -->{loop.S_FIRST_ROW}{loop.S_ROW_COUNT}{loop.S_LAST_ROW}<!-- END loop -->
+x
+<!-- BEGIN loop(0,1) -->{loop.S_FIRST_ROW}{loop.S_ROW_COUNT}{loop.S_LAST_ROW}<!-- END loop -->
+x
+<!-- BEGIN loop(2,4) -->{loop.S_FIRST_ROW}{loop.S_ROW_COUNT}{loop.S_LAST_ROW}<!-- END loop -->
+x
+<!-- BEGIN loop(0,-7) -->{loop.S_FIRST_ROW}{loop.S_ROW_COUNT}{loop.S_LAST_ROW}<!-- END loop -->
+x
+<!-- BEGIN loop(-2,6) -->{loop.S_FIRST_ROW}{loop.S_ROW_COUNT}{loop.S_LAST_ROW}<!-- END loop -->
+x
+<!-- BEGIN loop(-2,-1) -->{loop.S_FIRST_ROW}{loop.S_ROW_COUNT}{loop.S_LAST_ROW}<!-- END loop -->
diff --git a/tests/template/templates/loop_nested.html b/tests/template/templates/loop_nested.html
new file mode 100644
index 0000000000..571df97b4c
--- /dev/null
+++ b/tests/template/templates/loop_nested.html
@@ -0,0 +1,8 @@
+<!-- BEGIN outer -->
+ {outer.S_BLOCK_NAME} - {outer.S_ROW_NUM}/{outer.S_NUM_ROWS}<!-- IF outer.VARIABLE --> - {outer.VARIABLE}<!-- ENDIF -->
+
+ <!-- BEGIN middle -->
+ {middle.S_BLOCK_NAME} - {middle.S_ROW_NUM}/{middle.S_NUM_ROWS}<!-- IF middle.VARIABLE --> - {middle.VARIABLE}<!-- ENDIF -->
+
+ <!-- END middle -->
+<!-- END outer -->
diff --git a/tests/template/templates/loop_vars.html b/tests/template/templates/loop_vars.html
new file mode 100644
index 0000000000..4f02fd2e6c
--- /dev/null
+++ b/tests/template/templates/loop_vars.html
@@ -0,0 +1,21 @@
+<!-- BEGIN loop -->
+<!-- IF loop.S_FIRST_ROW -->first<!-- ENDIF -->
+
+{loop.S_ROW_COUNT}
+
+{loop.VARIABLE}
+
+<!-- IF loop.VARIABLE -->set<!-- ENDIF -->
+
+<!-- IF loop.S_LAST_ROW -->
+last
+<!-- ENDIF -->
+<!-- BEGIN inner -->
+
+{inner.S_ROW_COUNT}
+
+<!-- IF inner.S_LAST_ROW and inner.S_ROW_COUNT and inner.S_NUM_ROWS -->last inner<!-- ENDIF -->
+
+<!-- END inner -->
+<!-- END loop -->
+<!-- IF .loop.inner -->inner loop<!-- ENDIF -->
diff --git a/tests/template/templates/php.html b/tests/template/templates/php.html
new file mode 100644
index 0000000000..07a260cdb3
--- /dev/null
+++ b/tests/template/templates/php.html
@@ -0,0 +1 @@
+<!-- PHP -->echo "test";<!-- ENDPHP -->
diff --git a/tests/template/templates/variable.html b/tests/template/templates/variable.html
new file mode 100644
index 0000000000..f68f91597c
--- /dev/null
+++ b/tests/template/templates/variable.html
@@ -0,0 +1 @@
+{VARIABLE}