aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--code_sniffer/phpbb/Sniffs/Commenting/FileCommentSniff.php210
-rw-r--r--code_sniffer/phpbb/Tests/Commenting/FileCommentUnitTest.inc19
-rw-r--r--code_sniffer/phpbb/Tests/Commenting/FileCommentUnitTest.php51
-rw-r--r--code_sniffer/phpbb/build.xml23
-rw-r--r--code_sniffer/phpbb/phpbbCodingStandard.php43
-rw-r--r--phpBB/develop/create_schema_files.php1
-rw-r--r--phpBB/develop/mysql_upgrader.php1
-rw-r--r--phpBB/install/schemas/firebird_schema.sql1
-rw-r--r--phpBB/install/schemas/mssql_schema.sql3
-rw-r--r--phpBB/install/schemas/mysql_40_schema.sql1
-rw-r--r--phpBB/install/schemas/mysql_41_schema.sql1
-rw-r--r--phpBB/install/schemas/oracle_schema.sql2
-rw-r--r--phpBB/install/schemas/postgres_schema.sql1
-rw-r--r--phpBB/install/schemas/sqlite_schema.sql1
-rw-r--r--phpBB/styles/prosilver/template/ucp_register.html2
-rw-r--r--tests/all_tests.php54
-rw-r--r--tests/bbcode/all_tests.php44
-rw-r--r--tests/bbcode/parser_test.php31
-rw-r--r--tests/request/all_tests.php41
-rw-r--r--tests/request/request_class.php74
-rw-r--r--tests/request/request_var.php264
-rw-r--r--tests/security/all_tests.php88
-rw-r--r--tests/security/extract_current_page.php53
-rw-r--r--tests/security/redirect.php58
-rw-r--r--tests/template/all_tests.php41
-rw-r--r--tests/template/template.php666
-rw-r--r--tests/template/templates/_dummy_include.php3
-rw-r--r--tests/template/templates/basic.html20
-rw-r--r--tests/template/templates/define.html41
-rw-r--r--tests/template/templates/expressions.html88
-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.html23
-rw-r--r--tests/template/templates/loop_advanced.html59
-rw-r--r--tests/template/templates/loop_expressions.html11
-rw-r--r--tests/template/templates/loop_nested.html8
-rw-r--r--tests/template/templates/loop_vars.html23
-rw-r--r--tests/template/templates/php.html1
-rw-r--r--tests/template/templates/variable.html1
-rw-r--r--tests/test_framework/framework.php29
-rw-r--r--tests/test_framework/phpbb_test_case.php30
-rw-r--r--tests/text_processing/all_tests.php41
-rw-r--r--tests/text_processing/make_clickable.php106
-rw-r--r--tests/utf/all_tests.php43
-rw-r--r--tests/utf/utf8_clean_string_test.php32
-rw-r--r--tests/utf/utf8_wordwrap_test.php84
48 files changed, 2432 insertions, 1 deletions
diff --git a/code_sniffer/phpbb/Sniffs/Commenting/FileCommentSniff.php b/code_sniffer/phpbb/Sniffs/Commenting/FileCommentSniff.php
new file mode 100644
index 0000000000..e63c3f65fd
--- /dev/null
+++ b/code_sniffer/phpbb/Sniffs/Commenting/FileCommentSniff.php
@@ -0,0 +1,210 @@
+<?php
+/**
+*
+* @package code_sniffer
+* @version $Id: $
+* @copyright (c) 2007 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License
+*
+*/
+
+/**
+* Checks that each source file contains the standard header.
+*
+* Based on Coding Guidelines 1.ii File Header.
+*
+* @package code_sniffer
+* @author Manuel Pichler <mapi@phpundercontrol.org>
+*/
+class phpbb_Sniffs_Commenting_FileCommentSniff implements PHP_CodeSniffer_Sniff
+{
+ /**
+ * Returns an array of tokens this test wants to listen for.
+ *
+ * @return array
+ */
+ public function register()
+ {
+ return array(T_OPEN_TAG);
+ }
+
+ /**
+ * Processes this test, when one of its tokens is encountered.
+ *
+ * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
+ * @param int $stackPtr The position of the current token
+ * in the stack passed in $tokens.
+ *
+ * @return void
+ */
+ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
+ {
+ // We are only interested in the first file comment.
+ if ($stackPtr !== 0)
+ {
+ if ($phpcsFile->findPrevious(T_OPEN_TAG, $stackPtr - 1) !== false)
+ {
+ return;
+ }
+ }
+
+ // Fetch next non whitespace token
+ $tokens = $phpcsFile->getTokens();
+ $start = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true);
+
+ // Skip empty files
+ if ($tokens[$start]['code'] === T_CLOSE_TAG)
+ {
+ return;
+ }
+ // Mark as error if this is not a doc comment
+ else if ($start === false || $tokens[$start]['code'] !== T_DOC_COMMENT)
+ {
+ $phpcsFile->addError('Missing required file doc comment.', $stackPtr);
+ return;
+ }
+
+ // Find comment end token
+ $end = $phpcsFile->findNext(T_DOC_COMMENT, $start + 1, null, true) - 1;
+
+ // If there is no end, skip processing here
+ if ($end === false)
+ {
+ return;
+ }
+
+ // List of found comment tags
+ $tags = array();
+
+ // check comment lines without the first(/**) an last(*/) line
+ for ($i = $start + 1, $c = ($end - $start); $i <= $c; ++$i)
+ {
+ $line = $tokens[$i]['content'];
+
+ // Check that each line starts with a '*'
+ if (substr($line, 0, 1) !== '*')
+ {
+ $message = 'The file doc comment should not be idented.';
+ $phpcsFile->addWarning($message, $i);
+ }
+ else if (preg_match('/^\*\s+@([\w]+)\s+(.*)$/', $line, $match) !== 0)
+ {
+ $tags[$match[1]] = array($match[2], $i);
+ }
+ }
+
+ // Check that the first and last line is empty
+ if (trim($tokens[$start + 1]['content']) !== '*')
+ {
+ $message = 'The first file comment line should be empty.';
+ $phpcsFile->addWarning($message, ($start + 1));
+ }
+ if (trim($tokens[$end - $start]['content']) !== '*')
+ {
+ $message = 'The last file comment line should be empty.';
+ $phpcsFile->addWarning($message, ($end - $start));
+ }
+
+ $this->processPackage($phpcsFile, $start, $tags);
+ $this->processVersion($phpcsFile, $start, $tags);
+ $this->processCopyright($phpcsFile, $start, $tags);
+ $this->processLicense($phpcsFile, $start, $tags);
+
+ //print_r($tags);
+ }
+
+ /**
+ * Checks that the tags array contains a valid package tag
+ *
+ * @param PHP_CodeSniffer_File $phpcsFile The context source file instance.
+ * @param integer The stack pointer for the first comment token.
+ * @param array(string=>array) $tags The found file doc comment tags.
+ *
+ * @return void
+ */
+ protected function processPackage(PHP_CodeSniffer_File $phpcsFile, $ptr, $tags)
+ {
+ if (!isset($tags['package']))
+ {
+ $message = 'Missing require @package tag in file doc comment.';
+ $phpcsFile->addError($message, $ptr);
+ }
+ else if (preg_match('/^([\w]+)$/', $tags['package'][0]) === 0)
+ {
+ $message = 'Invalid content found for @package tag.';
+ $phpcsFile->addWarning($message, $tags['package'][1]);
+ }
+ }
+
+ /**
+ * Checks that the tags array contains a valid version tag
+ *
+ * @param PHP_CodeSniffer_File $phpcsFile The context source file instance.
+ * @param integer The stack pointer for the first comment token.
+ * @param array(string=>array) $tags The found file doc comment tags.
+ *
+ * @return void
+ */
+ protected function processVersion(PHP_CodeSniffer_File $phpcsFile, $ptr, $tags)
+ {
+ if (!isset($tags['version']))
+ {
+ $message = 'Missing require @version tag in file doc comment.';
+ $phpcsFile->addError($message, $ptr);
+ }
+ else if (preg_match('/^\$Id:[^\$]+\$$/', $tags['version'][0]) === 0)
+ {
+ $message = 'Invalid content found for @version tag, use "$Id: $".';
+ $phpcsFile->addError($message, $tags['version'][1]);
+ }
+ }
+
+ /**
+ * Checks that the tags array contains a valid copyright tag
+ *
+ * @param PHP_CodeSniffer_File $phpcsFile The context source file instance.
+ * @param integer The stack pointer for the first comment token.
+ * @param array(string=>array) $tags The found file doc comment tags.
+ *
+ * @return void
+ */
+ protected function processCopyright(PHP_CodeSniffer_File $phpcsFile, $ptr, $tags)
+ {
+ if (!isset($tags['copyright']))
+ {
+ $message = 'Missing require @copyright tag in file doc comment.';
+ $phpcsFile->addError($message, $ptr);
+ }
+ else if (preg_match('/^\(c\) 2[0-9]{3} phpBB Group\s*$/', $tags['copyright'][0]) === 0)
+ {
+ $message = 'Invalid content found for @copyright tag, use "(c) <year> phpBB Group".';
+ $phpcsFile->addError($message, $tags['copyright'][1]);
+ }
+ }
+
+ /**
+ * Checks that the tags array contains a valid license tag
+ *
+ * @param PHP_CodeSniffer_File $phpcsFile The context source file instance.
+ * @param integer The stack pointer for the first comment token.
+ * @param array(string=>array) $tags The found file doc comment tags.
+ *
+ * @return void
+ */
+ protected function processLicense(PHP_CodeSniffer_File $phpcsFile, $ptr, $tags)
+ {
+ $license = 'http://opensource.org/licenses/gpl-license.php GNU Public License';
+
+ if (!isset($tags['license']))
+ {
+ $message = 'Missing require @license tag in file doc comment.';
+ $phpcsFile->addError($message, $ptr);
+ }
+ else if (trim($tags['license'][0]) !== $license)
+ {
+ $message = 'Invalid content found for @license tag, use '
+ . '"' . $license . '".';
+ $phpcsFile->addError($message, $tags['license'][1]);
+ }
+ }
+} \ No newline at end of file
diff --git a/code_sniffer/phpbb/Tests/Commenting/FileCommentUnitTest.inc b/code_sniffer/phpbb/Tests/Commenting/FileCommentUnitTest.inc
new file mode 100644
index 0000000000..0ace1c1bda
--- /dev/null
+++ b/code_sniffer/phpbb/Tests/Commenting/FileCommentUnitTest.inc
@@ -0,0 +1,19 @@
+<?php
+/**
+*
+* @package code_sniffer³
+* @version $Id: $
+* @copyright (c) 2008 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php BSD License
+ *
+*/
+?>
+<?php
+/**
+* Broken but not first file doc comment.
+*
+* @version @package_version@
+* @license http://www.opensource.org/licenses/bsd-license.php BSD License
+* @copyright (c) 2007 phpBB Group
+*
+*/
diff --git a/code_sniffer/phpbb/Tests/Commenting/FileCommentUnitTest.php b/code_sniffer/phpbb/Tests/Commenting/FileCommentUnitTest.php
new file mode 100644
index 0000000000..849a7fb9a0
--- /dev/null
+++ b/code_sniffer/phpbb/Tests/Commenting/FileCommentUnitTest.php
@@ -0,0 +1,51 @@
+<?php
+/**
+*
+* @package code_sniffer
+* @version $Id: $
+* @copyright (c) 2007 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License
+*
+*/
+
+/**
+* Unit test class for the EmptyStatement sniff.
+*
+* @package code_sniffer
+* @author Manuel Pichler <mapi@phpundercontrol.org>
+*/
+class phpbb_Tests_Commenting_FileCommentUnitTest extends AbstractSniffUnitTest
+{
+
+ /**
+ * Returns the lines where errors should occur.
+ *
+ * The key of the array should represent the line number and the value
+ * should represent the number of errors that should occur on that line.
+ *
+ * @return array(int => int)
+ */
+ public function getErrorList()
+ {
+ return array(
+ 7 => 1 // BSD License error :)
+ );
+ }//end getErrorList()
+
+
+ /**
+ * Returns the lines where warnings should occur.
+ *
+ * The key of the array should represent the line number and the value
+ * should represent the number of warnings that should occur on that line.
+ *
+ * @return array(int => int)
+ */
+ public function getWarningList()
+ {
+ return array(
+ 4 => 1,
+ 8 => 1
+ );
+ }//end getWarningList()
+} \ No newline at end of file
diff --git a/code_sniffer/phpbb/build.xml b/code_sniffer/phpbb/build.xml
new file mode 100644
index 0000000000..b6d3bf6451
--- /dev/null
+++ b/code_sniffer/phpbb/build.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="code_sniffer" basedir="." default="install">
+
+ <property name="working.dir" value="${basedir}" />
+ <property name="target.dir" value="/usr/share/php/PHP/CodeSniffer/Standards" />
+
+ <!--
+ Install phpbb sniff
+ -->
+ <target name="install">
+ <delete dir="${target.dir}/phpbb" />
+ <mkdir dir="${target.dir}/phpbb"/>
+
+ <copy todir="${target.dir}/phpbb">
+ <fileset file="${working.dir}/phpbbCodingStandard.php" />
+ </copy>
+ <copy todir="${target.dir}/phpbb/Sniffs">
+ <fileset dir="${working.dir}/Sniffs" />
+ </copy>
+
+ </target>
+
+</project>
diff --git a/code_sniffer/phpbb/phpbbCodingStandard.php b/code_sniffer/phpbb/phpbbCodingStandard.php
new file mode 100644
index 0000000000..be51b54b40
--- /dev/null
+++ b/code_sniffer/phpbb/phpbbCodingStandard.php
@@ -0,0 +1,43 @@
+<?php
+/**
+*
+* @package code_sniffer
+* @version $Id: $
+* @copyright (c) 2007 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License
+*
+*/
+
+/**
+ * @ignore
+ */
+if (class_exists('PHP_CodeSniffer_Standards_CodingStandard', true) === false) {
+ throw new PHP_CodeSniffer_Exception(
+ 'Class PHP_CodeSniffer_Standards_CodingStandard not found'
+ );
+}
+
+/**
+ * Primary class for the phpbb coding standard.
+ *
+ * @package code_sniffer
+ */
+class PHP_CodeSniffer_Standards_phpbb_phpbbCodingStandard extends PHP_CodeSniffer_Standards_CodingStandard
+{
+ /**
+ * Return a list of external sniffs to include with this standard.
+ *
+ * External locations can be single sniffs, a whole directory of sniffs, or
+ * an entire coding standard. Locations start with the standard name. For
+ * example:
+ * PEAR => include all sniffs in this standard
+ * PEAR/Sniffs/Files => include all sniffs in this dir
+ * PEAR/Sniffs/Files/LineLengthSniff => include this single sniff
+ *
+ * @return array
+ */
+ public function getIncludedSniffs()
+ {
+ return array();
+ }
+} \ No newline at end of file
diff --git a/phpBB/develop/create_schema_files.php b/phpBB/develop/create_schema_files.php
index 0515d801f2..4fb7b0d8f7 100644
--- a/phpBB/develop/create_schema_files.php
+++ b/phpBB/develop/create_schema_files.php
@@ -1200,6 +1200,7 @@ function get_schema_struct()
'PRIMARY_KEY' => 'log_id',
'KEYS' => array(
'log_type' => array('INDEX', 'log_type'),
+ 'log_time' => array('INDEX', 'log_time'),
'forum_id' => array('INDEX', 'forum_id'),
'topic_id' => array('INDEX', 'topic_id'),
'reportee_id' => array('INDEX', 'reportee_id'),
diff --git a/phpBB/develop/mysql_upgrader.php b/phpBB/develop/mysql_upgrader.php
index 57230339e8..85da1dfa47 100644
--- a/phpBB/develop/mysql_upgrader.php
+++ b/phpBB/develop/mysql_upgrader.php
@@ -688,6 +688,7 @@ function get_schema_struct()
'PRIMARY_KEY' => 'log_id',
'KEYS' => array(
'log_type' => array('INDEX', 'log_type'),
+ 'log_time' => array('INDEX', 'log_time'),
'forum_id' => array('INDEX', 'forum_id'),
'topic_id' => array('INDEX', 'topic_id'),
'reportee_id' => array('INDEX', 'reportee_id'),
diff --git a/phpBB/install/schemas/firebird_schema.sql b/phpBB/install/schemas/firebird_schema.sql
index 85f86781de..ab622e8fde 100644
--- a/phpBB/install/schemas/firebird_schema.sql
+++ b/phpBB/install/schemas/firebird_schema.sql
@@ -529,6 +529,7 @@ CREATE TABLE phpbb_log (
ALTER TABLE phpbb_log ADD PRIMARY KEY (log_id);;
CREATE INDEX phpbb_log_log_type ON phpbb_log(log_type);;
+CREATE INDEX phpbb_log_log_time ON phpbb_log(log_time);;
CREATE INDEX phpbb_log_forum_id ON phpbb_log(forum_id);;
CREATE INDEX phpbb_log_topic_id ON phpbb_log(topic_id);;
CREATE INDEX phpbb_log_reportee_id ON phpbb_log(reportee_id);;
diff --git a/phpBB/install/schemas/mssql_schema.sql b/phpBB/install/schemas/mssql_schema.sql
index 0827b14cc2..068373c9a1 100644
--- a/phpBB/install/schemas/mssql_schema.sql
+++ b/phpBB/install/schemas/mssql_schema.sql
@@ -636,6 +636,9 @@ GO
CREATE INDEX [log_type] ON [phpbb_log]([log_type]) ON [PRIMARY]
GO
+CREATE INDEX [log_time] ON [phpbb_log]([log_time]) ON [PRIMARY]
+GO
+
CREATE INDEX [forum_id] ON [phpbb_log]([forum_id]) ON [PRIMARY]
GO
diff --git a/phpBB/install/schemas/mysql_40_schema.sql b/phpBB/install/schemas/mysql_40_schema.sql
index 19b1b4f0f7..813cf8613f 100644
--- a/phpBB/install/schemas/mysql_40_schema.sql
+++ b/phpBB/install/schemas/mysql_40_schema.sql
@@ -362,6 +362,7 @@ CREATE TABLE phpbb_log (
log_data mediumblob NOT NULL,
PRIMARY KEY (log_id),
KEY log_type (log_type),
+ KEY log_time (log_time),
KEY forum_id (forum_id),
KEY topic_id (topic_id),
KEY reportee_id (reportee_id),
diff --git a/phpBB/install/schemas/mysql_41_schema.sql b/phpBB/install/schemas/mysql_41_schema.sql
index 3b70630a9e..97369d2bf7 100644
--- a/phpBB/install/schemas/mysql_41_schema.sql
+++ b/phpBB/install/schemas/mysql_41_schema.sql
@@ -362,6 +362,7 @@ CREATE TABLE phpbb_log (
log_data mediumtext NOT NULL,
PRIMARY KEY (log_id),
KEY log_type (log_type),
+ KEY log_time (log_time),
KEY forum_id (forum_id),
KEY topic_id (topic_id),
KEY reportee_id (reportee_id),
diff --git a/phpBB/install/schemas/oracle_schema.sql b/phpBB/install/schemas/oracle_schema.sql
index d577fce46c..7be7cd0756 100644
--- a/phpBB/install/schemas/oracle_schema.sql
+++ b/phpBB/install/schemas/oracle_schema.sql
@@ -715,6 +715,8 @@ CREATE TABLE phpbb_log (
CREATE INDEX phpbb_log_log_type ON phpbb_log (log_type)
/
+CREATE INDEX phpbb_log_log_time ON phpbb_log (log_time)
+/
CREATE INDEX phpbb_log_forum_id ON phpbb_log (forum_id)
/
CREATE INDEX phpbb_log_topic_id ON phpbb_log (topic_id)
diff --git a/phpBB/install/schemas/postgres_schema.sql b/phpBB/install/schemas/postgres_schema.sql
index 50b3979adb..9cdf35024b 100644
--- a/phpBB/install/schemas/postgres_schema.sql
+++ b/phpBB/install/schemas/postgres_schema.sql
@@ -519,6 +519,7 @@ CREATE TABLE phpbb_log (
);
CREATE INDEX phpbb_log_log_type ON phpbb_log (log_type);
+CREATE INDEX phpbb_log_log_time ON phpbb_log (log_time);
CREATE INDEX phpbb_log_forum_id ON phpbb_log (forum_id);
CREATE INDEX phpbb_log_topic_id ON phpbb_log (topic_id);
CREATE INDEX phpbb_log_reportee_id ON phpbb_log (reportee_id);
diff --git a/phpBB/install/schemas/sqlite_schema.sql b/phpBB/install/schemas/sqlite_schema.sql
index 7ee821d395..34b4b05478 100644
--- a/phpBB/install/schemas/sqlite_schema.sql
+++ b/phpBB/install/schemas/sqlite_schema.sql
@@ -352,6 +352,7 @@ CREATE TABLE phpbb_log (
);
CREATE INDEX phpbb_log_log_type ON phpbb_log (log_type);
+CREATE INDEX phpbb_log_log_time ON phpbb_log (log_time);
CREATE INDEX phpbb_log_forum_id ON phpbb_log (forum_id);
CREATE INDEX phpbb_log_topic_id ON phpbb_log (topic_id);
CREATE INDEX phpbb_log_reportee_id ON phpbb_log (reportee_id);
diff --git a/phpBB/styles/prosilver/template/ucp_register.html b/phpBB/styles/prosilver/template/ucp_register.html
index 0c632f5c69..e63abaec05 100644
--- a/phpBB/styles/prosilver/template/ucp_register.html
+++ b/phpBB/styles/prosilver/template/ucp_register.html
@@ -48,7 +48,7 @@
</dl>
<dl>
<dt><label for="password_confirm">{L_CONFIRM_PASSWORD}:</label></dt>
- <dd><input type="password" tabindex="5" name="password_confirm" id="password_confirm" size="25" value="{PASSWORD_CONFIRM}" class="inputbox autowidth" title="{L_CONFIRM_PASSWORD}" /></dd>
+ <dd><input type="password" tabindex="5" name="password_confirm" id="password_confirm" size="25" value="{PASSWORD_CONFIRM}" class="inputbox autowidth" title="{L_CONFIRM_PASSWORD}" /></dd>
</dl>
<hr />
diff --git a/tests/all_tests.php b/tests/all_tests.php
new file mode 100644
index 0000000000..f22ee5dc49
--- /dev/null
+++ b/tests/all_tests.php
@@ -0,0 +1,54 @@
+<?php
+/**
+*
+* @package testing
+* @version $Id$
+* @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_all_tests::main');
+}
+
+require_once 'test_framework/framework.php';
+require_once 'PHPUnit/TextUI/TestRunner.php';
+
+require_once 'utf/all_tests.php';
+require_once 'request/all_tests.php';
+require_once 'security/all_tests.php';
+#require_once 'template/all_tests.php';
+#require_once 'bbcode/all_tests.php';
+require_once 'text_processing/all_tests.php';
+
+// exclude the test directory from code coverage reports
+PHPUnit_Util_Filter::addDirectoryToFilter('./');
+
+class phpbb_all_tests
+{
+ public static function main()
+ {
+ PHPUnit_TextUI_TestRunner::run(self::suite());
+ }
+
+ public static function suite()
+ {
+ $suite = new PHPUnit_Framework_TestSuite('phpBB');
+
+ $suite->addTest(phpbb_utf_all_tests::suite());
+ $suite->addTest(phpbb_request_all_tests::suite());
+ $suite->addTest(phpbb_security_all_tests::suite());
+# $suite->addTest(phpbb_template_all_tests::suite());
+# $suite->addTest(phpbb_bbcode_all_tests::suite());
+ $suite->addTest(phpbb_text_processing_all_tests::suite());
+
+ return $suite;
+ }
+}
+
+if (PHPUnit_MAIN_METHOD == 'phpbb_all_tests::main')
+{
+ phpbb_all_tests::main();
+}
diff --git a/tests/bbcode/all_tests.php b/tests/bbcode/all_tests.php
new file mode 100644
index 0000000000..f4200fd0a9
--- /dev/null
+++ b/tests/bbcode/all_tests.php
@@ -0,0 +1,44 @@
+<?php
+/**
+*
+* @package testing
+* @version $Id$
+* @copyright (c) 2008 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License
+*
+*/
+
+define('IN_PHPBB', true);
+
+if (!defined('PHPUnit_MAIN_METHOD'))
+{
+ define('PHPUnit_MAIN_METHOD', 'phpbb_bbcode_all_tests::main');
+}
+
+require_once 'test_framework/framework.php';
+require_once 'PHPUnit/TextUI/TestRunner.php';
+
+require_once 'bbcode/parser_test.php';
+
+class phpbb_bbcode_all_tests
+{
+ public static function main()
+ {
+ PHPUnit_TextUI_TestRunner::run(self::suite());
+ }
+
+ public static function suite()
+ {
+ $suite = new PHPUnit_Framework_TestSuite('phpBB Formatted Text / BBCode');
+
+ $suite->addTestSuite('phpbb_bbcode_parser_test');
+
+ return $suite;
+ }
+}
+
+if (PHPUnit_MAIN_METHOD == 'phpbb_bbcode_all_tests::main')
+{
+ phpbb_bbcode_all_tests::main();
+}
+?> \ No newline at end of file
diff --git a/tests/bbcode/parser_test.php b/tests/bbcode/parser_test.php
new file mode 100644
index 0000000000..729fe93fc2
--- /dev/null
+++ b/tests/bbcode/parser_test.php
@@ -0,0 +1,31 @@
+<?php
+/**
+*
+* @package testing
+* @version $Id$
+* @copyright (c) 2008 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License
+*
+*/
+
+define('IN_PHPBB', true);
+
+require_once 'test_framework/framework.php';
+require_once '../phpBB/includes/bbcode/bbcode_parser_base.php';
+require_once '../phpBB/includes/bbcode/bbcode_parser.php';
+
+class phpbb_bbcode_parser_test extends PHPUnit_Framework_TestCase
+{
+ public function test_both_passes()
+ {
+ $parser = new phpbb_bbcode_parser();
+
+ $result = $parser->first_pass('[i]Italic [u]underlined text[/u][/i]');
+ $result = $parser->second_pass($result);
+
+ $expected = '<span style="font-style: italic">Italic <span style="text-decoration: underline">underlined text</span></span>';
+
+ $this->assertEquals($expected, $result, 'Simple nested BBCode first+second pass');
+ }
+}
+?> \ No newline at end of file
diff --git a/tests/request/all_tests.php b/tests/request/all_tests.php
new file mode 100644
index 0000000000..dc5d26417f
--- /dev/null
+++ b/tests/request/all_tests.php
@@ -0,0 +1,41 @@
+<?php
+/**
+*
+* @package testing
+* @version $Id$
+* @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_request_all_tests::main');
+}
+
+require_once 'test_framework/framework.php';
+require_once 'PHPUnit/TextUI/TestRunner.php';
+
+require_once 'request/request_var.php';
+
+class phpbb_request_all_tests
+{
+ public static function main()
+ {
+ PHPUnit_TextUI_TestRunner::run(self::suite());
+ }
+
+ public static function suite()
+ {
+ $suite = new PHPUnit_Framework_TestSuite('phpBB Request Parameter Handling');
+
+ $suite->addTestSuite('phpbb_request_request_var_test');
+
+ return $suite;
+ }
+}
+
+if (PHPUnit_MAIN_METHOD == 'phpbb_request_all_tests::main')
+{
+ phpbb_request_all_tests::main();
+}
diff --git a/tests/request/request_class.php b/tests/request/request_class.php
new file mode 100644
index 0000000000..e8c2154bab
--- /dev/null
+++ b/tests/request/request_class.php
@@ -0,0 +1,74 @@
+<?php
+/**
+*
+* @package testing
+* @version $Id$
+* @copyright (c) 2008 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License
+*
+*/
+
+define('IN_PHPBB', true);
+
+require_once 'test_framework/framework.php';
+
+require_once '../phpBB/includes/functions.php';
+
+class phpbb_request_request_class_test extends phpbb_test_case
+{
+ protected function setUp()
+ {
+ $_POST['test'] = 1;
+ $_GET['test'] = 2;
+ $_COOKIE['test'] = 3;
+ $_REQUEST['test'] = 3;
+
+ // reread data from super globals
+ request::reset();
+ }
+
+ public function test_toggle_super_globals()
+ {
+ // toggle super globals
+ request::disable_super_globals();
+ request::enable_super_globals();
+
+ $this->assertEquals(1, $_POST['test'], 'Checking $_POST toggling via request::dis/enable_super_globals');
+ $this->assertEquals(2, $_GET['test'], 'Checking $_GET toggling via request::dis/enable_super_globals');
+ $this->assertEquals(3, $_COOKIE['test'], 'Checking $_COOKIE toggling via request::dis/enable_super_globals');
+ $this->assertEquals(3, $_REQUEST['test'], 'Checking $_REQUEST toggling via request::dis/enable_super_globals');
+
+ $_POST['x'] = 2;
+ $this->assertEquals($_POST, $GLOBALS['_POST'], 'Checking whether $_POST can still be accessed via $GLOBALS[\'_POST\']');
+ }
+
+ /**
+ * Checks that directly accessing $_POST will trigger
+ * an error.
+ */
+ public function test_disable_post_super_global()
+ {
+ request::disable_super_globals();
+
+ $this->setExpectedTriggerError(E_USER_ERROR);
+ $_POST['test'] = 3;
+ }
+
+ public function test_is_set_post()
+ {
+ $_GET['unset'] = '';
+ request::reset();
+
+ $this->assertTrue(request::is_set_post('test'));
+ $this->assertFalse(request::is_set_post('unset'));
+ }
+
+ /**
+ * Makes sure super globals work properly after these tests
+ */
+ protected function tearDown()
+ {
+ request::enable_super_globals();
+ request::reset();
+ }
+} \ No newline at end of file
diff --git a/tests/request/request_var.php b/tests/request/request_var.php
new file mode 100644
index 0000000000..c0f8a22d95
--- /dev/null
+++ b/tests/request/request_var.php
@@ -0,0 +1,264 @@
+<?php
+/**
+*
+* @package testing
+* @version $Id$
+* @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/functions.php';
+
+class phpbb_request_request_var_test extends phpbb_test_case
+{
+ /**
+ * @dataProvider request_variables
+ */
+ public function test_post($variable_value, $default, $multibyte, $expected)
+ {
+ $variable_name = 'name';
+ $this->unset_variables($variable_name);
+
+ $_POST[$variable_name] = $variable_value;
+ $_REQUEST[$variable_name] = $variable_value;
+
+ $result = request_var($variable_name, $default, $multibyte);
+
+ $label = 'Requesting POST variable, converting from ' . gettype($variable_value) . ' to ' . gettype($default) . (($multibyte) ? ' multibyte' : '');
+ $this->assertEquals($expected, $result, $label);
+ }
+
+ /**
+ * @dataProvider request_variables
+ */
+ public function test_get($variable_value, $default, $multibyte, $expected)
+ {
+ $variable_name = 'name';
+ $this->unset_variables($variable_name);
+
+ $_GET[$variable_name] = $variable_value;
+ $_REQUEST[$variable_name] = $variable_value;
+
+ $result = request_var($variable_name, $default, $multibyte);
+
+ $label = 'Requesting GET variable, converting from ' . gettype($variable_value) . ' to ' . gettype($default) . (($multibyte) ? ' multibyte' : '');
+ $this->assertEquals($expected, $result, $label);
+ }
+
+ /**
+ * @dataProvider request_variables
+ */
+ public function test_cookie($variable_value, $default, $multibyte, $expected)
+ {
+ $variable_name = 'name';
+ $this->unset_variables($variable_name);
+
+ $_GET[$variable_name] = false;
+ $_POST[$variable_name] = false;
+ $_REQUEST[$variable_name] = false;
+ $_COOKIE[$variable_name] = $variable_value;
+
+ $result = request_var($variable_name, $default, $multibyte, true);
+
+ $label = 'Requesting COOKIE variable, converting from ' . gettype($variable_value) . ' to ' . gettype($default) . (($multibyte) ? ' multibyte' : '');
+ $this->assertEquals($expected, $result, $label);
+ }
+
+ /**
+ * Helper for unsetting globals
+ */
+ private function unset_variables($var)
+ {
+ unset($_GET[$var], $_POST[$var], $_REQUEST[$var], $_COOKIE[$var]);
+ }
+
+ /**
+ * @dataProvider deep_access
+ * Only possible with 3.1.x (later)
+ public function test_deep_multi_dim_array_access($path, $default, $expected)
+ {
+ $this->unset_variables('var');
+
+ $_REQUEST['var'] = array(
+ 0 => array(
+ 'b' => array(
+ true => array(
+ 5 => 'c',
+ 6 => 'd',
+ ),
+ ),
+ ),
+ 2 => array(
+ 3 => array(
+ false => 5,
+ ),
+ ),
+ );
+
+ $result = request_var($path, $default);
+ $this->assertEquals($expected, $result, 'Testing deep access to multidimensional input arrays: ' . $path);
+ }
+
+ public static function deep_access()
+ {
+ return array(
+ // array(path, default, expected result)
+ array(array('var', 0, 'b', true, 5), '', 'c'),
+ array(array('var', 0, 'b', true, 6), '', 'd'),
+ array(array('var', 2, 3, false), 0, 5),
+ array(array('var', 0, 'b', true), array(0 => ''), array(5 => 'c', 6 => 'd')),
+ );
+ }
+*/
+ public static function request_variables()
+ {
+ return array(
+ // strings
+ array('abc', '', false, 'abc'),
+ array(' some spaces ', '', true, 'some spaces'),
+ array("\r\rsome\rcarriage\r\rreturns\r", '', true, "some\ncarriage\n\nreturns"),
+ array("\n\nsome\ncarriage\n\nreturns\n", '', true, "some\ncarriage\n\nreturns"),
+ array("\r\n\r\nsome\r\ncarriage\r\n\r\nreturns\r\n", '', true, "some\ncarriage\n\nreturns"),
+ array("we\xC2\xA1rd\xE1\x9A\x80ch\xCE\xB1r\xC2\xADacters", '', true, "we\xC2\xA1rd\xE1\x9A\x80ch\xCE\xB1r\xC2\xADacters"),
+ array("we\xC2\xA1rd\xE1\x9A\x80ch\xCE\xB1r\xC2\xADacters", '', false, "we??rd???ch??r??acters"),
+ array("Some <html> \"entities\" like &", '', true, "Some &lt;html&gt; &quot;entities&quot; like &amp;"),
+
+ // integers
+ array('1234', 0, false, 1234),
+ array('abc', 12, false, 0),
+ array('324abc', 0, false, 324),
+
+ // string to array
+ array('123', array(0), false, array()),
+ array('123', array(''), false, array()),
+
+ // 1 dimensional arrays
+ array(
+ // input:
+ array('123', 'abc'),
+ // default:
+ array(''),
+ false,
+ // expected:
+ array('123', 'abc')
+ ),
+ array(
+ // input:
+ array('123', 'abc'),
+ // default:
+ array(999),
+ false,
+ // expected:
+ array(123, 0)
+ ),
+ array(
+ // input:
+ array('xyz' => '123', 'abc' => 'abc'),
+ // default:
+ array('' => ''),
+ false,
+ // expected:
+ array('xyz' => '123', 'abc' => 'abc')
+ ),
+ array(
+ // input:
+ array('xyz' => '123', 'abc' => 'abc'),
+ // default:
+ array('' => 0),
+ false,
+ // expected:
+ array('xyz' => 123, 'abc' => 0)
+ ),
+
+ // 2 dimensional arrays
+ array(
+ // input:
+ '',
+ // default:
+ array(array(0)),
+ false,
+ // expected:
+ array()
+ ),
+ array(
+ // input:
+ array(
+ 'xyz' => array('123', 'def'),
+ 'abc' => 'abc'
+ ),
+ // default:
+ array('' => array('')),
+ false,
+ // expected:
+ array(
+ 'xyz' => array('123', 'def'),
+ 'abc' => array()
+ )
+ ),
+ array(
+ // input:
+ array(
+ 'xyz' => array('123', 'def'),
+ 'abc' => 'abc'
+ ),
+ // default:
+ array('' => array(0)),
+ false,
+ // expected:
+ array(
+ 'xyz' => array(123, 0),
+ 'abc' => array()
+ )
+ ),
+ /* 3-dimensional (not supported atm!
+ array(
+ // input:
+ array(
+ 0 => array(0 => array(3, '4', 'ab'), 1 => array()),
+ 1 => array(array(3, 4)),
+ ),
+ // default:
+ array(0 => array(0 => array(0))),
+ false,
+ // expected:
+ array(
+ 0 => array(0 => array(3, 4, 0), 1 => array()),
+ 1 => array(array(3, 4))
+ )
+ ),
+ array(
+ // input:
+ array(
+ 'ü' => array(array('c' => 'd')),
+ 'ä' => array(4 => array('a' => 2, 'ö' => 3)),
+ ),
+ // default:
+ array('' => array(0 => array('' => 0))),
+ false,
+ // expected:
+ array(
+ '??' => array(4 => array('a' => 2, '??' => 3)),
+ )
+ ),
+ array(
+ // input:
+ array(
+ 'ü' => array(array('c' => 'd')),
+ 'ä' => array(4 => array('a' => 2, 'ö' => 3)),
+ ),
+ // default:
+ array('' => array(0 => array('' => 0))),
+ true,
+ // expected:
+ array(
+ 'ü' => array(array('c' => 0)),
+ 'ä' => array(4 => array('a' => 2, 'ö' => 3)),
+ )
+ ),
+ */
+ );
+ }
+
+}
diff --git a/tests/security/all_tests.php b/tests/security/all_tests.php
new file mode 100644
index 0000000000..bff3ca82ab
--- /dev/null
+++ b/tests/security/all_tests.php
@@ -0,0 +1,88 @@
+<?php
+/**
+*
+* @package testing
+* @version $Id$
+* @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_security_all_tests::main');
+}
+
+require_once 'test_framework/framework.php';
+require_once 'PHPUnit/TextUI/TestRunner.php';
+
+require_once 'security/extract_current_page.php';
+require_once 'security/redirect.php';
+
+class phpbb_security_all_tests extends PHPUnit_Framework_TestSuite
+{
+ /**
+ * Set up the required user object and server variables for the suites
+ */
+ protected function setUp()
+ {
+ global $user, $phpbb_root_path;
+
+ // Put this into a global function being run by every test to init a proper user session
+ $_SERVER['HTTP_HOST'] = 'localhost';
+ $_SERVER['SERVER_NAME'] = 'localhost';
+ $_SERVER['SERVER_ADDR'] = '127.0.0.1';
+ $_SERVER['SERVER_PORT'] = 80;
+ $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
+ $_SERVER['QUERY_STRING'] = '';
+ $_SERVER['REQUEST_URI'] = '/tests/';
+ $_SERVER['SCRIPT_NAME'] = '/tests/index.php';
+ $_SERVER['PHP_SELF'] = '/tests/index.php';
+ $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14';
+ $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'de-de,de;q=0.8,en-us;q=0.5,en;q=0.3';
+
+/*
+ [HTTP_ACCEPT_ENCODING] => gzip,deflate
+ [HTTP_ACCEPT_CHARSET] => ISO-8859-1,utf-8;q=0.7,*;q=0.7
+ DOCUMENT_ROOT] => /var/www/
+ [SCRIPT_FILENAME] => /var/www/tests/index.php
+*/
+
+ // Set no user and trick a bit to circumvent errors
+ $user = new user();
+ $user->lang = true;
+ $user->browser = (!empty($_SERVER['HTTP_USER_AGENT'])) ? htmlspecialchars((string) $_SERVER['HTTP_USER_AGENT']) : '';
+ $user->referer = (!empty($_SERVER['HTTP_REFERER'])) ? htmlspecialchars((string) $_SERVER['HTTP_REFERER']) : '';
+ $user->forwarded_for = (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) ? (string) $_SERVER['HTTP_X_FORWARDED_FOR'] : '';
+ $user->host = (!empty($_SERVER['HTTP_HOST'])) ? (string) strtolower($_SERVER['HTTP_HOST']) : ((!empty($_SERVER['SERVER_NAME'])) ? $_SERVER['SERVER_NAME'] : getenv('SERVER_NAME'));
+ $user->page = session::extract_current_page($phpbb_root_path);
+ }
+
+ protected function tearDown()
+ {
+ global $user;
+ $user = NULL;
+ }
+
+ public static function main()
+ {
+ PHPUnit_TextUI_TestRunner::run(self::suite());
+ }
+
+ public static function suite()
+ {
+ // I bet there is a better method calling this... :)
+ $suite = new phpbb_security_all_tests('phpBB Security Fixes');
+
+ $suite->addTestSuite('phpbb_security_extract_current_page_test');
+ $suite->addTestSuite('phpbb_security_redirect_test');
+
+ return $suite;
+ }
+}
+
+if (PHPUnit_MAIN_METHOD == 'phpbb_security_all_tests::main')
+{
+ phpbb_security_all_tests::main();
+}
+?> \ No newline at end of file
diff --git a/tests/security/extract_current_page.php b/tests/security/extract_current_page.php
new file mode 100644
index 0000000000..2b61ac7062
--- /dev/null
+++ b/tests/security/extract_current_page.php
@@ -0,0 +1,53 @@
+<?php
+/**
+*
+* @package testing
+* @version $Id$
+* @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/functions.php';
+require_once '../phpBB/includes/session.php';
+
+class phpbb_security_extract_current_page_test extends phpbb_test_case
+{
+ public static function security_variables()
+ {
+ return array(
+ array('http://localhost/phpBB/index.php', 'mark=forums&x="><script>alert(/XSS/);</script>', 'mark=forums&x=%22%3E%3Cscript%3Ealert(/XSS/);%3C/script%3E'),
+ array('http://localhost/phpBB/index.php', 'mark=forums&x=%22%3E%3Cscript%3Ealert(/XSS/);%3C/script%3E', 'mark=forums&x=%22%3E%3Cscript%3Ealert(/XSS/);%3C/script%3E'),
+ );
+ }
+
+ /**
+ * @dataProvider security_variables
+ */
+ public function test_query_string_php_self($url, $query_string, $expected)
+ {
+ $_SERVER['PHP_SELF'] = $url;
+ $_SERVER['QUERY_STRING'] = $query_string;
+
+ $result = session::extract_current_page('./');
+
+ $label = 'Running extract_current_page on ' . $query_string . ' with PHP_SELF filled.';
+ $this->assertEquals($expected, $result['query_string'], $label);
+ }
+
+ /**
+ * @dataProvider security_variables
+ */
+ public function test_query_string_request_uri($url, $query_string, $expected)
+ {
+ $_SERVER['REQUEST_URI'] = $url . '?' . $query_string;
+ $_SERVER['QUERY_STRING'] = $query_string;
+
+ $result = session::extract_current_page('./');
+
+ $label = 'Running extract_current_page on ' . $query_string . ' with REQUEST_URI filled.';
+ $this->assertEquals($expected, $result['query_string'], $label);
+ }
+}
diff --git a/tests/security/redirect.php b/tests/security/redirect.php
new file mode 100644
index 0000000000..1d565ec7e3
--- /dev/null
+++ b/tests/security/redirect.php
@@ -0,0 +1,58 @@
+<?php
+/**
+*
+* @package testing
+* @version $Id$
+* @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/functions.php';
+require_once '../phpBB/includes/session.php';
+
+class phpbb_security_redirect_test extends phpbb_test_case
+{
+ public static function provider()
+ {
+ // array(Input -> redirect(), expected triggered error (else false), expected returned result url (else false))
+ return array(
+ array('data://x', false, 'http://localhost/phpBB'),
+ array('bad://localhost/phpBB/index.php', 'Tried to redirect to potentially insecure url.', false),
+ array('http://www.otherdomain.com/somescript.php', false, 'http://localhost/phpBB'),
+ array("http://localhost/phpBB/memberlist.php\n\rConnection: close", 'Tried to redirect to potentially insecure url.', false),
+ array('javascript:test', false, 'http://localhost/phpBB/../tests/javascript:test'),
+ array('http://localhost/phpBB/index.php;url=', 'Tried to redirect to potentially insecure url.', false),
+ );
+ }
+
+ protected function setUp()
+ {
+ $GLOBALS['config'] = array(
+ 'force_server_vars' => '0',
+ );
+ }
+
+ /**
+ * @dataProvider provider
+ */
+ public function test_redirect($test, $expected_error, $expected_result)
+ {
+ global $user;
+
+ if ($expected_error !== false)
+ {
+ $this->setExpectedTriggerError(E_USER_ERROR, $expected_error);
+ }
+
+ $result = redirect($test, true);
+
+ // only verify result if we did not expect an error
+ if ($expected_error === false)
+ {
+ $this->assertEquals($expected_result, $result);
+ }
+ }
+}
diff --git a/tests/template/all_tests.php b/tests/template/all_tests.php
new file mode 100644
index 0000000000..b4f6f741ca
--- /dev/null
+++ b/tests/template/all_tests.php
@@ -0,0 +1,41 @@
+<?php
+/**
+*
+* @package testing
+* @version $Id$
+* @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();
+} \ No newline at end of file
diff --git a/tests/template/template.php b/tests/template/template.php
new file mode 100644
index 0000000000..bde1c55e9d
--- /dev/null
+++ b/tests/template/template.php
@@ -0,0 +1,666 @@
+<?php
+/**
+*
+* @package testing
+* @version $Id$
+* @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 = false;
+
+ private function display($handle)
+ {
+ ob_start();
+ $this->assertTrue($this->template->display($handle, false));
+ 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',
+ ),
+ 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\n\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\n0\n1\nx\nset\nlast",
+ ),
+ 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\n101234561\n101234561\n1234561\n1\n101\n234\n10\n561\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\n\n00\n11\n22\n33\n44\n55\n66\n\n144\n144",
+ ),
+ array(
+ 'expressions.html',
+ array(),
+ array(),
+ array(),
+ trim(str_repeat("pass\n", 40)),
+ ),
+ array(
+ 'php.html',
+ array(),
+ array(),
+ array(),
+ '<!-- echo "test"; -->',
+ ),
+ 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'),
+ '',
+ ),
+ 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(
+ 'loop_expressions.html',
+ array(),
+ array('loop' => array(array(), array(), array(), array(), array(), array(), array(), array(), array(), array(), array(), array())),
+ array(),
+ "on\non\non\non\noff\noff\noff\noff\non\non\non\non\n\noff\noff\noff\non\non\non\noff\noff\noff\non\non\non",
+ ),
+ 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()
+ {
+ phpbb::$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);
+
+ phpbb::$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->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..aec5c010fd
--- /dev/null
+++ b/tests/template/templates/define.html
@@ -0,0 +1,41 @@
+<!-- DEFINE $VALUE = 'xyz' -->
+
+{$VALUE}
+
+<!-- DEFINE $VALUE = 'abc' -->
+
+{$VALUE}
+
+<!-- UNDEFINE $VALUE -->
+
+{$VALUE}
+
+<!-- DEFINE $VALUE -->
+
+<!-- BEGIN loop -->
+<!-- DEFINE loop.$VALUE = loop.S_ROW_NUM -->
+{loop.$VALUE}
+<!-- UNDEFINE $VALUE -->
+{loop.$VALUE}
+<!-- UNDEFINE loop.$VALUE -->
+{loop.$VALUE}
+
+<!-- END loop -->
+
+<!-- BEGIN test -->
+ <!-- BEGIN deep -->
+ <!-- BEGIN defines -->
+<!-- DEFINE test.deep.defines.$VALUE = 12 * 12 -->
+
+{test.deep.defines.$VALUE}
+
+<!-- UNDEFINE $VALUE -->
+
+{test.deep.defines.$VALUE}
+
+<!-- UNDEFINE test.deep.defines.$VALUE -->
+
+{test.deep.defines.$VALUE}
+ <!-- END defines -->
+ <!-- END deep -->
+<!-- END test -->
diff --git a/tests/template/templates/expressions.html b/tests/template/templates/expressions.html
new file mode 100644
index 0000000000..47a164e481
--- /dev/null
+++ b/tests/template/templates/expressions.html
@@ -0,0 +1,88 @@
+<!-- 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 !! true -->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..8ec3e66449
--- /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..42c78b9377
--- /dev/null
+++ b/tests/template/templates/includephp.html
@@ -0,0 +1 @@
+<!-- INCLUDEPHP _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..f1e1bf7e53
--- /dev/null
+++ b/tests/template/templates/loop.html
@@ -0,0 +1,23 @@
+<!-- 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_NUM}-block#{block.S_ROW_NUM}
+
+<!-- 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..1ed70f28c5
--- /dev/null
+++ b/tests/template/templates/loop_advanced.html
@@ -0,0 +1,59 @@
+<!-- BEGIN loop -->
+{loop.S_FIRST_ROW}
+{loop.S_ROW_NUM}
+{loop.S_LAST_ROW}
+<!-- END loop -->
+
+<!-- BEGIN loop(0) -->
+{loop.S_FIRST_ROW}
+{loop.S_ROW_NUM}
+{loop.S_LAST_ROW}
+<!-- END loop -->
+
+<!-- BEGIN loop(0,-1) -->
+{loop.S_FIRST_ROW}
+{loop.S_ROW_NUM}
+{loop.S_LAST_ROW}
+<!-- END loop -->
+
+<!-- BEGIN loop(1) -->
+{loop.S_FIRST_ROW}
+{loop.S_ROW_NUM}
+{loop.S_LAST_ROW}
+<!-- END loop -->
+
+<!-- BEGIN loop(1,1) -->
+{loop.S_FIRST_ROW}
+{loop.S_ROW_NUM}
+{loop.S_LAST_ROW}
+<!-- END loop -->
+
+<!-- BEGIN loop(0,1) -->
+{loop.S_FIRST_ROW}
+{loop.S_ROW_NUM}
+{loop.S_LAST_ROW}
+<!-- END loop -->
+
+<!-- BEGIN loop(2,4) -->
+{loop.S_FIRST_ROW}
+{loop.S_ROW_NUM}
+{loop.S_LAST_ROW}
+<!-- END loop -->
+
+<!-- BEGIN loop(0,-7) -->
+{loop.S_FIRST_ROW}
+{loop.S_ROW_NUM}
+{loop.S_LAST_ROW}
+<!-- END loop -->
+
+<!-- BEGIN loop(-2,6) -->
+{loop.S_FIRST_ROW}
+{loop.S_ROW_NUM}
+{loop.S_LAST_ROW}
+<!-- END loop -->
+
+<!-- BEGIN loop(-2,-1) -->
+{loop.S_FIRST_ROW}
+{loop.S_ROW_NUM}
+{loop.S_LAST_ROW}
+<!-- END loop -->
diff --git a/tests/template/templates/loop_expressions.html b/tests/template/templates/loop_expressions.html
new file mode 100644
index 0000000000..6bff53f388
--- /dev/null
+++ b/tests/template/templates/loop_expressions.html
@@ -0,0 +1,11 @@
+<!-- BEGIN loop -->
+
+<!-- IF loop.S_ROW_NUM is even by 4 -->on<!-- ELSE -->off<!-- ENDIF -->
+
+<!-- END loop -->
+
+<!-- BEGIN loop -->
+
+<!-- IF loop.S_ROW_NUM is odd by 3 -->on<!-- ELSE -->off<!-- ENDIF -->
+
+<!-- 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..1ecf49bdf2
--- /dev/null
+++ b/tests/template/templates/loop_vars.html
@@ -0,0 +1,23 @@
+<!-- BEGIN loop -->
+<!-- IF loop.S_FIRST_ROW -->first<!-- ENDIF -->
+
+{loop.S_ROW_COUNT}
+
+{loop.S_ROW_NUM}
+
+{loop.S_NUM_ROWS}
+
+{loop.VARIABLE}
+
+<!-- IF loop.VARIABLE -->set<!-- ENDIF -->
+
+<!-- IF loop.S_LAST_ROW -->last<!-- ENDIF -->
+<!-- BEGIN inner -->
+
+{inner.S_ROW_NUM}
+
+<!-- IF inner.S_LAST_ROW and inner.S_ROW_NUM 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}
diff --git a/tests/test_framework/framework.php b/tests/test_framework/framework.php
new file mode 100644
index 0000000000..01afd4e37e
--- /dev/null
+++ b/tests/test_framework/framework.php
@@ -0,0 +1,29 @@
+<?php
+
+define('IN_PHPBB', true);
+$phpbb_root_path = '../phpBB/';
+$phpEx = 'php';
+$table_prefix = '';
+
+// If we are on PHP >= 6.0.0 we do not need some code
+if (version_compare(PHP_VERSION, '6.0.0-dev', '>='))
+{
+ define('STRIP', false);
+}
+else
+{
+ @set_magic_quotes_runtime(0);
+ define('STRIP', (get_magic_quotes_gpc()) ? true : false);
+}
+
+require_once $phpbb_root_path . 'includes/constants.php';
+
+// require at least PHPUnit 3.3.0
+require_once 'PHPUnit/Runner/Version.php';
+if (version_compare(PHPUnit_Runner_Version::id(), '3.3.0', '<'))
+{
+ trigger_error('PHPUnit >= 3.3.0 required');
+}
+
+require_once 'PHPUnit/Framework.php';
+require_once 'test_framework/phpbb_test_case.php'; \ No newline at end of file
diff --git a/tests/test_framework/phpbb_test_case.php b/tests/test_framework/phpbb_test_case.php
new file mode 100644
index 0000000000..d5fdcf9889
--- /dev/null
+++ b/tests/test_framework/phpbb_test_case.php
@@ -0,0 +1,30 @@
+<?php
+
+class phpbb_test_case extends PHPUnit_Framework_TestCase
+{
+ protected $expectedTriggerError = false;
+
+ public function setExpectedTriggerError($errno, $message = '')
+ {
+ $exceptionName = '';
+ switch ($errno)
+ {
+ case E_NOTICE:
+ case E_STRICT:
+ PHPUnit_Framework_Error_Notice::$enabled = true;
+ $exceptionName = 'PHPUnit_Framework_Error_Notice';
+ break;
+
+ case E_WARNING:
+ PHPUnit_Framework_Error_Warning::$enabled = true;
+ $exceptionName = 'PHPUnit_Framework_Error_Warning';
+ break;
+
+ default:
+ $exceptionName = 'PHPUnit_Framework_Error';
+ break;
+ }
+ $this->expectedTriggerError = true;
+ $this->setExpectedException($exceptionName, (string) $message, $errno);
+ }
+} \ No newline at end of file
diff --git a/tests/text_processing/all_tests.php b/tests/text_processing/all_tests.php
new file mode 100644
index 0000000000..d53dd1127e
--- /dev/null
+++ b/tests/text_processing/all_tests.php
@@ -0,0 +1,41 @@
+<?php
+/**
+*
+* @package testing
+* @version $Id$
+* @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_text_processing_all_tests::main');
+}
+
+require_once 'test_framework/framework.php';
+require_once 'PHPUnit/TextUI/TestRunner.php';
+
+require_once 'text_processing/make_clickable.php';
+
+class phpbb_text_processing_all_tests
+{
+ public static function main()
+ {
+ PHPUnit_TextUI_TestRunner::run(self::suite());
+ }
+
+ public static function suite()
+ {
+ $suite = new PHPUnit_Framework_TestSuite('phpBB Text Processing Tools');
+
+ $suite->addTestSuite('phpbb_text_processing_make_clickable_test');
+
+ return $suite;
+ }
+}
+
+if (PHPUnit_MAIN_METHOD == 'phpbb_text_processing_all_tests::main')
+{
+ phpbb_text_processing_all_tests::main();
+}
diff --git a/tests/text_processing/make_clickable.php b/tests/text_processing/make_clickable.php
new file mode 100644
index 0000000000..25199c428a
--- /dev/null
+++ b/tests/text_processing/make_clickable.php
@@ -0,0 +1,106 @@
+<?php
+/**
+*
+* @package testing
+* @version $Id$
+* @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/functions.php';
+require_once '../phpBB/includes/functions_content.php';
+
+class phpbb_text_processing_make_clickable_test extends phpbb_test_case
+{
+ public static function make_clickable_data()
+ {
+ // value => whether it should work
+ $prefix_texts = array(
+ '' => true,
+ "np \n" => true,
+ 'bp text ' => true,
+ 'cp text>' => true,
+ 'ep text.' => array('w' => false), // doesn't work for www. type urls, but for everything else
+ );
+ $suffix_texts = array(
+ '' => true,
+ "\n ns" => true,
+ ' bs text.' => true,
+ '&gt;cs text' => true,
+ '&quot;ds text' => true,
+ '. es text.' => true,
+ ', fs text.' => true,
+ );
+
+ $urls = array(
+ 'http://example.com' => array('tag' => 'm', 'url' => false, 'text' => false), // false means same as key
+ 'http://example.com/' => array('tag' => 'm', 'url' => false, 'text' => false),
+ 'http://example.com/path?query=abc' => array('tag' => 'm', 'url' => false, 'text' => false),
+ 'http://example.com/1' => array('tag' => 'm', 'url' => false, 'text' => false),
+ 'http://example.com/some/very/long/path/with/over/55/characters?and=a&amp;long=query&amp;too=1' => array('tag' => 'm', 'url' => false, 'text' => 'http://example.com/some/very/long/path/ ... uery&amp;too=1'),
+ 'http://localhost' => array('tag' => 'm', 'url' => false, 'text' => false),
+ 'http://localhost/#abc' => array('tag' => 'm', 'url' => false, 'text' => false),
+
+ 'www.example.com/path/' => array('tag' => 'w', 'url' => 'http://www.example.com/path/', 'text' => false),
+ 'randomwww.example.com/path/' => false,
+
+ 'http://thisdomain.org' => array('tag' => 'm', 'url' => false, 'text' => false),
+ 'http://thisdomain.org/' => array('tag' => 'm', 'url' => false, 'text' => false),
+ 'http://thisdomain.org/1' => array('tag' => 'l', 'url' => false, 'text' => '1'),
+ 'http://thisdomain.org/path/some?query=abc#test' => array('tag' => 'l', 'url' => false, 'text' => 'path/some?query=abc#test'),
+
+ 'javascript:www.example.com/' => false,
+ );
+
+ $test_data = array();
+
+ // run the test for each combination
+ foreach ($prefix_texts as $prefix => $prefix_success)
+ {
+ foreach ($suffix_texts as $suffix => $suffix_success)
+ {
+ foreach ($urls as $url => $url_type)
+ {
+ $input = $prefix . $url . $suffix;
+ // no valid url => no change
+ $output = $input;
+
+ if (
+ ($prefix_success && $suffix_success && is_array($url_type)) &&
+ // handle except syntax for prefix/suffix
+ (!is_array($prefix_success) || !isset($prefix_success[$url_type['tag']]) || $prefix_success[$url_type['tag']] == true) &&
+ (!is_array($suffix_success) || !isset($suffix_success[$url_type['tag']]) || $suffix_success[$url_type['tag']] == true)
+ )
+ {
+ // false means it's the same as the url, less typing
+ $url_type['url'] = ($url_type['url']) ? $url_type['url'] : $url;
+ $url_type['text'] = ($url_type['text']) ? $url_type['text'] : $url;
+
+ $class = ($url_type['tag'] === 'l') ? 'postlink-local' : 'postlink';
+
+ // replace the url with the desired output format
+ $output = $prefix . '<!-- ' . $url_type['tag'] . ' --><a class="' . $class . '" href="' . $url_type['url'] . '">' . $url_type['text'] . '</a><!-- ' . $url_type['tag'] . ' -->' . $suffix;
+ }
+ $test_data[] = array($input, $output);
+ }
+ }
+ }
+
+ return $test_data;
+ }
+
+ /**
+ * @dataProvider make_clickable_data
+ */
+ public function test_make_clickable($input, $expected)
+ {
+ $result = make_clickable($input, 'http://thisdomain.org');
+
+ $label = 'Making text clickable: ' . $input;
+ $this->assertEquals($expected, $result, $label);
+ }
+
+}
diff --git a/tests/utf/all_tests.php b/tests/utf/all_tests.php
new file mode 100644
index 0000000000..bccabf6529
--- /dev/null
+++ b/tests/utf/all_tests.php
@@ -0,0 +1,43 @@
+<?php
+/**
+*
+* @package testing
+* @version $Id$
+* @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_utf_all_tests::main');
+}
+
+require_once 'test_framework/framework.php';
+require_once 'PHPUnit/TextUI/TestRunner.php';
+
+require_once 'utf/utf8_wordwrap_test.php';
+require_once 'utf/utf8_clean_string_test.php';
+
+class phpbb_utf_all_tests
+{
+ public static function main()
+ {
+ PHPUnit_TextUI_TestRunner::run(self::suite());
+ }
+
+ public static function suite()
+ {
+ $suite = new PHPUnit_Framework_TestSuite('phpBB Unicode Transformation Format');
+
+ $suite->addTestSuite('phpbb_utf_utf8_wordwrap_test');
+ $suite->addTestSuite('phpbb_utf_utf8_clean_string_test');
+
+ return $suite;
+ }
+}
+
+if (PHPUnit_MAIN_METHOD == 'phpbb_utf_all_tests::main')
+{
+ phpbb_utf_all_tests::main();
+}
diff --git a/tests/utf/utf8_clean_string_test.php b/tests/utf/utf8_clean_string_test.php
new file mode 100644
index 0000000000..bd9e3f5f26
--- /dev/null
+++ b/tests/utf/utf8_clean_string_test.php
@@ -0,0 +1,32 @@
+<?php
+/**
+*
+* @package testing
+* @version $Id$
+* @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/utf/utf_tools.php';
+
+class phpbb_utf_utf8_clean_string_test extends phpbb_test_case
+{
+ public static function cleanable_strings()
+ {
+ return array(
+ array('MiXed CaSe', 'mixed case', 'Checking case folding'),
+ array(' many spaces ', 'many spaces', 'Checking whitespace reduction'),
+ array("we\xC2\xA1rd\xE1\x9A\x80ch\xCE\xB1r\xC2\xADacters", 'weird characters', 'Checking confusables replacement'),
+ );
+ }
+
+ /**
+ * @dataProvider cleanable_strings
+ */
+ public function test_utf8_clean_string($input, $output, $label)
+ {
+ $this->assertEquals($output, utf8_clean_string($input), $label);
+ }
+}
diff --git a/tests/utf/utf8_wordwrap_test.php b/tests/utf/utf8_wordwrap_test.php
new file mode 100644
index 0000000000..51245ec418
--- /dev/null
+++ b/tests/utf/utf8_wordwrap_test.php
@@ -0,0 +1,84 @@
+<?php
+/**
+*
+* @package testing
+* @version $Id$
+* @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/utf/utf_tools.php';
+
+class phpbb_utf_utf8_wordwrap_test extends phpbb_test_case
+{
+ public function test_utf8_wordwrap_ascii()
+ {
+ // if the input is all ascii it should work exactly like php's wordwrap
+
+ $text = 'The quick brown fox jumped over the lazy dog.';
+
+ $php_wordwrap = wordwrap($text, 20);
+ $phpbb_utf8_wordwrap = utf8_wordwrap($text, 20);
+ $this->assertEquals($php_wordwrap, $phpbb_utf8_wordwrap, "Checking ASCII standard behaviour with length 20");
+
+ $php_wordwrap = wordwrap($text, 30, "<br />\n");
+ $phpbb_utf8_wordwrap = utf8_wordwrap($text, 30, "<br />\n");
+ $this->assertEquals($php_wordwrap, $phpbb_utf8_wordwrap, "Checking ASCII special break string with length 30");
+
+ $text = 'A very long woooooooooooord.';
+
+ $php_wordwrap = wordwrap($text, 8, "\n");
+ $phpbb_utf8_wordwrap = utf8_wordwrap($text, 8, "\n");
+ $this->assertEquals($php_wordwrap, $phpbb_utf8_wordwrap, 'Checking ASCII not cutting long words');
+
+ $php_wordwrap = wordwrap($text, 8, "\n", true);
+ $phpbb_utf8_wordwrap = utf8_wordwrap($text, 8, "\n", true);
+ $this->assertEquals($php_wordwrap, $phpbb_utf8_wordwrap, 'Checking ASCII cutting long words');
+ }
+
+ /**
+ * Helper function that generates meaningless greek text
+ */
+ private function turn_into_greek($string)
+ {
+ $greek_chars = array("\xCE\x90", "\xCE\x91", "\xCE\x92", "\xCE\x93", "\xCE\x94", "\xCE\x95", "\xCE\x96", "\xCE\x97", "\xCE\x98", "\xCE\x99");
+
+ $greek = '';
+ for ($i = 0, $n = strlen($string); $i < $n; $i++)
+ {
+ // replace each number with the character from the array
+ if (ctype_digit($string[$i]))
+ {
+ $greek .= $greek_chars[(int) $string[$i]];
+ }
+ else
+ {
+ $greek .= $string[$i];
+ }
+ }
+
+ return $greek;
+ }
+
+ public function test_utf8_wordwrap_utf8()
+ {
+ $text = "0123456 0123 012345 01234";
+ $greek = $this->turn_into_greek($text);
+
+ $expected = $this->turn_into_greek(wordwrap($text, 10));
+ $phpbb_utf8_wordwrap = utf8_wordwrap($greek, 10);
+ $this->assertEquals($expected, $phpbb_utf8_wordwrap, 'Checking UTF-8 standard behaviour with length 10');
+ }
+
+ public function test_utf8_wordwrap_utf8_cut()
+ {
+ $text = "0123456 0123 012345 01234";
+ $greek = $this->turn_into_greek($text);
+
+ $expected = $this->turn_into_greek(wordwrap($text, 5, "\n", true));
+ $phpbb_utf8_wordwrap = utf8_wordwrap($greek, 5, "\n", true);
+ $this->assertEquals($expected, $phpbb_utf8_wordwrap, 'Checking UTF-8 cutting long words');
+ }
+}